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  }