diff --git a/TESTING.md b/TESTING.md index a3d0ad770bc9..7ce657931f45 100644 --- a/TESTING.md +++ b/TESTING.md @@ -270,5 +270,25 @@ Here is an example that clears the bucket created in Step 3 with a timeout of 5 RemoteStorageHelper.forceDelete(storage, bucket, 5, TimeUnit.SECONDS); ``` +### Testing code that uses Translate + +`RemoteTranslateHelper` contains convenience methods to make is easier to run tests against the +Google Translate service. + +1. Create a test Google Cloud project. + +2. Follow [Translate Quickstart](https://cloud.google.com/translate/v2/quickstart) to get an API +key. + +3. Create a `RemoteTranslateHelper` object using your project ID and API key. Here is an example +that uses the `RemoteTranslateHelper` to list supported languages. + ```java + RemoteTranslateHelper translateHelper = RemoteTranslateHelper.create(PROJECT_ID, API_KEY); + Translate translate = translateHelper.options().service(); + List languages = translate.listSupportedLanguages(); + ``` + +4. Run your tests. + [cloud-platform-storage-authentication]:https://cloud.google.com/storage/docs/authentication?hl=en#service_accounts [create-service-account]:https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount diff --git a/gcloud-java-examples/src/main/java/com/google/cloud/examples/translate/TranslateExample.java b/gcloud-java-examples/src/main/java/com/google/cloud/examples/translate/TranslateExample.java index 3b2e10a7bee8..0e9666d23818 100644 --- a/gcloud-java-examples/src/main/java/com/google/cloud/examples/translate/TranslateExample.java +++ b/gcloud-java-examples/src/main/java/com/google/cloud/examples/translate/TranslateExample.java @@ -169,27 +169,32 @@ private static void printUsage() { actionAndParams.append(' ').append(param); } } - System.out.printf("Usage: %s [] operation *%s%n", + System.out.printf("Usage: %s [] [] operation *%s%n", TranslateExample.class.getSimpleName(), actionAndParams); } @SuppressWarnings("unchecked") public static void main(String... args) throws Exception { - if (args.length < 2) { - System.out.println("Missing required api key and action"); + if (args.length < 1) { + System.out.println("Missing required action"); printUsage(); return; } - TranslateOptions.Builder optionsBuilder = TranslateOptions.builder(args[0]); + TranslateOptions.Builder optionsBuilder = TranslateOptions.builder(); TranslateAction action; String actionName; if (args.length >= 3 && !ACTIONS.containsKey(args[1])) { + optionsBuilder.apiKey(args[0]); actionName = args[2]; optionsBuilder.targetLanguage(args[1]); args = Arrays.copyOfRange(args, 3, args.length); - } else { + } else if (args.length >= 2 && !ACTIONS.containsKey(args[0])) { + optionsBuilder.apiKey(args[0]); actionName = args[1]; args = Arrays.copyOfRange(args, 2, args.length); + } else { + actionName = args[0]; + args = Arrays.copyOfRange(args, 1, args.length); } action = ACTIONS.get(actionName); if (action == null) { diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateOptions.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateOptions.java index 12973b360b92..86f3507aed01 100644 --- a/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateOptions.java +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateOptions.java @@ -17,6 +17,7 @@ package com.google.cloud.translate; import static com.google.common.base.MoreObjects.firstNonNull; +import static com.google.common.base.Preconditions.checkArgument; import com.google.cloud.AuthCredentials; import com.google.cloud.HttpServiceOptions; @@ -34,6 +35,7 @@ public class TranslateOptions extends HttpServiceOptions { private static final long serialVersionUID = 5997441123713672886L; + private static final String API_KEY_ENV_NAME = "GOOGLE_API_KEY"; private static final Set SCOPES = ImmutableSet.of(); private final String apiKey; @@ -62,12 +64,10 @@ public TranslateRpc create(TranslateOptions options) { public static class Builder extends HttpServiceOptions.Builder { - private final String apiKey; + private String apiKey; private String targetLanguage; - private Builder(String apiKey) { - this.apiKey = apiKey; - } + private Builder() {} private Builder(TranslateOptions options) { super(options); @@ -96,6 +96,16 @@ public Builder authCredentials(AuthCredentials authCredentials) { return self(); } + /** + * Sets the API key used to issue requets. If not set, the API key is looked for in the + * {@code GOOGLE_API_KEY} environment variable. For instructions on how to get an API key see + * Translate quickstart. + */ + public Builder apiKey(String apiKey) { + this.apiKey = apiKey; + return this; + } + /** * Sets the code for the default target language. If not set, english ({@code en}) is used. * {@link Translate#translate(List, TranslateOption...)} and @@ -112,13 +122,18 @@ public Builder targetLanguage(String targetLanguage) { @Override public TranslateOptions build() { + // Auth credentials are not used by Translate + authCredentials(AuthCredentials.noAuth()); return new TranslateOptions(this); } } private TranslateOptions(Builder builder) { super(TranslateFactory.class, TranslateRpcFactory.class, builder); - this.apiKey = builder.apiKey; + this.apiKey = builder.apiKey != null ? builder.apiKey : defaultApiKey(); + checkArgument(this.apiKey != null, + "An API key is required for this service but could not be determined from the builder " + + "or the environment. Please set an API key using the builder."); this.targetLanguage = firstNonNull(builder.targetLanguage, Locale.ENGLISH.getLanguage()); } @@ -142,6 +157,10 @@ protected Set scopes() { return SCOPES; } + protected String defaultApiKey() { + return System.getProperty(API_KEY_ENV_NAME, System.getenv(API_KEY_ENV_NAME)); + } + /** * Returns the API key, to be used used to send requests. */ @@ -156,15 +175,6 @@ public String targetLanguage() { return targetLanguage; } - /** - * Returns a default {@code TranslateOptions} instance given an API key. For instructions on - * how to get an API key see Translate - * quickstart. - */ - public static TranslateOptions defaultInstance(String apiKey) { - return builder(apiKey).build(); - } - @SuppressWarnings("unchecked") @Override public Builder toBuilder() { @@ -188,11 +198,16 @@ public boolean equals(Object obj) { } /** - * Creates a builder for {@code TranslateOptions} objects given an api key. For instructions on - * how to get an API key see Translate - * quickstart. + * Returns a default {@code TranslateOptions} instance. + */ + public static TranslateOptions defaultInstance() { + return builder().build(); + } + + /** + * Returns a builder for {@code TranslateOptions} objects. */ - public static Builder builder(String apiKey) { - return new Builder(apiKey); + public static Builder builder() { + return new Builder(); } } diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/testing/RemoteTranslateHelper.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/testing/RemoteTranslateHelper.java new file mode 100644 index 000000000000..a903d08ddb9b --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/testing/RemoteTranslateHelper.java @@ -0,0 +1,83 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate.testing; + +import com.google.cloud.RetryParams; +import com.google.cloud.translate.TranslateOptions; + +/** + * Utility to create a remote translate configuration for testing. Translate options can be obtained + * via the {@link #options()} method. Returned options have custom + * {@link TranslateOptions#retryParams()}: {@link RetryParams#retryMaxAttempts()} is {@code 10}, + * {@link RetryParams#retryMinAttempts()} is {@code 6}, {@link RetryParams#maxRetryDelayMillis()} + * is {@code 30000}, {@link RetryParams#totalRetryPeriodMillis()} is {@code 120000} and + * {@link RetryParams#initialRetryDelayMillis()} is {@code 250}. + * {@link TranslateOptions#connectTimeout()} and {@link TranslateOptions#readTimeout()} are both set + * to {@code 60000}. + */ +public class RemoteTranslateHelper { + + private final TranslateOptions options; + + private RemoteTranslateHelper(TranslateOptions options) { + this.options = options; + } + + /** + * Returns a {@link TranslateOptions} object to be used for testing. + */ + public TranslateOptions options() { + return options; + } + + /** + * Creates a {@code RemoteTranslateHelper} object for the given API key. + * + * @param apiKey API key used to issue requests to Google Translate. + */ + public static RemoteTranslateHelper create(String apiKey) { + TranslateOptions translateOptions = TranslateOptions.builder() + .apiKey(apiKey) + .retryParams(retryParams()) + .connectTimeout(60000) + .readTimeout(60000) + .build(); + return new RemoteTranslateHelper(translateOptions); + } + + /** + * Creates a {@code RemoteStorageHelper} object. + */ + public static RemoteTranslateHelper create() { + TranslateOptions translateOption = TranslateOptions.builder() + .retryParams(retryParams()) + .connectTimeout(60000) + .readTimeout(60000) + .build(); + return new RemoteTranslateHelper(translateOption); + } + + private static RetryParams retryParams() { + return RetryParams.builder() + .retryMaxAttempts(10) + .retryMinAttempts(6) + .maxRetryDelayMillis(30000) + .totalRetryPeriodMillis(120000) + .initialRetryDelayMillis(250) + .build(); + } +} diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/testing/package-info.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/testing/package-info.java new file mode 100644 index 000000000000..02f64ebeb689 --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/testing/package-info.java @@ -0,0 +1,30 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A testing helper for Google Translate. + * + *

A simple usage example: + *

Before the test: + *

 {@code
+ * RemoteTranslateHelper helper = RemoteTranslateHelper.create();
+ * Translate translate = helper.options().service();
+ * } 
+ * + * @see + * gcloud-java tools for testing + */ +package com.google.cloud.translate.testing; diff --git a/gcloud-java-translate/src/test/java/com/google/cloud/translate/SerializationTest.java b/gcloud-java-translate/src/test/java/com/google/cloud/translate/SerializationTest.java new file mode 100644 index 000000000000..adc597a56301 --- /dev/null +++ b/gcloud-java-translate/src/test/java/com/google/cloud/translate/SerializationTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import com.google.api.services.translate.model.DetectionsResourceItems; +import com.google.api.services.translate.model.TranslationsResource; +import com.google.cloud.AuthCredentials; +import com.google.cloud.BaseSerializationTest; +import com.google.cloud.Restorable; + +import java.io.Serializable; + +public class SerializationTest extends BaseSerializationTest { + + private static final String API_KEY = "apiKey"; + private static final String LANGUAGE = "en"; + private static final float CONFIDENCE = 0.42F; + private static final DetectionsResourceItems DETECTION_PB = + new DetectionsResourceItems().setLanguage(LANGUAGE).setConfidence(CONFIDENCE); + private static final Detection DETECTION = Detection.fromPb(DETECTION_PB); + private static final String TRANSLATED_TEXT = "Hello world"; + private static final TranslationsResource TRANSLATION_PB = new TranslationsResource() + .setTranslatedText(TRANSLATED_TEXT) + .setDetectedSourceLanguage(LANGUAGE); + private static final Translation TRANSLATION = Translation.fromPb(TRANSLATION_PB); + private static final TranslateException TRANSLATE_EXCEPTION = + new TranslateException(42, "message"); + private static final Translate.LanguageListOption LANGUAGE_LIST_OPTION = + Translate.LanguageListOption.targetLanguage(LANGUAGE); + private static final Translate.TranslateOption TRANSLATE_OPTION = + Translate.TranslateOption.sourceLanguage(LANGUAGE); + + @Override + protected Serializable[] serializableObjects() { + TranslateOptions options = TranslateOptions.builder() + .apiKey(API_KEY) + .authCredentials(AuthCredentials.createForAppEngine()) + .build(); + TranslateOptions otherOptions = options.toBuilder() + .authCredentials(null) + .build(); + return new Serializable[]{DETECTION, TRANSLATION, TRANSLATE_EXCEPTION, LANGUAGE_LIST_OPTION, + TRANSLATE_OPTION, options, otherOptions}; + } + + @Override + protected Restorable[] restorableObjects() { + return null; + } +} diff --git a/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateImplTest.java b/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateImplTest.java index 92f0f3cfad50..5c98c2c0cd23 100644 --- a/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateImplTest.java +++ b/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateImplTest.java @@ -105,7 +105,8 @@ public void setUp() { EasyMock.expect(rpcFactoryMock.create(EasyMock.anyObject(TranslateOptions.class))) .andReturn(translateRpcMock); EasyMock.replay(rpcFactoryMock); - options = TranslateOptions.builder(API_KEY) + options = TranslateOptions.builder() + .apiKey(API_KEY) .serviceRpcFactory(rpcFactoryMock) .retryParams(RetryParams.noRetries()) .build(); diff --git a/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateTest.java b/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateTest.java new file mode 100644 index 000000000000..899ee32a7109 --- /dev/null +++ b/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import static org.junit.Assert.assertEquals; + +import com.google.cloud.translate.Translate.LanguageListOption; +import com.google.cloud.translate.Translate.TranslateOption; +import com.google.cloud.translate.spi.TranslateRpc; + +import org.junit.Test; + +public class TranslateTest { + + private static final String LANGUAGE = "en"; + + @Test + public void testListOptions() { + // target language + LanguageListOption listOption = LanguageListOption.targetLanguage(LANGUAGE); + assertEquals(TranslateRpc.Option.TARGET_LANGUAGE, listOption.rpcOption()); + assertEquals(LANGUAGE, listOption.value()); + } + + @Test + public void testTranslateOptions() { + // target language + TranslateOption translateOption = TranslateOption.targetLanguage(LANGUAGE); + assertEquals(TranslateRpc.Option.TARGET_LANGUAGE, translateOption.rpcOption()); + assertEquals(LANGUAGE, translateOption.value()); + // source language + translateOption = TranslateOption.sourceLanguage(LANGUAGE); + assertEquals(TranslateRpc.Option.SOURCE_LANGUAGE, translateOption.rpcOption()); + assertEquals(LANGUAGE, translateOption.value()); + } +} diff --git a/gcloud-java-translate/src/test/java/com/google/cloud/translate/it/ITTranslateTest.java b/gcloud-java-translate/src/test/java/com/google/cloud/translate/it/ITTranslateTest.java new file mode 100644 index 000000000000..c92c09b5ac14 --- /dev/null +++ b/gcloud-java-translate/src/test/java/com/google/cloud/translate/it/ITTranslateTest.java @@ -0,0 +1,125 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate.it; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.google.cloud.translate.Detection; +import com.google.cloud.translate.Language; +import com.google.cloud.translate.Translate; +import com.google.cloud.translate.Translate.LanguageListOption; +import com.google.cloud.translate.Translate.TranslateOption; +import com.google.cloud.translate.Translation; +import com.google.cloud.translate.testing.RemoteTranslateHelper; +import com.google.common.collect.ImmutableList; + +import org.junit.Test; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class ITTranslateTest { + + private static final Translate TRANSLATE = RemoteTranslateHelper.create().options().service(); + private static final String[] LANGUAGES = {"af", "sq", "ar", "hy", "az", "eu", "be", "bn", "bs", + "bg", "ca", "ceb", "ny", "zh-TW", "hr", "cs", "da", "nl", "en", "eo", "et", "tl", "fi", "fr", + "gl", "ka", "de", "el", "gu", "ht", "ha", "iw", "hi", "hmn", "hu", "is", "ig", "id", "ga", + "it", "ja", "jw", "kn", "kk", "km", "ko", "lo", "la", "lv", "lt", "mk", "mg", "ms", "ml", + "mt", "mi", "mr", "mn", "my", "ne", "no", "fa", "pl", "pt", "ro", "ru", "sr", "st", "si", + "sk", "sl", "so", "es", "su", "sw", "sv", "tg", "ta", "te", "th", "tr", "uk", "ur", "uz", + "vi", "cy", "yi", "yo", "zu"}; + + @Test + public void testListSupportedLanguages() { + Set supportedLanguages = new HashSet<>(); + List languages = TRANSLATE.listSupportedLanguages(); + for (Language language : languages) { + supportedLanguages.add(language.code()); + assertNotNull(language.name()); + } + for (String code : LANGUAGES) { + assertTrue(supportedLanguages.contains(code)); + } + } + + @Test + public void testListSupportedLanguagesWithOptions() { + Set supportedLanguages = new HashSet<>(); + List languages = TRANSLATE.listSupportedLanguages( + LanguageListOption.targetLanguage("es")); + for (Language language : languages) { + supportedLanguages.add(language.code()); + assertNotNull(language.name()); + } + for (String code : LANGUAGES) { + assertTrue(supportedLanguages.contains(code)); + } + } + + @Test + public void testDetectLanguageOfTexts() { + List detections = TRANSLATE.detect("Hello", "Hallo"); + Detection detection = detections.get(0); + assertEquals("en", detection.language()); + detection = detections.get(1); + assertEquals("de", detection.language()); + } + + @Test + public void testDetectLanguageOfTextList() { + List detections = TRANSLATE.detect(ImmutableList.of("Hello", "Hallo")); + Detection detection = detections.get(0); + assertEquals("en", detection.language()); + detection = detections.get(1); + assertEquals("de", detection.language()); + } + + @Test + public void testDetectLanguageOfText() { + Detection detection = TRANSLATE.detect("Hello"); + assertEquals("en", detection.language()); + } + + @Test + public void testTranslateTextList() { + List translations = TRANSLATE.translate(ImmutableList.of("Hola", "Hallo")); + Translation translation = translations.get(0); + assertEquals("Hello", translation.translatedText()); + assertEquals("es", translation.sourceLanguage()); + translation = translations.get(1); + assertEquals("Hello", translation.translatedText()); + assertEquals("de", translation.sourceLanguage()); + } + + @Test + public void testTranslateText() { + Translation translation = TRANSLATE.translate("Hola"); + assertEquals("Hello", translation.translatedText()); + assertEquals("es", translation.sourceLanguage()); + } + + @Test + public void testTranslateTextWithOptions() { + Translation translation = TRANSLATE.translate("Hola", + TranslateOption.sourceLanguage("es"), TranslateOption.targetLanguage("de")); + assertEquals("Hallo", translation.translatedText()); + assertEquals("es", translation.sourceLanguage()); + } +}