* Add Get() and GetOptions. * Removed watcher. Outline of client. YAML templates * Added default service and deployment templates and types * Added API tests and cleaned up errors. * Small refactoring. Template package is no more. * Ripped out existing code in preparation to small rework * Reshuffled the source code to make it organized better * Create service and deployment in kubernetes runtime * Major cleanup and refactoring of Kubernetes runtime * Service now handles low level K8s API calls across both K8s deployment an service API objects * Runtime has a task queue that serves for queueing runtime action requests * General refactoring * No need for Lock in k8s service * Added kubernetes runtime env var to default deployment * Enable running different versions of the same service * Can't delete services through labels * Proto cruft. Added runtime.CreateOptions implementation in proto * Removed proxy service from default env variables * Make service name mandatory param to Get method * Get Delete changes from https://github.com/micro/go-micro/pull/945 * Replaced template files with global variables * Validate service names before sending K8s API request * Refactored Kubernetes API client. Fixed typos. * Added client.Resource to make API resources more explicit in code
		
			
				
	
	
		
			170 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			170 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package api
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"net/http"
 | 
						|
	"net/http/httptest"
 | 
						|
	"reflect"
 | 
						|
	"testing"
 | 
						|
)
 | 
						|
 | 
						|
type testcase struct {
 | 
						|
	Token  string
 | 
						|
	ReqFn  func(opts *Options) *Request
 | 
						|
	Method string
 | 
						|
	URI    string
 | 
						|
	Body   interface{}
 | 
						|
	Header map[string]string
 | 
						|
	Assert func(req *http.Request) bool
 | 
						|
}
 | 
						|
 | 
						|
type assertFn func(req *http.Request) bool
 | 
						|
 | 
						|
var tests = []testcase{
 | 
						|
	testcase{
 | 
						|
		ReqFn: func(opts *Options) *Request {
 | 
						|
			return NewRequest(opts).Get().Resource("service")
 | 
						|
		},
 | 
						|
		Method: "GET",
 | 
						|
		URI:    "/api/v1/namespaces/default/services/",
 | 
						|
	},
 | 
						|
	testcase{
 | 
						|
		ReqFn: func(opts *Options) *Request {
 | 
						|
			return NewRequest(opts).Get().Resource("service").Name("foo")
 | 
						|
		},
 | 
						|
		Method: "GET",
 | 
						|
		URI:    "/api/v1/namespaces/default/services/foo",
 | 
						|
	},
 | 
						|
	testcase{
 | 
						|
		ReqFn: func(opts *Options) *Request {
 | 
						|
			return NewRequest(opts).Get().Resource("service").Namespace("test").Name("bar")
 | 
						|
		},
 | 
						|
		Method: "GET",
 | 
						|
		URI:    "/api/v1/namespaces/test/services/bar",
 | 
						|
	},
 | 
						|
	testcase{
 | 
						|
		ReqFn: func(opts *Options) *Request {
 | 
						|
			return NewRequest(opts).Get().Resource("deployment").Name("foo")
 | 
						|
		},
 | 
						|
		Method: "GET",
 | 
						|
		URI:    "/apis/apps/v1/namespaces/default/deployments/foo",
 | 
						|
	},
 | 
						|
	testcase{
 | 
						|
		ReqFn: func(opts *Options) *Request {
 | 
						|
			return NewRequest(opts).Get().Resource("deployment").Namespace("test").Name("foo")
 | 
						|
		},
 | 
						|
		Method: "GET",
 | 
						|
		URI:    "/apis/apps/v1/namespaces/test/deployments/foo",
 | 
						|
	},
 | 
						|
	testcase{
 | 
						|
		ReqFn: func(opts *Options) *Request {
 | 
						|
			return NewRequest(opts).Get().Resource("pod").Params(&Params{LabelSelector: map[string]string{"foo": "bar"}})
 | 
						|
		},
 | 
						|
		Method: "GET",
 | 
						|
		URI:    "/api/v1/namespaces/default/pods/?labelSelector=foo%3Dbar",
 | 
						|
	},
 | 
						|
	testcase{
 | 
						|
		ReqFn: func(opts *Options) *Request {
 | 
						|
			return NewRequest(opts).Post().Resource("service").Name("foo").Body(map[string]string{"foo": "bar"})
 | 
						|
		},
 | 
						|
		Method: "POST",
 | 
						|
		URI:    "/api/v1/namespaces/default/services/foo",
 | 
						|
		Body:   map[string]string{"foo": "bar"},
 | 
						|
	},
 | 
						|
	testcase{
 | 
						|
		ReqFn: func(opts *Options) *Request {
 | 
						|
			return NewRequest(opts).Post().Resource("deployment").Namespace("test").Name("foo").Body(map[string]string{"foo": "bar"})
 | 
						|
		},
 | 
						|
		Method: "POST",
 | 
						|
		URI:    "/apis/apps/v1/namespaces/test/deployments/foo",
 | 
						|
		Body:   map[string]string{"foo": "bar"},
 | 
						|
	},
 | 
						|
	testcase{
 | 
						|
		ReqFn: func(opts *Options) *Request {
 | 
						|
			return NewRequest(opts).Put().Resource("endpoint").Name("baz").Body(map[string]string{"bam": "bar"})
 | 
						|
		},
 | 
						|
		Method: "PUT",
 | 
						|
		URI:    "/api/v1/namespaces/default/endpoints/baz",
 | 
						|
		Body:   map[string]string{"bam": "bar"},
 | 
						|
	},
 | 
						|
	testcase{
 | 
						|
		ReqFn: func(opts *Options) *Request {
 | 
						|
			return NewRequest(opts).Patch().Resource("endpoint").Name("baz").Body(map[string]string{"bam": "bar"})
 | 
						|
		},
 | 
						|
		Method: "PATCH",
 | 
						|
		URI:    "/api/v1/namespaces/default/endpoints/baz",
 | 
						|
		Body:   map[string]string{"bam": "bar"},
 | 
						|
	},
 | 
						|
	testcase{
 | 
						|
		ReqFn: func(opts *Options) *Request {
 | 
						|
			return NewRequest(opts).Patch().Resource("endpoint").Name("baz").SetHeader("foo", "bar")
 | 
						|
		},
 | 
						|
		Method: "PATCH",
 | 
						|
		URI:    "/api/v1/namespaces/default/endpoints/baz",
 | 
						|
		Header: map[string]string{"foo": "bar"},
 | 
						|
	},
 | 
						|
	testcase{
 | 
						|
		ReqFn: func(opts *Options) *Request {
 | 
						|
			return NewRequest(opts).Patch().Resource("deployment").Name("baz").SetHeader("foo", "bar")
 | 
						|
		},
 | 
						|
		Method: "PATCH",
 | 
						|
		URI:    "/apis/apps/v1/namespaces/default/deployments/baz",
 | 
						|
		Header: map[string]string{"foo": "bar"},
 | 
						|
	},
 | 
						|
}
 | 
						|
 | 
						|
var wrappedHandler = func(test *testcase, t *testing.T) http.HandlerFunc {
 | 
						|
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		auth := r.Header.Get("Authorization")
 | 
						|
		if len(test.Token) > 0 && (len(auth) == 0 || auth != "Bearer "+test.Token) {
 | 
						|
			t.Errorf("test case token (%s) did not match expected token (%s)", "Bearer "+test.Token, auth)
 | 
						|
		}
 | 
						|
 | 
						|
		if len(test.Method) > 0 && test.Method != r.Method {
 | 
						|
			t.Errorf("test case Method (%s) did not match expected Method (%s)", test.Method, r.Method)
 | 
						|
		}
 | 
						|
 | 
						|
		if len(test.URI) > 0 && test.URI != r.URL.RequestURI() {
 | 
						|
			t.Errorf("test case URI (%s) did not match expected URI (%s)", test.URI, r.URL.RequestURI())
 | 
						|
		}
 | 
						|
 | 
						|
		if test.Body != nil {
 | 
						|
			var res map[string]string
 | 
						|
			decoder := json.NewDecoder(r.Body)
 | 
						|
			if err := decoder.Decode(&res); err != nil {
 | 
						|
				t.Errorf("decoding body failed: %v", err)
 | 
						|
			}
 | 
						|
			if !reflect.DeepEqual(res, test.Body) {
 | 
						|
				t.Error("body did not match")
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if test.Header != nil {
 | 
						|
			for k, v := range test.Header {
 | 
						|
				if r.Header.Get(k) != v {
 | 
						|
					t.Error("header did not exist")
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		w.WriteHeader(http.StatusOK)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func TestRequest(t *testing.T) {
 | 
						|
	for _, test := range tests {
 | 
						|
		ts := httptest.NewServer(wrappedHandler(&test, t))
 | 
						|
		req := test.ReqFn(&Options{
 | 
						|
			Host:        ts.URL,
 | 
						|
			Client:      &http.Client{},
 | 
						|
			BearerToken: &test.Token,
 | 
						|
			Namespace:   "default",
 | 
						|
		})
 | 
						|
		res := req.Do()
 | 
						|
		if res.Error() != nil {
 | 
						|
			t.Errorf("request failed with %v", res.Error())
 | 
						|
		}
 | 
						|
		ts.Close()
 | 
						|
	}
 | 
						|
}
 |