github.com/confluentinc/confluent-kafka-go@v1.9.2/schemaregistry/schemaregistry_client_test.go (about) 1 /** 2 * Copyright 2022 Confluent Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package schemaregistry 18 19 import ( 20 "fmt" 21 "io/ioutil" 22 "log" 23 "sort" 24 "strconv" 25 "testing" 26 ) 27 28 var schemaTests = [][]string{ 29 {"./test/avro/complex.avsc"}, 30 {"./test/avro/union.avsc"}, 31 {"./test/avro/null.avsc"}, 32 {"./test/avro/bool.avsc"}, 33 {"./test/avro/int.avsc"}, 34 {"./test/avro/long.avsc"}, 35 {"./test/avro/float.avsc"}, 36 {"./test/avro/double.avsc"}, 37 {"./test/avro/advanced.avsc", "./test/avro/advanced-2.avsc"}, 38 {"./test/avro/string.avsc"}, 39 } 40 41 func testRegister(subject string, schema SchemaInfo) (id int) { 42 id, err := srClient.Register(subject, schema, false) 43 maybeFail(subject, err) 44 return id 45 } 46 47 func testGetBySubjectAndID(subject string, id int) SchemaInfo { 48 schema, err := srClient.GetBySubjectAndID(subject, id) 49 maybeFail(strconv.Itoa(id), err) 50 return schema 51 } 52 53 func testGetBySubjectAndIDNotFound(subject string, id int) { 54 _, err := srClient.GetBySubjectAndID(subject, id) 55 if err == nil { 56 maybeFail("testGetBySubjectAndIDNotFound", fmt.Errorf("Expected error, found nil")) 57 } 58 } 59 60 func testGetID(subject string, schema SchemaInfo, expected int) int { 61 actual, err := srClient.GetID(subject, schema, false) 62 maybeFail(subject, err, expect(actual, expected)) 63 return actual 64 } 65 66 func testGetIDNotFound(subject string, schema SchemaInfo) { 67 _, err := srClient.GetID(subject, schema, false) 68 if err == nil { 69 maybeFail("testGetIDNotFound", fmt.Errorf("Expected error, found nil")) 70 } 71 } 72 73 func testGetLatestSchemaMetadata(subject string) { 74 _, err := srClient.GetLatestSchemaMetadata(subject) 75 maybeFail(subject, err) 76 } 77 78 func testGetSchemaMetadata(subject string, versionID int, expected string) { 79 actual, err := srClient.GetSchemaMetadata(subject, versionID) 80 // avoid nil pointer dereference 81 maybeFail(subject, err) 82 maybeFail(subject, expect(expected, actual.Schema)) 83 } 84 85 func testGetVersion(subject string, schema SchemaInfo) (version int) { 86 actual, err := srClient.GetVersion(subject, schema, false) 87 maybeFail(subject, err) 88 return actual 89 } 90 91 func testGetVersionNotFound(subject string, schema SchemaInfo) { 92 _, err := srClient.GetVersion(subject, schema, false) 93 if err == nil { 94 maybeFail("testGetVersionNotFound", fmt.Errorf("Expected error, found nil")) 95 } 96 } 97 98 func testGetAllVersions(subject string, expected []int) { 99 actual, err := srClient.GetAllVersions(subject) 100 sort.Ints(actual) 101 sort.Ints(expected) 102 maybeFail(subject, err, expect(actual, expected)) 103 } 104 105 func testGetCompatibility(subject string, expected Compatibility) { 106 actual, err := srClient.GetCompatibility(subject) 107 maybeFail(subject, err, expect(actual, expected)) 108 } 109 110 func testUpdateCompatibility(subject string, update Compatibility, expected Compatibility) { 111 actual, err := srClient.UpdateCompatibility(subject, update) 112 maybeFail(subject, err, expect(actual, expected)) 113 } 114 115 func testGetDefaultCompatibility(expected Compatibility) { 116 actual, err := srClient.GetDefaultCompatibility() 117 maybeFail("Default Compatibility", err, expect(actual, expected)) 118 } 119 120 func testUpdateDefaultCompatibility(update Compatibility, expected Compatibility) { 121 actual, err := srClient.UpdateDefaultCompatibility(update) 122 maybeFail("Default Compatibility", err, expect(actual, expected)) 123 } 124 125 func testGetAllSubjects(expected []string) { 126 actual, err := srClient.GetAllSubjects() 127 sort.Strings(actual) 128 sort.Strings(expected) 129 maybeFail("All Subjects", err, expect(actual, expected)) 130 } 131 132 func testDeleteSubject(subject string, permanent bool, expected []int, ids []int, schemas []SchemaInfo) { 133 actual, err := srClient.DeleteSubject(subject, permanent) 134 sort.Ints(actual) 135 sort.Ints(expected) 136 maybeFail(subject, err, expect(actual, expected)) 137 for i := range expected { 138 if permanent { 139 testGetBySubjectAndIDNotFound(subject, ids[i]) 140 } else { 141 testGetBySubjectAndID(subject, ids[i]) 142 } 143 testGetIDNotFound(subject, schemas[i]) 144 testGetVersionNotFound(subject, schemas[i]) 145 } 146 } 147 148 func testDeleteSubjectVersion(subject string, permanent bool, version int, expected int, id int, schema SchemaInfo) { 149 actual, err := srClient.DeleteSubjectVersion(subject, version, permanent) 150 maybeFail(subject, err, expect(actual, expected)) 151 if permanent { 152 testGetBySubjectAndIDNotFound(subject, id) 153 } else { 154 testGetBySubjectAndID(subject, id) 155 } 156 testGetIDNotFound(subject, schema) 157 testGetVersionNotFound(subject, schema) 158 } 159 160 func testTestCompatibility(subject string, version int, schema SchemaInfo, expected bool) { 161 actual, err := srClient.TestCompatibility(subject, version, schema) 162 maybeFail(subject, err, expect(actual, expected)) 163 } 164 165 func testRemainingVersions(subjects []string, schemas [][]SchemaInfo, ids [][]int, versions [][]int) { 166 for i := range subjects { 167 for j := range schemas[i] { 168 testGetID(subjects[i], schemas[i][j], ids[i][j]) 169 foundVersion := testGetVersion(subjects[i], schemas[i][j]) 170 maybeFail("testRemainingVersions", expect(foundVersion, versions[i][j])) 171 } 172 } 173 } 174 175 func TestClient(t *testing.T) { 176 maybeFail = initFailFunc(t) 177 178 url := testconf.getString("SchemaRegistryURL") 179 if url == "" { 180 url = "mock://" 181 } 182 conf := NewConfig(url) 183 184 var err error 185 srClient, err = NewClient(conf) 186 maybeFail("schema registry client instantiation ", err) 187 188 var subjects = make([]string, len(schemaTests)) 189 var ids = make([][]int, len(schemaTests)) 190 var versions = make([][]int, len(schemaTests)) 191 var schemas = make([][]SchemaInfo, len(schemaTests)) 192 var version int 193 194 for idx, schemaTestVersions := range schemaTests { 195 var currentVersions = make([]int, 0) 196 subject := fmt.Sprintf("schema%d-key", idx) 197 srClient.DeleteSubject(subject, false) 198 srClient.DeleteSubject(subject, true) 199 subjects[idx] = subject 200 for _, schemaTest := range schemaTestVersions { 201 buff, err := ioutil.ReadFile(schemaTest) 202 if err != nil { 203 panic(err) 204 } 205 schema := SchemaInfo{ 206 Schema: string(buff), 207 } 208 209 id := testRegister(subject, schema) 210 version = testGetVersion(subject, schema) 211 212 // The schema registry will return a normalized Avro Schema so we can't directly compare the two 213 // To work around this we retrieve a normalized schema from the Schema registry first for comparison 214 normalized := testGetBySubjectAndID(subject, id) 215 testGetSchemaMetadata(subject, version, normalized.Schema) 216 testGetLatestSchemaMetadata(subject) 217 218 testUpdateCompatibility(subject, Forward, Forward) 219 testGetCompatibility(subject, Forward) 220 221 testUpdateDefaultCompatibility(None, None) 222 testGetDefaultCompatibility(None) 223 224 currentVersions = append(currentVersions, version) 225 testGetAllVersions(subject, currentVersions) 226 227 ids[idx] = append(ids[idx], id) 228 versions[idx] = append(versions[idx], version) 229 schemas[idx] = append(schemas[idx], schema) 230 } 231 } 232 233 lastSubject := len(subjects) - 1 234 secondToLastSubject := len(subjects) - 2 235 testDeleteSubject(subjects[lastSubject], false, versions[lastSubject], ids[lastSubject], schemas[lastSubject]) 236 testDeleteSubjectVersion(subjects[secondToLastSubject], false, versions[secondToLastSubject][0], versions[secondToLastSubject][0], ids[secondToLastSubject][0], schemas[secondToLastSubject][0]) 237 // Second to last subject now has only one version 238 initialVersionsSecondToLastSubject := versions[secondToLastSubject][0:] 239 initialSchemasSecondToLastSubject := schemas[secondToLastSubject][0:] 240 initialIdsSecondToLastSubject := ids[secondToLastSubject][0:] 241 versions[secondToLastSubject] = versions[secondToLastSubject][1:] 242 schemas[secondToLastSubject] = schemas[secondToLastSubject][1:] 243 ids[secondToLastSubject] = ids[secondToLastSubject][1:] 244 // Only last subject has been removed completely 245 testGetAllSubjects(subjects[:lastSubject]) 246 remainingSubjects := subjects[:lastSubject] 247 testRemainingVersions(remainingSubjects, schemas, ids, versions) 248 // Cleanup subjects 249 for i := range remainingSubjects { 250 testDeleteSubject(remainingSubjects[i], false, versions[i], ids[i], schemas[i]) 251 if i == secondToLastSubject { 252 testDeleteSubject(remainingSubjects[i], true, initialVersionsSecondToLastSubject, initialIdsSecondToLastSubject, initialSchemasSecondToLastSubject) 253 } else { 254 testDeleteSubject(remainingSubjects[i], true, versions[i], ids[i], schemas[i]) 255 } 256 } 257 } 258 259 func init() { 260 if !testconfRead() { 261 log.Print("WARN: Missing testconf.json, using mock client") 262 } 263 }