2828import java .io .ByteArrayOutputStream ;
2929import java .io .ObjectInputStream ;
3030import java .io .ObjectOutputStream ;
31+ import java .util .Base64 ;
3132import java .util .Collections ;
3233import java .util .HashMap ;
3334import java .util .Map ;
4243/** Tests for {@link S3EncryptionConfig}. */
4344class S3EncryptionConfigTest {
4445
45- @ ParameterizedTest
46- @ MethodSource
47- void noArgFactories_encryptionTypeCorrect (
48- S3EncryptionConfig config ,
49- S3EncryptionConfig .EncryptionType expectedType ,
50- boolean expectedEnabled ,
51- ServerSideEncryption expectedSse ) {
52- assertThat (config .getEncryptionType ()).isEqualTo (expectedType );
53- assertThat (config .isEnabled ()).isEqualTo (expectedEnabled );
54- assertThat (config .getKmsKeyId ()).isNull ();
55- assertThat (config .getServerSideEncryption ()).isEqualTo (expectedSse );
56- }
57-
58- static Stream <Arguments > noArgFactories_encryptionTypeCorrect () {
59- return Stream .of (
60- Arguments .of (S3EncryptionConfig .none (), NONE , false , null ),
61- Arguments .of (S3EncryptionConfig .sseS3 (), SSE_S3 , true , ServerSideEncryption .AES256 ),
62- Arguments .of (
63- S3EncryptionConfig .sseKms (), SSE_KMS , true , ServerSideEncryption .AWS_KMS ));
64- }
65-
66- @ Test
67- void sseKms_withKeyId_keyIdStoredAndEnabled () {
68- S3EncryptionConfig c = S3EncryptionConfig .sseKms ("arn:aws:kms:us-east-1:123:key/abc" );
69-
70- assertThat (c .getKmsKeyId ()).isEqualTo ("arn:aws:kms:us-east-1:123:key/abc" );
71- assertThat (c .isEnabled ()).isTrue ();
72- }
73-
7446 @ Test
7547 void sseKms_withContext_contextStoredDefensively () {
7648 Map <String , String > ctx = new HashMap <>(Map .of ("dept" , "finance" ));
@@ -89,6 +61,48 @@ void sseKms_nullContext_contextIsEmpty() {
8961 assertThat (c .hasEncryptionContext ()).isFalse ();
9062 }
9163
64+ @ ParameterizedTest
65+ @ MethodSource
66+ void sseKms_contextOnlyFactory_absentContext_hasEncryptionContextFalse (
67+ Map <String , String > context ) {
68+ S3EncryptionConfig c = S3EncryptionConfig .sseKms (context );
69+
70+ assertThat (c .getEncryptionContext ()).isEmpty ();
71+ assertThat (c .hasEncryptionContext ()).isFalse ();
72+ }
73+
74+ static Stream <Arguments > sseKms_contextOnlyFactory_absentContext_hasEncryptionContextFalse () {
75+ return Stream .of (
76+ Arguments .of (Collections .emptyMap ()),
77+ Arguments .of ((Object ) null ));
78+ }
79+
80+ @ Test
81+ void sseKms_contextOnlyFactory_contextMutatedAfterCreation_contextUnchanged () {
82+ Map <String , String > ctx = new HashMap <>(Map .of ("dept" , "finance" ));
83+ S3EncryptionConfig c = S3EncryptionConfig .sseKms (ctx );
84+ ctx .put ("extra" , "value" );
85+
86+ assertThat (c .getEncryptionContext ()).isEqualTo (Map .of ("dept" , "finance" ));
87+ }
88+
89+ @ ParameterizedTest
90+ @ MethodSource
91+ void getServerSideEncryption_allTypes_returnsCorrectSseValue (
92+ String configType , ServerSideEncryption expected ) {
93+ S3EncryptionConfig c =
94+ S3EncryptionConfig .fromConfig (configType , null , Collections .emptyMap ());
95+
96+ assertThat (c .getServerSideEncryption ()).isEqualTo (expected );
97+ }
98+
99+ static Stream <Arguments > getServerSideEncryption_allTypes_returnsCorrectSseValue () {
100+ return Stream .of (
101+ Arguments .of (null , null ),
102+ Arguments .of ("sse-s3" , ServerSideEncryption .AES256 ),
103+ Arguments .of ("sse-kms" , ServerSideEncryption .AWS_KMS ));
104+ }
105+
92106 @ ParameterizedTest
93107 @ MethodSource
94108 void fromConfig_typeVariants_returnExpectedType (
@@ -105,6 +119,7 @@ static Stream<Arguments> fromConfig_typeVariants_returnExpectedType() {
105119 Arguments .of ("" , NONE ),
106120 Arguments .of ("none" , NONE ),
107121 Arguments .of ("NONE" , NONE ),
122+ Arguments .of (" " , NONE ),
108123 Arguments .of ("sse-s3" , SSE_S3 ),
109124 Arguments .of ("AES256" , SSE_S3 ),
110125 Arguments .of ("sse-kms" , SSE_KMS ),
@@ -141,6 +156,15 @@ void fromConfig_sseKmsDefaultKeyWithContext_contextPreserved() {
141156 .isTrue ();
142157 }
143158
159+ @ Test
160+ void fromConfig_sseS3WithContext_contextIgnored () {
161+ S3EncryptionConfig c =
162+ S3EncryptionConfig .fromConfig ("sse-s3" , null , Map .of ("dept" , "finance" ));
163+
164+ assertThat (c .getEncryptionType ()).isEqualTo (SSE_S3 );
165+ assertThat (c .getEncryptionContext ()).isEmpty ();
166+ }
167+
144168 @ Test
145169 void fromConfig_unknownType_throwsIllegalArgument () {
146170 assertThatThrownBy (
@@ -151,42 +175,67 @@ void fromConfig_unknownType_throwsIllegalArgument() {
151175 .hasMessageContaining ("invalid-type" );
152176 }
153177
154- @ Test
155- void toString_noKeyOrContext_containsTypeOnly () {
156- S3EncryptionConfig c = S3EncryptionConfig .none ();
178+ @ ParameterizedTest
179+ @ MethodSource
180+ void serializeEncryptionContext_exactOutput_correctBase64Json (
181+ Map <String , String > context , String expectedDecoded ) {
182+ S3EncryptionConfig c = S3EncryptionConfig .sseKms (context );
183+ String decoded = new String (Base64 .getDecoder ().decode (c .serializeEncryptionContext ()));
157184
158- assertThat (c .toString ()).contains ("NONE" );
159- assertThat (c .toString ()).doesNotContain ("kmsKeyId" );
160- assertThat (c .toString ()).doesNotContain ("encryptionContext" );
185+ assertThat (decoded ).isEqualTo (expectedDecoded );
186+ }
187+
188+ static Stream <Arguments > serializeEncryptionContext_exactOutput_correctBase64Json () {
189+ return Stream .of (
190+ Arguments .of (Collections .emptyMap (), "{}" ),
191+ Arguments .of (Map .of ("k" , "v" ), "{\" k\" :\" v\" }" ));
161192 }
162193
163194 @ Test
164- void toString_withKeyId_includesKeyId () {
165- S3EncryptionConfig c = S3EncryptionConfig .sseKms ("my-key" );
195+ void serializeEncryptionContext_multipleEntries_allEntriesPresent () {
196+ S3EncryptionConfig c = S3EncryptionConfig .sseKms (Map .of ("k1" , "v1" , "k2" , "v2" ));
197+ String decoded = new String (Base64 .getDecoder ().decode (c .serializeEncryptionContext ()));
166198
167- assertThat (c . toString ()) .contains ("my-key " );
199+ assertThat (decoded ) .contains ("\" k1 \" : \" v1 \" " , " \" k2 \" : \" v2 \" " );
168200 }
169201
170- @ Test
171- void toString_withContext_includesContextKeys () {
172- S3EncryptionConfig c = S3EncryptionConfig .sseKms ("k" , Map .of ("dept" , "finance" ));
202+ @ ParameterizedTest
203+ @ MethodSource
204+ void serializeEncryptionContext_jsonSpecialChars_escapedCorrectly (
205+ String key , String value , String expectedFragment ) {
206+ S3EncryptionConfig c = S3EncryptionConfig .sseKms (Map .of (key , value ));
207+ String decoded = new String (Base64 .getDecoder ().decode (c .serializeEncryptionContext ()));
173208
174- assertThat (c . toString ()) .contains ("dept" );
209+ assertThat (decoded ) .contains (expectedFragment );
175210 }
176211
177- @ Test
178- void serialization_roundTrip_preservesAllFields () throws Exception {
179- S3EncryptionConfig original = S3EncryptionConfig .sseKms ("key-id" , Map .of ("k" , "v" ));
212+ static Stream <Arguments > serializeEncryptionContext_jsonSpecialChars_escapedCorrectly () {
213+ return Stream .of (
214+ Arguments .of ("k" , "val\" ue" , "\" k\" :\" val\\ \" ue\" " ),
215+ Arguments .of ("k" , "val\\ ue" , "\" k\" :\" val\\ \\ ue\" " ),
216+ Arguments .of ("k\" ey" , "v" , "\" k\\ \" ey\" :\" v\" " ));
217+ }
180218
219+ @ ParameterizedTest
220+ @ MethodSource
221+ void serialization_roundTrip_preservesAllFields (S3EncryptionConfig config ) throws Exception {
181222 ByteArrayOutputStream bos = new ByteArrayOutputStream ();
182- new ObjectOutputStream (bos ).writeObject (original );
223+ new ObjectOutputStream (bos ).writeObject (config );
183224 S3EncryptionConfig copy =
184225 (S3EncryptionConfig )
185226 new ObjectInputStream (new ByteArrayInputStream (bos .toByteArray ()))
186227 .readObject ();
187228
188- assertThat (copy .getEncryptionType ()).isEqualTo (original .getEncryptionType ());
189- assertThat (copy .getKmsKeyId ()).isEqualTo (original .getKmsKeyId ());
190- assertThat (copy .getEncryptionContext ()).isEqualTo (original .getEncryptionContext ());
229+ assertThat (copy .getEncryptionType ()).isEqualTo (config .getEncryptionType ());
230+ assertThat (copy .getKmsKeyId ()).isEqualTo (config .getKmsKeyId ());
231+ assertThat (copy .getEncryptionContext ()).isEqualTo (config .getEncryptionContext ());
232+ }
233+
234+ static Stream <Arguments > serialization_roundTrip_preservesAllFields () {
235+ return Stream .of (
236+ Arguments .of (S3EncryptionConfig .sseKms ("key-id" , Map .of ("k" , "v" ))),
237+ Arguments .of (S3EncryptionConfig .none ()),
238+ Arguments .of (S3EncryptionConfig .sseS3 ()),
239+ Arguments .of (S3EncryptionConfig .sseKms ()));
191240 }
192241}
0 commit comments