// 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.adwords.lib.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import com.google.api.ads.adwords.lib.client.AdWordsSession.Builder;
import com.google.api.ads.adwords.lib.client.AdWordsSession.ImmutableAdWordsSession;
import com.google.api.ads.adwords.lib.client.reporting.ReportingConfiguration;
import com.google.api.ads.common.lib.exception.ValidationException;
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.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 java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
/** Tests for {@link AdWordsSession}. */
@RunWith(Parameterized.class)
public class AdWordsSessionTest {
/** 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;
/** A ReportingConfiguration suitable for use in this test. */
private final ReportingConfiguration reportingConfiguration;
@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 AdWordsSessionTest(boolean isImmutable) {
this.isImmutable = isImmutable;
this.credential = new Credential(BearerToken.authorizationHeaderAccessMethod());
this.reportingConfiguration =
new ReportingConfiguration.Builder().skipReportHeader(true).skipReportSummary(true).build();
this.allSettingsBuilder =
new AdWordsSession.Builder()
.withClientCustomerId("customer id")
.withDeveloperToken("developer token")
.withEndpoint("https://www.google.com")
.enablePartialFailure()
.enableValidateOnly()
.withOAuth2Credential(credential)
.withUserAgent("user agent")
.withReportingConfiguration(reportingConfiguration);
}
private AdWordsSession 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());
}
};
}
/** Tests that the builder correctly reads properties from a configuration. */
@Test
public void testReadPropertiesFromConfiguration() throws ValidationException {
PropertiesConfiguration config = new PropertiesConfiguration();
config.setProperty("api.adwords.clientCustomerId", "1234567890");
config.setProperty("api.adwords.userAgent", "FooBar");
config.setProperty("api.adwords.developerToken", "devTokendevTokendevTok");
config.setProperty("api.adwords.isPartialFailure", "false");
AdWordsSession session =
build(new AdWordsSession.Builder().from(config).withOAuth2Credential(credential));
assertEquals("1234567890", session.getClientCustomerId());
assertEquals("FooBar", session.getUserAgent());
assertEquals("devTokendevTokendevTok", session.getDeveloperToken());
assertFalse(session.isPartialFailure());
assertNull(
"reporting configuration should be null if no reporting options are in the config",
session.getReportingConfiguration());
}
/**
* Tests that the builder correctly reads properties from a configuration when reporting options
* are included in the configuration.
*/
@Test
public void testReadPropertiesFromConfigurationWithReportingConfig() throws ValidationException {
PropertiesConfiguration config = new PropertiesConfiguration();
config.setProperty("api.adwords.clientCustomerId", "1234567890");
config.setProperty("api.adwords.userAgent", "FooBar");
config.setProperty("api.adwords.developerToken", "devTokendevTokendevTok");
config.setProperty("api.adwords.isPartialFailure", "false");
config.setProperty("api.adwords.reporting.skipHeader", "true");
config.setProperty("api.adwords.reporting.skipColumnHeader", "true");
config.setProperty("api.adwords.reporting.skipSummary", "false");
config.setProperty("api.adwords.reporting.useRawEnumValues", "false");
AdWordsSession session =
build(new AdWordsSession.Builder().from(config).withOAuth2Credential(credential));
assertEquals("1234567890", session.getClientCustomerId());
assertEquals("FooBar", session.getUserAgent());
assertEquals("devTokendevTokendevTok", session.getDeveloperToken());
assertFalse(session.isPartialFailure());
assertNotNull(
"reporting configuration should not be null if reporting options are in the config",
session.getReportingConfiguration());
assertTrue(session.getReportingConfiguration().isSkipReportHeader());
assertTrue(session.getReportingConfiguration().isSkipColumnHeader());
assertFalse(session.getReportingConfiguration().isSkipReportSummary());
assertFalse(session.getReportingConfiguration().isUseRawEnumValues());
assertNull(
"includeZeroImpressions is not settable from ads.properties, so should be null",
session.getReportingConfiguration().isIncludeZeroImpressions());
}
/** 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.adwords.clientCustomerId", "1234567890");
config.setProperty("api.adwords.userAgent", "FooBar");
config.setProperty("api.adwords.developerToken", "devTokendevTokendevTok");
config.setProperty("api.adwords.isPartialFailure", "false");
config.setProperty("api.adwords.endpoint", badEndpoint);
thrown.expect(ValidationException.class);
thrown.expect(createTriggerMatcher(Matchers.<String>equalTo("endpoint")));
thrown.expectMessage(badEndpoint);
build(new AdWordsSession.Builder().from(config).withOAuth2Credential(credential));
}
/** Tests that the builder correctly reads properties from a configuration. */
@Test
public void testReadPropertiesFromConfiguration_noUserAgent() throws ValidationException {
PropertiesConfiguration config = new PropertiesConfiguration();
AdWordsSession adWordsSession =
build(
new AdWordsSession.Builder()
.from(config)
.withDeveloperToken("devTokendevTokendevTok")
.withOAuth2Credential(credential));
assertEquals(AdWordsSession.UNKNOWN_USER_AGENT, adWordsSession.getUserAgent());
}
/** Tests that the builder correctly reads properties from a configuration. */
@Test
public void testReadPropertiesFromConfiguration_defaultUserAgent() throws ValidationException {
PropertiesConfiguration config = new PropertiesConfiguration();
config.setProperty("api.adwords.userAgent", "INSERT_USERAGENT_HERE");
AdWordsSession adWordsSession =
build(
new AdWordsSession.Builder()
.from(config)
.withDeveloperToken("devTokendevTokendevTok")
.withOAuth2Credential(credential));
assertEquals(AdWordsSession.UNKNOWN_USER_AGENT, adWordsSession.getUserAgent());
}
/** Tests that the builder builds correctly with a default endpoint. */
@Test
public void testBuilder_defaultEndpoint() throws Exception {
AdWordsSession adWordsSession =
build(
new AdWordsSession.Builder()
.withUserAgent("FooBar")
.withOAuth2Credential(credential)
.withDeveloperToken("developerToken"));
assertEquals("FooBar", adWordsSession.getUserAgent());
assertSame(credential, adWordsSession.getOAuth2Credential());
assertEquals(AdWordsSession.DEFAULT_ENDPOINT, adWordsSession.getEndpoint());
assertEquals("developerToken", adWordsSession.getDeveloperToken());
}
/** Tests that the builder builds correctly for OAuth2. */
@Test
public void testBuilder_oAuth2() throws Exception {
AdWordsSession adWordsSession =
build(
new AdWordsSession.Builder()
.withUserAgent("FooBar")
.withEndpoint("https://www.google.com")
.withOAuth2Credential(credential)
.withDeveloperToken("developerToken"));
assertEquals("FooBar", adWordsSession.getUserAgent());
assertSame(credential, adWordsSession.getOAuth2Credential());
assertEquals("https://www.google.com", adWordsSession.getEndpoint());
assertEquals("developerToken", adWordsSession.getDeveloperToken());
}
/**
* 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 {
AdWordsSession.Builder builder =
new AdWordsSession.Builder()
.withUserAgent("FooBar")
.withOAuth2Credential(credential)
.withEndpoint("https://www.google.com")
.withDeveloperToken("developerToken");
assertNotSame(build(builder), build(builder));
}
/** Tests that the builder does not build for no auths. */
@Test
public void testBuilder_noAuths() throws Exception {
thrown.expect(ValidationException.class);
thrown.expectMessage("OAuth2");
build(
new AdWordsSession.Builder()
.withUserAgent("FooBar")
.withEndpoint("https://www.google.com")
.withDeveloperToken("developerToken"));
}
/** Tests that the builder builds with the 'unknown' user agent if none specified. */
@Test
public void testBuilder_noUserAgent() throws Exception {
AdWordsSession adWordsSession =
build(
new AdWordsSession.Builder()
.withOAuth2Credential(credential)
.withEndpoint("https://www.google.com")
.withDeveloperToken("developerToken"));
assertEquals(AdWordsSession.UNKNOWN_USER_AGENT, adWordsSession.getUserAgent());
}
/**
* Tests that the builder builds with the 'unknown' user agent if the default user agent is
* specified.
*/
@Test
public void testBuilder_defaultUserAgent() throws Exception {
AdWordsSession adWordsSession =
build(
new AdWordsSession.Builder()
.withOAuth2Credential(credential)
.withEndpoint("https://www.google.com")
.withUserAgent("INSERT_USERAGENT_HERE")
.withDeveloperToken("developerToken"));
assertEquals(AdWordsSession.UNKNOWN_USER_AGENT, adWordsSession.getUserAgent());
}
/** Tests that using a non-ASCII user agent will fail. */
@Test
public void testBuilder_nonAsciiUserAgent() throws Exception {
String nonAsciiUserAgent = "スーパー";
thrown.expect(ValidationException.class);
thrown.expectMessage("User agent");
thrown.expectMessage("ASCII");
thrown.expectMessage(nonAsciiUserAgent);
build(
new AdWordsSession.Builder()
.withOAuth2Credential(credential)
.withUserAgent(nonAsciiUserAgent)
.withEndpoint("https://www.google.com")
.withDeveloperToken("developerToken"));
}
/** Tests that setting authentication to null errors. */
@Test
public void testSetAuthentication_null() throws Exception {
AdWordsSession adWordsSession =
build(
new AdWordsSession.Builder()
.withUserAgent("FooBar")
.withEndpoint("https://www.google.com")
.withOAuth2Credential(credential)
.withDeveloperToken("developerToken"));
if (isImmutable) {
thrown.expect(UnsupportedOperationException.class);
} else {
thrown.expect(NullPointerException.class);
}
thrown.expectMessage("oAuth2Credential");
adWordsSession.setOAuth2Credential(null);
}
@Test
public void testBuilder_withReportingConfiguration() throws Exception {
ReportingConfiguration reportingConfiguration =
new ReportingConfiguration.Builder().skipReportHeader(true).skipReportSummary(true).build();
AdWordsSession adWordsSession =
build(
new AdWordsSession.Builder()
.withUserAgent("FooBar")
.withEndpoint("https://www.google.com")
.withOAuth2Credential(credential)
.withDeveloperToken("developerToken")
.withReportingConfiguration(reportingConfiguration));
ReportingConfiguration sessionReportingConfig = adWordsSession.getReportingConfiguration();
assertNotNull(
"reporting configuration should not be null when passed to the builder",
sessionReportingConfig);
}
/** Tests that the builder builds correctly with all available settings. */
@Test
public void testBuilder_allSettings() throws Exception {
AdWordsSession adWordsSession = build(allSettingsBuilder);
assertEquals("customer id", adWordsSession.getClientCustomerId());
assertEquals("developer token", adWordsSession.getDeveloperToken());
assertEquals("https://www.google.com", adWordsSession.getEndpoint());
assertTrue(adWordsSession.isPartialFailure());
assertTrue(adWordsSession.isValidateOnly());
assertSame(credential, adWordsSession.getOAuth2Credential());
assertEquals("user agent", adWordsSession.getUserAgent());
assertSame(reportingConfiguration, adWordsSession.getReportingConfiguration());
}
/** Tests that copy builder copies all values correctly. */
@Test
public void testImmutable_copyBuilder() throws Exception {
AdWordsSession adWordsSession = build(allSettingsBuilder);
AdWordsSession copy = build(adWordsSession.newBuilder());
assertNotSame(adWordsSession, copy);
for (Method method : ImmutableAdWordsSession.class.getMethods()) {
if (method.getName().startsWith("get") && method.getParameterTypes().length == 1) {
Object originalAttributeValue = method.invoke(adWordsSession);
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 and reporting configuration as
// the original.
assertSame(adWordsSession.getOAuth2Credential(), copy.getOAuth2Credential());
assertSame(adWordsSession.getReportingConfiguration(), copy.getReportingConfiguration());
}
/** Tests that copy constructor on {@link ImmutableAdWordsSession} copies all values correctly. */
@Test
public void testImmutable_setters_fail() throws Exception {
if (!isImmutable) {
assertTrue("Skipping immutability test because !isImmutable", true);
return;
}
ImmutableAdWordsSession immutableAdWordsSession = allSettingsBuilder.buildImmutable();
// Find each setter method and confirm that the immutable session throws an exception when the
// method is invoked.
for (Method method : ImmutableAdWordsSession.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 = ImmutableAdWordsSession.class.getMethod(getMethodName);
// Get the attribute value from the original session to use in the setter method invocation
// below.
Object attributeValue = getMethod.invoke(immutableAdWordsSession);
// Attempt to invoke the setter on the original session and verify that this
// throws an UnsupportedOperationException.
try {
method.invoke(immutableAdWordsSession, attributeValue);
fail(
"Invocation of setter method "
+ method.getName()
+ " should have failed for an ImmutableAdWordsSession, but it succeeded");
} catch (InvocationTargetException e) {
assertEquals(
"UnsupportedOperationException is expected on set",
UnsupportedOperationException.class,
e.getCause().getClass());
}
}
}
}
}