github.com/hernad/nomad@v1.6.112/command/job_history_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package command 5 6 import ( 7 "strings" 8 "testing" 9 10 "github.com/hernad/nomad/api" 11 "github.com/hernad/nomad/ci" 12 "github.com/hernad/nomad/command/agent" 13 "github.com/hernad/nomad/nomad/mock" 14 "github.com/hernad/nomad/nomad/structs" 15 "github.com/mitchellh/cli" 16 "github.com/posener/complete" 17 "github.com/shoenig/test/must" 18 "github.com/stretchr/testify/assert" 19 ) 20 21 func TestJobHistoryCommand_Implements(t *testing.T) { 22 ci.Parallel(t) 23 var _ cli.Command = &JobDispatchCommand{} 24 } 25 26 func TestJobHistoryCommand_Fails(t *testing.T) { 27 ci.Parallel(t) 28 ui := cli.NewMockUi() 29 cmd := &JobHistoryCommand{Meta: Meta{Ui: ui}} 30 31 // Fails on misuse 32 if code := cmd.Run([]string{"some", "bad", "args"}); code != 1 { 33 t.Fatalf("expected exit code 1, got: %d", code) 34 } 35 if out := ui.ErrorWriter.String(); !strings.Contains(out, commandErrorText(cmd)) { 36 t.Fatalf("expected help output, got: %s", out) 37 } 38 ui.ErrorWriter.Reset() 39 40 if code := cmd.Run([]string{"-address=nope", "foo"}); code != 1 { 41 t.Fatalf("expected exit code 1, got: %d", code) 42 } 43 if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error querying job prefix") { 44 t.Fatalf("expected failed query error, got: %s", out) 45 } 46 ui.ErrorWriter.Reset() 47 } 48 49 func TestJobHistoryCommand_AutocompleteArgs(t *testing.T) { 50 ci.Parallel(t) 51 assert := assert.New(t) 52 53 srv, _, url := testServer(t, true, nil) 54 defer srv.Shutdown() 55 56 ui := cli.NewMockUi() 57 cmd := &JobHistoryCommand{Meta: Meta{Ui: ui, flagAddress: url}} 58 59 // Create a fake job 60 state := srv.Agent.Server().State() 61 j := mock.Job() 62 assert.Nil(state.UpsertJob(structs.MsgTypeTestSetup, 1000, nil, j)) 63 64 prefix := j.ID[:len(j.ID)-5] 65 args := complete.Args{Last: prefix} 66 predictor := cmd.AutocompleteArgs() 67 68 res := predictor.Predict(args) 69 assert.Equal(1, len(res)) 70 assert.Equal(j.ID, res[0]) 71 } 72 73 func TestJobHistoryCommand_ACL(t *testing.T) { 74 ci.Parallel(t) 75 76 // Start server with ACL enabled. 77 srv, _, url := testServer(t, true, func(c *agent.Config) { 78 c.ACL.Enabled = true 79 }) 80 defer srv.Shutdown() 81 82 // Create a job. 83 job := mock.MinJob() 84 state := srv.Agent.Server().State() 85 err := state.UpsertJob(structs.MsgTypeTestSetup, 100, nil, job) 86 must.NoError(t, err) 87 88 testCases := []struct { 89 name string 90 jobPrefix bool 91 aclPolicy string 92 expectedErr string 93 }{ 94 { 95 name: "no token", 96 aclPolicy: "", 97 expectedErr: api.PermissionDeniedErrorContent, 98 }, 99 { 100 name: "missing read-job", 101 aclPolicy: ` 102 namespace "default" { 103 capabilities = ["list-jobs"] 104 } 105 `, 106 expectedErr: api.PermissionDeniedErrorContent, 107 }, 108 { 109 name: "read-job allowed", 110 aclPolicy: ` 111 namespace "default" { 112 capabilities = ["read-job"] 113 } 114 `, 115 }, 116 { 117 name: "job prefix requires list-job", 118 jobPrefix: true, 119 aclPolicy: ` 120 namespace "default" { 121 capabilities = ["read-job"] 122 } 123 `, 124 expectedErr: "job versions not found", 125 }, 126 { 127 name: "job prefix works with list-job", 128 jobPrefix: true, 129 aclPolicy: ` 130 namespace "default" { 131 capabilities = ["read-job", "list-jobs"] 132 } 133 `, 134 }, 135 } 136 137 for i, tc := range testCases { 138 t.Run(tc.name, func(t *testing.T) { 139 ui := cli.NewMockUi() 140 cmd := &JobHistoryCommand{Meta: Meta{Ui: ui}} 141 args := []string{ 142 "-address", url, 143 } 144 145 if tc.aclPolicy != "" { 146 // Create ACL token with test case policy and add it to the 147 // command. 148 policyName := nonAlphaNum.ReplaceAllString(tc.name, "-") 149 token := mock.CreatePolicyAndToken(t, state, uint64(302+i), policyName, tc.aclPolicy) 150 args = append(args, "-token", token.SecretID) 151 } 152 153 // Add job ID or job ID prefix to the command. 154 if tc.jobPrefix { 155 args = append(args, job.ID[:3]) 156 } else { 157 args = append(args, job.ID) 158 } 159 160 // Run command. 161 code := cmd.Run(args) 162 if tc.expectedErr == "" { 163 must.Zero(t, code) 164 } else { 165 must.One(t, code) 166 must.StrContains(t, ui.ErrorWriter.String(), tc.expectedErr) 167 } 168 }) 169 } 170 }