Skip to content

Commit 353d2db

Browse files
committed
Merge pull request #754 from mziccard/serialization-tests
Create base class for serialization tests
2 parents 7d48ec7 + 83ddb08 commit 353d2db

File tree

15 files changed

+367
-268
lines changed

15 files changed

+367
-268
lines changed

gcloud-java-bigquery/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@
3939
</exclusion>
4040
</exclusions>
4141
</dependency>
42+
<dependency>
43+
<groupId>${project.groupId}</groupId>
44+
<artifactId>gcloud-java-core</artifactId>
45+
<version>${project.version}</version>
46+
<type>test-jar</type>
47+
<scope>test</scope>
48+
</dependency>
4249
<dependency>
4350
<groupId>junit</groupId>
4451
<artifactId>junit</artifactId>

gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/BigQueryException.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.google.gcloud.RetryHelper.RetryInterruptedException;
2323

2424
import java.io.IOException;
25+
import java.util.Objects;
2526
import java.util.Set;
2627

2728
/**
@@ -73,6 +74,23 @@ protected Set<Error> retryableErrors() {
7374
return RETRYABLE_ERRORS;
7475
}
7576

77+
@Override
78+
public boolean equals(Object obj) {
79+
if (obj == this) {
80+
return true;
81+
}
82+
if (!(obj instanceof BigQueryException)) {
83+
return false;
84+
}
85+
BigQueryException other = (BigQueryException) obj;
86+
return super.equals(other) && Objects.equals(error, other.error);
87+
}
88+
89+
@Override
90+
public int hashCode() {
91+
return Objects.hash(super.hashCode(), error);
92+
}
93+
7694
/**
7795
* Translate RetryHelperException to the BigQueryException that caused the error. This method will
7896
* always throw an exception.

gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/SerializationTest.java

Lines changed: 15 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,19 @@
1616

1717
package com.google.gcloud.bigquery;
1818

19-
import static org.junit.Assert.assertEquals;
20-
import static org.junit.Assert.assertNotSame;
21-
2219
import com.google.common.collect.ImmutableList;
2320
import com.google.common.collect.ImmutableMap;
2421
import com.google.gcloud.AuthCredentials;
25-
import com.google.gcloud.RestorableState;
26-
import com.google.gcloud.RetryParams;
27-
import com.google.gcloud.WriteChannel;
22+
import com.google.gcloud.BaseSerializationTest;
23+
import com.google.gcloud.Restorable;
2824
import com.google.gcloud.bigquery.StandardTableDefinition.StreamingBuffer;
2925

30-
import org.junit.Test;
31-
32-
import java.io.ByteArrayInputStream;
33-
import java.io.ByteArrayOutputStream;
34-
import java.io.IOException;
35-
import java.io.ObjectInputStream;
36-
import java.io.ObjectOutputStream;
3726
import java.io.Serializable;
3827
import java.nio.charset.StandardCharsets;
3928
import java.util.List;
4029
import java.util.Map;
4130

42-
public class SerializationTest {
31+
public class SerializationTest extends BaseSerializationTest {
4332

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

234-
@Test
235-
public void testServiceOptions() throws Exception {
225+
@Override
226+
protected Serializable[] serializableObjects() {
236227
BigQueryOptions options = BigQueryOptions.builder()
237228
.projectId("p1")
238229
.authCredentials(AuthCredentials.createForAppEngine())
239230
.build();
240-
BigQueryOptions serializedCopy = serializeAndDeserialize(options);
241-
assertEquals(options, serializedCopy);
242-
243-
options = options.toBuilder()
231+
BigQueryOptions otherOptions = options.toBuilder()
244232
.projectId("p2")
245-
.retryParams(RetryParams.defaultInstance())
246233
.authCredentials(null)
247234
.build();
248-
serializedCopy = serializeAndDeserialize(options);
249-
assertEquals(options, serializedCopy);
250-
}
251-
252-
@Test
253-
public void testModelAndRequests() throws Exception {
254-
Serializable[] objects = {DOMAIN_ACCESS, GROUP_ACCESS, USER_ACCESS, VIEW_ACCESS, DATASET_ID,
235+
return new Serializable[]{DOMAIN_ACCESS, GROUP_ACCESS, USER_ACCESS, VIEW_ACCESS, DATASET_ID,
255236
DATASET_INFO, TABLE_ID, CSV_OPTIONS, STREAMING_BUFFER, TABLE_DEFINITION,
256237
EXTERNAL_TABLE_DEFINITION, VIEW_DEFINITION, TABLE_SCHEMA, TABLE_INFO, VIEW_INFO,
257238
EXTERNAL_TABLE_INFO, INLINE_FUNCTION, URI_FUNCTION, JOB_STATISTICS, EXTRACT_STATISTICS,
258239
LOAD_STATISTICS, QUERY_STATISTICS, BIGQUERY_ERROR, JOB_STATUS, JOB_ID,
259240
COPY_JOB_CONFIGURATION, EXTRACT_JOB_CONFIGURATION, LOAD_CONFIGURATION,
260241
LOAD_JOB_CONFIGURATION, QUERY_JOB_CONFIGURATION, JOB_INFO, INSERT_ALL_REQUEST,
261-
INSERT_ALL_RESPONSE, FIELD_VALUE, QUERY_REQUEST, QUERY_RESPONSE,
242+
INSERT_ALL_RESPONSE, FIELD_VALUE, QUERY_REQUEST, QUERY_RESPONSE, BIG_QUERY_EXCEPTION,
262243
BigQuery.DatasetOption.fields(), BigQuery.DatasetDeleteOption.deleteContents(),
263244
BigQuery.DatasetListOption.all(), BigQuery.TableOption.fields(),
264245
BigQuery.TableListOption.pageSize(42L), BigQuery.JobOption.fields(),
265-
BigQuery.JobListOption.allUsers(), DATASET, TABLE, JOB};
266-
for (Serializable obj : objects) {
267-
Object copy = serializeAndDeserialize(obj);
268-
assertEquals(obj, obj);
269-
assertEquals(obj, copy);
270-
assertNotSame(obj, copy);
271-
assertEquals(copy, copy);
272-
}
246+
BigQuery.JobListOption.allUsers(), DATASET, TABLE, JOB, options, otherOptions};
273247
}
274248

275-
@Test
276-
public void testWriteChannelState() throws IOException, ClassNotFoundException {
277-
BigQueryOptions options = BigQueryOptions.builder()
278-
.projectId("p2")
279-
.retryParams(RetryParams.defaultInstance())
280-
.build();
249+
@Override
250+
protected Restorable<?>[] restorableObjects() {
251+
BigQueryOptions options = BigQueryOptions.builder().projectId("p2").build();
281252
// avoid closing when you don't want partial writes upon failure
282253
@SuppressWarnings("resource")
283254
TableDataWriteChannel writer =
284255
new TableDataWriteChannel(options, LOAD_CONFIGURATION, "upload-id");
285-
RestorableState<WriteChannel> state = writer.capture();
286-
RestorableState<WriteChannel> deserializedState = serializeAndDeserialize(state);
287-
assertEquals(state, deserializedState);
288-
assertEquals(state.hashCode(), deserializedState.hashCode());
289-
assertEquals(state.toString(), deserializedState.toString());
290-
}
291-
292-
@SuppressWarnings("unchecked")
293-
private <T> T serializeAndDeserialize(T obj)
294-
throws IOException, ClassNotFoundException {
295-
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
296-
try (ObjectOutputStream output = new ObjectOutputStream(bytes)) {
297-
output.writeObject(obj);
298-
}
299-
try (ObjectInputStream input =
300-
new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()))) {
301-
return (T) input.readObject();
302-
}
256+
return new Restorable<?>[]{writer};
303257
}
304258
}

gcloud-java-core/src/main/java/com/google/gcloud/AuthCredentials.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,20 @@ private static class NoAuthCredentialsState
276276
public AuthCredentials restore() {
277277
return INSTANCE;
278278
}
279+
280+
@Override
281+
public int hashCode() {
282+
return getClass().getName().hashCode();
283+
}
284+
285+
@Override
286+
public boolean equals(Object obj) {
287+
return obj instanceof NoAuthCredentialsState;
288+
}
279289
}
280290

291+
private NoAuthCredentials() {}
292+
281293
@Override
282294
public GoogleCredentials credentials() {
283295
return null;

gcloud-java-core/src/main/java/com/google/gcloud/BaseServiceException.java

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@
3232
*/
3333
public class BaseServiceException extends RuntimeException {
3434

35+
private static final long serialVersionUID = 759921776378760835L;
36+
public static final int UNKNOWN_CODE = 0;
37+
38+
private final int code;
39+
private final boolean retryable;
40+
private final String reason;
41+
private final boolean idempotent;
42+
private final String location;
43+
private final String debugInfo;
44+
3545
protected static final class Error implements Serializable {
3646

3747
private static final long serialVersionUID = -4019600198652965721L;
@@ -79,16 +89,6 @@ public int hashCode() {
7989
}
8090
}
8191

82-
private static final long serialVersionUID = 759921776378760835L;
83-
public static final int UNKNOWN_CODE = 0;
84-
85-
private final int code;
86-
private final boolean retryable;
87-
private final String reason;
88-
private final boolean idempotent;
89-
private final String location;
90-
private final String debugInfo;
91-
9292
public BaseServiceException(IOException exception, boolean idempotent) {
9393
super(message(exception), exception);
9494
int code = UNKNOWN_CODE;
@@ -198,6 +198,31 @@ protected String debugInfo() {
198198
return debugInfo;
199199
}
200200

201+
@Override
202+
public boolean equals(Object obj) {
203+
if (obj == this) {
204+
return true;
205+
}
206+
if (!(obj instanceof BaseServiceException)) {
207+
return false;
208+
}
209+
BaseServiceException other = (BaseServiceException) obj;
210+
return Objects.equals(getCause(), other.getCause())
211+
&& Objects.equals(getMessage(), other.getMessage())
212+
&& code == other.code
213+
&& retryable == other.retryable
214+
&& Objects.equals(reason, other.reason)
215+
&& idempotent == other.idempotent
216+
&& Objects.equals(location, other.location)
217+
&& Objects.equals(debugInfo, other.debugInfo);
218+
}
219+
220+
@Override
221+
public int hashCode() {
222+
return Objects.hash(getCause(), getMessage(), code, retryable, reason, idempotent, location,
223+
debugInfo);
224+
}
225+
201226
protected static String reason(GoogleJsonError error) {
202227
if (error.getErrors() != null && !error.getErrors().isEmpty()) {
203228
return error.getErrors().get(0).getReason();

gcloud-java-core/src/main/java/com/google/gcloud/ExceptionHandler.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import java.io.Serializable;
2828
import java.lang.reflect.Method;
29+
import java.util.Objects;
2930
import java.util.Set;
3031
import java.util.concurrent.Callable;
3132

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

263+
@Override
264+
public int hashCode() {
265+
return Objects.hash(interceptors, retriableExceptions, nonRetriableExceptions, retryInfo);
266+
}
267+
268+
@Override
269+
public boolean equals(Object obj) {
270+
if (obj == this) {
271+
return true;
272+
}
273+
if (!(obj instanceof ExceptionHandler)) {
274+
return false;
275+
}
276+
ExceptionHandler other = (ExceptionHandler) obj;
277+
return Objects.equals(interceptors, other.interceptors)
278+
&& Objects.equals(retriableExceptions, other.retriableExceptions)
279+
&& Objects.equals(nonRetriableExceptions, other.nonRetriableExceptions)
280+
&& Objects.equals(retryInfo, other.retryInfo);
281+
}
282+
262283
/**
263284
* Returns an instance which retry any checked exception and abort on any runtime exception.
264285
*/
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright 2016 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.gcloud;
18+
19+
import static com.google.common.base.MoreObjects.firstNonNull;
20+
import static org.junit.Assert.assertEquals;
21+
import static org.junit.Assert.assertNotSame;
22+
23+
import org.junit.Test;
24+
25+
import java.io.ByteArrayInputStream;
26+
import java.io.ByteArrayOutputStream;
27+
import java.io.IOException;
28+
import java.io.ObjectInputStream;
29+
import java.io.ObjectOutputStream;
30+
import java.io.Serializable;
31+
32+
/**
33+
* Base class for serialization tests. To use this class in your tests override the
34+
* {@code serializableObjects()} method to return all objects that must be serializable. Also
35+
* override {@code restorableObjects()} method to return all restorable objects whose state must be
36+
* tested for proper serialization. Both methods can return {@code null} if no such object needs to
37+
* be tested.
38+
*/
39+
public abstract class BaseSerializationTest {
40+
41+
/**
42+
* Returns all objects for which correct serialization must be tested.
43+
*/
44+
protected abstract Serializable[] serializableObjects();
45+
46+
/**
47+
* Returns all restorable objects whose state must be tested for proper serialization.
48+
*/
49+
protected abstract Restorable<?>[] restorableObjects();
50+
51+
@Test
52+
public void testSerializableObjects() throws Exception {
53+
for (Serializable obj : firstNonNull(serializableObjects(), new Serializable[0])) {
54+
Object copy = serializeAndDeserialize(obj);
55+
assertEquals(obj, obj);
56+
assertEquals(obj, copy);
57+
assertEquals(obj.hashCode(), copy.hashCode());
58+
assertEquals(obj.toString(), copy.toString());
59+
assertNotSame(obj, copy);
60+
assertEquals(copy, copy);
61+
}
62+
}
63+
64+
@Test
65+
public void testRestorableObjects() throws Exception {
66+
for (Restorable restorable : firstNonNull(restorableObjects(), new Restorable[0])) {
67+
RestorableState<?> state = restorable.capture();
68+
RestorableState<?> deserializedState = serializeAndDeserialize(state);
69+
assertEquals(state, deserializedState);
70+
assertEquals(state.hashCode(), deserializedState.hashCode());
71+
assertEquals(state.toString(), deserializedState.toString());
72+
}
73+
}
74+
75+
@SuppressWarnings("unchecked")
76+
public <T> T serializeAndDeserialize(T obj) throws IOException, ClassNotFoundException {
77+
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
78+
try (ObjectOutputStream output = new ObjectOutputStream(bytes)) {
79+
output.writeObject(obj);
80+
}
81+
try (ObjectInputStream input =
82+
new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()))) {
83+
return (T) input.readObject();
84+
}
85+
}
86+
}

0 commit comments

Comments
 (0)