github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/sink/codec/avro/mock_schema_registry.go (about) 1 // Copyright 2020 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package avro 15 16 import ( 17 "encoding/json" 18 "io" 19 "net/http" 20 "sync" 21 22 "github.com/jarcoal/httpmock" 23 ) 24 25 type mockConfluentRegistrySchema struct { 26 content string 27 version int 28 ID int 29 } 30 31 type mockRegistry struct { 32 mu sync.Mutex 33 subjects map[string]*mockConfluentRegistrySchema 34 newID int 35 } 36 37 func startHTTPInterceptForTestingRegistry() { 38 httpmock.Activate() 39 40 registry := mockRegistry{ 41 subjects: make(map[string]*mockConfluentRegistrySchema), 42 newID: 1, 43 } 44 45 httpmock.RegisterResponder( 46 "GET", 47 "http://127.0.0.1:8081", 48 httpmock.NewStringResponder(200, "{}"), 49 ) 50 51 httpmock.RegisterResponder("POST", `=~^http://127.0.0.1:8081/subjects/(.+)/versions`, 52 func(req *http.Request) (*http.Response, error) { 53 subject, err := httpmock.GetSubmatch(req, 1) 54 if err != nil { 55 return nil, err 56 } 57 reqBody, err := io.ReadAll(req.Body) 58 if err != nil { 59 return nil, err 60 } 61 var reqData registerRequest 62 err = json.Unmarshal(reqBody, &reqData) 63 if err != nil { 64 return nil, err 65 } 66 67 var respData registerResponse 68 registry.mu.Lock() 69 item, exists := registry.subjects[subject] 70 if !exists { 71 item = &mockConfluentRegistrySchema{ 72 content: reqData.Schema, 73 version: 1, 74 ID: registry.newID, 75 } 76 registry.subjects[subject] = item 77 respData.SchemaID = registry.newID 78 } else { 79 if item.content == reqData.Schema { 80 respData.SchemaID = item.ID 81 } else { 82 item.content = reqData.Schema 83 item.version++ 84 item.ID = registry.newID 85 respData.SchemaID = registry.newID 86 } 87 } 88 registry.newID++ 89 registry.mu.Unlock() 90 return httpmock.NewJsonResponse(200, &respData) 91 }) 92 93 httpmock.RegisterResponder("GET", `=~^http://127.0.0.1:8081/schemas/ids/(.+)`, 94 func(req *http.Request) (*http.Response, error) { 95 id, err := httpmock.GetSubmatchAsInt(req, 1) 96 if err != nil { 97 return httpmock.NewStringResponse(500, "Internal Server Error"), err 98 } 99 100 for key, item := range registry.subjects { 101 if item.ID == int(id) { 102 var respData lookupResponse 103 respData.Schema = item.content 104 respData.Name = key 105 respData.SchemaID = item.ID 106 return httpmock.NewJsonResponse(200, &respData) 107 } 108 } 109 110 return httpmock.NewStringResponse(404, "Not Found"), nil 111 }) 112 113 httpmock.RegisterResponder("DELETE", `=~^http://127.0.0.1:8081/subjects/(.+)`, 114 func(req *http.Request) (*http.Response, error) { 115 subject, err := httpmock.GetSubmatch(req, 1) 116 if err != nil { 117 return nil, err 118 } 119 120 registry.mu.Lock() 121 defer registry.mu.Unlock() 122 item, exists := registry.subjects[subject] 123 if !exists { 124 return httpmock.NewStringResponse(404, ""), nil 125 } 126 127 delete(registry.subjects, subject) 128 // simplify the response not returning all the versions 129 return httpmock.NewJsonResponse(200, []int{item.version}) 130 }) 131 132 failCounter := 0 133 httpmock.RegisterResponder("POST", `=~^http://127.0.0.1:8081/may-fail`, 134 func(req *http.Request) (*http.Response, error) { 135 _, _ = io.ReadAll(req.Body) 136 if failCounter < 3 { 137 failCounter++ 138 return httpmock.NewStringResponse(500, ""), nil 139 } 140 return httpmock.NewStringResponse(200, ""), nil 141 }) 142 } 143 144 func stopHTTPInterceptForTestingRegistry() { 145 httpmock.DeactivateAndReset() 146 }