@@ -190,6 +190,60 @@ const demoSchemaWithUnion = `
190190 ]
191191}
192192`
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+ `
193247
194248class FakeClock extends Clock {
195249 fixedNow : number = 0
@@ -320,6 +374,38 @@ describe('AvroSerializer', () => {
320374 expect ( obj2 . otherField . boolField ) . toEqual ( nested . boolField ) ;
321375 expect ( obj2 . otherField . bytesField ) . toEqual ( nested . bytesField ) ;
322376 } )
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+ } )
323409 it ( 'basic encryption' , async ( ) => {
324410 let conf : ClientConfig = {
325411 baseURLs : [ baseURL ] ,
@@ -876,6 +962,124 @@ describe('AvroSerializer', () => {
876962 expect ( obj2 . boolField ) . toEqual ( obj . boolField ) ;
877963 expect ( obj2 . bytesField ) . toEqual ( obj . bytesField ) ;
878964 } )
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+ } )
8791083 it ( 'jsonata fully compatible' , async ( ) => {
8801084 let rule1To2 = "$merge([$sift($, function($v, $k) {$k != 'size'}), {'height': $.'size'}])"
8811085 let rule2To1 = "$merge([$sift($, function($v, $k) {$k != 'height'}), {'size': $.'height'}])"
0 commit comments