...

Source file src/k8s.io/client-go/util/testing/fake_openapi_handler.go

Documentation: k8s.io/client-go/util/testing

     1  /*
     2  Copyright 2021 The Kubernetes Authors.
     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 testing
    18  
    19  import (
    20  	"encoding/json"
    21  	"io"
    22  	"io/fs"
    23  	"net/http"
    24  	"net/http/httptest"
    25  	"os"
    26  	"path/filepath"
    27  	"strings"
    28  	"sync"
    29  
    30  	"k8s.io/kube-openapi/pkg/handler3"
    31  	"k8s.io/kube-openapi/pkg/spec3"
    32  )
    33  
    34  type FakeOpenAPIServer struct {
    35  	HttpServer      *httptest.Server
    36  	ServedDocuments map[string]*spec3.OpenAPI
    37  	RequestCounters map[string]int
    38  }
    39  
    40  // Creates a mock OpenAPIV3 server as it would be on a standing kubernetes
    41  // API server.
    42  //
    43  // specsPath - Give a path to some test data organized so that each GroupVersion
    44  // has its own OpenAPI V3 JSON file.
    45  //
    46  //	i.e. apps/v1beta1 is stored in <specsPath>/apps/v1beta1.json
    47  func NewFakeOpenAPIV3Server(specsPath string) (*FakeOpenAPIServer, error) {
    48  	mux := &testMux{
    49  		counts: map[string]int{},
    50  	}
    51  	server := httptest.NewServer(mux)
    52  
    53  	openAPIVersionedService := handler3.NewOpenAPIService()
    54  	err := openAPIVersionedService.RegisterOpenAPIV3VersionedService("/openapi/v3", mux)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	grouped := make(map[string][]byte)
    60  	var testV3Specs = make(map[string]*spec3.OpenAPI)
    61  
    62  	addSpec := func(path string) {
    63  		file, err := os.Open(path)
    64  		if err != nil {
    65  			panic(err)
    66  		}
    67  
    68  		defer file.Close()
    69  		vals, err := io.ReadAll(file)
    70  		if err != nil {
    71  			panic(err)
    72  		}
    73  
    74  		rel, err := filepath.Rel(specsPath, path)
    75  		if err == nil {
    76  			grouped[rel[:(len(rel)-len(filepath.Ext(rel)))]] = vals
    77  		}
    78  	}
    79  
    80  	filepath.WalkDir(specsPath, func(path string, d fs.DirEntry, err error) error {
    81  		if filepath.Ext(path) != ".json" || d.IsDir() {
    82  			return nil
    83  		}
    84  
    85  		addSpec(path)
    86  		return nil
    87  	})
    88  
    89  	for gv, jsonSpec := range grouped {
    90  		spec := &spec3.OpenAPI{}
    91  		err = json.Unmarshal(jsonSpec, spec)
    92  		if err != nil {
    93  			return nil, err
    94  		}
    95  
    96  		testV3Specs[gv] = spec
    97  		openAPIVersionedService.UpdateGroupVersion(gv, spec)
    98  	}
    99  
   100  	return &FakeOpenAPIServer{
   101  		HttpServer:      server,
   102  		ServedDocuments: testV3Specs,
   103  		RequestCounters: mux.counts,
   104  	}, nil
   105  }
   106  
   107  ////////////////////////////////////////////////////////////////////////////////
   108  // Tiny Test HTTP Mux
   109  ////////////////////////////////////////////////////////////////////////////////
   110  // Implements the mux interface used by handler3 for registering the OpenAPI
   111  //	handlers
   112  
   113  type testMux struct {
   114  	lock      sync.Mutex
   115  	prefixMap map[string]http.Handler
   116  	pathMap   map[string]http.Handler
   117  	counts    map[string]int
   118  }
   119  
   120  func (t *testMux) Handle(path string, handler http.Handler) {
   121  	t.lock.Lock()
   122  	defer t.lock.Unlock()
   123  
   124  	if t.pathMap == nil {
   125  		t.pathMap = make(map[string]http.Handler)
   126  	}
   127  	t.pathMap[path] = handler
   128  }
   129  
   130  func (t *testMux) HandlePrefix(path string, handler http.Handler) {
   131  	t.lock.Lock()
   132  	defer t.lock.Unlock()
   133  
   134  	if t.prefixMap == nil {
   135  		t.prefixMap = make(map[string]http.Handler)
   136  	}
   137  	t.prefixMap[path] = handler
   138  }
   139  
   140  func (t *testMux) ServeHTTP(w http.ResponseWriter, req *http.Request) {
   141  	t.lock.Lock()
   142  	defer t.lock.Unlock()
   143  
   144  	if t.counts == nil {
   145  		t.counts = make(map[string]int)
   146  	}
   147  
   148  	if val, exists := t.counts[req.URL.Path]; exists {
   149  		t.counts[req.URL.Path] = val + 1
   150  	} else {
   151  		t.counts[req.URL.Path] = 1
   152  	}
   153  
   154  	if handler, ok := t.pathMap[req.URL.Path]; ok {
   155  		handler.ServeHTTP(w, req)
   156  		return
   157  	}
   158  
   159  	for k, v := range t.prefixMap {
   160  		if strings.HasPrefix(req.URL.Path, k) {
   161  			v.ServeHTTP(w, req)
   162  			return
   163  		}
   164  	}
   165  
   166  	w.WriteHeader(http.StatusNotFound)
   167  }
   168  

View as plain text