From d592fd5df6d1b8be0d4361fa72953602887b66d4 Mon Sep 17 00:00:00 2001 From: James Rasell Date: Tue, 1 Oct 2019 14:45:17 +0200 Subject: [PATCH] Add acceptance test for meta policy engine and scaling actions. The acceptance testing has been expanded to cover scaling actions as well as the Nomad meta policy backend. The Nomad meta engine requires Sherpa to run in a different mode than the rest of the tests, therefore the make targets have been split to make this clear until the whole process is automated. The scale tests are particulary basic, but are a start for further work in the future. These tests have already uncovered #59. --- GNUmakefile | 6 +- test/acctest/acctest.go | 8 +- test/acctest/helpers.go | 52 +- test/{policy_test.go => api_policy_test.go} | 37 +- test/meta_policy_test.go | 532 ++++++++++++++++++++ test/scale_in_test.go | 143 ++++++ test/scale_out_test.go | 142 ++++++ 7 files changed, 908 insertions(+), 12 deletions(-) rename test/{policy_test.go => api_policy_test.go} (91%) create mode 100644 test/meta_policy_test.go create mode 100644 test/scale_in_test.go create mode 100644 test/scale_out_test.go diff --git a/GNUmakefile b/GNUmakefile index 4251a75..432b4f7 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -14,10 +14,14 @@ test: ## Run the Sherpa test suite with coverage @go test ./... -cover -v -tags -race \ "$(BUILDTAGS)" $(shell go list ./... | grep -v vendor) -acctest: ## Run the Sherpa acceptance test suite +acctest-standard: ## Run the Sherpa acceptance test suite @echo "==> Running $@..." @SHERPA_ACC=1 go test ./test -count 1 -v -mod vendor +acctest-meta: ## Run the Sherpa Nomad meta acceptance test suite + @echo "==> Running $@..." + @SHERPA_ACC=1 SHERPA_ACC_META=1 go test ./test -count 1 -v -mod vendor + release: ## Trigger the release build script @echo "==> Running $@..." @goreleaser --rm-dist diff --git a/test/acctest/acctest.go b/test/acctest/acctest.go index db7cb45..94b89d6 100644 --- a/test/acctest/acctest.go +++ b/test/acctest/acctest.go @@ -16,8 +16,8 @@ type TestCase struct { // Steps are ran in order stopping on failure Steps []TestStep - // CleanupFunc is called at the end of the TestCase if set - CleanupFunc TestStateFunc + // CleanupFuncs is called at the end of the TestCase if set + CleanupFuncs []TestStateFunc } // TestStep is a single step within a TestCase @@ -110,8 +110,8 @@ func Test(t *testing.T, c TestCase) { } } - if c.CleanupFunc != nil { - err = c.CleanupFunc(state) + for i := range c.CleanupFuncs { + err = c.CleanupFuncs[i](state) if err != nil { t.Errorf("cleanup failed: %s", err) } diff --git a/test/acctest/helpers.go b/test/acctest/helpers.go index b211d5b..62fb143 100644 --- a/test/acctest/helpers.go +++ b/test/acctest/helpers.go @@ -2,12 +2,17 @@ package acctest import ( "fmt" + "time" + + nomad "github.com/hashicorp/nomad/api" ) +func StringToPointer(s string) *string { return &s } +func IntToPointer(i int) *int { return &i } + // CleanupPurgeJob is a cleanup func to purge the TestCase job from Nomad func CleanupPurgeJob(s *TestState) error { _, _, err := s.Nomad.Jobs().Deregister(s.JobName, true, nil) - // TODO: wait for action to complete return err } @@ -23,6 +28,28 @@ func CheckErrEqual(expected string) func(error) bool { } } +// CheckJobReachesStatus performs a check, with a timeout that the test job reaches to desired +// status. +func CheckJobReachesStatus(s *TestState, status string) error { + timeout := time.After(30 * time.Second) + tick := time.Tick(500 * time.Millisecond) + + for { + select { + case <-timeout: + return fmt.Errorf("timeout reached on checking that job %s reaches status %s", s.JobName, status) + case <-tick: + j, _, err := s.Nomad.Jobs().Info(s.JobName, nil) + if err != nil { + return err + } + if *j.Status == status { + return nil + } + } + } +} + // CheckDeploymentStatus is a TestStateFunc to check if the latest deployment of // the TestCase job in Nomad matches the desired status func CheckDeploymentStatus(status string) TestStateFunc { @@ -61,3 +88,26 @@ func CheckTaskGroupCount(groupName string, count int) TestStateFunc { return fmt.Errorf("unable to find task group %s", groupName) } } + +func BuildBaseTestJob(name string) *nomad.Job { + return &nomad.Job{ + ID: StringToPointer(name), + Name: StringToPointer(name), + Datacenters: []string{"dc1"}, + } +} + +func BuildBaseTaskGroup(group, task string) *nomad.TaskGroup { + return &nomad.TaskGroup{ + Name: StringToPointer(group), + Tasks: []*nomad.Task{{ + Name: task, + Driver: "docker", + Config: map[string]interface{}{"image": "redis:3.2"}, + Resources: &nomad.Resources{ + CPU: IntToPointer(500), + MemoryMB: IntToPointer(256), + }, + }}, + } +} diff --git a/test/policy_test.go b/test/api_policy_test.go similarity index 91% rename from test/policy_test.go rename to test/api_policy_test.go index 9f1bcc0..630ad1e 100644 --- a/test/policy_test.go +++ b/test/api_policy_test.go @@ -2,6 +2,7 @@ package test import ( "fmt" + "os" "testing" "github.com/jrasell/sherpa/pkg/api" @@ -9,6 +10,10 @@ import ( ) func TestPolicy_list(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") != "" { + t.SkipNow() + } + acctest.Test(t, acctest.TestCase{ Steps: []acctest.TestStep{ { @@ -51,11 +56,15 @@ func TestPolicy_list(t *testing.T) { }, }, }, - CleanupFunc: acctest.CleanupSherpaPolicy, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupSherpaPolicy}, }) } func TestPolicy_readJob(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") != "" { + t.SkipNow() + } + groupName := "group" acctest.Test(t, acctest.TestCase{ @@ -93,11 +102,15 @@ func TestPolicy_readJob(t *testing.T) { }, }, }, - CleanupFunc: acctest.CleanupSherpaPolicy, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupSherpaPolicy}, }) } func TestPolicy_readJobGroup(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") != "" { + t.SkipNow() + } + groupName := "group" acctest.Test(t, acctest.TestCase{ @@ -134,11 +147,15 @@ func TestPolicy_readJobGroup(t *testing.T) { }, }, }, - CleanupFunc: acctest.CleanupSherpaPolicy, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupSherpaPolicy}, }) } func TestPolicy_write(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") != "" { + t.SkipNow() + } + groupName := "group" acctest.Test(t, acctest.TestCase{ @@ -198,11 +215,15 @@ func TestPolicy_write(t *testing.T) { }, }, }, - CleanupFunc: acctest.CleanupSherpaPolicy, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupSherpaPolicy}, }) } func TestPolicy_deleteJobPolicy(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") != "" { + t.SkipNow() + } + groupName := "group" acctest.Test(t, acctest.TestCase{ @@ -252,11 +273,15 @@ func TestPolicy_deleteJobPolicy(t *testing.T) { CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), }, }, - CleanupFunc: acctest.CleanupSherpaPolicy, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupSherpaPolicy}, }) } func TestPolicy_deleteJobGroupPolicy(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") != "" { + t.SkipNow() + } + acctest.Test(t, acctest.TestCase{ Steps: []acctest.TestStep{ { @@ -326,6 +351,6 @@ func TestPolicy_deleteJobGroupPolicy(t *testing.T) { }, }, }, - CleanupFunc: acctest.CleanupSherpaPolicy, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupSherpaPolicy}, }) } diff --git a/test/meta_policy_test.go b/test/meta_policy_test.go new file mode 100644 index 0000000..bebd9b6 --- /dev/null +++ b/test/meta_policy_test.go @@ -0,0 +1,532 @@ +package test + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/nomad/api" + "github.com/jrasell/sherpa/test/acctest" +) + +const ( + testMetaGroupName1 = "sherpa-acctest-group-1" + testMetaTaskName1 = "sherpa-acctest-task-1" + testMetaGroupName2 = "sherpa-acctest-group-2" + testMetaTaskName2 = "sherpa-acctest-task-2" +) + +type meta string + +const ( + metaPartial meta = "partial" + metaAll meta = "all" + metaNone meta = "none" +) + +func TestMetaPolicy_singleTaskGroupFullMetaRemoveAllMeta(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") == "" { + t.SkipNow() + } + + acctest.Test(t, acctest.TestCase{ + Steps: []acctest.TestStep{ + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobPolicy(s.JobName) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Register(buildMetaTestJob(false, s.JobName, metaAll), nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "running") + }, + }, + { + Runner: func(s *acctest.TestState) error { + policy, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName1) + if err != nil { + return err + } + + if policy.MaxCount != 5 { + return fmt.Errorf("expected policy %s/%s to match the MaxCount", s.JobName, testMetaGroupName1) + } + + return nil + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Register(buildMetaTestJob(false, s.JobName, metaNone), nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "running") + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName1) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + }, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupPurgeJob}, + }) +} + +func TestMetaPolicy_singleTaskGroupFullMetaStopJob(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") == "" { + t.SkipNow() + } + + acctest.Test(t, acctest.TestCase{ + Steps: []acctest.TestStep{ + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobPolicy(s.JobName) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Register(buildMetaTestJob(false, s.JobName, metaAll), nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "running") + }, + }, + { + Runner: func(s *acctest.TestState) error { + policy, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName1) + if err != nil { + return err + } + + if policy.MaxCount != 5 { + return fmt.Errorf("expected policy %s/%s to match the MaxCount", s.JobName, testMetaGroupName1) + } + + return nil + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Deregister(s.JobName, false, nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "dead") + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName1) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + }, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupPurgeJob}, + }) +} + +func TestMetaPolicy_multiTaskGroupFullMetaRemoveAllMeta(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") == "" { + t.SkipNow() + } + + acctest.Test(t, acctest.TestCase{ + Steps: []acctest.TestStep{ + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobPolicy(s.JobName) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Register(buildMetaTestJob(true, s.JobName, metaAll), nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "running") + }, + }, + { + Runner: func(s *acctest.TestState) error { + policy1, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName1) + if err != nil { + return err + } + + if policy1.MaxCount != 5 { + return fmt.Errorf("expected policy %s/%s to match the MaxCount", s.JobName, testMetaGroupName1) + } + + policy2, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName2) + if err != nil { + return err + } + + if policy2.MaxCount != 5 { + return fmt.Errorf("expected policy %s/%s to match the MaxCount", s.JobName, testMetaGroupName2) + } + + return nil + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Register(buildMetaTestJob(true, s.JobName, metaNone), nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "running") + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName1) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + }, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupPurgeJob}, + }) +} + +func TestMetaPolicy_multiTaskGroupFullMetaStopJob(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") == "" { + t.SkipNow() + } + + acctest.Test(t, acctest.TestCase{ + Steps: []acctest.TestStep{ + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobPolicy(s.JobName) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Register(buildMetaTestJob(true, s.JobName, metaAll), nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "running") + }, + }, + { + Runner: func(s *acctest.TestState) error { + policy1, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName1) + if err != nil { + return err + } + + if policy1.MaxCount != 5 { + return fmt.Errorf("expected policy %s/%s to match the MaxCount", s.JobName, testMetaGroupName1) + } + + policy2, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName2) + if err != nil { + return err + } + + if policy2.MaxCount != 5 { + return fmt.Errorf("expected policy %s/%s to match the MaxCount", s.JobName, testMetaGroupName2) + } + + return nil + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Deregister(s.JobName, false, nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "dead") + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName1) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + }, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupPurgeJob}, + }) +} + +func TestMetaPolicy_multiTaskGroupPartialMetaRemoveAllMeta(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") == "" { + t.SkipNow() + } + + acctest.Test(t, acctest.TestCase{ + Steps: []acctest.TestStep{ + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobPolicy(s.JobName) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Register(buildMetaTestJob(true, s.JobName, metaPartial), nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "running") + }, + }, + { + Runner: func(s *acctest.TestState) error { + policy1, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName1) + if err != nil { + return err + } + + if policy1.MaxCount != 5 { + return fmt.Errorf("expected policy %s/%s to match the MaxCount", s.JobName, testMetaGroupName1) + } + return nil + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName2) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Register(buildMetaTestJob(true, s.JobName, metaNone), nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "running") + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName1) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + }, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupPurgeJob}, + }) +} + +func TestMetaPolicy_multiTaskGroupPartialMetaStopJob(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") == "" { + t.SkipNow() + } + + acctest.Test(t, acctest.TestCase{ + Steps: []acctest.TestStep{ + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobPolicy(s.JobName) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Register(buildMetaTestJob(true, s.JobName, metaPartial), nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "running") + }, + }, + { + Runner: func(s *acctest.TestState) error { + policy1, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName1) + if err != nil { + return err + } + + if policy1.MaxCount != 5 { + return fmt.Errorf("expected policy %s/%s to match the MaxCount", s.JobName, testMetaGroupName1) + } + return nil + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName2) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Deregister(s.JobName, false, nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "dead") + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName1) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobPolicy(s.JobName) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + }, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupPurgeJob}, + }) +} + +func TestMetaPolicy_multiTaskGroupPartialMetaAddAllMeta(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") == "" { + t.SkipNow() + } + + acctest.Test(t, acctest.TestCase{ + Steps: []acctest.TestStep{ + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobPolicy(s.JobName) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Register(buildMetaTestJob(true, s.JobName, metaPartial), nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "running") + }, + }, + { + Runner: func(s *acctest.TestState) error { + policy1, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName1) + if err != nil { + return err + } + + if policy1.MaxCount != 5 { + return fmt.Errorf("expected policy %s/%s to match the MaxCount", s.JobName, testMetaGroupName1) + } + return nil + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName2) + return err + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 404: 404 page not found"), + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Register(buildMetaTestJob(true, s.JobName, metaAll), nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "running") + }, + }, + { + Runner: func(s *acctest.TestState) error { + policy1, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName1) + if err != nil { + return err + } + + if policy1.MaxCount != 5 { + return fmt.Errorf("expected policy %s/%s to match the MaxCount", s.JobName, testMetaGroupName1) + } + + policy2, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testMetaGroupName2) + if err != nil { + return err + } + + if policy2.MaxCount != 5 { + return fmt.Errorf("expected policy %s/%s to match the MaxCount", s.JobName, testMetaGroupName2) + } + + return nil + }, + }, + }, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupPurgeJob}, + }) +} + +func buildMetaTestJob(multiGroup bool, name string, metaType meta) *api.Job { + j := acctest.BuildBaseTestJob(name) + j.TaskGroups = append(j.TaskGroups, acctest.BuildBaseTaskGroup(testMetaGroupName1, testMetaTaskName1)) + + if multiGroup { + j.TaskGroups = append(j.TaskGroups, acctest.BuildBaseTaskGroup(testMetaGroupName2, testMetaTaskName2)) + } + + switch metaType { + case metaAll: + for i := range j.TaskGroups { + j.TaskGroups[i].Meta = buildMeta() + } + case metaPartial: + j.TaskGroups[0].Meta = buildMeta() + case metaNone: + } + + return j +} + +func buildMeta() map[string]string { + return map[string]string{"sherpa_enabled": "true", "sherpa_max_count": "5"} +} diff --git a/test/scale_in_test.go b/test/scale_in_test.go new file mode 100644 index 0000000..d029b4f --- /dev/null +++ b/test/scale_in_test.go @@ -0,0 +1,143 @@ +package test + +import ( + "fmt" + "os" + "testing" + + nomad "github.com/hashicorp/nomad/api" + "github.com/jrasell/sherpa/pkg/api" + "github.com/jrasell/sherpa/test/acctest" +) + +const ( + testScaleInGroupName1 = "sherpa-acctest-group-1" + testScaleInTaskName1 = "sherpa-acctest-task-1" +) + +func TestScaleIn_singleTaskGroupCountSet(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") != "" { + t.SkipNow() + } + + acctest.Test(t, acctest.TestCase{ + Steps: []acctest.TestStep{ + { + Runner: func(s *acctest.TestState) error { + policy := &api.JobGroupPolicy{Enabled: true, MaxCount: 5, MinCount: 1} + return s.Sherpa.Policies().WriteJobGroupPolicy(s.JobName, testScaleInGroupName1, policy) + }, + }, + { + Runner: func(s *acctest.TestState) error { + policy1, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testScaleInGroupName1) + if err != nil { + return err + } + + if policy1.MaxCount != 5 { + return fmt.Errorf("expected policy %s/%s to match the MaxCount", s.JobName, testMetaGroupName1) + } + if policy1.MinCount != 1 { + return fmt.Errorf("expected policy %s/%s to match the MinCount", s.JobName, testMetaGroupName1) + } + return nil + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Register(buildScaleInTestJob(s.JobName), nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "running") + }, + }, + { + Runner: func(s *acctest.TestState) error { + resp, err := s.Sherpa.Scale().JobGroupIn(s.JobName, testScaleInGroupName1, 2) + if err != nil { + return err + } + + if resp == nil { + return fmt.Errorf("expected non-nil scale out response") + } + + if _, err = s.Sherpa.Scale().Info(resp.ID.String()); err != nil { + return err + } + return nil + }, + }, + { + Runner: acctest.CheckTaskGroupCount(testScaleInGroupName1, 1), + }, + }, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupSherpaPolicy, acctest.CleanupPurgeJob}, + }) +} + +func TestScaleIn_singleTaskGroupCountSetTooLow(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") != "" { + t.SkipNow() + } + + acctest.Test(t, acctest.TestCase{ + Steps: []acctest.TestStep{ + { + Runner: func(s *acctest.TestState) error { + policy := &api.JobGroupPolicy{Enabled: true, MaxCount: 2, MinCount: 1} + return s.Sherpa.Policies().WriteJobGroupPolicy(s.JobName, testScaleInGroupName1, policy) + }, + }, + { + Runner: func(s *acctest.TestState) error { + policy1, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testScaleInGroupName1) + if err != nil { + return err + } + + if policy1.MaxCount != 2 { + return fmt.Errorf("expected policy %s/%s to match the MaxCount", s.JobName, testMetaGroupName1) + } + if policy1.MinCount != 1 { + return fmt.Errorf("expected policy %s/%s to match the MinCount", s.JobName, testMetaGroupName1) + } + return nil + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Register(buildScaleInTestJob(s.JobName), nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "running") + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Scale().JobGroupIn(s.JobName, testScaleInGroupName1, 10) + if err != nil { + return err + } + return nil + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 304:"), + }, + { + Runner: acctest.CheckTaskGroupCount(testScaleInGroupName1, 3), + }, + }, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupSherpaPolicy, acctest.CleanupPurgeJob}, + }) +} + +func buildScaleInTestJob(name string) *nomad.Job { + j := acctest.BuildBaseTestJob(name) + j.TaskGroups = append(j.TaskGroups, acctest.BuildBaseTaskGroup(testScaleInGroupName1, testScaleInTaskName1)) + j.TaskGroups[0].Count = acctest.IntToPointer(3) + return j +} diff --git a/test/scale_out_test.go b/test/scale_out_test.go new file mode 100644 index 0000000..a7abca1 --- /dev/null +++ b/test/scale_out_test.go @@ -0,0 +1,142 @@ +package test + +import ( + "fmt" + "os" + "testing" + + nomad "github.com/hashicorp/nomad/api" + "github.com/jrasell/sherpa/pkg/api" + "github.com/jrasell/sherpa/test/acctest" +) + +const ( + testScaleOutGroupName1 = "sherpa-acctest-group-1" + testScaleOutTaskName1 = "sherpa-acctest-task-1" +) + +func TestScaleOut_singleTaskGroupCountSet(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") != "" { + t.SkipNow() + } + + acctest.Test(t, acctest.TestCase{ + Steps: []acctest.TestStep{ + { + Runner: func(s *acctest.TestState) error { + policy := &api.JobGroupPolicy{Enabled: true, MaxCount: 5, MinCount: 1} + return s.Sherpa.Policies().WriteJobGroupPolicy(s.JobName, testScaleOutGroupName1, policy) + }, + }, + { + Runner: func(s *acctest.TestState) error { + policy1, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testScaleOutGroupName1) + if err != nil { + return err + } + + if policy1.MaxCount != 5 { + return fmt.Errorf("expected policy %s/%s to match the MaxCount", s.JobName, testMetaGroupName1) + } + if policy1.MinCount != 1 { + return fmt.Errorf("expected policy %s/%s to match the MinCount", s.JobName, testMetaGroupName1) + } + return nil + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Register(buildScaleOutTestJob(s.JobName), nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "running") + }, + }, + { + Runner: func(s *acctest.TestState) error { + resp, err := s.Sherpa.Scale().JobGroupOut(s.JobName, testScaleOutGroupName1, 2) + if err != nil { + return err + } + + if resp == nil { + return fmt.Errorf("expected non-nil scale out response") + } + + if _, err = s.Sherpa.Scale().Info(resp.ID.String()); err != nil { + return err + } + return nil + }, + }, + { + Runner: acctest.CheckTaskGroupCount(testScaleOutGroupName1, 3), + }, + }, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupSherpaPolicy, acctest.CleanupPurgeJob}, + }) +} + +func TestScaleOut_singleTaskGroupCountSetTooHigh(t *testing.T) { + if os.Getenv("SHERPA_ACC_META") != "" { + t.SkipNow() + } + + acctest.Test(t, acctest.TestCase{ + Steps: []acctest.TestStep{ + { + Runner: func(s *acctest.TestState) error { + policy := &api.JobGroupPolicy{Enabled: true, MaxCount: 2, MinCount: 1} + return s.Sherpa.Policies().WriteJobGroupPolicy(s.JobName, testScaleOutGroupName1, policy) + }, + }, + { + Runner: func(s *acctest.TestState) error { + policy1, err := s.Sherpa.Policies().ReadJobGroupPolicy(s.JobName, testScaleOutGroupName1) + if err != nil { + return err + } + + if policy1.MaxCount != 2 { + return fmt.Errorf("expected policy %s/%s to match the MaxCount", s.JobName, testMetaGroupName1) + } + if policy1.MinCount != 1 { + return fmt.Errorf("expected policy %s/%s to match the MinCount", s.JobName, testMetaGroupName1) + } + return nil + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, _, err := s.Nomad.Jobs().Register(buildScaleOutTestJob(s.JobName), nil) + if err != nil { + return err + } + return acctest.CheckJobReachesStatus(s, "running") + }, + }, + { + Runner: func(s *acctest.TestState) error { + _, err := s.Sherpa.Scale().JobGroupOut(s.JobName, testScaleOutGroupName1, 10) + if err != nil { + return err + } + return nil + }, + ExpectErr: true, + CheckErr: acctest.CheckErrEqual("unexpected response code 304:"), + }, + { + Runner: acctest.CheckTaskGroupCount(testScaleOutGroupName1, 1), + }, + }, + CleanupFuncs: []acctest.TestStateFunc{acctest.CleanupSherpaPolicy, acctest.CleanupPurgeJob}, + }) +} + +func buildScaleOutTestJob(name string) *nomad.Job { + j := acctest.BuildBaseTestJob(name) + j.TaskGroups = append(j.TaskGroups, acctest.BuildBaseTaskGroup(testScaleOutGroupName1, testScaleOutTaskName1)) + return j +}