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  }