forked from rook/rook
- multiple file systems are allowed - multiple mds instances are allowed per file system. - a keyring is created per mds instance - double the desired mds instances are started, half in standby mode
414 lines
14 KiB
Go
414 lines
14 KiB
Go
/*
|
|
Copyright 2016 The Rook 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 client
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"testing"
|
|
|
|
"github.com/rook/rook/pkg/model"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
const (
|
|
SuccessGetNodesContent = `[{"nodeID": "node1","publicIp": "1.2.3.100","privateIp": "10.0.0.100","storage": 100},{"nodeID": "node2","ipAddr": "10.0.0.101","storage": 200}]`
|
|
SuccessGetPoolsContent = "[{\"poolName\":\"rbd\",\"poolNum\":0,\"type\":0,\"replicatedConfig\":{\"size\":1},\"erasureCodedConfig\":{\"dataChunkCount\":0,\"codingChunkCount\":0,\"algorithm\":\"\"}},{\"poolName\":\"ecPool1\",\"poolNum\":1,\"type\":1,\"replicatedConfig\":{\"size\":0},\"erasureCodedConfig\":{\"dataChunkCount\":2,\"codingChunkCount\":1,\"algorithm\":\"jerasure::reed_sol_van\"}}]"
|
|
SuccessCreatePoolContent = `pool 'ecPool1' created`
|
|
SuccessGetBlockImagesContent = `[{"imageName":"myimage1","poolName":"rbd","size":10485760,"device":"","mountPoint":""},{"imageName":"myimage2","poolName":"rbd2","size":10485761,"device":"","mountPoint":""}]`
|
|
SuccessCreateBlockImageContent = `succeeded created image myimage3`
|
|
SuccessDeleteBlockImageContent = `succeeded deleting image myimage3`
|
|
SuccessGetClientAccessInfoContent = `{"monAddresses":["10.37.129.214:6790/0"],"userName":"admin","secretKey":"AQBsCv1X5oD9GhAARHVU9N+kFRWDjyLA1dqzIg=="}`
|
|
SuccessGetFilesystemsContent = `[{"name":"myfs1","metadataPool":"myfs1-metadata","dataPools":["myfs1-data"]}]`
|
|
SuccessGetObjectStoreConnectionInfoContent = `{"host":"rook-ceph-rgw-default:12345", "accessKey":"UST0JAP8CE61FDE0Q4BE", "secretKey":"tVCuH20xTokjEpVJc7mKjL8PLTfGh4NZ3le3zg9X"}`
|
|
)
|
|
|
|
func TestURL(t *testing.T) {
|
|
client := NewRookNetworkRestClient(GetRestURL("10.0.1.2:8124"), http.DefaultClient)
|
|
assert.Equal(t, "http://10.0.1.2:8124", client.URL())
|
|
}
|
|
|
|
func TestRookRestError(t *testing.T) {
|
|
err := RookRestError{Query: "foo", Status: http.StatusBadRequest, Body: []byte("error body")}
|
|
assert.Equal(t, "HTTP status code 400 for query foo: 'error body'", err.Error())
|
|
}
|
|
|
|
func TestGetNodes(t *testing.T) {
|
|
mockServer := NewMockHttpServer(200, SuccessGetNodesContent)
|
|
defer mockServer.Close()
|
|
mockHttpClient := NewMockHttpClient(mockServer.URL)
|
|
client := NewRookNetworkRestClient(mockServer.URL, mockHttpClient)
|
|
|
|
// invoke the GetNodes method that will use our mock http client/server to return a successful response
|
|
getNodesResponse, err := client.GetNodes()
|
|
assert.Nil(t, err)
|
|
assert.NotNil(t, getNodesResponse)
|
|
assert.Equal(t, 2, len(getNodesResponse))
|
|
|
|
var testNode model.Node
|
|
for i := range getNodesResponse {
|
|
if getNodesResponse[i].NodeID == "node1" {
|
|
testNode = getNodesResponse[i]
|
|
break
|
|
}
|
|
}
|
|
|
|
assert.NotNil(t, testNode)
|
|
assert.Equal(t, "1.2.3.100", testNode.PublicIP)
|
|
assert.Equal(t, "10.0.0.100", testNode.PrivateIP)
|
|
assert.Equal(t, uint64(100), testNode.Storage)
|
|
}
|
|
|
|
func TestGetPools(t *testing.T) {
|
|
mockServer := NewMockHttpServer(200, SuccessGetPoolsContent)
|
|
defer mockServer.Close()
|
|
mockHttpClient := NewMockHttpClient(mockServer.URL)
|
|
client := NewRookNetworkRestClient(mockServer.URL, mockHttpClient)
|
|
|
|
// invoke the GetPools method that will use our mock http client/server to return a successful response
|
|
getPoolsResponse, err := client.GetPools()
|
|
assert.Nil(t, err)
|
|
assert.NotNil(t, getPoolsResponse)
|
|
assert.Equal(t, 2, len(getPoolsResponse))
|
|
|
|
expectedPool1 := model.Pool{
|
|
Name: "ecPool1",
|
|
Number: 1,
|
|
Type: model.ErasureCoded,
|
|
ErasureCodedConfig: model.ErasureCodedPoolConfig{
|
|
DataChunkCount: 2,
|
|
CodingChunkCount: 1,
|
|
Algorithm: "jerasure::reed_sol_van",
|
|
},
|
|
}
|
|
var actualPool model.Pool
|
|
for i := range getPoolsResponse {
|
|
if getPoolsResponse[i].Name == "ecPool1" {
|
|
actualPool = getPoolsResponse[i]
|
|
break
|
|
}
|
|
}
|
|
|
|
assert.NotNil(t, actualPool)
|
|
assert.Equal(t, expectedPool1, actualPool)
|
|
}
|
|
|
|
func TestCreatePool(t *testing.T) {
|
|
mockServer := NewMockHttpServer(200, SuccessCreatePoolContent)
|
|
defer mockServer.Close()
|
|
mockHttpClient := NewMockHttpClient(mockServer.URL)
|
|
client := NewRookNetworkRestClient(mockServer.URL, mockHttpClient)
|
|
|
|
// invoke the CreatePool method that will use our mock http client/server to return a successful response
|
|
newPool := model.Pool{
|
|
Name: "ecPool1",
|
|
Number: 1,
|
|
Type: model.ErasureCoded,
|
|
ErasureCodedConfig: model.ErasureCodedPoolConfig{
|
|
DataChunkCount: 2,
|
|
CodingChunkCount: 1,
|
|
Algorithm: "jerasure::reed_sol_van",
|
|
},
|
|
}
|
|
createPoolResponse, err := client.CreatePool(newPool)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, "pool 'ecPool1' created\n", createPoolResponse)
|
|
}
|
|
|
|
func TestGetBlockImages(t *testing.T) {
|
|
mockServer := NewMockHttpServer(200, SuccessGetBlockImagesContent)
|
|
defer mockServer.Close()
|
|
mockHttpClient := NewMockHttpClient(mockServer.URL)
|
|
client := NewRookNetworkRestClient(mockServer.URL, mockHttpClient)
|
|
|
|
getBlockImagesResponse, err := client.GetBlockImages()
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 2, len(getBlockImagesResponse))
|
|
|
|
expectedImage := model.BlockImage{
|
|
Name: "myimage2",
|
|
PoolName: "rbd2",
|
|
Size: 10485761,
|
|
}
|
|
var actualImage *model.BlockImage
|
|
for i := range getBlockImagesResponse {
|
|
if getBlockImagesResponse[i].Name == expectedImage.Name {
|
|
actualImage = &(getBlockImagesResponse[i])
|
|
break
|
|
}
|
|
}
|
|
assert.NotNil(t, actualImage)
|
|
assert.Equal(t, expectedImage, *actualImage)
|
|
}
|
|
|
|
func TestCreateBlockImage(t *testing.T) {
|
|
mockServer := NewMockHttpServer(200, SuccessCreateBlockImageContent)
|
|
defer mockServer.Close()
|
|
mockHttpClient := NewMockHttpClient(mockServer.URL)
|
|
client := NewRookNetworkRestClient(mockServer.URL, mockHttpClient)
|
|
|
|
newImage := model.BlockImage{
|
|
Name: "myimage3",
|
|
PoolName: "rbd2",
|
|
Size: 10485762,
|
|
}
|
|
|
|
response, err := client.CreateBlockImage(newImage)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, SuccessCreateBlockImageContent+"\n", response)
|
|
}
|
|
|
|
func TestDeleteBlockImage(t *testing.T) {
|
|
mockServer := NewMockHttpServer(200, SuccessDeleteBlockImageContent)
|
|
defer mockServer.Close()
|
|
mockHttpClient := NewMockHttpClient(mockServer.URL)
|
|
client := NewRookNetworkRestClient(mockServer.URL, mockHttpClient)
|
|
|
|
deleteImage := model.BlockImage{
|
|
Name: "myimage3",
|
|
PoolName: "rbd2",
|
|
}
|
|
|
|
response, err := client.DeleteBlockImage(deleteImage)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, SuccessDeleteBlockImageContent+"\n", response)
|
|
}
|
|
|
|
func TestGetClientAccessInfo(t *testing.T) {
|
|
mockServer := NewMockHttpServer(200, SuccessGetClientAccessInfoContent)
|
|
defer mockServer.Close()
|
|
mockHttpClient := NewMockHttpClient(mockServer.URL)
|
|
client := NewRookNetworkRestClient(mockServer.URL, mockHttpClient)
|
|
|
|
expectedClientAccessInfo := model.ClientAccessInfo{
|
|
MonAddresses: []string{"10.37.129.214:6790/0"},
|
|
UserName: "admin",
|
|
SecretKey: "AQBsCv1X5oD9GhAARHVU9N+kFRWDjyLA1dqzIg==",
|
|
}
|
|
|
|
actualClientAccessInfo, err := client.GetClientAccessInfo()
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, expectedClientAccessInfo, actualClientAccessInfo)
|
|
}
|
|
|
|
func TestGetFilesystems(t *testing.T) {
|
|
mockServer := NewMockHttpServer(200, SuccessGetFilesystemsContent)
|
|
defer mockServer.Close()
|
|
mockHttpClient := NewMockHttpClient(mockServer.URL)
|
|
client := NewRookNetworkRestClient(mockServer.URL, mockHttpClient)
|
|
|
|
expectedFilesystems := []model.Filesystem{
|
|
{Name: "myfs1", MetadataPool: "myfs1-metadata", DataPools: []string{"myfs1-data"}},
|
|
}
|
|
|
|
actualFilesystems, err := client.GetFilesystems()
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, expectedFilesystems, actualFilesystems)
|
|
}
|
|
|
|
func TestCreateFilesystem(t *testing.T) {
|
|
mockServer := NewMockHttpServer(202, "")
|
|
defer mockServer.Close()
|
|
mockHttpClient := NewMockHttpClient(mockServer.URL)
|
|
client := NewRookNetworkRestClient(mockServer.URL, mockHttpClient)
|
|
|
|
fsr := model.FilesystemRequest{Name: "myfs1"}
|
|
resp, err := client.CreateFilesystem(fsr)
|
|
assert.NotNil(t, err)
|
|
assert.True(t, IsHttpAccepted(err))
|
|
assert.Equal(t, "", resp)
|
|
}
|
|
|
|
func TestDeleteFilesystem(t *testing.T) {
|
|
mockServer := NewMockHttpServer(202, "")
|
|
defer mockServer.Close()
|
|
mockHttpClient := NewMockHttpClient(mockServer.URL)
|
|
client := NewRookNetworkRestClient(mockServer.URL, mockHttpClient)
|
|
|
|
fsr := model.FilesystemRequest{Name: "myfs1"}
|
|
resp, err := client.DeleteFilesystem(fsr)
|
|
assert.NotNil(t, err)
|
|
assert.True(t, IsHttpAccepted(err))
|
|
assert.Equal(t, "", resp)
|
|
}
|
|
|
|
func TestCreateObjectStore(t *testing.T) {
|
|
mockServer := NewMockHttpServer(202, "")
|
|
defer mockServer.Close()
|
|
mockHttpClient := NewMockHttpClient(mockServer.URL)
|
|
client := NewRookNetworkRestClient(mockServer.URL, mockHttpClient)
|
|
|
|
store := model.ObjectStore{Name: "default", Gateway: model.Gateway{Port: 123}}
|
|
resp, err := client.CreateObjectStore(store)
|
|
assert.NotNil(t, err)
|
|
assert.True(t, IsHttpAccepted(err))
|
|
assert.Equal(t, "", resp)
|
|
}
|
|
|
|
func TestGetObjectStoreConnectionInfo(t *testing.T) {
|
|
mockServer := NewMockHttpServer(200, SuccessGetObjectStoreConnectionInfoContent)
|
|
defer mockServer.Close()
|
|
mockHttpClient := NewMockHttpClient(mockServer.URL)
|
|
client := NewRookNetworkRestClient(mockServer.URL, mockHttpClient)
|
|
|
|
expectedResp := model.ObjectStoreConnectInfo{
|
|
Host: "rook-ceph-rgw-default:12345",
|
|
}
|
|
|
|
resp, err := client.GetObjectStoreConnectionInfo("default")
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, expectedResp, *resp)
|
|
}
|
|
|
|
func TestGetNodesFailure(t *testing.T) {
|
|
ClientFailureHelper(t, func(client RookRestClient) (interface{}, error) { return client.GetNodes() })
|
|
}
|
|
|
|
func TestGetPoolsFailure(t *testing.T) {
|
|
ClientFailureHelper(t, func(client RookRestClient) (interface{}, error) { return client.GetPools() })
|
|
}
|
|
|
|
func TestCreatePoolFailure(t *testing.T) {
|
|
clientFunc := func(client RookRestClient) (interface{}, error) {
|
|
return client.CreatePool(model.Pool{Name: "pool1"})
|
|
}
|
|
verifyFunc := getStringVerifyFunc(t)
|
|
ClientFailureHelperWithVerification(t, clientFunc, verifyFunc)
|
|
}
|
|
|
|
func TestGetBlockImagesFailure(t *testing.T) {
|
|
ClientFailureHelper(t, func(client RookRestClient) (interface{}, error) { return client.GetBlockImages() })
|
|
}
|
|
|
|
func TestCreateBlockImageFailure(t *testing.T) {
|
|
clientFunc := func(client RookRestClient) (interface{}, error) {
|
|
return client.CreateBlockImage(model.BlockImage{Name: "image1"})
|
|
}
|
|
verifyFunc := getStringVerifyFunc(t)
|
|
ClientFailureHelperWithVerification(t, clientFunc, verifyFunc)
|
|
}
|
|
|
|
func TestDeleteBlockImageFailure(t *testing.T) {
|
|
clientFunc := func(client RookRestClient) (interface{}, error) {
|
|
return client.DeleteBlockImage(model.BlockImage{Name: "image1"})
|
|
}
|
|
verifyFunc := getStringVerifyFunc(t)
|
|
ClientFailureHelperWithVerification(t, clientFunc, verifyFunc)
|
|
}
|
|
|
|
func TestGetClientAccessInfoFailure(t *testing.T) {
|
|
clientFunc := func(client RookRestClient) (interface{}, error) {
|
|
return client.GetClientAccessInfo()
|
|
}
|
|
verifyFunc := func(resp interface{}, err error) {
|
|
assert.NotNil(t, err)
|
|
assert.Equal(t, model.ClientAccessInfo{}, resp.(model.ClientAccessInfo))
|
|
}
|
|
ClientFailureHelperWithVerification(t, clientFunc, verifyFunc)
|
|
}
|
|
|
|
func TestGetFilesystemsFailure(t *testing.T) {
|
|
ClientFailureHelper(t, func(client RookRestClient) (interface{}, error) { return client.GetFilesystems() })
|
|
}
|
|
|
|
func TestCreateFilesystemFailure(t *testing.T) {
|
|
clientFunc := func(client RookRestClient) (interface{}, error) {
|
|
return client.CreateFilesystem(model.FilesystemRequest{Name: "myfs1"})
|
|
}
|
|
verifyFunc := getStringVerifyFunc(t)
|
|
ClientFailureHelperWithVerification(t, clientFunc, verifyFunc)
|
|
}
|
|
|
|
func TestDeleteFilesystemFailure(t *testing.T) {
|
|
clientFunc := func(client RookRestClient) (interface{}, error) {
|
|
return client.DeleteFilesystem(model.FilesystemRequest{Name: "myfs1"})
|
|
}
|
|
verifyFunc := getStringVerifyFunc(t)
|
|
ClientFailureHelperWithVerification(t, clientFunc, verifyFunc)
|
|
}
|
|
|
|
func TestCreateObjectStoreFailure(t *testing.T) {
|
|
clientFunc := func(client RookRestClient) (interface{}, error) {
|
|
return client.CreateObjectStore(model.ObjectStore{Name: "name"})
|
|
}
|
|
verifyFunc := getStringVerifyFunc(t)
|
|
ClientFailureHelperWithVerification(t, clientFunc, verifyFunc)
|
|
}
|
|
|
|
func TestGetObjectStoreConnectionInfoFailure(t *testing.T) {
|
|
clientFunc := func(client RookRestClient) (interface{}, error) {
|
|
return client.GetObjectStoreConnectionInfo("default")
|
|
}
|
|
verifyFunc := func(resp interface{}, err error) {
|
|
assert.NotNil(t, err)
|
|
assert.Nil(t, resp)
|
|
}
|
|
ClientFailureHelperWithVerification(t, clientFunc, verifyFunc)
|
|
}
|
|
|
|
func ClientFailureHelper(t *testing.T, clientFunc func(RookRestClient) (interface{}, error)) {
|
|
verifyFunc := func(resp interface{}, err error) {
|
|
assert.NotNil(t, err)
|
|
assert.Nil(t, resp)
|
|
}
|
|
ClientFailureHelperWithVerification(t, clientFunc, verifyFunc)
|
|
}
|
|
|
|
func ClientFailureHelperWithVerification(t *testing.T, clientFunc func(RookRestClient) (interface{}, error),
|
|
verifyFunc func(interface{}, error)) {
|
|
|
|
mockServer := NewMockHttpServer(500, "something went wrong!")
|
|
defer mockServer.Close()
|
|
mockHttpClient := NewMockHttpClient(mockServer.URL)
|
|
client := NewRookNetworkRestClient(mockServer.URL, mockHttpClient)
|
|
|
|
// invoke the client func
|
|
resp, err := clientFunc(client)
|
|
|
|
// invoke the verification func to verify resp and err
|
|
verifyFunc(resp, err)
|
|
}
|
|
|
|
func getStringVerifyFunc(t *testing.T) func(resp interface{}, err error) {
|
|
return func(resp interface{}, err error) {
|
|
assert.NotNil(t, err)
|
|
assert.Equal(t, "", resp.(string))
|
|
}
|
|
}
|
|
|
|
func NewMockHttpServer(responseStatusCode int, responseBody string) *httptest.Server {
|
|
// create and return a mock http server that will return the specified HTTP status code and response body content
|
|
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(responseStatusCode)
|
|
w.Header().Set("Content-Type", "application/json")
|
|
fmt.Fprintln(w, responseBody)
|
|
}))
|
|
}
|
|
|
|
func NewMockHttpClient(mockServerURL string) *http.Client {
|
|
// create a transport that will use direct all network traffic to the mock HTTP server
|
|
transport := &http.Transport{
|
|
Proxy: func(request *http.Request) (*url.URL, error) {
|
|
return url.Parse(mockServerURL)
|
|
},
|
|
}
|
|
|
|
// return a http client that uses our transport
|
|
return &http.Client{Transport: transport}
|
|
}
|