// Copyright 2011 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.api.ads.dfp.lib.client; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import com.google.api.ads.common.lib.exception.ValidationException; import com.google.api.ads.dfp.lib.client.DfpSession.Builder; import com.google.api.ads.dfp.lib.client.DfpSession.ImmutableDfpSession; import com.google.api.client.auth.oauth2.BearerToken; import com.google.api.client.auth.oauth2.Credential; import com.google.common.collect.Lists; import org.apache.commons.configuration.PropertiesConfiguration; import org.hamcrest.CustomTypeSafeMatcher; import org.hamcrest.Matcher; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import org.mockito.MockitoAnnotations; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; /** * Tests for {@link DfpSession}. */ @RunWith(Parameterized.class) public class DfpSessionTest { /** Whether this test is testing immutable sessions. */ private final boolean isImmutable; /** A Builder with all options explicitly set. */ private final Builder allSettingsBuilder; /** A Credential suitable for use in this test. */ private final Credential credential; @Rule public ExpectedException thrown = ExpectedException.none(); @Parameters(name = "{index}: isImmutable={0}") public static List<Object[]> data() { List<Object[]> data = Lists.newArrayList(); data.add(new Object[] {false}); data.add(new Object[] {true}); return data; } public DfpSessionTest(boolean isImmutable) { this.isImmutable = isImmutable; this.credential = new Credential(BearerToken.authorizationHeaderAccessMethod()); this.allSettingsBuilder = new DfpSession.Builder() .withApplicationName("FooBar") .withEndpoint("https://ads.google.com") .withOAuth2Credential(credential) .withNetworkCode("networkCode"); } private DfpSession build(Builder builder) throws ValidationException { if (isImmutable) { return builder.buildImmutable(); } return builder.build(); } private Matcher<ValidationException> createTriggerMatcher(final Matcher<String> matcher) { return new CustomTypeSafeMatcher<ValidationException>("Trigger") { @Override protected boolean matchesSafely(ValidationException ve) { return matcher.matches(ve.getTrigger()); } }; } @Before public void setUp() { MockitoAnnotations.initMocks(this); } /** * Tests that the builder correctly reads properties from a configuration. */ @Test public void testReadPropertiesFromConfiguration() throws ValidationException { PropertiesConfiguration config = new PropertiesConfiguration(); config.setProperty("api.dfp.email", "email"); config.setProperty("api.dfp.password", "password"); config.setProperty("api.dfp.applicationName", "FooBar"); DfpSession session = new DfpSession.Builder().from(config).withOAuth2Credential(credential).build(); assertEquals(session.getApplicationName(), "FooBar"); assertSame(session.getOAuth2Credential(), credential); assertEquals(session.getEndpoint(), DfpSession.DEFAULT_ENDPOINT); } /** * Tests that the builder correctly reads properties from a configuration. */ @Test public void testReadPropertiesFromConfiguration_badEndpoint() throws ValidationException { String badEndpoint = "3efsdafasd"; PropertiesConfiguration config = new PropertiesConfiguration(); config.setProperty("api.dfp.email", "email"); config.setProperty("api.dfp.password", "password"); config.setProperty("api.dfp.applicationName", "FooBar"); config.setProperty("api.dfp.endpoint", badEndpoint); thrown.expect(ValidationException.class); thrown.expect(createTriggerMatcher(Matchers.<String>equalTo("endpoint"))); thrown.expectMessage(badEndpoint); build(new DfpSession.Builder().from(config).withOAuth2Credential(credential)); } /** * Tests that the builder correctly reads properties from a configuration. */ @Test public void testReadPropertiesFromConfiguration_noApplicationName() throws ValidationException { PropertiesConfiguration config = new PropertiesConfiguration(); thrown.expect(ValidationException.class); thrown.expect(createTriggerMatcher(Matchers.<String>equalTo("applicationName"))); build(new DfpSession.Builder().from(config).withOAuth2Credential(credential)); } /** * Tests that the builder correctly reads properties from a configuration. */ @Test public void testReadPropertiesFromConfiguration_defaultApplicationName() throws ValidationException { PropertiesConfiguration config = new PropertiesConfiguration(); config.setProperty("api.dfp.applicationName", "INSERT_APPLICATION_NAME_HERE"); thrown.expect(ValidationException.class); thrown.expect(createTriggerMatcher(Matchers.<String>equalTo("applicationName"))); build(new DfpSession.Builder().from(config).withOAuth2Credential(credential)); } /** * Tests that the builder builds correctly with a default endpoint. */ @Test public void testBuilder_defaultEndpoint() throws Exception { DfpSession dfpSession = build( new DfpSession.Builder() .withApplicationName("FooBar") .withOAuth2Credential(credential) .withNetworkCode("networkCode")); assertEquals(dfpSession.getApplicationName(), "FooBar"); assertSame(dfpSession.getOAuth2Credential(), credential); assertEquals(dfpSession.getEndpoint(), DfpSession.DEFAULT_ENDPOINT); assertEquals(dfpSession.getNetworkCode(), "networkCode"); } /** * Tests that the builder builds correctly for OAuth2. */ @Test public void testBuilder_oAuth2() throws Exception { DfpSession dfpSession = build(allSettingsBuilder); assertEquals(dfpSession.getApplicationName(), "FooBar"); assertSame(dfpSession.getOAuth2Credential(), credential); assertEquals(dfpSession.getEndpoint(), "https://ads.google.com"); assertEquals(dfpSession.getNetworkCode(), "networkCode"); } /** * Makes sure the builder returns a copy so that making (un-validated) changes * in the builder doesn't mutate previously built objects. */ @Test public void testBuilder_returnsCopies() throws Exception { DfpSession.Builder builder = new DfpSession.Builder() .withApplicationName("FooBar") .withOAuth2Credential(credential) .withNetworkCode("networkCode"); assertNotSame(builder.build(), builder.build()); } /** * Tests that the builder does not build for no auths. */ @Test public void testBuilder_noAuths() throws Exception { thrown.expect(ValidationException.class); thrown.expectMessage(Matchers.<String>equalTo("OAuth2 authentication must be used.")); build( new DfpSession.Builder() .withApplicationName("FooBar") .withEndpoint("https://ads.google.com") .withNetworkCode("networkCode")); } /** * Tests that the builder does not build with no application name. */ @Test public void testBuilder_noApplicationName() throws Exception { thrown.expect(ValidationException.class); thrown.expectMessage( Matchers.<String>equalTo( "Application name must be set and not be the default [INSERT_APPLICATION_NAME_HERE]")); build( new DfpSession.Builder() .withEndpoint("https://ads.google.com") .withNetworkCode("networkCode") .withOAuth2Credential(credential)); } /** * Tests that the builder does not build with default application name. */ @Test public void testBuilder_defaultApplicationName() throws Exception { thrown.expect(ValidationException.class); thrown.expectMessage( Matchers.<String>equalTo( "Application name must be set and not be the default [INSERT_APPLICATION_NAME_HERE]")); build( new DfpSession.Builder() .withEndpoint("https://ads.google.com") .withNetworkCode("networkCode") .withOAuth2Credential(credential) .withApplicationName("INSERT_APPLICATION_NAME_HERE")); } /** * Tests that the builder does not build with a whitespace application name. */ @Test public void testBuilder_whitespaceApplicationName() throws Exception { thrown.expect(ValidationException.class); thrown.expectMessage( Matchers.<String>equalTo( "Application name must be set and not be the default [INSERT_APPLICATION_NAME_HERE]")); build( new DfpSession.Builder() .withEndpoint("https://ads.google.com") .withNetworkCode("networkCode") .withOAuth2Credential(credential) .withApplicationName(" ")); } /** * Tests that setting authentication to null errors. */ @Test public void testSetAutentication_null() throws Exception { DfpSession dfpSession = build( new DfpSession.Builder() .withApplicationName("FooBar") .withEndpoint("https://ads.google.com") .withOAuth2Credential(credential) .withNetworkCode("networkCode")); if (isImmutable) { thrown.expect(UnsupportedOperationException.class); } else { thrown.expect(NullPointerException.class); } thrown.expectMessage("oAuth2Credential"); dfpSession.setOAuth2Credential(null); } /** * Tests that copy builder copies all values correctly. */ @Test public void testImmutable_copyBuilder() throws Exception { DfpSession dfpSession = build(allSettingsBuilder); DfpSession copy = build(dfpSession.newBuilder()); assertNotSame(dfpSession, copy); for (Method method : ImmutableDfpSession.class.getMethods()) { if (method.getName().startsWith("get") && method.getParameterTypes().length == 1) { Object originalAttributeValue = method.invoke(dfpSession); Object copyAttributeValue = method.invoke(copy); assertEquals( "Copied session value does not match original for getter: " + method.getName(), originalAttributeValue, copyAttributeValue); } } // The copy should point to the same OAuth2 credential as the original. assertSame(dfpSession.getOAuth2Credential(), copy.getOAuth2Credential()); } /** * Tests that copy constructor on {@link ImmutableDfpSession} copies all values correctly. */ @Test public void testImmutable_setters_fail() throws Exception { if (!isImmutable) { assertTrue("Skipping immutability test because !isImmutable", true); return; } ImmutableDfpSession immutableDfpSession = allSettingsBuilder.buildImmutable(); // Find each setter method and confirm that the immutable session throws an exception when the // method is invoked. for (Method method : ImmutableDfpSession.class.getMethods()) { if (method.getName().startsWith("set") && method.getParameterTypes().length == 1) { Class<?> parameterType = method.getParameterTypes()[0]; String attributeName = method.getName().substring("set".length()); String getterPrefix = "get"; if (parameterType.equals(boolean.class) || parameterType.equals(Boolean.class)) { getterPrefix = "is"; } String getMethodName = getterPrefix + attributeName.substring(0, 1).toUpperCase() + attributeName.substring(1); Method getMethod = ImmutableDfpSession.class.getMethod(getMethodName); // Get the attribute value from the original session to use in the setter method invocation // below. Object attributeValue = getMethod.invoke(immutableDfpSession); // Attempt to invoke the setter on the original session and verify that this // throws an UnsupportedOperationException. try { method.invoke(immutableDfpSession, attributeValue); fail( "Invocation of setter method " + method.getName() + " should have failed for an ImmutableDfpSession, but it succeeded"); } catch (InvocationTargetException e) { assertEquals( "UnsupportedOperationException is expected on set", UnsupportedOperationException.class, e.getCause().getClass()); } } } } }