Skip to content

Commit

Permalink
Merge pull request #754 from mziccard/serialization-tests
Browse files Browse the repository at this point in the history
Create base class for serialization tests
  • Loading branch information
aozarov committed Mar 18, 2016
2 parents 7d48ec7 + 83ddb08 commit 353d2db
Show file tree
Hide file tree
Showing 15 changed files with 367 additions and 268 deletions.
7 changes: 7 additions & 0 deletions gcloud-java-bigquery/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>gcloud-java-core</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.google.gcloud.RetryHelper.RetryInterruptedException;

import java.io.IOException;
import java.util.Objects;
import java.util.Set;

/**
Expand Down Expand Up @@ -73,6 +74,23 @@ protected Set<Error> retryableErrors() {
return RETRYABLE_ERRORS;
}

@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof BigQueryException)) {
return false;
}
BigQueryException other = (BigQueryException) obj;
return super.equals(other) && Objects.equals(error, other.error);
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), error);
}

/**
* Translate RetryHelperException to the BigQueryException that caused the error. This method will
* always throw an exception.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,19 @@

package com.google.gcloud.bigquery;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gcloud.AuthCredentials;
import com.google.gcloud.RestorableState;
import com.google.gcloud.RetryParams;
import com.google.gcloud.WriteChannel;
import com.google.gcloud.BaseSerializationTest;
import com.google.gcloud.Restorable;
import com.google.gcloud.bigquery.StandardTableDefinition.StreamingBuffer;

import org.junit.Test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

public class SerializationTest {
public class SerializationTest extends BaseSerializationTest {

private static final Acl DOMAIN_ACCESS =
Acl.of(new Acl.Domain("domain"), Acl.Role.WRITER);
Expand Down Expand Up @@ -230,75 +219,40 @@ public class SerializationTest {
new Dataset(BIGQUERY, new DatasetInfo.BuilderImpl(DATASET_INFO));
private static final Table TABLE = new Table(BIGQUERY, new TableInfo.BuilderImpl(TABLE_INFO));
private static final Job JOB = new Job(BIGQUERY, new JobInfo.BuilderImpl(JOB_INFO));
private static final BigQueryException BIG_QUERY_EXCEPTION =
new BigQueryException(42, "message", BIGQUERY_ERROR);

@Test
public void testServiceOptions() throws Exception {
@Override
protected Serializable[] serializableObjects() {
BigQueryOptions options = BigQueryOptions.builder()
.projectId("p1")
.authCredentials(AuthCredentials.createForAppEngine())
.build();
BigQueryOptions serializedCopy = serializeAndDeserialize(options);
assertEquals(options, serializedCopy);

options = options.toBuilder()
BigQueryOptions otherOptions = options.toBuilder()
.projectId("p2")
.retryParams(RetryParams.defaultInstance())
.authCredentials(null)
.build();
serializedCopy = serializeAndDeserialize(options);
assertEquals(options, serializedCopy);
}

@Test
public void testModelAndRequests() throws Exception {
Serializable[] objects = {DOMAIN_ACCESS, GROUP_ACCESS, USER_ACCESS, VIEW_ACCESS, DATASET_ID,
return new Serializable[]{DOMAIN_ACCESS, GROUP_ACCESS, USER_ACCESS, VIEW_ACCESS, DATASET_ID,
DATASET_INFO, TABLE_ID, CSV_OPTIONS, STREAMING_BUFFER, TABLE_DEFINITION,
EXTERNAL_TABLE_DEFINITION, VIEW_DEFINITION, TABLE_SCHEMA, TABLE_INFO, VIEW_INFO,
EXTERNAL_TABLE_INFO, INLINE_FUNCTION, URI_FUNCTION, JOB_STATISTICS, EXTRACT_STATISTICS,
LOAD_STATISTICS, QUERY_STATISTICS, BIGQUERY_ERROR, JOB_STATUS, JOB_ID,
COPY_JOB_CONFIGURATION, EXTRACT_JOB_CONFIGURATION, LOAD_CONFIGURATION,
LOAD_JOB_CONFIGURATION, QUERY_JOB_CONFIGURATION, JOB_INFO, INSERT_ALL_REQUEST,
INSERT_ALL_RESPONSE, FIELD_VALUE, QUERY_REQUEST, QUERY_RESPONSE,
INSERT_ALL_RESPONSE, FIELD_VALUE, QUERY_REQUEST, QUERY_RESPONSE, BIG_QUERY_EXCEPTION,
BigQuery.DatasetOption.fields(), BigQuery.DatasetDeleteOption.deleteContents(),
BigQuery.DatasetListOption.all(), BigQuery.TableOption.fields(),
BigQuery.TableListOption.pageSize(42L), BigQuery.JobOption.fields(),
BigQuery.JobListOption.allUsers(), DATASET, TABLE, JOB};
for (Serializable obj : objects) {
Object copy = serializeAndDeserialize(obj);
assertEquals(obj, obj);
assertEquals(obj, copy);
assertNotSame(obj, copy);
assertEquals(copy, copy);
}
BigQuery.JobListOption.allUsers(), DATASET, TABLE, JOB, options, otherOptions};
}

@Test
public void testWriteChannelState() throws IOException, ClassNotFoundException {
BigQueryOptions options = BigQueryOptions.builder()
.projectId("p2")
.retryParams(RetryParams.defaultInstance())
.build();
@Override
protected Restorable<?>[] restorableObjects() {
BigQueryOptions options = BigQueryOptions.builder().projectId("p2").build();
// avoid closing when you don't want partial writes upon failure
@SuppressWarnings("resource")
TableDataWriteChannel writer =
new TableDataWriteChannel(options, LOAD_CONFIGURATION, "upload-id");
RestorableState<WriteChannel> state = writer.capture();
RestorableState<WriteChannel> deserializedState = serializeAndDeserialize(state);
assertEquals(state, deserializedState);
assertEquals(state.hashCode(), deserializedState.hashCode());
assertEquals(state.toString(), deserializedState.toString());
}

@SuppressWarnings("unchecked")
private <T> T serializeAndDeserialize(T obj)
throws IOException, ClassNotFoundException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (ObjectOutputStream output = new ObjectOutputStream(bytes)) {
output.writeObject(obj);
}
try (ObjectInputStream input =
new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()))) {
return (T) input.readObject();
}
return new Restorable<?>[]{writer};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,20 @@ private static class NoAuthCredentialsState
public AuthCredentials restore() {
return INSTANCE;
}

@Override
public int hashCode() {
return getClass().getName().hashCode();
}

@Override
public boolean equals(Object obj) {
return obj instanceof NoAuthCredentialsState;
}
}

private NoAuthCredentials() {}

@Override
public GoogleCredentials credentials() {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@
*/
public class BaseServiceException extends RuntimeException {

private static final long serialVersionUID = 759921776378760835L;
public static final int UNKNOWN_CODE = 0;

private final int code;
private final boolean retryable;
private final String reason;
private final boolean idempotent;
private final String location;
private final String debugInfo;

protected static final class Error implements Serializable {

private static final long serialVersionUID = -4019600198652965721L;
Expand Down Expand Up @@ -79,16 +89,6 @@ public int hashCode() {
}
}

private static final long serialVersionUID = 759921776378760835L;
public static final int UNKNOWN_CODE = 0;

private final int code;
private final boolean retryable;
private final String reason;
private final boolean idempotent;
private final String location;
private final String debugInfo;

public BaseServiceException(IOException exception, boolean idempotent) {
super(message(exception), exception);
int code = UNKNOWN_CODE;
Expand Down Expand Up @@ -198,6 +198,31 @@ protected String debugInfo() {
return debugInfo;
}

@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof BaseServiceException)) {
return false;
}
BaseServiceException other = (BaseServiceException) obj;
return Objects.equals(getCause(), other.getCause())
&& Objects.equals(getMessage(), other.getMessage())
&& code == other.code
&& retryable == other.retryable
&& Objects.equals(reason, other.reason)
&& idempotent == other.idempotent
&& Objects.equals(location, other.location)
&& Objects.equals(debugInfo, other.debugInfo);
}

@Override
public int hashCode() {
return Objects.hash(getCause(), getMessage(), code, retryable, reason, idempotent, location,
debugInfo);
}

protected static String reason(GoogleJsonError error) {
if (error.getErrors() != null && !error.getErrors().isEmpty()) {
return error.getErrors().get(0).getReason();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Callable;

Expand Down Expand Up @@ -259,6 +260,26 @@ boolean shouldRetry(Exception ex) {
return retryResult == Interceptor.RetryResult.RETRY;
}

@Override
public int hashCode() {
return Objects.hash(interceptors, retriableExceptions, nonRetriableExceptions, retryInfo);
}

@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof ExceptionHandler)) {
return false;
}
ExceptionHandler other = (ExceptionHandler) obj;
return Objects.equals(interceptors, other.interceptors)
&& Objects.equals(retriableExceptions, other.retriableExceptions)
&& Objects.equals(nonRetriableExceptions, other.nonRetriableExceptions)
&& Objects.equals(retryInfo, other.retryInfo);
}

/**
* Returns an instance which retry any checked exception and abort on any runtime exception.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* 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.gcloud;

import static com.google.common.base.MoreObjects.firstNonNull;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;

import org.junit.Test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
* Base class for serialization tests. To use this class in your tests override the
* {@code serializableObjects()} method to return all objects that must be serializable. Also
* override {@code restorableObjects()} method to return all restorable objects whose state must be
* tested for proper serialization. Both methods can return {@code null} if no such object needs to
* be tested.
*/
public abstract class BaseSerializationTest {

/**
* Returns all objects for which correct serialization must be tested.
*/
protected abstract Serializable[] serializableObjects();

/**
* Returns all restorable objects whose state must be tested for proper serialization.
*/
protected abstract Restorable<?>[] restorableObjects();

@Test
public void testSerializableObjects() throws Exception {
for (Serializable obj : firstNonNull(serializableObjects(), new Serializable[0])) {
Object copy = serializeAndDeserialize(obj);
assertEquals(obj, obj);
assertEquals(obj, copy);
assertEquals(obj.hashCode(), copy.hashCode());
assertEquals(obj.toString(), copy.toString());
assertNotSame(obj, copy);
assertEquals(copy, copy);
}
}

@Test
public void testRestorableObjects() throws Exception {
for (Restorable restorable : firstNonNull(restorableObjects(), new Restorable[0])) {
RestorableState<?> state = restorable.capture();
RestorableState<?> deserializedState = serializeAndDeserialize(state);
assertEquals(state, deserializedState);
assertEquals(state.hashCode(), deserializedState.hashCode());
assertEquals(state.toString(), deserializedState.toString());
}
}

@SuppressWarnings("unchecked")
public <T> T serializeAndDeserialize(T obj) throws IOException, ClassNotFoundException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (ObjectOutputStream output = new ObjectOutputStream(bytes)) {
output.writeObject(obj);
}
try (ObjectInputStream input =
new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()))) {
return (T) input.readObject();
}
}
}
Loading

0 comments on commit 353d2db

Please sign in to comment.