Skip to content

Commit 8ec7c2b

Browse files
sfc-gh-ggengclaude
andauthored
[SNOW-3249917] Port 25 missing JDBC unit tests for replicated classes (#1147)
* [SNOW-3249917] Port 25 missing JDBC unit tests for replicated classes Port unit tests from snowflake-jdbc v3.25.1 for all replicated classes that had JDBC tests but were missing ingest tests. All converted from JUnit 5 to JUnit 4 to match project test infrastructure. Tests ported: - Security: SecretDetectorTest (masking), EncryptionProviderTest (CBC), GcmEncryptionProviderTest (GCM) - HTTP: RestRequestTest (retry/backoff), JdbcHttpUtilTest (client build), AttributeEnhancingHttpRequestRetryHandlerTest, HeaderCustomizerHttpRequestInterceptorTest, URLUtilTest - Storage: AwsSdkGCPSignerTest, SnowflakeAzureClientTest, SnowflakeS3ClientTest, StageInfoGcsCustomEndpointTest - Core: FileCacheManagerTest, ObjectMapperFactoryTest, ExecTimeTelemetryDataTest, SnowflakeFileTransferConfigTest, SnowflakeConnectStringTest - Logging: EventHandlerTest, EventTest, SFFormatterTest, SFLoggerFactoryTest, JDK14LoggerTest (@ignore) - Telemetry: TelemetryServiceOOBTest, TelemetryThreadPoolTest, TelemetryJsonTest 1 test @ignore'd: FileCacheManagerTest.throwWhenOverrideCacheFile... (requires mockito-inline for Mockito.mockStatic; project uses PowerMock) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix dependency issues: add hamcrest-core, exclude JDBC vulnerabilities - Add hamcrest-core:1.3 as explicit test dependency (used by ported tests: RestRequestTest, JdbcHttpUtilTest, SnowflakeConnectStringTest, SecretDetectorTest) - Exclude vulnerable transitive deps from snowflake-jdbc-thin in both main pom and e2e-jar-test pom: - grpc-netty-shaded (CVE-2025-55163, CVSS 8.7) - commons-lang3 (CVE-2025-48924, CVSS 8.8) - javax.servlet-api (license: CDDL-1.1/GPL-2.0) - javax.annotation-api (license: CDDL-1.1/GPL-2.0) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 137b006 commit 8ec7c2b

27 files changed

Lines changed: 3546 additions & 0 deletions

e2e-jar-test/pom.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,24 @@
5353
<groupId>net.snowflake</groupId>
5454
<artifactId>snowflake-jdbc-thin</artifactId>
5555
<version>3.25.1</version>
56+
<exclusions>
57+
<exclusion>
58+
<groupId>io.grpc</groupId>
59+
<artifactId>grpc-netty-shaded</artifactId>
60+
</exclusion>
61+
<exclusion>
62+
<groupId>javax.annotation</groupId>
63+
<artifactId>javax.annotation-api</artifactId>
64+
</exclusion>
65+
<exclusion>
66+
<groupId>javax.servlet</groupId>
67+
<artifactId>javax.servlet-api</artifactId>
68+
</exclusion>
69+
<exclusion>
70+
<groupId>org.apache.commons</groupId>
71+
<artifactId>commons-lang3</artifactId>
72+
</exclusion>
73+
</exclusions>
5674
</dependency>
5775
<dependency>
5876
<groupId>net.snowflake.snowflake-ingest-java-e2e-jar-test</groupId>

pom.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@
185185
<groupId>io.grpc</groupId>
186186
<artifactId>grpc-context</artifactId>
187187
</exclusion>
188+
<exclusion>
189+
<groupId>io.grpc</groupId>
190+
<artifactId>grpc-netty-shaded</artifactId>
191+
</exclusion>
188192
<exclusion>
189193
<groupId>javax.annotation</groupId>
190194
<artifactId>javax.annotation-api</artifactId>
@@ -193,6 +197,10 @@
193197
<groupId>javax.servlet</groupId>
194198
<artifactId>javax.servlet-api</artifactId>
195199
</exclusion>
200+
<exclusion>
201+
<groupId>org.apache.commons</groupId>
202+
<artifactId>commons-lang3</artifactId>
203+
</exclusion>
196204
<exclusion>
197205
<groupId>org.jsoup</groupId>
198206
<artifactId>jsoup</artifactId>
@@ -1027,6 +1035,12 @@
10271035
<artifactId>assertj-core</artifactId>
10281036
<scope>test</scope>
10291037
</dependency>
1038+
<dependency>
1039+
<groupId>org.hamcrest</groupId>
1040+
<artifactId>hamcrest-core</artifactId>
1041+
<version>1.3</version>
1042+
<scope>test</scope>
1043+
</dependency>
10301044
<dependency>
10311045
<groupId>org.mockito</groupId>
10321046
<artifactId>mockito-core</artifactId>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Ported from snowflake-jdbc: net.snowflake.client.jdbc.telemetry.TelemetryTest
2+
package net.snowflake.ingest.connection.telemetry;
3+
4+
import static org.junit.Assert.assertEquals;
5+
6+
import com.fasterxml.jackson.databind.ObjectMapper;
7+
import com.fasterxml.jackson.databind.node.ArrayNode;
8+
import com.fasterxml.jackson.databind.node.ObjectNode;
9+
import java.util.LinkedList;
10+
import org.junit.Test;
11+
12+
/** Telemetry unit tests */
13+
public class TelemetryJsonTest {
14+
private ObjectMapper mapper = new ObjectMapper();
15+
16+
@Test
17+
public void testJsonConversion() {
18+
19+
ObjectNode log1 = mapper.createObjectNode();
20+
log1.put("type", "query");
21+
log1.put("query_id", "sdasdasdasdasds");
22+
long timestamp1 = 12345678;
23+
ObjectNode log2 = mapper.createObjectNode();
24+
log2.put("type", "query");
25+
log2.put("query_id", "eqweqweqweqwe");
26+
long timestamp2 = 22345678;
27+
28+
LinkedList<TelemetryData> list = new LinkedList<>();
29+
list.add(new TelemetryData(log1, timestamp1));
30+
list.add(new TelemetryData(log2, timestamp2));
31+
32+
String result = TelemetryClient.logsToString(list);
33+
34+
ObjectNode expect = mapper.createObjectNode();
35+
ArrayNode logs = mapper.createArrayNode();
36+
ObjectNode message1 = mapper.createObjectNode();
37+
message1.put("timestamp", timestamp1 + "");
38+
message1.set("message", log1);
39+
logs.add(message1);
40+
ObjectNode message2 = mapper.createObjectNode();
41+
message2.put("timestamp", timestamp2 + "");
42+
message2.set("message", log2);
43+
logs.add(message2);
44+
expect.set("logs", logs);
45+
46+
assertEquals(expect.toString(), result);
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Ported from snowflake-jdbc:
2+
// net.snowflake.client.core.AttributeEnhancingHttpRequestRetryHandlerTest
3+
package net.snowflake.ingest.streaming.internal.fileTransferAgent;
4+
5+
import static org.junit.Assert.assertEquals;
6+
7+
import java.io.IOException;
8+
import org.apache.http.protocol.BasicHttpContext;
9+
import org.apache.http.protocol.HttpContext;
10+
import org.junit.Test;
11+
12+
public class AttributeEnhancingHttpRequestRetryHandlerTest {
13+
private final IOException dummyException = new IOException("Test exception");
14+
15+
@Test
16+
public void testAttributeSetCount0() {
17+
verifyAttributeSet(0);
18+
}
19+
20+
@Test
21+
public void testAttributeSetCount3() {
22+
verifyAttributeSet(3);
23+
}
24+
25+
@Test
26+
public void testAttributeSetCount5() {
27+
verifyAttributeSet(5);
28+
}
29+
30+
@Test
31+
public void testAttributeSetCount10() {
32+
verifyAttributeSet(10);
33+
}
34+
35+
private void verifyAttributeSet(int executionCount) {
36+
HttpContext context = new BasicHttpContext();
37+
AttributeEnhancingHttpRequestRetryHandler handler =
38+
new AttributeEnhancingHttpRequestRetryHandler();
39+
40+
handler.retryRequest(dummyException, executionCount, context);
41+
42+
assertEquals(
43+
"Attribute should be set to the provided executionCount: " + executionCount,
44+
executionCount,
45+
context.getAttribute(AttributeEnhancingHttpRequestRetryHandler.EXECUTION_COUNT_ATTRIBUTE));
46+
}
47+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Ported from snowflake-jdbc: net.snowflake.client.jdbc.cloud.storage.AwsSdkGCPSignerTest
2+
package net.snowflake.ingest.streaming.internal.fileTransferAgent;
3+
4+
import static org.junit.Assert.assertTrue;
5+
6+
import com.amazonaws.DefaultRequest;
7+
import com.amazonaws.auth.AWSCredentials;
8+
import com.amazonaws.auth.BasicAWSCredentials;
9+
import com.amazonaws.http.HttpMethodName;
10+
import java.util.HashMap;
11+
import org.junit.Test;
12+
13+
public class AwsSdkGCPSignerTest {
14+
15+
@Test
16+
public void testSign() {
17+
AWSCredentials creds = new BasicAWSCredentials("access_key", "");
18+
AwsSdkGCPSigner signer = new AwsSdkGCPSigner();
19+
20+
DefaultRequest request = new DefaultRequest("S3");
21+
22+
HashMap<String, String> headers = new HashMap<>();
23+
headers.put("x-amz-storage-class", "storage_class");
24+
headers.put("x-amz-meta-custom", "custom_meta");
25+
26+
request.setHttpMethod(HttpMethodName.GET);
27+
request.setHeaders(headers);
28+
29+
signer.sign(request, creds);
30+
31+
assertTrue(request.getHeaders().get("Authorization").equals("Bearer access_key"));
32+
assertTrue(request.getHeaders().get("Accept-Encoding").equals("gzip,deflate"));
33+
assertTrue(request.getHeaders().get("x-goog-storage-class").equals("storage_class"));
34+
assertTrue(request.getHeaders().get("x-goog-meta-custom").equals("custom_meta"));
35+
}
36+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Ported from snowflake-jdbc: net.snowflake.client.jdbc.cloud.storage.EncryptionProviderTest
2+
package net.snowflake.ingest.streaming.internal.fileTransferAgent;
3+
4+
import static org.junit.Assert.assertArrayEquals;
5+
import static org.mockito.Mockito.mock;
6+
import static org.mockito.Mockito.verify;
7+
8+
import java.io.ByteArrayInputStream;
9+
import java.io.File;
10+
import java.io.InputStream;
11+
import java.nio.charset.StandardCharsets;
12+
import java.nio.file.Files;
13+
import java.security.SecureRandom;
14+
import java.util.Base64;
15+
import javax.crypto.CipherInputStream;
16+
import org.apache.commons.io.FileUtils;
17+
import org.apache.commons.io.IOUtils;
18+
import org.junit.Before;
19+
import org.junit.Test;
20+
import org.mockito.ArgumentCaptor;
21+
22+
public class EncryptionProviderTest {
23+
private final SecureRandom random = new SecureRandom();
24+
25+
private final ArgumentCaptor<StorageObjectMetadata> storageObjectMetadataArgumentCaptor =
26+
ArgumentCaptor.forClass(StorageObjectMetadata.class);
27+
private final ArgumentCaptor<MatDesc> matDescArgumentCaptor =
28+
ArgumentCaptor.forClass(MatDesc.class);
29+
private final ArgumentCaptor<byte[]> ivDataArgumentCaptor = ArgumentCaptor.forClass(byte[].class);
30+
private final ArgumentCaptor<byte[]> encKekArgumentCaptor = ArgumentCaptor.forClass(byte[].class);
31+
private final ArgumentCaptor<Long> contentLengthArgumentCaptor =
32+
ArgumentCaptor.forClass(Long.class);
33+
34+
private final StorageObjectMetadata meta = mock(StorageObjectMetadata.class);
35+
private final SnowflakeStorageClient storageClient = mock(SnowflakeStorageClient.class);
36+
37+
private final String queryStageMasterKey =
38+
Base64.getEncoder().encodeToString(random.generateSeed(16));
39+
private final RemoteStoreFileEncryptionMaterial encMat = new RemoteStoreFileEncryptionMaterial();
40+
41+
byte[] plainText = "the quick brown fox jumps over the lazy dog".getBytes(StandardCharsets.UTF_8);
42+
43+
@Before
44+
public void setUp() {
45+
encMat.setQueryStageMasterKey(queryStageMasterKey);
46+
encMat.setSmkId(123);
47+
encMat.setQueryId("query-id");
48+
}
49+
50+
@Test
51+
public void testEncryptAndDecryptStream() throws Exception {
52+
InputStream plainTextStream = new ByteArrayInputStream(plainText);
53+
54+
CipherInputStream encrypted =
55+
EncryptionProvider.encrypt(meta, plainText.length, plainTextStream, encMat, storageClient);
56+
byte[] cipherText = IOUtils.toByteArray(encrypted);
57+
verify(storageClient)
58+
.addEncryptionMetadata(
59+
storageObjectMetadataArgumentCaptor.capture(),
60+
matDescArgumentCaptor.capture(),
61+
ivDataArgumentCaptor.capture(),
62+
encKekArgumentCaptor.capture(),
63+
contentLengthArgumentCaptor.capture());
64+
65+
InputStream inputStream =
66+
EncryptionProvider.decryptStream(
67+
new ByteArrayInputStream(cipherText),
68+
Base64.getEncoder().encodeToString(encKekArgumentCaptor.getValue()),
69+
Base64.getEncoder().encodeToString(ivDataArgumentCaptor.getValue()),
70+
encMat);
71+
byte[] decryptedPlainText = IOUtils.toByteArray(inputStream);
72+
assertArrayEquals(plainText, decryptedPlainText);
73+
}
74+
75+
@Test
76+
public void testEncryptAndDecryptFile() throws Exception {
77+
File tempFile = Files.createTempFile("encryption", "").toFile();
78+
tempFile.deleteOnExit();
79+
80+
CipherInputStream encrypted =
81+
EncryptionProvider.encrypt(
82+
meta, plainText.length, new ByteArrayInputStream(plainText), encMat, storageClient);
83+
FileUtils.writeByteArrayToFile(tempFile, IOUtils.toByteArray(encrypted));
84+
verify(storageClient)
85+
.addEncryptionMetadata(
86+
storageObjectMetadataArgumentCaptor.capture(),
87+
matDescArgumentCaptor.capture(),
88+
ivDataArgumentCaptor.capture(),
89+
encKekArgumentCaptor.capture(),
90+
contentLengthArgumentCaptor.capture());
91+
92+
EncryptionProvider.decrypt(
93+
tempFile,
94+
Base64.getEncoder().encodeToString(encKekArgumentCaptor.getValue()),
95+
Base64.getEncoder().encodeToString(ivDataArgumentCaptor.getValue()),
96+
encMat);
97+
byte[] decryptedCipherText = FileUtils.readFileToByteArray(tempFile);
98+
assertArrayEquals(plainText, decryptedCipherText);
99+
}
100+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Ported from snowflake-jdbc: net.snowflake.client.core.ExecTimeTelemetryDataTest
2+
package net.snowflake.ingest.streaming.internal.fileTransferAgent;
3+
4+
import static org.junit.Assert.assertEquals;
5+
import static org.junit.Assert.assertNotNull;
6+
import static org.junit.Assert.assertNull;
7+
8+
import net.minidev.json.JSONObject;
9+
import net.minidev.json.parser.JSONParser;
10+
import net.minidev.json.parser.ParseException;
11+
import org.junit.Test;
12+
13+
public class ExecTimeTelemetryDataTest {
14+
15+
@Test
16+
public void testExecTimeTelemetryData() throws ParseException {
17+
ExecTimeTelemetryData execTimeTelemetryData = new ExecTimeTelemetryData();
18+
execTimeTelemetryData.sendData = true;
19+
execTimeTelemetryData.setBindStart();
20+
execTimeTelemetryData.setOCSPStatus(true);
21+
execTimeTelemetryData.setBindEnd();
22+
execTimeTelemetryData.setHttpClientStart();
23+
execTimeTelemetryData.setHttpClientEnd();
24+
execTimeTelemetryData.setGzipStart();
25+
execTimeTelemetryData.setGzipEnd();
26+
execTimeTelemetryData.setQueryEnd();
27+
execTimeTelemetryData.setQueryId("queryid");
28+
execTimeTelemetryData.setProcessResultChunkStart();
29+
execTimeTelemetryData.setProcessResultChunkEnd();
30+
execTimeTelemetryData.setResponseIOStreamStart();
31+
execTimeTelemetryData.setResponseIOStreamEnd();
32+
execTimeTelemetryData.setCreateResultSetStart();
33+
execTimeTelemetryData.setCreateResultSetEnd();
34+
execTimeTelemetryData.incrementRetryCount();
35+
execTimeTelemetryData.setRequestId("mockId");
36+
execTimeTelemetryData.addRetryLocation("retry");
37+
38+
String telemetry = execTimeTelemetryData.generateTelemetry();
39+
JSONParser parser = new JSONParser(JSONParser.MODE_JSON_SIMPLE);
40+
JSONObject json = (JSONObject) parser.parse(telemetry);
41+
assertNotNull(json.get("BindStart"));
42+
assertNotNull(json.get("BindEnd"));
43+
assertEquals(json.get("ocspEnabled"), true);
44+
assertNotNull(json.get("HttpClientStart"));
45+
assertNotNull(json.get("HttpClientEnd"));
46+
assertNotNull(json.get("GzipStart"));
47+
assertNotNull(json.get("GzipEnd"));
48+
assertNotNull(json.get("QueryEnd"));
49+
assertEquals("queryid", json.get("QueryID"));
50+
assertNotNull(json.get("ProcessResultChunkStart"));
51+
assertNotNull(json.get("ProcessResultChunkEnd"));
52+
assertNotNull(json.get("ResponseIOStreamStart"));
53+
assertNotNull(json.get("CreateResultSetStart"));
54+
assertNotNull(json.get("CreateResultSetEnd"));
55+
assertNotNull(json.get("ElapsedQueryTime"));
56+
assertNotNull(json.get("ElapsedResultProcessTime"));
57+
assertNull(json.get("QueryFunction"));
58+
assertNull(json.get("BatchID"));
59+
assertEquals(1, ((Long) json.get("RetryCount")).intValue());
60+
assertEquals("mockId", json.get("RequestID"));
61+
assertEquals("retry", json.get("RetryLocations"));
62+
assertEquals(true, json.get("Urgent"));
63+
assertEquals("ExecutionTimeRecord", json.get("eventType"));
64+
}
65+
66+
@Test
67+
public void testRetryLocation() throws ParseException {
68+
TelemetryService.enableHTAP();
69+
ExecTimeTelemetryData execTimeTelemetryData =
70+
new ExecTimeTelemetryData("queryFunction", "batchId");
71+
execTimeTelemetryData.addRetryLocation("hello");
72+
execTimeTelemetryData.addRetryLocation("world");
73+
execTimeTelemetryData.sendData = true;
74+
String telemetry = execTimeTelemetryData.generateTelemetry();
75+
76+
JSONParser parser = new JSONParser(JSONParser.MODE_JSON_SIMPLE);
77+
JSONObject json = (JSONObject) parser.parse(telemetry);
78+
assertEquals("queryFunction", json.get("QueryFunction"));
79+
assertEquals("batchId", json.get("BatchID"));
80+
assertNotNull(json.get("QueryStart"));
81+
assertEquals("hello, world", json.get("RetryLocations"));
82+
TelemetryService.disableHTAP();
83+
}
84+
}

0 commit comments

Comments
 (0)