2014-06-06 23:40:48 +00:00
|
|
|
/*
|
|
|
|
Copyright 2014 Google Inc. All rights reserved.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
2014-06-23 18:32:11 +00:00
|
|
|
|
2014-06-06 23:40:48 +00:00
|
|
|
package client
|
|
|
|
|
|
|
|
import (
|
2014-07-25 19:28:20 +00:00
|
|
|
"encoding/json"
|
2014-06-07 11:38:16 +00:00
|
|
|
"net/http"
|
2014-06-06 23:40:48 +00:00
|
|
|
"net/http/httptest"
|
|
|
|
"net/url"
|
2014-08-28 13:56:38 +00:00
|
|
|
"path"
|
2014-06-06 23:40:48 +00:00
|
|
|
"reflect"
|
2014-11-14 03:09:03 +00:00
|
|
|
"strings"
|
2014-06-06 23:40:48 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
2014-12-08 05:56:43 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
|
2015-03-15 21:51:41 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
|
2014-06-20 16:47:39 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
2014-09-02 17:55:27 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
2014-06-06 23:40:48 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
2014-07-25 19:28:20 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
|
2014-06-06 23:40:48 +00:00
|
|
|
)
|
|
|
|
|
2015-03-20 22:22:51 +00:00
|
|
|
const nameRequiredError = "resource name may not be empty"
|
2014-06-06 23:40:48 +00:00
|
|
|
|
2014-09-30 00:15:00 +00:00
|
|
|
type testRequest struct {
|
|
|
|
Method string
|
|
|
|
Path string
|
|
|
|
Header string
|
|
|
|
Query url.Values
|
|
|
|
Body runtime.Object
|
|
|
|
RawBody *string
|
|
|
|
}
|
|
|
|
|
|
|
|
type Response struct {
|
|
|
|
StatusCode int
|
|
|
|
Body runtime.Object
|
|
|
|
RawBody *string
|
|
|
|
}
|
|
|
|
|
|
|
|
type testClient struct {
|
|
|
|
*Client
|
|
|
|
Request testRequest
|
|
|
|
Response Response
|
|
|
|
Error bool
|
2014-10-24 17:16:02 +00:00
|
|
|
Created bool
|
2014-12-08 05:56:43 +00:00
|
|
|
Version string
|
2014-09-30 00:15:00 +00:00
|
|
|
server *httptest.Server
|
|
|
|
handler *util.FakeHandler
|
|
|
|
// For query args, an optional function to validate the contents
|
|
|
|
// useful when the contents can change but still be correct.
|
|
|
|
// Maps from query arg key to validator.
|
|
|
|
// If no validator is present, string equality is used.
|
|
|
|
QueryValidator map[string]func(string, string) bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *testClient) Setup() *testClient {
|
|
|
|
c.handler = &util.FakeHandler{
|
|
|
|
StatusCode: c.Response.StatusCode,
|
|
|
|
}
|
|
|
|
if responseBody := body(c.Response.Body, c.Response.RawBody); responseBody != nil {
|
|
|
|
c.handler.ResponseBody = *responseBody
|
|
|
|
}
|
|
|
|
c.server = httptest.NewServer(c.handler)
|
|
|
|
if c.Client == nil {
|
2014-12-08 05:56:43 +00:00
|
|
|
version := c.Version
|
|
|
|
if len(version) == 0 {
|
|
|
|
version = testapi.Version()
|
|
|
|
}
|
2014-09-30 00:15:00 +00:00
|
|
|
c.Client = NewOrDie(&Config{
|
|
|
|
Host: c.server.URL,
|
2014-12-08 05:56:43 +00:00
|
|
|
Version: version,
|
2014-09-30 00:15:00 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
c.QueryValidator = map[string]func(string, string) bool{}
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *testClient) Validate(t *testing.T, received runtime.Object, err error) {
|
|
|
|
c.ValidateCommon(t, err)
|
|
|
|
|
2015-01-26 17:52:50 +00:00
|
|
|
if c.Response.Body != nil && !api.Semantic.DeepDerivative(c.Response.Body, received) {
|
2014-11-06 22:53:28 +00:00
|
|
|
t.Errorf("bad response for request %#v: expected %#v, got %#v", c.Request, c.Response.Body, received)
|
2014-09-11 23:01:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-30 00:15:00 +00:00
|
|
|
func (c *testClient) ValidateRaw(t *testing.T, received []byte, err error) {
|
|
|
|
c.ValidateCommon(t, err)
|
|
|
|
|
|
|
|
if c.Response.Body != nil && !reflect.DeepEqual(c.Response.Body, received) {
|
2014-11-06 22:53:28 +00:00
|
|
|
t.Errorf("bad response for request %#v: expected %#v, got %#v", c.Request, c.Response.Body, received)
|
2014-09-30 00:15:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *testClient) ValidateCommon(t *testing.T, err error) {
|
|
|
|
defer c.server.Close()
|
|
|
|
|
|
|
|
if c.Error {
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("error expected for %#v, got none", c.Request)
|
2014-08-28 13:56:38 +00:00
|
|
|
}
|
2014-09-30 00:15:00 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("no error expected for %#v, got: %v", c.Request, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.handler.RequestReceived == nil {
|
|
|
|
t.Errorf("handler had an empty request, %#v", c)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
requestBody := body(c.Request.Body, c.Request.RawBody)
|
|
|
|
actualQuery := c.handler.RequestReceived.URL.Query()
|
2014-11-14 03:09:03 +00:00
|
|
|
t.Logf("got query: %v", actualQuery)
|
2014-12-19 21:32:42 +00:00
|
|
|
t.Logf("path: %v", c.Request.Path)
|
2014-09-30 00:15:00 +00:00
|
|
|
// We check the query manually, so blank it out so that FakeHandler.ValidateRequest
|
|
|
|
// won't check it.
|
|
|
|
c.handler.RequestReceived.URL.RawQuery = ""
|
2015-03-24 23:40:18 +00:00
|
|
|
c.handler.ValidateRequest(t, path.Join(c.Request.Path), c.Request.Method, requestBody)
|
2014-09-30 00:15:00 +00:00
|
|
|
for key, values := range c.Request.Query {
|
|
|
|
validator, ok := c.QueryValidator[key]
|
|
|
|
if !ok {
|
2014-11-14 03:09:03 +00:00
|
|
|
switch key {
|
2015-03-24 23:40:18 +00:00
|
|
|
case api.LabelSelectorQueryParam(testapi.Version()):
|
2014-11-14 03:09:03 +00:00
|
|
|
validator = validateLabels
|
2015-03-24 23:40:18 +00:00
|
|
|
case api.FieldSelectorQueryParam(testapi.Version()):
|
2015-02-25 16:19:10 +00:00
|
|
|
validator = validateFields
|
2014-11-14 03:09:03 +00:00
|
|
|
default:
|
|
|
|
validator = func(a, b string) bool { return a == b }
|
|
|
|
}
|
2014-08-15 21:14:22 +00:00
|
|
|
}
|
2014-09-30 00:15:00 +00:00
|
|
|
observed := actualQuery.Get(key)
|
2014-11-14 03:09:03 +00:00
|
|
|
wanted := strings.Join(values, "")
|
|
|
|
if !validator(wanted, observed) {
|
|
|
|
t.Errorf("Unexpected query arg for key: %s. Expected %s, Received %s", key, wanted, observed)
|
2014-09-30 00:15:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if c.Request.Header != "" {
|
|
|
|
if c.handler.RequestReceived.Header.Get(c.Request.Header) == "" {
|
|
|
|
t.Errorf("header %q not found in request %#v", c.Request.Header, c.handler.RequestReceived)
|
2014-08-15 21:14:22 +00:00
|
|
|
}
|
|
|
|
}
|
2014-09-30 00:15:00 +00:00
|
|
|
|
|
|
|
if expected, received := requestBody, c.handler.RequestBody; expected != nil && *expected != received {
|
|
|
|
t.Errorf("bad body for request %#v: expected %s, got %s", c.Request, *expected, received)
|
|
|
|
}
|
2014-08-15 21:14:22 +00:00
|
|
|
}
|
|
|
|
|
2014-12-22 16:41:17 +00:00
|
|
|
// buildResourcePath is a convenience function for knowing if a namespace should be in a path param or not
|
2014-12-09 19:23:21 +00:00
|
|
|
func buildResourcePath(namespace, resource string) string {
|
|
|
|
if len(namespace) > 0 {
|
2015-01-06 17:36:08 +00:00
|
|
|
if !(testapi.Version() == "v1beta1" || testapi.Version() == "v1beta2") {
|
2015-03-24 12:00:26 +00:00
|
|
|
return path.Join("namespaces", namespace, resource)
|
2014-12-19 21:32:42 +00:00
|
|
|
}
|
2014-12-09 19:23:21 +00:00
|
|
|
}
|
|
|
|
return resource
|
|
|
|
}
|
|
|
|
|
2014-12-22 16:41:17 +00:00
|
|
|
// buildQueryValues is a convenience function for knowing if a namespace should be in a query param or not
|
2014-12-19 21:32:42 +00:00
|
|
|
func buildQueryValues(namespace string, query url.Values) url.Values {
|
|
|
|
v := url.Values{}
|
|
|
|
if query != nil {
|
|
|
|
for key, values := range query {
|
|
|
|
for _, value := range values {
|
|
|
|
v.Add(key, value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(namespace) > 0 {
|
2015-03-24 23:40:18 +00:00
|
|
|
if api.PreV1Beta3(testapi.Version()) {
|
2014-12-19 21:32:42 +00:00
|
|
|
v.Set("namespace", namespace)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
2014-06-20 16:47:39 +00:00
|
|
|
func validateLabels(a, b string) bool {
|
2015-02-25 16:19:10 +00:00
|
|
|
sA, eA := labels.Parse(a)
|
|
|
|
if eA != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
sB, eB := labels.Parse(b)
|
|
|
|
if eB != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return sA.String() == sB.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateFields(a, b string) bool {
|
2015-03-15 21:51:41 +00:00
|
|
|
sA, _ := fields.ParseSelector(a)
|
|
|
|
sB, _ := fields.ParseSelector(b)
|
2014-06-20 16:47:39 +00:00
|
|
|
return sA.String() == sB.String()
|
|
|
|
}
|
|
|
|
|
2014-09-08 01:31:11 +00:00
|
|
|
func body(obj runtime.Object, raw *string) *string {
|
2014-06-07 11:38:16 +00:00
|
|
|
if obj != nil {
|
2015-03-24 23:40:18 +00:00
|
|
|
bs, _ := testapi.Codec().Encode(obj)
|
2014-06-07 11:38:16 +00:00
|
|
|
body := string(bs)
|
|
|
|
return &body
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
2014-06-07 11:38:16 +00:00
|
|
|
return raw
|
|
|
|
}
|
|
|
|
|
2014-07-25 19:28:20 +00:00
|
|
|
func TestGetServerVersion(t *testing.T) {
|
|
|
|
expect := version.Info{
|
|
|
|
Major: "foo",
|
|
|
|
Minor: "bar",
|
|
|
|
GitCommit: "baz",
|
|
|
|
}
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
|
|
output, err := json.Marshal(expect)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected encoding error: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
w.Write(output)
|
|
|
|
}))
|
2014-09-30 00:15:00 +00:00
|
|
|
client := NewOrDie(&Config{Host: server.URL})
|
2014-07-25 19:28:20 +00:00
|
|
|
|
|
|
|
got, err := client.ServerVersion()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected encoding error: %v", err)
|
|
|
|
}
|
|
|
|
if e, a := expect, *got; !reflect.DeepEqual(e, a) {
|
|
|
|
t.Errorf("expected %v, got %v", e, a)
|
|
|
|
}
|
|
|
|
}
|
2014-08-27 21:07:22 +00:00
|
|
|
|
2014-12-03 05:55:44 +00:00
|
|
|
func TestGetServerAPIVersions(t *testing.T) {
|
|
|
|
versions := []string{"v1", "v2", "v3"}
|
|
|
|
expect := api.APIVersions{Versions: versions}
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
|
|
output, err := json.Marshal(expect)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected encoding error: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
w.Write(output)
|
|
|
|
}))
|
|
|
|
client := NewOrDie(&Config{Host: server.URL})
|
|
|
|
got, err := client.ServerAPIVersions()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected encoding error: %v", err)
|
|
|
|
}
|
|
|
|
if e, a := expect, *got; !reflect.DeepEqual(e, a) {
|
|
|
|
t.Errorf("expected %v, got %v", e, a)
|
|
|
|
}
|
|
|
|
}
|