From e05f9e0ce5b4ef6cc2c7826e2925f03c9798bcea Mon Sep 17 00:00:00 2001 From: Marco Ziccardi Date: Fri, 12 Aug 2016 11:54:06 +0200 Subject: [PATCH] Add Translate.listSupportedLanguages method and tests --- .../com/google/cloud/translate/Option.java | 72 ++++++++ .../com/google/cloud/translate/Translate.java | 46 +++++ .../google/cloud/translate/TranslateImpl.java | 64 +++++++ .../cloud/translate/TranslateOptions.java | 12 +- .../google/cloud/translate/OptionTest.java | 62 +++++++ .../cloud/translate/TranslateImplTest.java | 158 ++++++++++++++++++ 6 files changed, 410 insertions(+), 4 deletions(-) create mode 100644 gcloud-java-translate/src/main/java/com/google/cloud/translate/Option.java create mode 100644 gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateImpl.java create mode 100644 gcloud-java-translate/src/test/java/com/google/cloud/translate/OptionTest.java create mode 100644 gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateImplTest.java diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/Option.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/Option.java new file mode 100644 index 000000000000..7fc05678e39e --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/Option.java @@ -0,0 +1,72 @@ +/* + * 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 com.google.common.base.Preconditions.checkNotNull; + +import com.google.cloud.translate.spi.TranslateRpc; +import com.google.common.base.MoreObjects; + +import java.io.Serializable; +import java.util.Objects; + +/** + * Base class for Translate operation option. + */ +abstract class Option implements Serializable { + + private static final long serialVersionUID = 8546712558603322394L; + + private final TranslateRpc.Option rpcOption; + private final Object value; + + Option(TranslateRpc.Option rpcOption, Object value) { + this.rpcOption = checkNotNull(rpcOption); + this.value = value; + } + + TranslateRpc.Option rpcOption() { + return rpcOption; + } + + Object value() { + return value; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Option)) { + return false; + } + Option other = (Option) obj; + return Objects.equals(rpcOption, other.rpcOption) + && Objects.equals(value, other.value); + } + + @Override + public int hashCode() { + return Objects.hash(rpcOption, value); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("name", rpcOption.value()) + .add("value", value) + .toString(); + } +} diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/Translate.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/Translate.java index 1b1a3b9b12be..1d661a978794 100644 --- a/gcloud-java-translate/src/main/java/com/google/cloud/translate/Translate.java +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/Translate.java @@ -17,6 +17,9 @@ package com.google.cloud.translate; import com.google.cloud.Service; +import com.google.cloud.translate.spi.TranslateRpc; + +import java.util.List; /** * An interface for Google Translate. @@ -24,4 +27,47 @@ * @see Google Translate */ public interface Translate extends Service { + + /** + * Class for specifying supported language listing options. + */ + class LanguageListOption extends Option { + + private static final long serialVersionUID = 1982978040516658597L; + + private LanguageListOption(TranslateRpc.Option rpcOption, String value) { + super(rpcOption, value); + } + + /** + * Returns an option for setting the target language. If this option is not provided, the value + * returned by {@link TranslateOptions#targetLanguage()} is used. When provided, the returned + * {@link Language#name()} will be in the language specified by the {@code targetLanguage} code. + * + * @param targetLanguage the target language code + */ + public static LanguageListOption targetLanguage(String targetLanguage) { + return new LanguageListOption(TranslateRpc.Option.TARGET_LANGUAGE, targetLanguage); + } + } + + /** + * Returns the list of languages supported by Google Translate. If + * {@link LanguageListOption#targetLanguage(String)} is provided, {@link Language#name()} values + * are localized according to the provided target language. If no such option is passed, + * {@link Language#name()} values are localized according to + * {@link TranslateOptions#targetLanguage()}. + * + *

Example of listing supported languages, localized according to + * {@link TranslateOptions#targetLanguage()}: + *

 {@code
+   * List languages = translate.listSupportedLanguages();
+   * }
+ * Or according to another target language: + *
 {@code
+   * List languages = translate.listSupportedLanguages(
+   *     LanguageListOption.targetLanguage("es"));
+   * }
+ */ + List listSupportedLanguages(LanguageListOption... options); } diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateImpl.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateImpl.java new file mode 100644 index 000000000000..36d0b3afc863 --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateImpl.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 static com.google.cloud.RetryHelper.runWithRetries; +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.api.services.translate.model.LanguagesResource; +import com.google.cloud.BaseService; +import com.google.cloud.RetryHelper.RetryHelperException; +import com.google.cloud.translate.spi.TranslateRpc; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; + +final class TranslateImpl extends BaseService implements Translate { + + private final TranslateRpc translateRpc; + + TranslateImpl(TranslateOptions options) { + super(options); + translateRpc = options.rpc(); + } + + @Override + public List listSupportedLanguages(final LanguageListOption... options) { + try { + return Lists.transform(runWithRetries(new Callable>() { + @Override + public List call() { + return translateRpc.listSupportedLanguages(optionMap(options)); + } + }, options().retryParams(), EXCEPTION_HANDLER, options().clock()), Language.FROM_PB_FUNCTION); + } catch (RetryHelperException e) { + throw TranslateException.translateAndThrow(e); + } + } + + private Map optionMap(Option... options) { + Map optionMap = Maps.newEnumMap(TranslateRpc.Option.class); + for (Option option : options) { + Object prev = optionMap.put(option.rpcOption(), option.value()); + checkArgument(prev == null, "Duplicate option %s", option); + } + return optionMap; + } +} 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 599d4a1d389f..42d6e200b823 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 @@ -43,9 +43,7 @@ public static class DefaultTranslateFactory implements TranslateFactory { @Override public Translate create(TranslateOptions options) { - return null; - // todo(mziccard) uncomment as soon as TranslateImpl is implemented - // return new TranslateImpl(options); + return new TranslateImpl(options); } } @@ -174,7 +172,13 @@ public int hashCode() { @Override public boolean equals(Object obj) { - return obj instanceof TranslateOptions && baseEquals((TranslateOptions) obj); + if (!(obj instanceof TranslateOptions)) { + return false; + } + TranslateOptions options = (TranslateOptions) obj; + return baseEquals(options) + && apiKey.equals(options.apiKey) + && targetLanguage.equals(options.targetLanguage); } /** diff --git a/gcloud-java-translate/src/test/java/com/google/cloud/translate/OptionTest.java b/gcloud-java-translate/src/test/java/com/google/cloud/translate/OptionTest.java new file mode 100644 index 000000000000..152e5c10c455 --- /dev/null +++ b/gcloud-java-translate/src/test/java/com/google/cloud/translate/OptionTest.java @@ -0,0 +1,62 @@ +/* + * 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 static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; + +import com.google.cloud.translate.spi.TranslateRpc; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class OptionTest { + + private static final TranslateRpc.Option RPC_OPTION = TranslateRpc.Option.SOURCE_LANGUAGE; + private static final String VALUE = "some value"; + private static final String OTHER_VALUE = "another value"; + private static final Option OPTION = new Option(RPC_OPTION, VALUE) {}; + private static final Option OPTION_EQUALS = new Option(RPC_OPTION, VALUE) {}; + private static final Option OPTION_NOT_EQUALS = new Option(RPC_OPTION, OTHER_VALUE) {}; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testEquals() { + assertEquals(OPTION, OPTION_EQUALS); + assertNotEquals(OPTION, OPTION_NOT_EQUALS); + } + + @Test + public void testHashCode() { + assertEquals(OPTION.hashCode(), OPTION_EQUALS.hashCode()); + } + + @Test + public void testConstructor() { + assertEquals(RPC_OPTION, OPTION.rpcOption()); + assertEquals(VALUE, OPTION.value()); + Option option = new Option(RPC_OPTION, null) {}; + assertEquals(RPC_OPTION, option.rpcOption()); + assertNull(option.value()); + thrown.expect(NullPointerException.class); + new Option(null, VALUE) {}; + } +} 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 new file mode 100644 index 000000000000..73bca24c118b --- /dev/null +++ b/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateImplTest.java @@ -0,0 +1,158 @@ +/* + * 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 static org.junit.Assert.assertSame; + +import com.google.api.services.translate.model.LanguagesResource; +import com.google.cloud.RetryParams; +import com.google.cloud.translate.Translate.LanguageListOption; +import com.google.cloud.translate.spi.TranslateRpc; +import com.google.cloud.translate.spi.TranslateRpcFactory; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +import org.easymock.EasyMock; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.util.List; +import java.util.Map; + +public class TranslateImplTest { + + private static final String API_KEY = "api_key"; + private static final String TARGET_LANGUAGE = "es"; + + private static final LanguagesResource LANGUAGE1_PB = + new LanguagesResource().setLanguage("en").setName("english"); + private static final LanguagesResource LANGUAGE2_PB = + new LanguagesResource().setLanguage("es").setName("spanish"); + private static final LanguagesResource LANGUAGE3_PB = + new LanguagesResource().setLanguage("en").setName("inglés"); + private static final LanguagesResource LANGUAGE4_PB = + new LanguagesResource().setLanguage("es").setName("español"); + private static final Language LANGUAGE1 = Language.fromPb(LANGUAGE1_PB); + private static final Language LANGUAGE2 = Language.fromPb(LANGUAGE2_PB); + private static final Language LANGUAGE3 = Language.fromPb(LANGUAGE3_PB); + private static final Language LANGUAGE4 = Language.fromPb(LANGUAGE4_PB); + private static final List LANGUAGES1 = ImmutableList.of(LANGUAGE1, LANGUAGE2); + private static final List LANGUAGES2 = ImmutableList.of(LANGUAGE3, LANGUAGE4); + + // Empty TranslateRpc options + private static final Map EMPTY_RPC_OPTIONS = ImmutableMap.of(); + + // Language list options + private static final LanguageListOption LANGUAGE_LIST_OPTION = + LanguageListOption.targetLanguage(TARGET_LANGUAGE); + private static final Map LANGUAGE_LIST_OPTIONS = ImmutableMap.of( + TranslateRpc.Option.TARGET_LANGUAGE, LANGUAGE_LIST_OPTION.value()); + + private TranslateOptions options; + private TranslateRpcFactory rpcFactoryMock; + private TranslateRpc translateRpcMock; + private Translate translate; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Before + public void setUp() { + rpcFactoryMock = EasyMock.createMock(TranslateRpcFactory.class); + translateRpcMock = EasyMock.createMock(TranslateRpc.class); + EasyMock.expect(rpcFactoryMock.create(EasyMock.anyObject(TranslateOptions.class))) + .andReturn(translateRpcMock); + EasyMock.replay(rpcFactoryMock); + options = TranslateOptions.builder(API_KEY) + .serviceRpcFactory(rpcFactoryMock) + .retryParams(RetryParams.noRetries()) + .build(); + } + + @After + public void tearDown() throws Exception { + EasyMock.verify(rpcFactoryMock, translateRpcMock); + } + + private void initializeService() { + translate = options.service(); + } + + @Test + public void testGetOptions() { + EasyMock.replay(translateRpcMock); + initializeService(); + assertSame(options, translate.options()); + } + + @Test + public void testListSupporteLanguages() { + EasyMock.expect(translateRpcMock.listSupportedLanguages(EMPTY_RPC_OPTIONS)) + .andReturn(ImmutableList.of(LANGUAGE1_PB, LANGUAGE2_PB)); + EasyMock.replay(translateRpcMock); + initializeService(); + assertEquals(LANGUAGES1, translate.listSupportedLanguages()); + } + + @Test + public void testListSupporteLanguagesWithOptions() { + EasyMock.expect(translateRpcMock.listSupportedLanguages(LANGUAGE_LIST_OPTIONS)) + .andReturn(ImmutableList.of(LANGUAGE3_PB, LANGUAGE4_PB)); + EasyMock.replay(translateRpcMock); + initializeService(); + assertEquals(LANGUAGES2, translate.listSupportedLanguages( + LanguageListOption.targetLanguage(TARGET_LANGUAGE))); + } + + @Test + public void testRetryableException() { + EasyMock.expect(translateRpcMock.listSupportedLanguages(EMPTY_RPC_OPTIONS)) + .andThrow(new TranslateException(500, "internalError")) + .andReturn(ImmutableList.of(LANGUAGE1_PB, LANGUAGE2_PB)); + EasyMock.replay(translateRpcMock); + translate = options.toBuilder().retryParams(RetryParams.defaultInstance()).build().service(); + assertEquals(LANGUAGES1, translate.listSupportedLanguages()); + } + + @Test + public void testNonRetryableException() { + String exceptionMessage = "Not Implemented"; + EasyMock.expect(translateRpcMock.listSupportedLanguages(EMPTY_RPC_OPTIONS)) + .andThrow(new TranslateException(501, exceptionMessage)); + EasyMock.replay(translateRpcMock); + translate = options.toBuilder().retryParams(RetryParams.defaultInstance()).build().service(); + thrown.expect(TranslateException.class); + thrown.expectMessage(exceptionMessage); + translate.listSupportedLanguages(); + } + + @Test + public void testRuntimeException() { + String exceptionMessage = "Artificial runtime exception"; + EasyMock.expect(translateRpcMock.listSupportedLanguages(EMPTY_RPC_OPTIONS)) + .andThrow(new RuntimeException(exceptionMessage)); + EasyMock.replay(translateRpcMock); + translate = options.toBuilder().retryParams(RetryParams.defaultInstance()).build().service(); + thrown.expect(TranslateException.class); + thrown.expectMessage(exceptionMessage); + translate.listSupportedLanguages(); + } +}