func TestVolumeListEmpty(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // Get volumes, there should be none r, err := http.Get(ts.URL + "/volumes") tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, err == nil) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") // Read response var msg VolumeListResponse err = utils.GetJsonFromResponse(r, &msg) tests.Assert(t, err == nil) tests.Assert(t, len(msg.Volumes) == 0) }
func TestVolumeCreateSmallSize(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // VolumeCreate JSON Request request := []byte(`{ "size" : 0 }`) // Send request r, err := http.Post(ts.URL+"/volumes", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusBadRequest) body, err := ioutil.ReadAll(io.LimitReader(r.Body, r.ContentLength)) tests.Assert(t, err == nil) r.Body.Close() tests.Assert(t, strings.Contains(string(body), "Invalid volume size")) }
func TestVolumeEntryExpandMaxBrickLimit(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Create a large cluster err := setupSampleDbWithTopology(app, 10, // clusters 4, // nodes_per_cluster 24, // devices_per_node, 600*GB, // disksize) ) tests.Assert(t, err == nil) // Create large volume v := createSampleVolumeEntry(100) err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err == nil) // Add a bunch of bricks until the limit fakebricks := make(sort.StringSlice, BrickMaxNum-len(v.Bricks)) v.Bricks = append(v.Bricks, fakebricks...) // Try to expand the volume, but it will return that the max number // of bricks has been reached err = v.Expand(app.db, app.executor, app.allocator, 100) tests.Assert(t, err == ErrMaxBricks, err) }
func TestAppAdvsettings(t *testing.T) { dbfile := tests.Tempfile() defer os.Remove(dbfile) os.Setenv("HEKETI_EXECUTOR", "mock") defer os.Unsetenv("HEKETI_EXECUTOR") data := []byte(`{ "glusterfs" : { "executor" : "crazyexec", "allocator" : "simple", "db" : "` + dbfile + `", "brick_max_size_gb" : 1024, "brick_min_size_gb" : 1, "max_bricks_per_volume" : 33 } }`) bmax, bmin, bnum := BrickMaxSize, BrickMinSize, BrickMaxNum defer func() { BrickMaxSize, BrickMinSize, BrickMaxNum = bmax, bmin, bnum }() app := NewApp(bytes.NewReader(data)) tests.Assert(t, app != nil) tests.Assert(t, app.conf.Executor == "mock") tests.Assert(t, BrickMaxNum == 33) tests.Assert(t, BrickMaxSize == 1*TB) tests.Assert(t, BrickMinSize == 1*GB) }
func TestVolumeEntryNameConflictMultiCluster(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Create 10 clusters err := setupSampleDbWithTopology(app, 10, // clusters 3, // nodes_per_cluster 6, // devices_per_node, 6*TB, // disksize) ) tests.Assert(t, err == nil) // Create 10 volumes for i := 0; i < 10; i++ { v := createSampleVolumeEntry(1024) v.Info.Name = "myvol" err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err == nil) } // Create another volume same name v := createSampleVolumeEntry(10000) v.Info.Name = "myvol" err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err != nil, err) }
func TestVolumeEntryDoNotAllowDeviceOnSameNode(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Create cluster with plenty of space, but // it will not have enough nodes err := setupSampleDbWithTopology(app, 1, // clusters 1, // nodes_per_cluster 200, // devices_per_node, 6*TB, // disksize) ) tests.Assert(t, err == nil) // Create volume v := createSampleVolumeEntry(100) err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err != nil, err) tests.Assert(t, err == ErrNoSpace) v = createSampleVolumeEntry(10000) err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err != nil, err) tests.Assert(t, err == ErrNoSpace) }
func TestNewBrickEntryFromId(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Create a brick b := NewBrickEntry(10, 20, 5, "abc", "def") // Save element in database err := app.db.Update(func(tx *bolt.Tx) error { return b.Save(tx) }) tests.Assert(t, err == nil) var brick *BrickEntry err = app.db.View(func(tx *bolt.Tx) error { var err error brick, err = NewBrickEntryFromId(tx, b.Info.Id) return err }) tests.Assert(t, err == nil) tests.Assert(t, reflect.DeepEqual(brick, b)) }
func TestNewBrickEntryNewInfoResponse(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Create a brick b := NewBrickEntry(10, 20, 5, "abc", "def") // Save element in database err := app.db.Update(func(tx *bolt.Tx) error { return b.Save(tx) }) tests.Assert(t, err == nil) var info *api.BrickInfo err = app.db.View(func(tx *bolt.Tx) error { brick, err := NewBrickEntryFromId(tx, b.Id()) if err != nil { return err } info, err = brick.NewInfoResponse(tx) return err }) tests.Assert(t, err == nil) tests.Assert(t, reflect.DeepEqual(*info, b.Info)) }
func TestVolumeEntryFromId(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Create a volume entry v := createSampleVolumeEntry(1024) // Save in database err := app.db.Update(func(tx *bolt.Tx) error { return v.Save(tx) }) tests.Assert(t, err == nil) // Load from database var entry *VolumeEntry err = app.db.View(func(tx *bolt.Tx) error { var err error entry, err = NewVolumeEntryFromId(tx, v.Info.Id) return err }) tests.Assert(t, err == nil) tests.Assert(t, reflect.DeepEqual(entry, v)) }
func TestVolumeExpandIdNotFound(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // JSON Request request := []byte(`{ "expand_size" : 100 }`) // Now that we have some data in the database, we can // make a request for the clutser list r, err := http.Post(ts.URL+"/volumes/12345/expand", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusNotFound, r.StatusCode) body, err := ioutil.ReadAll(io.LimitReader(r.Body, r.ContentLength)) tests.Assert(t, err == nil) r.Body.Close() tests.Assert(t, strings.Contains(string(body), "Id not found")) }
func TestClientCluster(t *testing.T) { db := tests.Tempfile() defer os.Remove(db) // Create the app app := glusterfs.NewTestApp(db) defer app.Close() // Setup the server ts := setupHeketiServer(app) defer ts.Close() // Create cluster with unknown user c := NewClient(ts.URL, "asdf", "") tests.Assert(t, c != nil) cluster, err := c.ClusterCreate() tests.Assert(t, err != nil) tests.Assert(t, cluster == nil) // Create cluster with bad password c = NewClient(ts.URL, "admin", "badpassword") tests.Assert(t, c != nil) cluster, err = c.ClusterCreate() tests.Assert(t, err != nil) tests.Assert(t, cluster == nil) // Create cluster correctly c = NewClient(ts.URL, "admin", TEST_ADMIN_KEY) tests.Assert(t, c != nil) cluster, err = c.ClusterCreate() tests.Assert(t, err == nil) tests.Assert(t, cluster.Id != "") tests.Assert(t, len(cluster.Nodes) == 0) tests.Assert(t, len(cluster.Volumes) == 0) // Request bad id info, err := c.ClusterInfo("bad") tests.Assert(t, err != nil) tests.Assert(t, info == nil) // Get information about the client info, err = c.ClusterInfo(cluster.Id) tests.Assert(t, err == nil) tests.Assert(t, reflect.DeepEqual(info, cluster)) // Get a list of clusters list, err := c.ClusterList() tests.Assert(t, err == nil) tests.Assert(t, len(list.Clusters) == 1) tests.Assert(t, list.Clusters[0] == info.Id) // Delete non-existent cluster err = c.ClusterDelete("badid") tests.Assert(t, err != nil) // Delete current cluster err = c.ClusterDelete(info.Id) tests.Assert(t, err == nil) }
func TestAppLogLevel(t *testing.T) { dbfile := tests.Tempfile() defer os.Remove(dbfile) levels := []string{ "none", "critical", "error", "warning", "info", "debug", } logger.SetLevel(utils.LEVEL_DEBUG) for _, level := range levels { data := []byte(`{ "glusterfs" : { "executor" : "mock", "allocator" : "simple", "db" : "` + dbfile + `", "loglevel" : "` + level + `" } }`) app := NewApp(bytes.NewReader(data)) tests.Assert(t, app != nil, level, string(data)) switch level { case "none": tests.Assert(t, logger.Level() == utils.LEVEL_NOLOG) case "critical": tests.Assert(t, logger.Level() == utils.LEVEL_CRITICAL) case "error": tests.Assert(t, logger.Level() == utils.LEVEL_ERROR) case "warning": tests.Assert(t, logger.Level() == utils.LEVEL_WARNING) case "info": tests.Assert(t, logger.Level() == utils.LEVEL_INFO) case "debug": tests.Assert(t, logger.Level() == utils.LEVEL_DEBUG) } app.Close() } // Test that an unknown value does not change the loglevel logger.SetLevel(utils.LEVEL_NOLOG) data := []byte(`{ "glusterfs" : { "executor" : "mock", "allocator" : "simple", "db" : "` + dbfile + `", "loglevel" : "blah" } }`) app := NewApp(bytes.NewReader(data)) tests.Assert(t, app != nil) tests.Assert(t, logger.Level() == utils.LEVEL_NOLOG) }
func TestVolumeDelete(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // Setup database err := setupSampleDbWithTopology(app, 1, // clusters 10, // nodes_per_cluster 10, // devices_per_node, 5*TB, // disksize) ) tests.Assert(t, err == nil) // Create a volume v := createSampleVolumeEntry(100) tests.Assert(t, v != nil) err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err == nil) // Delete the volume req, err := http.NewRequest("DELETE", ts.URL+"/volumes/"+v.Info.Id, nil) tests.Assert(t, err == nil) r, err := http.DefaultClient.Do(req) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusAccepted) location, err := r.Location() tests.Assert(t, err == nil) // Query queue until finished for { r, err = http.Get(location.String()) tests.Assert(t, err == nil) if r.Header.Get("X-Pending") == "true" { tests.Assert(t, r.StatusCode == http.StatusOK) time.Sleep(time.Millisecond * 10) continue } else { tests.Assert(t, r.StatusCode == http.StatusNoContent) tests.Assert(t, err == nil) break } } // Check it is not there r, err = http.Get(ts.URL + "/volumes/" + v.Info.Id) tests.Assert(t, r.StatusCode == http.StatusNotFound) tests.Assert(t, err == nil) }
func TestVolumeList(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // Create some volumes numvolumes := 1000 err := app.db.Update(func(tx *bolt.Tx) error { for i := 0; i < numvolumes; i++ { v := createSampleVolumeEntry(100) err := v.Save(tx) if err != nil { return err } } return nil }) tests.Assert(t, err == nil) // Get volumes, there should be none r, err := http.Get(ts.URL + "/volumes") tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, err == nil) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") // Read response var msg VolumeListResponse err = utils.GetJsonFromResponse(r, &msg) tests.Assert(t, err == nil) tests.Assert(t, len(msg.Volumes) == numvolumes) // Check that all the volumes are in the database err = app.db.View(func(tx *bolt.Tx) error { for _, id := range msg.Volumes { _, err := NewVolumeEntryFromId(tx, id) if err != nil { return err } } return nil }) tests.Assert(t, err == nil) }
func TestVolumeCreateBadDispersionValues(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // VolumeCreate JSON Request request := []byte(`{ "size" : 100, "durability": { "type": "disperse", "disperse": { "data" : 8, "redundancy" : 1 } } }`) // Send request r, err := http.Post(ts.URL+"/volumes", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusBadRequest) body, err := ioutil.ReadAll(io.LimitReader(r.Body, r.ContentLength)) tests.Assert(t, err == nil) r.Body.Close() tests.Assert(t, strings.Contains(string(body), "Invalid dispersion combination")) // VolumeCreate JSON Request request = []byte(`{ "size" : 100, "durability": { "type": "disperse", "disperse": { "data" : 4, "redundancy" : 3 } } }`) // Send request r, err = http.Post(ts.URL+"/volumes", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusBadRequest) body, err = ioutil.ReadAll(io.LimitReader(r.Body, r.ContentLength)) tests.Assert(t, err == nil) r.Body.Close() tests.Assert(t, strings.Contains(string(body), "Invalid dispersion combination")) }
func TestVolumeEntryDestroyCheck(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Lots of nodes with little drives err := setupSampleDbWithTopology(app, 1, // clusters 4, // nodes_per_cluster 4, // devices_per_node, 500*GB, // disksize) ) tests.Assert(t, err == nil) // Create a volume with a snapshot factor of 1.5 // For a 200G vol, it would get a brick size of 100G, with a thin pool // size of 100G * 1.5 = 150GB. v := createSampleVolumeEntry(200) v.Info.Snapshot.Enable = true v.Info.Snapshot.Factor = 1.5 err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err == nil) // Test that a volume that is sharing space in a thin pool // with either a clone or a snapshot cannot be deleted app.xo.MockBrickDestroyCheck = func(host string, brick *executors.BrickRequest) error { return fmt.Errorf("BRICKMOCK") } err = v.Destroy(app.db, app.executor) tests.Assert(t, err != nil) tests.Assert(t, err.Error() == "BRICKMOCK") app.xo.MockBrickDestroyCheck = func(host string, brick *executors.BrickRequest) error { return nil } // Check that a volume with snapshots cannot be deleted app.xo.MockVolumeDestroyCheck = func(host, volume string) error { return fmt.Errorf("VOLMOCK") } err = v.Destroy(app.db, app.executor) tests.Assert(t, err != nil) tests.Assert(t, err.Error() == "VOLMOCK") app.xo.MockVolumeDestroyCheck = func(host, volume string) error { return nil } // Now it should be able to be deleted err = v.Destroy(app.db, app.executor) tests.Assert(t, err == nil) }
func TestVolumeInfo(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // Setup database err := setupSampleDbWithTopology(app, 1, // clusters 10, // nodes_per_cluster 10, // devices_per_node, 5*TB, // disksize) ) tests.Assert(t, err == nil) // Create a volume req := &VolumeCreateRequest{} req.Size = 100 req.Durability.Type = DURABILITY_STRING_EC v := NewVolumeEntryFromRequest(req) tests.Assert(t, v != nil) err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err == nil) // Now that we have some data in the database, we can // make a request for the clutser list r, err := http.Get(ts.URL + "/volumes/" + v.Info.Id) tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, err == nil) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") // Read response var msg VolumeInfoResponse err = utils.GetJsonFromResponse(r, &msg) tests.Assert(t, err == nil) tests.Assert(t, msg.Id == v.Info.Id) tests.Assert(t, msg.Cluster == v.Info.Cluster) tests.Assert(t, msg.Name == v.Info.Name) tests.Assert(t, msg.Size == v.Info.Size) tests.Assert(t, reflect.DeepEqual(msg.Durability, v.Info.Durability)) tests.Assert(t, reflect.DeepEqual(msg.Snapshot, v.Info.Snapshot)) for _, brick := range msg.Bricks { tests.Assert(t, utils.SortedStringHas(v.Bricks, brick.Id)) } }
func TestVolumeEntryCreateBrickCreationFailure(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Lots of nodes with little drives err := setupSampleDbWithTopology(app, 1, // clusters 4, // nodes_per_cluster 4, // devices_per_node, 500*GB, // disksize) ) tests.Assert(t, err == nil) // Cause a brick creation failure mockerror := errors.New("MOCK") app.xo.MockBrickCreate = func(host string, brick *executors.BrickRequest) (*executors.BrickInfo, error) { return nil, mockerror } // Create a volume with a snapshot factor of 1.5 // For a 200G vol, it would get a brick size of 100G, with a thin pool // size of 100G * 1.5 = 150GB. v := createSampleVolumeEntry(200) err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err == mockerror) // Check database is still clean. No bricks and No volumes err = app.db.View(func(tx *bolt.Tx) error { volumes, err := VolumeList(tx) tests.Assert(t, err == nil) tests.Assert(t, len(volumes) == 0) bricks, err := BrickList(tx) tests.Assert(t, err == nil) tests.Assert(t, len(bricks) == 0) clusters, err := ClusterList(tx) tests.Assert(t, err == nil) tests.Assert(t, len(clusters) == 1) cluster, err := NewClusterEntryFromId(tx, clusters[0]) tests.Assert(t, err == nil) tests.Assert(t, len(cluster.Info.Volumes) == 0) return nil }) tests.Assert(t, err == nil) }
func TestNewNodeEntryNewInfoResponse(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Create a node req := &api.NodeAddRequest{ ClusterId: "123", Hostnames: api.HostAddresses{ Manage: []string{"manage"}, Storage: []string{"storage"}, }, Zone: 99, } n := NewNodeEntryFromRequest(req) // Save element in database err := app.db.Update(func(tx *bolt.Tx) error { return n.Save(tx) }) tests.Assert(t, err == nil) var info *api.NodeInfoResponse err = app.db.View(func(tx *bolt.Tx) error { node, err := NewNodeEntryFromId(tx, n.Info.Id) if err != nil { return err } info, err = node.NewInfoReponse(tx) if err != nil { return err } return nil }) tests.Assert(t, err == nil) tests.Assert(t, info.ClusterId == n.Info.ClusterId) tests.Assert(t, info.Id == n.Info.Id) tests.Assert(t, info.Zone == n.Info.Zone) tests.Assert(t, len(info.Hostnames.Manage) == 1) tests.Assert(t, len(info.Hostnames.Storage) == 1) tests.Assert(t, reflect.DeepEqual(info.Hostnames.Manage, n.Info.Hostnames.Manage)) tests.Assert(t, reflect.DeepEqual(info.Hostnames.Storage, n.Info.Hostnames.Storage)) }
func TestSimpleAllocatorInitFromDb(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Setup database app := NewTestApp(tmpfile) defer app.Close() // Create large cluster err := setupSampleDbWithTopology(app, 1, // clusters 10, // nodes_per_cluster 20, // devices_per_node, 600*GB, // disksize) ) tests.Assert(t, err == nil) // Get the cluster list var clusterId string err = app.db.View(func(tx *bolt.Tx) error { clusters, err := ClusterList(tx) if err != nil { return err } tests.Assert(t, len(clusters) == 1) clusterId = clusters[0] return nil }) tests.Assert(t, err == nil) // Create an allocator and initialize it from the DB a := NewSimpleAllocatorFromDb(app.db) tests.Assert(t, a != nil) // Get the nodes from the ring ch, _, errc := a.GetNodes(clusterId, utils.GenUUID()) var devices int for d := range ch { devices++ tests.Assert(t, d != "") } err = <-errc tests.Assert(t, devices == 10*20) tests.Assert(t, err == nil) }
func TestVolumeEntrySaveDelete(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Create a volume entry v := createSampleVolumeEntry(1024) // Save in database err := app.db.Update(func(tx *bolt.Tx) error { return v.Save(tx) }) tests.Assert(t, err == nil) // Delete entry which has devices var entry *VolumeEntry err = app.db.Update(func(tx *bolt.Tx) error { var err error entry, err = NewVolumeEntryFromId(tx, v.Info.Id) if err != nil { return err } err = entry.Delete(tx) if err != nil { return err } return nil }) tests.Assert(t, err == nil) // Check volume has been deleted and is not in db err = app.db.View(func(tx *bolt.Tx) error { var err error entry, err = NewVolumeEntryFromId(tx, v.Info.Id) if err != nil { return err } return nil }) tests.Assert(t, err == ErrNotFound) }
func TestVolumeEntryCreateMaxBrickSize(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Create 500TB of storage err := setupSampleDbWithTopology(app, 1, // clusters 10, // nodes_per_cluster 10, // devices_per_node, 5*TB, // disksize) ) tests.Assert(t, err == nil) // Create a volume whose bricks must be at most BrickMaxSize v := createSampleVolumeEntry(int(BrickMaxSize / GB * 4)) err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err == nil) // Get volume information var info *api.VolumeInfoResponse err = app.db.View(func(tx *bolt.Tx) error { entry, err := NewVolumeEntryFromId(tx, v.Info.Id) if err != nil { return err } info, err = entry.NewInfoResponse(tx) if err != nil { return err } return nil }) tests.Assert(t, err == nil) // Check the size of the bricks are not bigger than BrickMaxSize tests.Assert(t, len(info.Bricks) == 8) for b := 1; b < len(info.Bricks); b++ { tests.Assert(t, info.Bricks[b].Size <= BrickMaxSize) } tests.Assert(t, info.Cluster == v.Info.Cluster) }
func TestNewDeviceEntryFromIdNotFound(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Test for ID not found err := app.db.View(func(tx *bolt.Tx) error { _, err := NewDeviceEntryFromId(tx, "123") return err }) tests.Assert(t, err == ErrNotFound) }
func TestVolumeEntryExpandCreateBricksFailure(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Create large cluster err := setupSampleDbWithTopology(app, 10, // clusters 10, // nodes_per_cluster 20, // devices_per_node, 600*GB, // disksize) ) tests.Assert(t, err == nil) // Create volume v := createSampleVolumeEntry(100) err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err == nil) // Save a copy of the volume before expansion vcopy := &VolumeEntry{} *vcopy = *v // Mock create bricks to fail ErrMock := errors.New("MOCK") app.xo.MockBrickCreate = func(host string, brick *executors.BrickRequest) (*executors.BrickInfo, error) { return nil, ErrMock } // Expand volume err = v.Expand(app.db, app.executor, app.allocator, 500) tests.Assert(t, err == ErrMock) // Check db is the same as before expansion var entry *VolumeEntry err = app.db.View(func(tx *bolt.Tx) error { var err error entry, err = NewVolumeEntryFromId(tx, v.Info.Id) return err }) tests.Assert(t, err == nil) tests.Assert(t, reflect.DeepEqual(vcopy, entry)) }
func TestDeviceAddBadRequests(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // ClusterCreate JSON Request request := []byte(`{ bad json }`) // Post bad JSON r, err := http.Post(ts.URL+"/devices", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == 422) // Make a request with no device request = []byte(`{ "node" : "123" }`) // Post bad JSON r, err = http.Post(ts.URL+"/devices", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusBadRequest) // Make a request with unknown node request = []byte(`{ "node" : "123", "name" : "/dev/fake", "weight" : 20 }`) // Post unknown node r, err = http.Post(ts.URL+"/devices", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusNotFound) }
func TestClusterCreate(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // ClusterCreate JSON Request request := []byte(`{ }`) // Post nothing r, err := http.Post(ts.URL+"/clusters", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusCreated) // Read JSON var msg ClusterInfoResponse err = utils.GetJsonFromResponse(r, &msg) tests.Assert(t, err == nil) // Test JSON tests.Assert(t, len(msg.Nodes) == 0) tests.Assert(t, len(msg.Volumes) == 0) // Check that the data on the database is recorded correctly var entry ClusterEntry err = app.db.View(func(tx *bolt.Tx) error { return entry.Unmarshal( tx.Bucket([]byte(BOLTDB_BUCKET_CLUSTER)). Get([]byte(msg.Id))) }) tests.Assert(t, err == nil) // Make sure they entries are euqal tests.Assert(t, entry.Info.Id == msg.Id) tests.Assert(t, len(entry.Info.Volumes) == 0) tests.Assert(t, len(entry.Info.Nodes) == 0) }
func TestDeviceInfo(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // Create a device to save in the db device := NewDeviceEntry() device.Info.Id = "abc" device.Info.Name = "/dev/fake1" device.Info.Weight = 101 device.NodeId = "def" device.StorageSet(10000) device.StorageAllocate(1000) // Save device in the db err := app.db.Update(func(tx *bolt.Tx) error { return device.Save(tx) }) tests.Assert(t, err == nil) // Get device information r, err := http.Get(ts.URL + "/devices/" + device.Info.Id) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") var info DeviceInfoResponse err = utils.GetJsonFromResponse(r, &info) tests.Assert(t, info.Id == device.Info.Id) tests.Assert(t, info.Name == device.Info.Name) tests.Assert(t, info.Weight == device.Info.Weight) tests.Assert(t, info.Storage.Free == device.Info.Storage.Free) tests.Assert(t, info.Storage.Used == device.Info.Storage.Used) tests.Assert(t, info.Storage.Total == device.Info.Storage.Total) }
func TestVolumeEntryCreateRunOutOfSpaceMaxBrickLimit(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Lots of nodes with little drives err := setupSampleDbWithTopology(app, 1, // clusters 20, // nodes_per_cluster 40, // devices_per_node, // Must be larger than the brick min size BrickMinSize*2, // disksize ) tests.Assert(t, err == nil) // Create a volume who will be broken down to // Shouldn't be able to break it down enough to allocate volume v := createSampleVolumeEntry(BrickMaxNum * 2 * int(BrickMinSize/GB)) err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err == ErrNoSpace) // Check database volume does not exist err = app.db.View(func(tx *bolt.Tx) error { _, err := NewVolumeEntryFromId(tx, v.Info.Id) return err }) tests.Assert(t, err == ErrNotFound) // Check no bricks or volumes exist var bricks []string var volumes []string err = app.db.View(func(tx *bolt.Tx) error { bricks = EntryKeys(tx, BOLTDB_BUCKET_BRICK) volumes = EntryKeys(tx, BOLTDB_BUCKET_VOLUME) return nil }) tests.Assert(t, len(bricks) == 0) tests.Assert(t, len(volumes) == 0) }
func TestVolumeEntryCreateRunOutOfSpaceMinBrickSizeLimit(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Total 80GB err := setupSampleDbWithTopology(app, 1, // clusters 2, // nodes_per_cluster 4, // devices_per_node, 10*GB, // disksize, 10G) ) tests.Assert(t, err == nil) // Create a 100 GB volume // Shouldn't be able to break it down enough to allocate volume v := createSampleVolumeEntry(100) err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err == ErrNoSpace) tests.Assert(t, v.Info.Cluster == "") // Check database volume does not exist err = app.db.View(func(tx *bolt.Tx) error { _, err := NewVolumeEntryFromId(tx, v.Info.Id) return err }) tests.Assert(t, err == ErrNotFound) // Check no bricks or volumes exist var bricks []string var volumes []string err = app.db.View(func(tx *bolt.Tx) error { bricks = EntryKeys(tx, BOLTDB_BUCKET_BRICK) volumes = EntryKeys(tx, BOLTDB_BUCKET_VOLUME) return nil }) tests.Assert(t, err == nil) tests.Assert(t, len(bricks) == 0, bricks) tests.Assert(t, len(volumes) == 0) }
func TestVolumeEntryExpandNoSpace(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() // Create cluster err := setupSampleDbWithTopology(app, 10, // clusters 2, // nodes_per_cluster 2, // devices_per_node, 600*GB, // disksize) ) tests.Assert(t, err == nil) // Create large volume v := createSampleVolumeEntry(1190) err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err == nil) // Save a copy of the volume before expansion vcopy := &VolumeEntry{} *vcopy = *v // Asking for a large amount will require too many little bricks err = v.Expand(app.db, app.executor, app.allocator, 5000) tests.Assert(t, err == ErrMaxBricks, err) // Asking for a small amount will set the bricks too small err = v.Expand(app.db, app.executor, app.allocator, 10) tests.Assert(t, err == ErrMininumBrickSize, err) // Check db is the same as before expansion var entry *VolumeEntry err = app.db.View(func(tx *bolt.Tx) error { var err error entry, err = NewVolumeEntryFromId(tx, v.Info.Id) return err }) tests.Assert(t, err == nil, err) tests.Assert(t, reflect.DeepEqual(vcopy, entry)) }