Skip to content

Commit dfc0e81

Browse files
committed
test(dataconverter): cover converter sample behavior
Signed-off-by: “Kevin” <kevlar_ksb@yahoo.com>
1 parent 3bcb571 commit dfc0e81

1 file changed

Lines changed: 266 additions & 0 deletions

File tree

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
/*
2+
* Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not
7+
* use this file except in compliance with the License. A copy of the License is
8+
* located at
9+
*
10+
* http://aws.amazon.com/apache2.0
11+
*
12+
* or in the "license" file accompanying this file. This file is distributed on
13+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
14+
* express or implied. See the License for the specific language governing
15+
* permissions and limitations under the License.
16+
*/
17+
18+
package com.uber.cadence.samples.dataconverter;
19+
20+
import static org.junit.Assert.assertArrayEquals;
21+
import static org.junit.Assert.assertEquals;
22+
import static org.junit.Assert.assertFalse;
23+
import static org.junit.Assert.assertTrue;
24+
import static org.junit.Assert.fail;
25+
26+
import com.uber.cadence.client.WorkflowClient;
27+
import com.uber.cadence.client.WorkflowClientOptions;
28+
import com.uber.cadence.client.WorkflowOptions;
29+
import com.uber.cadence.converter.DataConverterException;
30+
import com.uber.cadence.testing.TestEnvironmentOptions;
31+
import com.uber.cadence.testing.TestWorkflowEnvironment;
32+
import com.uber.cadence.worker.Worker;
33+
import java.io.IOException;
34+
import java.nio.file.Files;
35+
import java.nio.file.Path;
36+
import java.time.Duration;
37+
import java.util.Arrays;
38+
import java.util.LinkedHashMap;
39+
import java.util.Map;
40+
import java.util.stream.Stream;
41+
import org.junit.After;
42+
import org.junit.Rule;
43+
import org.junit.Test;
44+
import org.junit.rules.TemporaryFolder;
45+
46+
public class DataConverterSamplesTest {
47+
48+
@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
49+
50+
private TestWorkflowEnvironment testEnv;
51+
52+
@After
53+
public void tearDown() {
54+
if (testEnv != null) {
55+
testEnv.close();
56+
}
57+
}
58+
59+
@Test
60+
public void testCompressedConverterRoundTrip() {
61+
CompressedJsonDataConverter converter = new CompressedJsonDataConverter();
62+
CompressedDataConverterWorkflow.LargePayload payload =
63+
CompressedDataConverterWorkflow.createLargePayload();
64+
65+
byte[] encoded = converter.toData(payload);
66+
CompressedDataConverterWorkflow.LargePayload decoded =
67+
converter.fromData(
68+
encoded,
69+
CompressedDataConverterWorkflow.LargePayload.class,
70+
CompressedDataConverterWorkflow.LargePayload.class);
71+
72+
assertEquals(payload.id, decoded.id);
73+
assertEquals(payload.name, decoded.name);
74+
assertEquals(payload.items.size(), decoded.items.size());
75+
assertEquals(payload.history.size(), decoded.history.size());
76+
}
77+
78+
@Test
79+
public void testCompressedConverterRejectsMalformedPayload() {
80+
CompressedJsonDataConverter converter = new CompressedJsonDataConverter();
81+
82+
try {
83+
converter.fromData(new byte[] {1, 2, 3}, String.class, String.class);
84+
fail("expected malformed gzip payload to fail");
85+
} catch (DataConverterException e) {
86+
assertTrue(e.getMessage().contains("gunzip"));
87+
}
88+
}
89+
90+
@Test
91+
public void testCompressedConverterRejectsPayloadAboveLimit() {
92+
CompressedJsonDataConverter encoder = new CompressedJsonDataConverter();
93+
CompressedJsonDataConverter decoder = new CompressedJsonDataConverter(8);
94+
byte[] encoded = encoder.toData("this string inflates beyond the configured limit");
95+
96+
try {
97+
decoder.fromData(encoded, String.class, String.class);
98+
fail("expected oversized decompressed payload to fail");
99+
} catch (DataConverterException e) {
100+
assertTrue(e.getMessage().contains("maximum size"));
101+
}
102+
}
103+
104+
@Test
105+
public void testEncryptedConverterRoundTripAndRandomNonce() {
106+
EncryptedJsonDataConverter converter =
107+
new EncryptedJsonDataConverter(EncryptionKeyLoader.DEMO_ENCRYPTION_KEY);
108+
EncryptedDataConverterWorkflow.SensitiveCustomerRecord record =
109+
EncryptedDataConverterWorkflow.createSensitiveCustomerRecord();
110+
111+
byte[] first = converter.toData(record);
112+
byte[] second = converter.toData(record);
113+
114+
assertFalse(Arrays.equals(first, second));
115+
EncryptedDataConverterWorkflow.SensitiveCustomerRecord decoded =
116+
converter.fromData(
117+
first,
118+
EncryptedDataConverterWorkflow.SensitiveCustomerRecord.class,
119+
EncryptedDataConverterWorkflow.SensitiveCustomerRecord.class);
120+
assertEquals(record.customerId, decoded.customerId);
121+
assertEquals(record.ssn, decoded.ssn);
122+
assertEquals(record.medicalNotes, decoded.medicalNotes);
123+
}
124+
125+
@Test
126+
public void testEncryptedConverterRejectsShortCiphertext() {
127+
EncryptedJsonDataConverter converter =
128+
new EncryptedJsonDataConverter(EncryptionKeyLoader.DEMO_ENCRYPTION_KEY);
129+
130+
try {
131+
converter.fromData(new byte[] {1, 2, 3}, String.class, String.class);
132+
fail("expected short ciphertext to fail");
133+
} catch (DataConverterException e) {
134+
assertTrue(e.getMessage().contains("Ciphertext too short"));
135+
}
136+
}
137+
138+
@Test
139+
public void testEncryptedConverterWorksInWorkflowEnvironment() {
140+
EncryptedJsonDataConverter converter =
141+
new EncryptedJsonDataConverter(EncryptionKeyLoader.DEMO_ENCRYPTION_KEY);
142+
TestEnvironmentOptions options =
143+
new TestEnvironmentOptions.Builder()
144+
.setWorkflowClientOptions(
145+
WorkflowClientOptions.newBuilder().setDataConverter(converter).build())
146+
.build();
147+
testEnv = TestWorkflowEnvironment.newInstance(options);
148+
Worker worker = testEnv.newWorker(DataConverterConstants.TASK_LIST_ENCRYPTION);
149+
worker.registerWorkflowImplementationTypes(EncryptedDataConverterWorkflow.WorkflowImpl.class);
150+
worker.registerActivitiesImplementations(new EncryptedDataConverterWorkflow.ActivitiesImpl());
151+
testEnv.start();
152+
153+
WorkflowClient workflowClient =
154+
testEnv.newWorkflowClient(
155+
WorkflowClientOptions.newBuilder().setDataConverter(converter).build());
156+
WorkflowOptions workflowOptions =
157+
new WorkflowOptions.Builder()
158+
.setTaskList(DataConverterConstants.TASK_LIST_ENCRYPTION)
159+
.setExecutionStartToCloseTimeout(Duration.ofMinutes(1))
160+
.build();
161+
EncryptedDataConverterWorkflow.WorkflowIface workflow =
162+
workflowClient.newWorkflowStub(
163+
EncryptedDataConverterWorkflow.WorkflowIface.class, workflowOptions);
164+
165+
EncryptedDataConverterWorkflow.SensitiveCustomerRecord result = workflow.run();
166+
167+
assertEquals("cust_8a7f3b2e", result.customerId);
168+
assertEquals("workflow-processor-v2 (Encrypted)", result.processedBy);
169+
}
170+
171+
@Test
172+
public void testS3OffloadConverterInlinesBelowThreshold() {
173+
RecordingBlobStore store = new RecordingBlobStore();
174+
S3OffloadDataConverter converter = new S3OffloadDataConverter(store, "bucket", 1024);
175+
176+
byte[] encoded = converter.toData("small");
177+
String decoded = converter.fromData(encoded, String.class, String.class);
178+
179+
assertEquals(S3OffloadDataConverter.INLINE_PREFIX, encoded[0]);
180+
assertEquals("small", decoded);
181+
assertTrue(store.blobs.isEmpty());
182+
}
183+
184+
@Test
185+
public void testS3OffloadConverterOffloadsAndUsesIdempotentReference() {
186+
RecordingBlobStore store = new RecordingBlobStore();
187+
S3OffloadDataConverter converter = new S3OffloadDataConverter(store, "bucket", 1);
188+
189+
byte[] first = converter.toData("large enough to offload");
190+
byte[] second = converter.toData("large enough to offload");
191+
String decoded = converter.fromData(first, String.class, String.class);
192+
193+
assertEquals(S3OffloadDataConverter.OFFLOAD_PREFIX, first[0]);
194+
assertArrayEquals(first, second);
195+
assertEquals("large enough to offload", decoded);
196+
assertEquals(1, store.blobs.size());
197+
}
198+
199+
@Test
200+
public void testS3OffloadConverterRejectsUnknownPrefix() {
201+
S3OffloadDataConverter converter =
202+
new S3OffloadDataConverter(new RecordingBlobStore(), "bucket", 1);
203+
204+
try {
205+
converter.fromData(new byte[] {0x7f}, String.class, String.class);
206+
fail("expected unknown prefix to fail");
207+
} catch (DataConverterException e) {
208+
assertTrue(e.getMessage().contains("unknown prefix"));
209+
}
210+
}
211+
212+
@Test
213+
public void testS3OffloadConverterValidatesConstructorInputs() {
214+
expectIllegalArgument(() -> new S3OffloadDataConverter(null, "bucket", 1));
215+
expectIllegalArgument(() -> new S3OffloadDataConverter(new RecordingBlobStore(), " ", 1));
216+
expectIllegalArgument(() -> new S3OffloadDataConverter(new RecordingBlobStore(), "bucket", -1));
217+
}
218+
219+
@Test
220+
public void testLocalFsBlobStoreHashesUnsafeKeys() throws Exception {
221+
Path baseDir = temporaryFolder.newFolder("blobs").toPath();
222+
LocalFsBlobStore store = new LocalFsBlobStore(baseDir);
223+
byte[] data = new byte[] {1, 2, 3};
224+
225+
store.put("../escape", data);
226+
store.put(".", data);
227+
store.put("bucket\\nested/key", data);
228+
229+
assertArrayEquals(data, store.get("../escape"));
230+
assertArrayEquals(data, store.get("."));
231+
assertArrayEquals(data, store.get("bucket\\nested/key"));
232+
try (Stream<Path> files = Files.list(baseDir)) {
233+
assertEquals(3, files.filter(Files::isRegularFile).count());
234+
}
235+
try (Stream<Path> files = Files.list(baseDir)) {
236+
assertTrue(files.allMatch(path -> path.getFileName().toString().matches("[0-9a-f]{64}")));
237+
}
238+
}
239+
240+
private static void expectIllegalArgument(Runnable runnable) {
241+
try {
242+
runnable.run();
243+
fail("expected IllegalArgumentException");
244+
} catch (IllegalArgumentException expected) {
245+
// Expected.
246+
}
247+
}
248+
249+
private static final class RecordingBlobStore implements BlobStore {
250+
final Map<String, byte[]> blobs = new LinkedHashMap<>();
251+
252+
@Override
253+
public void put(String key, byte[] data) {
254+
blobs.put(key, data);
255+
}
256+
257+
@Override
258+
public byte[] get(String key) throws IOException {
259+
byte[] data = blobs.get(key);
260+
if (data == null) {
261+
throw new IOException("missing key " + key);
262+
}
263+
return data;
264+
}
265+
}
266+
}

0 commit comments

Comments
 (0)