Files
my-rook-config/pkg/api/handlers_test.go
T

274 lines
9.8 KiB
Go

package api
import (
"encoding/json"
"fmt"
"log"
"net/http"
"net/http/httptest"
"path"
"strings"
"testing"
etcd "github.com/coreos/etcd/client"
ctx "golang.org/x/net/context"
ceph "github.com/quantum/castle/pkg/cephmgr/client"
testceph "github.com/quantum/castle/pkg/cephmgr/client/test"
"github.com/quantum/castle/pkg/cephmgr/test"
"github.com/quantum/castle/pkg/clusterd/inventory"
"github.com/quantum/castle/pkg/util"
"github.com/stretchr/testify/assert"
)
func TestAddRemoveDeviceHandler(t *testing.T) {
req, err := http.NewRequest("POST", "http://10.0.0.100/device", strings.NewReader(`{"name":"foo"}`))
assert.Nil(t, err)
w := httptest.NewRecorder()
etcdClient := util.NewMockEtcdClient()
h := NewHandler(etcdClient, nil, nil)
// missing the node id
h.AddDevice(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
// successful request
req, err = http.NewRequest("POST", "http://10.0.0.100/device", strings.NewReader(`{"name":"foo","nodeId":"123"}`))
assert.Nil(t, err)
h = NewHandler(etcdClient, nil, nil)
w = httptest.NewRecorder()
h.AddDevice(w, req)
assert.Equal(t, http.StatusOK, w.Code)
devices := etcdClient.GetChildDirs("/castle/services/ceph/osd/desired/123/device")
assert.Equal(t, 1, devices.Count())
assert.True(t, devices.Contains("foo"))
// remove the device
req, err = http.NewRequest("POST", "http://10.0.0.100/device/remove", strings.NewReader(`{"name":"foo","nodeId":"123"}`))
assert.Nil(t, err)
h = NewHandler(etcdClient, nil, nil)
w = httptest.NewRecorder()
h.RemoveDevice(w, req)
assert.Equal(t, http.StatusOK, w.Code)
// check the desired state
devices = etcdClient.GetChildDirs("/castle/services/ceph/osd/desired/123/device")
assert.Equal(t, 0, devices.Count())
}
func TestRemoveDeviceHandler(t *testing.T) {
}
func TestGetNodesHandler(t *testing.T) {
req, err := http.NewRequest("GET", "http://10.0.0.100/node", nil)
if err != nil {
log.Fatal(err)
}
w := httptest.NewRecorder()
etcdClient := util.NewMockEtcdClient()
etcdClient.SetValue("/castle/services/ceph/name", "cluster5")
cephFactory := &testceph.MockConnectionFactory{Fsid: "myfsid", SecretKey: "mykey"}
h := NewHandler(etcdClient, &test.MockConnectionFactory{}, cephFactory)
// no nodes discovered, should return empty set
h.GetNodes(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, `[]`, w.Body.String())
// set up a discovered node in etcd
inventory.SetIPAddress(etcdClient, "node1", "10.0.0.11")
inventory.SetLocation(etcdClient, "node1", "root=default,dc=datacenter1")
nodeConfigKey := path.Join(inventory.NodesConfigKey, "node1")
etcdClient.CreateDir(nodeConfigKey)
inventory.TestSetDiskInfo(etcdClient, nodeConfigKey, "MB2CK3F6S5041EPCPJ4T", "sda", "506d4869-29ee-4bfd-bf21-dfd597bd222e",
100, true, false, "btrfs", "/mnt/abc", inventory.Disk, "", false)
inventory.TestSetDiskInfo(etcdClient, nodeConfigKey, "2B9C7KZN3VBM77PSA63P", "sdb", "506d4869-29ee-4bfd-bf21-dfd597bd222e",
50, false, false, "ext4", "/mnt/def", inventory.Disk, "", false)
appliedOSDKey := "/castle/services/ceph/osd/applied/node1/devices"
etcdClient.SetValue(path.Join(appliedOSDKey, "sda", "serial"), "MB2CK3F6S5041EPCPJ4T")
etcdClient.SetValue(path.Join(appliedOSDKey, "sdb", "serial"), "2B9C7KZN3VBM77PSA63P")
// since a node exists (with storage), it should be returned now
w = httptest.NewRecorder()
h.GetNodes(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "[{\"nodeId\":\"node1\",\"clusterName\":\"cluster5\",\"ipAddr\":\"10.0.0.11\",\"storage\":150,\"lastUpdated\":31536000000000000,\"state\":1,\"location\":\"root=default,dc=datacenter1\"}]",
w.Body.String())
}
func TestGetNodesHandlerFailure(t *testing.T) {
req, err := http.NewRequest("GET", "http://10.0.0.100/node", nil)
if err != nil {
log.Fatal(err)
}
w := httptest.NewRecorder()
etcdClient := util.NewMockEtcdClient()
// failure during node lookup, should return an error status code
etcdClient.MockGet = func(context ctx.Context, key string, opts *etcd.GetOptions) (*etcd.Response, error) {
return nil, fmt.Errorf("mock etcd GET error")
}
cephFactory := &testceph.MockConnectionFactory{Fsid: "myfsid", SecretKey: "mykey"}
h := NewHandler(etcdClient, &test.MockConnectionFactory{}, cephFactory)
h.GetNodes(w, req)
assert.Equal(t, http.StatusInternalServerError, w.Code)
assert.Equal(t, ``, w.Body.String())
}
func TestGetMonsHandler(t *testing.T) {
etcdClient := util.NewMockEtcdClient()
cephFactory := &testceph.MockConnectionFactory{Fsid: "myfsid", SecretKey: "mykey"}
req, err := http.NewRequest("GET", "http://10.0.0.100/mon", nil)
assert.Nil(t, err)
// first return no mons
w := httptest.NewRecorder()
// no mons will be returned, should be empty output
h := NewHandler(etcdClient, &test.MockConnectionFactory{}, cephFactory)
h.GetMonitors(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, `[]`, w.Body.String())
// now return some monitors from etcd
key := "/castle/services/ceph/monitor/desired/a"
etcdClient.SetValue(path.Join(key, "id"), "mon0")
etcdClient.SetValue(path.Join(key, "ipaddress"), "1.2.3.4")
etcdClient.SetValue(path.Join(key, "port"), "8765")
// monitors should be returned now, verify the output
w = httptest.NewRecorder()
h = NewHandler(etcdClient, &test.MockConnectionFactory{}, cephFactory)
h.GetMonitors(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "{\"status\":{\"quorum\":[0],\"monmap\":{\"mons\":[{\"name\":\"mon0\",\"rank\":0,\"addr\":\"10.37.129.87:6790\"}]}},\"desired\":[{\"name\":\"mon0\",\"endpoint\":\"1.2.3.4:8765\"}]}", w.Body.String())
}
func TestGetPoolsHandler(t *testing.T) {
req, err := http.NewRequest("GET", "http://10.0.0.100/pool", nil)
if err != nil {
log.Fatal(err)
}
// first return no storage pools
w := httptest.NewRecorder()
etcdClient := util.NewMockEtcdClient()
cephFactory := &testceph.MockConnectionFactory{Fsid: "myfsid", SecretKey: "mykey"}
connFactory := &test.MockConnectionFactory{}
cephFactory.Conn = &testceph.MockConnection{
MockMonCommand: func(args []byte) (buffer []byte, info string, err error) {
return []byte(`[]`), "", nil
},
}
connFactory.MockConnectAsAdmin = func(cephFactory ceph.ConnectionFactory, etcdClient etcd.KeysAPI) (ceph.Connection, error) {
return cephFactory.NewConnWithClusterAndUser("mycluster", "admin")
}
// no storage pools will be returned, should be empty output
h := NewHandler(etcdClient, connFactory, cephFactory)
h.GetPools(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, `[]`, w.Body.String())
// now return some storage pools from the ceph connection
w = httptest.NewRecorder()
cephFactory.Conn = &testceph.MockConnection{
MockMonCommand: func(args []byte) (buffer []byte, info string, err error) {
cephPools := []ceph.CephStoragePool{
{Number: 0, Name: "pool0"},
{Number: 1, Name: "pool1"},
}
resp, err := json.Marshal(cephPools)
assert.Nil(t, err)
return resp, "", nil
},
}
// storage pools should be returned now, verify the output
h = NewHandler(etcdClient, connFactory, cephFactory)
h.GetPools(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "[{\"poolName\":\"pool0\",\"poolNum\":0},{\"poolName\":\"pool1\",\"poolNum\":1}]", w.Body.String())
}
func TestGetPoolsHandlerFailure(t *testing.T) {
req, err := http.NewRequest("GET", "http://10.0.0.100/pool", nil)
if err != nil {
log.Fatal(err)
}
// encounter an error during GetPools
w := httptest.NewRecorder()
etcdClient := util.NewMockEtcdClient()
cephFactory := &testceph.MockConnectionFactory{Fsid: "myfsid", SecretKey: "mykey"}
connFactory := &test.MockConnectionFactory{}
connFactory.MockConnectAsAdmin = func(cephFactory ceph.ConnectionFactory, etcdClient etcd.KeysAPI) (ceph.Connection, error) {
return nil, fmt.Errorf("mock error for connect as admin")
}
h := NewHandler(etcdClient, connFactory, cephFactory)
h.GetPools(w, req)
assert.Equal(t, http.StatusInternalServerError, w.Code)
assert.Equal(t, "", w.Body.String())
}
func TestCreatePoolHandler(t *testing.T) {
req, err := http.NewRequest("POST", "http://10.0.0.100/pool", strings.NewReader(`{"poolname":"pool1"}`))
if err != nil {
log.Fatal(err)
}
w := httptest.NewRecorder()
etcdClient := util.NewMockEtcdClient()
cephFactory := &testceph.MockConnectionFactory{Fsid: "myfsid", SecretKey: "mykey"}
connFactory := &test.MockConnectionFactory{}
cephFactory.Conn = &testceph.MockConnection{
MockMonCommand: func(args []byte) (buffer []byte, info string, err error) {
return []byte(""), "successfully created pool1", nil
},
}
connFactory.MockConnectAsAdmin = func(cephFactory ceph.ConnectionFactory, etcdClient etcd.KeysAPI) (ceph.Connection, error) {
return cephFactory.NewConnWithClusterAndUser("mycluster", "admin")
}
h := NewHandler(etcdClient, connFactory, cephFactory)
h.CreatePool(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "successfully created pool1", w.Body.String())
}
func TestCreatePoolHandlerFailure(t *testing.T) {
req, err := http.NewRequest("POST", "http://10.0.0.100/pool", strings.NewReader(`{"poolname":"pool1"}`))
if err != nil {
log.Fatal(err)
}
w := httptest.NewRecorder()
etcdClient := util.NewMockEtcdClient()
cephFactory := &testceph.MockConnectionFactory{Fsid: "myfsid", SecretKey: "mykey"}
connFactory := &test.MockConnectionFactory{}
cephFactory.Conn = &testceph.MockConnection{
MockMonCommand: func(args []byte) (buffer []byte, info string, err error) {
errMsg := "mock failure to create pool1"
return []byte(""), errMsg, fmt.Errorf(errMsg)
},
}
connFactory.MockConnectAsAdmin = func(cephFactory ceph.ConnectionFactory, etcdClient etcd.KeysAPI) (ceph.Connection, error) {
return cephFactory.NewConnWithClusterAndUser("mycluster", "admin")
}
h := NewHandler(etcdClient, connFactory, cephFactory)
h.CreatePool(w, req)
assert.Equal(t, http.StatusInternalServerError, w.Code)
assert.Equal(t, "", w.Body.String())
}