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  }