11package net .snowflake .client .internal .jdbc .cloud .storage ;
22
33import static org .junit .jupiter .api .Assertions .assertEquals ;
4+ import static org .junit .jupiter .api .Assertions .assertFalse ;
5+ import static org .junit .jupiter .api .Assertions .assertNotNull ;
6+ import static org .junit .jupiter .api .Assertions .assertNull ;
7+ import static org .junit .jupiter .api .Assertions .assertTrue ;
48
9+ import java .lang .reflect .Field ;
10+ import java .net .URI ;
11+ import java .util .HashMap ;
12+ import java .util .Map ;
13+ import java .util .Optional ;
14+ import net .snowflake .client .api .exception .SnowflakeSQLException ;
515import org .junit .jupiter .api .Test ;
16+ import software .amazon .awssdk .services .s3 .S3AsyncClient ;
617
18+ /**
19+ * Unit tests for {@link SnowflakeS3Client} endpoint selection (GS {@code stageInfo.endPoint} and
20+ * regional URL mode). Uses {@link S3AsyncClient#serviceClientConfiguration()}{@code
21+ * .endpointOverride()} to read the effective override.
22+ */
723public class SnowflakeS3ClientTest {
824
925 @ Test
@@ -14,4 +30,153 @@ public void shouldDetermineDomainForRegion() {
1430 assertEquals (
1531 "amazonaws.com.cn" , SnowflakeS3Client .getDomainSuffixForRegionalUrl ("CN-NORTHWEST-1" ));
1632 }
33+
34+ /** Documents why bare hostnames must be normalized before {@code endpointOverride(URI)}. */
35+ @ Test
36+ public void uriCreate_bareAwsHostname_hasNullScheme () {
37+ assertNull (URI .create ("s3.us-west-2.amazonaws.com" ).getScheme ());
38+ }
39+
40+ @ Test
41+ public void endpointOverride_stageEndPointWithoutScheme_prependsHttps () throws Exception {
42+ SnowflakeS3Client client =
43+ newClient (
44+ "eu-west-1" ,
45+ "s3.eu-west-1.amazonaws.com" ,
46+ false ,
47+ /* isClientSideEncrypted */ false );
48+ try {
49+ URI override = endpointOverride (client ).orElseThrow ();
50+ assertEquals ("https" , override .getScheme ());
51+ assertEquals ("s3.eu-west-1.amazonaws.com" , override .getHost ());
52+ } finally {
53+ client .shutdown ();
54+ }
55+ }
56+
57+ @ Test
58+ public void endpointOverride_stageEndPointWithHttps_unchanged () throws Exception {
59+ String url = "https://s3-fips.us-gov-west-1.amazonaws.com" ;
60+ SnowflakeS3Client client =
61+ newClient ("us-gov-west-1" , url , false , /* isClientSideEncrypted */ false );
62+ try {
63+ URI override = endpointOverride (client ).orElseThrow ();
64+ assertEquals (URI .create (url ), override );
65+ } finally {
66+ client .shutdown ();
67+ }
68+ }
69+
70+ @ Test
71+ public void endpointOverride_stageEndPointWithHttp_unchanged () throws Exception {
72+ String url = "http://minio.local:9000" ;
73+ SnowflakeS3Client client =
74+ newClient ("us-east-1" , url , false , /* isClientSideEncrypted */ false );
75+ try {
76+ URI override = endpointOverride (client ).orElseThrow ();
77+ assertEquals ("http" , override .getScheme ());
78+ assertEquals ("minio.local" , override .getHost ());
79+ assertEquals (9000 , override .getPort ());
80+ } finally {
81+ client .shutdown ();
82+ }
83+ }
84+
85+ @ Test
86+ public void endpointOverride_useS3RegionalUrl_commercialRegion () throws Exception {
87+ SnowflakeS3Client client =
88+ newClient (
89+ "us-west-2" ,
90+ /* stageEndPoint */ null ,
91+ /* useS3RegionalUrl */ true ,
92+ /* isClientSideEncrypted */ false );
93+ try {
94+ URI override = endpointOverride (client ).orElseThrow ();
95+ assertEquals (URI .create ("https://s3.us-west-2.amazonaws.com" ), override );
96+ } finally {
97+ client .shutdown ();
98+ }
99+ }
100+
101+ @ Test
102+ public void endpointOverride_useS3RegionalUrl_chinaRegion () throws Exception {
103+ SnowflakeS3Client client =
104+ newClient (
105+ "cn-northwest-1" ,
106+ /* stageEndPoint */ null ,
107+ /* useS3RegionalUrl */ true ,
108+ /* isClientSideEncrypted */ false );
109+ try {
110+ URI override = endpointOverride (client ).orElseThrow ();
111+ assertEquals (URI .create ("https://s3.cn-northwest-1.amazonaws.com.cn" ), override );
112+ } finally {
113+ client .shutdown ();
114+ }
115+ }
116+
117+ @ Test
118+ public void endpointOverride_noStageEndPoint_noRegionalUrl_noOverride () throws Exception {
119+ SnowflakeS3Client client =
120+ newClient (
121+ "eu-central-1" ,
122+ /* stageEndPoint */ null ,
123+ /* useS3RegionalUrl */ false ,
124+ /* isClientSideEncrypted */ false );
125+ try {
126+ assertFalse (endpointOverride (client ).isPresent ());
127+ } finally {
128+ client .shutdown ();
129+ }
130+ }
131+
132+ /** Regression: scheme-less {@code stageEndPoint} must not NPE inside AWS SDK v2 client build. */
133+ @ Test
134+ public void constructor_schemeLessStageEndPoint_doesNotThrowNpe () throws Exception {
135+ SnowflakeS3Client client = null ;
136+ try {
137+ client =
138+ newClient (
139+ "us-west-2" ,
140+ "s3.us-west-2.amazonaws.com" ,
141+ false ,
142+ /* isClientSideEncrypted */ false );
143+ assertNotNull (client );
144+ assertTrue (endpointOverride (client ).isPresent ());
145+ assertNotNull (endpointOverride (client ).get ().getScheme ());
146+ } finally {
147+ if (client != null ) {
148+ client .shutdown ();
149+ }
150+ }
151+ }
152+
153+ private static SnowflakeS3Client newClient (
154+ String stageRegion ,
155+ String stageEndPoint ,
156+ boolean useS3RegionalUrl ,
157+ boolean isClientSideEncrypted )
158+ throws SnowflakeSQLException {
159+ Map <String , String > creds = new HashMap <>();
160+ creds .put ("AWS_KEY_ID" , "AKIA_TEST" );
161+ creds .put ("AWS_SECRET_KEY" , "testSecretAccessKey" );
162+ SnowflakeS3Client .ClientConfiguration config =
163+ new SnowflakeS3Client .ClientConfiguration (2 , 3 , 5_000 , 5_000 );
164+ return new SnowflakeS3Client (
165+ creds ,
166+ config ,
167+ /* encMat */ null ,
168+ /* proxyProperties */ null ,
169+ stageRegion ,
170+ stageEndPoint ,
171+ isClientSideEncrypted ,
172+ /* session */ null ,
173+ useS3RegionalUrl );
174+ }
175+
176+ private static Optional <URI > endpointOverride (SnowflakeS3Client client ) throws Exception {
177+ Field f = SnowflakeS3Client .class .getDeclaredField ("amazonClient" );
178+ f .setAccessible (true );
179+ S3AsyncClient aws = (S3AsyncClient ) f .get (client );
180+ return aws .serviceClientConfiguration ().endpointOverride ();
181+ }
17182}
0 commit comments