k3s/pkg/cloudprovider/providers/mesos/client_test.go

272 lines
7.0 KiB
Go

/*
Copyright 2015 The Kubernetes Authors 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.
*/
package mesos
import (
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"reflect"
"testing"
"time"
log "github.com/golang/glog"
"github.com/mesos/mesos-go/detector"
"github.com/mesos/mesos-go/mesosutil"
"golang.org/x/net/context"
)
// Test data
const (
TEST_MASTER_ID = "master-12345"
TEST_MASTER_IP = 177048842 // 10.141.141.10
TEST_MASTER_PORT = 5050
TEST_STATE_JSON = `
{
"version": "0.22.0",
"unregistered_frameworks": [],
"started_tasks": 0,
"start_time": 1429456501.61141,
"staged_tasks": 0,
"slaves": [
{
"resources": {
"ports": "[31000-32000]",
"mem": 15360,
"disk": 470842,
"cpus": 8
},
"registered_time": 1429456502.46999,
"pid": "slave(1)@mesos1.internal.company.com:5050",
"id": "20150419-081501-16777343-5050-16383-S2",
"hostname": "mesos1.internal.company.com",
"attributes": {},
"active": true
},
{
"resources": {
"ports": "[31000-32000]",
"mem": 15360,
"disk": 470842,
"cpus": 8
},
"registered_time": 1429456502.4144,
"pid": "slave(1)@mesos2.internal.company.com:5050",
"id": "20150419-081501-16777343-5050-16383-S1",
"hostname": "mesos2.internal.company.com",
"attributes": {},
"active": true
},
{
"resources": {
"ports": "[31000-32000]",
"mem": 15360,
"disk": 470842,
"cpus": 8
},
"registered_time": 1429456502.02879,
"pid": "slave(1)@mesos3.internal.company.com:5050",
"id": "20150419-081501-16777343-5050-16383-S0",
"hostname": "mesos3.internal.company.com",
"attributes": {},
"active": true
}
],
"pid": "master@mesos-master0.internal.company.com:5050",
"orphan_tasks": [],
"lost_tasks": 0,
"leader": "master@mesos-master0.internal.company.com:5050",
"killed_tasks": 0,
"failed_tasks": 0,
"elected_time": 1429456501.61638,
"deactivated_slaves": 0,
"completed_frameworks": [],
"build_user": "buildbot",
"build_time": 1425085311,
"build_date": "2015-02-27 17:01:51",
"activated_slaves": 3,
"finished_tasks": 0,
"flags": {
"zk_session_timeout": "10secs",
"work_dir": "/tmp/mesos/local/Lc9arz",
"webui_dir": "/usr/local/share/mesos/webui",
"version": "false",
"user_sorter": "drf",
"slave_reregister_timeout": "10mins",
"logbufsecs": "0",
"log_auto_initialize": "true",
"initialize_driver_logging": "true",
"framework_sorter": "drf",
"authenticators": "crammd5",
"authenticate_slaves": "false",
"authenticate": "false",
"allocation_interval": "1secs",
"logging_level": "INFO",
"quiet": "false",
"recovery_slave_removal_limit": "100%",
"registry": "replicated_log",
"registry_fetch_timeout": "1mins",
"registry_store_timeout": "5secs",
"registry_strict": "false",
"root_submissions": "true"
},
"frameworks": [],
"git_branch": "refs/heads/0.22.0-rc1",
"git_sha": "46834faca67f877631e1beb7d61be5c080ec3dc2",
"git_tag": "0.22.0-rc1",
"hostname": "localhost",
"id": "20150419-081501-16777343-5050-16383"
}`
)
// Mocks
type FakeMasterDetector struct {
callback detector.MasterChanged
done chan struct{}
}
func newFakeMasterDetector() *FakeMasterDetector {
return &FakeMasterDetector{
done: make(chan struct{}),
}
}
func (md FakeMasterDetector) Cancel() {
close(md.done)
}
func (md FakeMasterDetector) Detect(cb detector.MasterChanged) error {
md.callback = cb
leadingMaster := mesosutil.NewMasterInfo(TEST_MASTER_ID, TEST_MASTER_IP, TEST_MASTER_PORT)
cb.OnMasterChanged(leadingMaster)
return nil
}
func (md FakeMasterDetector) Done() <-chan struct{} {
return md.done
}
// Auxiliary functions
func makeHttpMocks() (*httptest.Server, *http.Client, *http.Transport) {
httpServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.V(4).Infof("Mocking response for HTTP request: %#v", r)
if r.URL.Path == "/state.json" {
w.WriteHeader(200) // OK
w.Header().Set("Content-Type", "application/json")
fmt.Fprintln(w, TEST_STATE_JSON)
} else {
w.WriteHeader(400)
fmt.Fprintln(w, "Bad Request")
}
}))
// Intercept all client requests and feed them to the test server
transport := &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
return url.Parse(httpServer.URL)
},
}
httpClient := &http.Client{Transport: transport}
return httpServer, httpClient, transport
}
// Tests
// test mesos.parseMesosState
func Test_parseMesosState(t *testing.T) {
state, err := parseMesosState([]byte(TEST_STATE_JSON))
if err != nil {
t.Fatalf("parseMesosState does not yield an error")
}
if state == nil {
t.Fatalf("parseMesosState yields a non-nil state")
}
if len(state.nodes) != 3 {
t.Fatalf("parseMesosState yields a state with 3 nodes")
}
}
// test mesos.listSlaves
func Test_listSlaves(t *testing.T) {
defer log.Flush()
md := FakeMasterDetector{}
// TODO: Uncomment next two lines and remove third line when fix #19254
// defer httpServer.Close()
// httpServer, httpClient, httpTransport := makeHttpMocks()
_, httpClient, httpTransport := makeHttpMocks()
cacheTTL := 500 * time.Millisecond
mesosClient, err := createMesosClient(md, httpClient, httpTransport, cacheTTL)
if err != nil {
t.Fatalf("createMesosClient does not yield an error")
}
slaveNodes, err := mesosClient.listSlaves(context.TODO())
if err != nil {
t.Fatalf("listSlaves does not yield an error")
}
if len(slaveNodes) != 3 {
t.Fatalf("listSlaves yields a collection of size 3")
}
expectedHostnames := map[string]struct{}{
"mesos1.internal.company.com": {},
"mesos2.internal.company.com": {},
"mesos3.internal.company.com": {},
}
actualHostnames := make(map[string]struct{})
for _, node := range slaveNodes {
actualHostnames[node.hostname] = struct{}{}
}
if !reflect.DeepEqual(expectedHostnames, actualHostnames) {
t.Fatalf("listSlaves yields a collection with the expected hostnames")
}
}
// test mesos.clusterName
func Test_clusterName(t *testing.T) {
defer log.Flush()
md := FakeMasterDetector{}
// TODO: Uncomment next two lines and remove third line when fix #19254
// defer httpServer.Close()
// httpServer, httpClient, httpTransport := makeHttpMocks()
_, httpClient, httpTransport := makeHttpMocks()
cacheTTL := 500 * time.Millisecond
mesosClient, err := createMesosClient(md, httpClient, httpTransport, cacheTTL)
name, err := mesosClient.clusterName(context.TODO())
if err != nil {
t.Fatalf("clusterName does not yield an error")
}
if name != defaultClusterName {
t.Fatalf("clusterName yields the expected (default) value")
}
}