github.com/thomasobenaus/nomad@v0.11.1/command/job_periodic_force_test.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/hashicorp/nomad/api" 8 "github.com/hashicorp/nomad/helper" 9 "github.com/hashicorp/nomad/nomad/mock" 10 "github.com/hashicorp/nomad/nomad/structs" 11 "github.com/hashicorp/nomad/testutil" 12 "github.com/mitchellh/cli" 13 "github.com/posener/complete" 14 "github.com/stretchr/testify/require" 15 ) 16 17 func TestJobPeriodicForceCommand_Implements(t *testing.T) { 18 t.Parallel() 19 var _ cli.Command = &JobPeriodicForceCommand{} 20 } 21 22 func TestJobPeriodicForceCommand_Fails(t *testing.T) { 23 t.Parallel() 24 ui := new(cli.MockUi) 25 cmd := &JobPeriodicForceCommand{Meta: Meta{Ui: ui}} 26 27 // Fails on misuse 28 code := cmd.Run([]string{"some", "bad", "args"}) 29 require.Equal(t, code, 1, "expected error") 30 out := ui.ErrorWriter.String() 31 require.Contains(t, out, commandErrorText(cmd), "expected help output") 32 ui.ErrorWriter.Reset() 33 34 code = cmd.Run([]string{"-address=nope", "12"}) 35 require.Equal(t, code, 1, "expected error") 36 out = ui.ErrorWriter.String() 37 require.Contains(t, out, "Error forcing periodic job", "expected force error") 38 } 39 40 func TestJobPeriodicForceCommand_AutocompleteArgs(t *testing.T) { 41 t.Parallel() 42 43 srv, _, url := testServer(t, true, nil) 44 defer srv.Shutdown() 45 46 ui := new(cli.MockUi) 47 cmd := &JobPeriodicForceCommand{Meta: Meta{Ui: ui, flagAddress: url}} 48 49 // Create a fake job, not periodic 50 state := srv.Agent.Server().State() 51 j := mock.Job() 52 require.NoError(t, state.UpsertJob(1000, j)) 53 54 predictor := cmd.AutocompleteArgs() 55 56 res := predictor.Predict(complete.Args{Last: j.ID[:len(j.ID)-5]}) 57 require.Empty(t, res) 58 59 // Create another fake job, periodic 60 state = srv.Agent.Server().State() 61 j2 := mock.Job() 62 j2.Periodic = &structs.PeriodicConfig{ 63 Enabled: true, 64 Spec: "spec", 65 SpecType: "cron", 66 ProhibitOverlap: true, 67 TimeZone: "test zone", 68 } 69 require.NoError(t, state.UpsertJob(1000, j2)) 70 71 res = predictor.Predict(complete.Args{Last: j2.ID[:len(j.ID)-5]}) 72 require.Equal(t, []string{j2.ID}, res) 73 74 res = predictor.Predict(complete.Args{}) 75 require.Equal(t, []string{j2.ID}, res) 76 } 77 78 func TestJobPeriodicForceCommand_NonPeriodicJob(t *testing.T) { 79 t.Parallel() 80 srv, client, url := testServer(t, true, nil) 81 defer srv.Shutdown() 82 testutil.WaitForResult(func() (bool, error) { 83 nodes, _, err := client.Nodes().List(nil) 84 if err != nil { 85 return false, err 86 } 87 if len(nodes) == 0 { 88 return false, fmt.Errorf("missing node") 89 } 90 if _, ok := nodes[0].Drivers["mock_driver"]; !ok { 91 return false, fmt.Errorf("mock_driver not ready") 92 } 93 return true, nil 94 }, func(err error) { 95 require.NoError(t, err) 96 }) 97 98 // Register a job 99 j := testJob("job_not_periodic") 100 101 ui := new(cli.MockUi) 102 cmd := &JobPeriodicForceCommand{Meta: Meta{Ui: ui, flagAddress: url}} 103 104 resp, _, err := client.Jobs().Register(j, nil) 105 require.NoError(t, err) 106 code := waitForSuccess(ui, client, fullId, t, resp.EvalID) 107 require.Equal(t, 0, code) 108 109 code = cmd.Run([]string{"-address=" + url, "job_not_periodic"}) 110 require.Equal(t, 1, code, "expected exit code") 111 out := ui.ErrorWriter.String() 112 require.Contains(t, out, "No periodic job(s)", "non-periodic error message") 113 } 114 115 func TestJobPeriodicForceCommand_SuccessfulPeriodicForceDetach(t *testing.T) { 116 t.Parallel() 117 srv, client, url := testServer(t, true, nil) 118 defer srv.Shutdown() 119 testutil.WaitForResult(func() (bool, error) { 120 nodes, _, err := client.Nodes().List(nil) 121 if err != nil { 122 return false, err 123 } 124 if len(nodes) == 0 { 125 return false, fmt.Errorf("missing node") 126 } 127 if _, ok := nodes[0].Drivers["mock_driver"]; !ok { 128 return false, fmt.Errorf("mock_driver not ready") 129 } 130 return true, nil 131 }, func(err error) { 132 require.NoError(t, err) 133 }) 134 135 // Register a job 136 j := testJob("job1_is_periodic") 137 j.Periodic = &api.PeriodicConfig{ 138 SpecType: helper.StringToPtr(api.PeriodicSpecCron), 139 Spec: helper.StringToPtr("*/15 * * * * *"), 140 ProhibitOverlap: helper.BoolToPtr(true), 141 TimeZone: helper.StringToPtr("Europe/Minsk"), 142 } 143 144 ui := new(cli.MockUi) 145 cmd := &JobPeriodicForceCommand{Meta: Meta{Ui: ui, flagAddress: url}} 146 147 _, _, err := client.Jobs().Register(j, nil) 148 require.NoError(t, err) 149 150 code := cmd.Run([]string{"-address=" + url, "-detach", "job1_is_periodic"}) 151 require.Equal(t, 0, code, "expected no error code") 152 out := ui.OutputWriter.String() 153 require.Contains(t, out, "Force periodic successful") 154 require.Contains(t, out, "Evaluation ID:") 155 } 156 157 func TestJobPeriodicForceCommand_SuccessfulPeriodicForce(t *testing.T) { 158 t.Parallel() 159 srv, client, url := testServer(t, true, nil) 160 defer srv.Shutdown() 161 testutil.WaitForResult(func() (bool, error) { 162 nodes, _, err := client.Nodes().List(nil) 163 if err != nil { 164 return false, err 165 } 166 if len(nodes) == 0 { 167 return false, fmt.Errorf("missing node") 168 } 169 if _, ok := nodes[0].Drivers["mock_driver"]; !ok { 170 return false, fmt.Errorf("mock_driver not ready") 171 } 172 return true, nil 173 }, func(err error) { 174 require.NoError(t, err) 175 }) 176 177 // Register a job 178 j := testJob("job2_is_periodic") 179 j.Periodic = &api.PeriodicConfig{ 180 SpecType: helper.StringToPtr(api.PeriodicSpecCron), 181 Spec: helper.StringToPtr("*/15 * * * * *"), 182 ProhibitOverlap: helper.BoolToPtr(true), 183 TimeZone: helper.StringToPtr("Europe/Minsk"), 184 } 185 186 ui := new(cli.MockUi) 187 cmd := &JobPeriodicForceCommand{Meta: Meta{Ui: ui, flagAddress: url}} 188 189 _, _, err := client.Jobs().Register(j, nil) 190 require.NoError(t, err) 191 192 code := cmd.Run([]string{"-address=" + url, "job2_is_periodic"}) 193 require.Equal(t, 0, code, "expected no error code") 194 out := ui.OutputWriter.String() 195 require.Contains(t, out, "Monitoring evaluation") 196 require.Contains(t, out, "finished with status \"complete\"") 197 }