@@ -190,6 +190,60 @@ const demoSchemaWithUnion = `
190
190
]
191
191
}
192
192
`
193
+ const schemaEvolution1 = `
194
+ {
195
+ "name": "SchemaEvolution",
196
+ "type": "record",
197
+ "fields": [
198
+ {
199
+ "name": "fieldToDelete",
200
+ "type": "string"
201
+ }
202
+ ]
203
+ }
204
+ `
205
+ const schemaEvolution2 = `
206
+ {
207
+ "name": "SchemaEvolution",
208
+ "type": "record",
209
+ "fields": [
210
+ {
211
+ "name": "newOptionalField",
212
+ "type": ["string", "null"],
213
+ "default": "optional"
214
+ }
215
+ ]
216
+ }
217
+ `
218
+ const complexSchema = `
219
+ {
220
+ "name": "ComplexSchema",
221
+ "type": "record",
222
+ "fields": [
223
+ {
224
+ "name": "arrayField",
225
+ "type": {
226
+ "type": "array",
227
+ "items": "string"
228
+ },
229
+ "confluent:tags": [ "PII" ]
230
+ },
231
+ {
232
+ "name": "mapField",
233
+ "type": {
234
+ "type": "map",
235
+ "values": "string"
236
+ },
237
+ "confluent:tags": [ "PII" ]
238
+ },
239
+ {
240
+ "name": "unionField",
241
+ "type": ["null", "string"],
242
+ "confluent:tags": [ "PII" ]
243
+ }
244
+ ]
245
+ }
246
+ `
193
247
194
248
class FakeClock extends Clock {
195
249
fixedNow : number = 0
@@ -320,6 +374,38 @@ describe('AvroSerializer', () => {
320
374
expect ( obj2 . otherField . boolField ) . toEqual ( nested . boolField ) ;
321
375
expect ( obj2 . otherField . bytesField ) . toEqual ( nested . bytesField ) ;
322
376
} )
377
+ it ( 'schema evolution' , async ( ) => {
378
+ let conf : ClientConfig = {
379
+ baseURLs : [ baseURL ] ,
380
+ cacheCapacity : 1000
381
+ }
382
+ let client = SchemaRegistryClient . newClient ( conf )
383
+ let ser = new AvroSerializer ( client , SerdeType . VALUE , { useLatestVersion : true } )
384
+
385
+ let obj = {
386
+ fieldToDelete : "bye" ,
387
+ }
388
+ let info : SchemaInfo = {
389
+ schemaType : 'AVRO' ,
390
+ schema : schemaEvolution1 ,
391
+ }
392
+
393
+ await client . register ( subject , info , false )
394
+
395
+ let bytes = await ser . serialize ( topic , obj )
396
+
397
+ info = {
398
+ schemaType : 'AVRO' ,
399
+ schema : schemaEvolution2 ,
400
+ }
401
+
402
+ await client . register ( subject , info , false )
403
+
404
+ let deser = new AvroDeserializer ( client , SerdeType . VALUE , { useLatestVersion : true } )
405
+ let obj2 = await deser . deserialize ( topic , bytes )
406
+ expect ( obj2 . fieldToDelete ) . toEqual ( undefined ) ;
407
+ expect ( obj2 . newOptionalField ) . toEqual ( "optional" ) ;
408
+ } )
323
409
it ( 'basic encryption' , async ( ) => {
324
410
let conf : ClientConfig = {
325
411
baseURLs : [ baseURL ] ,
@@ -876,6 +962,124 @@ describe('AvroSerializer', () => {
876
962
expect ( obj2 . boolField ) . toEqual ( obj . boolField ) ;
877
963
expect ( obj2 . bytesField ) . toEqual ( obj . bytesField ) ;
878
964
} )
965
+ it ( 'complex encryption' , async ( ) => {
966
+ let conf : ClientConfig = {
967
+ baseURLs : [ baseURL ] ,
968
+ cacheCapacity : 1000
969
+ }
970
+ let client = SchemaRegistryClient . newClient ( conf )
971
+ let serConfig : AvroSerializerConfig = {
972
+ useLatestVersion : true ,
973
+ ruleConfig : {
974
+ secret : 'mysecret'
975
+ }
976
+ }
977
+ let ser = new AvroSerializer ( client , SerdeType . VALUE , serConfig )
978
+ let dekClient = fieldEncryptionExecutor . client !
979
+
980
+ let encRule : Rule = {
981
+ name : 'test-encrypt' ,
982
+ kind : 'TRANSFORM' ,
983
+ mode : RuleMode . WRITEREAD ,
984
+ type : 'ENCRYPT' ,
985
+ tags : [ 'PII' ] ,
986
+ params : {
987
+ 'encrypt.kek.name' : 'kek1' ,
988
+ 'encrypt.kms.type' : 'local-kms' ,
989
+ 'encrypt.kms.key.id' : 'mykey' ,
990
+ } ,
991
+ onFailure : 'ERROR,NONE'
992
+ }
993
+ let ruleSet : RuleSet = {
994
+ domainRules : [ encRule ]
995
+ }
996
+
997
+ let info : SchemaInfo = {
998
+ schemaType : 'AVRO' ,
999
+ schema : complexSchema ,
1000
+ ruleSet
1001
+ }
1002
+
1003
+ await client . register ( subject , info , false )
1004
+
1005
+ let obj = {
1006
+ arrayField : [ 'hello' ] ,
1007
+ mapField : { 'key' : 'world' } ,
1008
+ unionField : 'bye' ,
1009
+ }
1010
+ let bytes = await ser . serialize ( topic , obj )
1011
+
1012
+ let deserConfig : AvroDeserializerConfig = {
1013
+ ruleConfig : {
1014
+ secret : 'mysecret'
1015
+ }
1016
+ }
1017
+ let deser = new AvroDeserializer ( client , SerdeType . VALUE , deserConfig )
1018
+ fieldEncryptionExecutor . client = dekClient
1019
+ let obj2 = await deser . deserialize ( topic , bytes )
1020
+ expect ( obj2 . arrayField ) . toEqual ( [ 'hello' ] ) ;
1021
+ expect ( obj2 . mapField ) . toEqual ( { 'key' : 'world' } ) ;
1022
+ expect ( obj2 . unionField ) . toEqual ( 'bye' ) ;
1023
+ } )
1024
+ it ( 'complex encryption with null' , async ( ) => {
1025
+ let conf : ClientConfig = {
1026
+ baseURLs : [ baseURL ] ,
1027
+ cacheCapacity : 1000
1028
+ }
1029
+ let client = SchemaRegistryClient . newClient ( conf )
1030
+ let serConfig : AvroSerializerConfig = {
1031
+ useLatestVersion : true ,
1032
+ ruleConfig : {
1033
+ secret : 'mysecret'
1034
+ }
1035
+ }
1036
+ let ser = new AvroSerializer ( client , SerdeType . VALUE , serConfig )
1037
+ let dekClient = fieldEncryptionExecutor . client !
1038
+
1039
+ let encRule : Rule = {
1040
+ name : 'test-encrypt' ,
1041
+ kind : 'TRANSFORM' ,
1042
+ mode : RuleMode . WRITEREAD ,
1043
+ type : 'ENCRYPT' ,
1044
+ tags : [ 'PII' ] ,
1045
+ params : {
1046
+ 'encrypt.kek.name' : 'kek1' ,
1047
+ 'encrypt.kms.type' : 'local-kms' ,
1048
+ 'encrypt.kms.key.id' : 'mykey' ,
1049
+ } ,
1050
+ onFailure : 'ERROR,NONE'
1051
+ }
1052
+ let ruleSet : RuleSet = {
1053
+ domainRules : [ encRule ]
1054
+ }
1055
+
1056
+ let info : SchemaInfo = {
1057
+ schemaType : 'AVRO' ,
1058
+ schema : complexSchema ,
1059
+ ruleSet
1060
+ }
1061
+
1062
+ await client . register ( subject , info , false )
1063
+
1064
+ let obj = {
1065
+ arrayField : [ 'hello' ] ,
1066
+ mapField : { 'key' : 'world' } ,
1067
+ unionField : null
1068
+ }
1069
+ let bytes = await ser . serialize ( topic , obj )
1070
+
1071
+ let deserConfig : AvroDeserializerConfig = {
1072
+ ruleConfig : {
1073
+ secret : 'mysecret'
1074
+ }
1075
+ }
1076
+ let deser = new AvroDeserializer ( client , SerdeType . VALUE , deserConfig )
1077
+ fieldEncryptionExecutor . client = dekClient
1078
+ let obj2 = await deser . deserialize ( topic , bytes )
1079
+ expect ( obj2 . arrayField ) . toEqual ( [ 'hello' ] ) ;
1080
+ expect ( obj2 . mapField ) . toEqual ( { 'key' : 'world' } ) ;
1081
+ expect ( obj2 . unionField ) . toEqual ( null ) ;
1082
+ } )
879
1083
it ( 'jsonata fully compatible' , async ( ) => {
880
1084
let rule1To2 = "$merge([$sift($, function($v, $k) {$k != 'size'}), {'height': $.'size'}])"
881
1085
let rule2To1 = "$merge([$sift($, function($v, $k) {$k != 'height'}), {'size': $.'height'}])"
0 commit comments