Files
nomad/command/recommendation_list_test.go
2024-12-19 15:41:11 +00:00

169 lines
7.1 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package command
import (
"sort"
"testing"
"github.com/hashicorp/cli"
"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/ci"
"github.com/hashicorp/nomad/testutil"
"github.com/shoenig/test/must"
)
func TestRecommendationListCommand_Run(t *testing.T) {
ci.Parallel(t)
srv, client, url := testServer(t, true, nil)
defer srv.Shutdown()
testutil.WaitForLeader(t, srv.Agent.RPC)
clientID := srv.Agent.Client().NodeID()
testutil.WaitForClient(t, srv.Agent.Client().RPC, clientID, srv.Agent.Client().Region())
ui := cli.NewMockUi()
cmd := &RecommendationListCommand{Meta: Meta{Ui: ui}}
// Perform an initial list, which should return zero results.
code := cmd.Run([]string{"-address=" + url})
if srv.Enterprise {
must.Zero(t, code)
out := ui.OutputWriter.String()
must.StrContains(t, out, "No recommendations found")
} else {
must.One(t, code)
must.StrContains(t, ui.ErrorWriter.String(), "Nomad Enterprise only endpoint")
}
// Register a test job to write a recommendation against.
testJob := testJob("recommendation_list")
regResp, _, err := client.Jobs().Register(testJob, nil)
must.NoError(t, err)
registerCode := waitForSuccess(ui, client, fullId, t, regResp.EvalID)
must.Zero(t, registerCode)
// Write a recommendation.
rec := api.Recommendation{
JobID: *testJob.ID,
Group: *testJob.TaskGroups[0].Name,
Task: testJob.TaskGroups[0].Tasks[0].Name,
Resource: "CPU",
Value: 1050,
Meta: map[string]interface{}{"test-meta-entry": "test-meta-value"},
Stats: map[string]float64{"p13": 1.13},
}
_, _, err = client.Recommendations().Upsert(&rec, nil)
if srv.Enterprise {
must.NoError(t, err)
} else {
must.ErrorContains(t, err, "Nomad Enterprise only endpoint")
}
// Perform a new list which should yield results.
code = cmd.Run([]string{"-address=" + url})
if srv.Enterprise {
must.Zero(t, code)
out := ui.OutputWriter.String()
must.StrContains(t, out, "ID")
must.StrContains(t, out, "Job")
must.StrContains(t, out, "Group")
must.StrContains(t, out, "Task")
must.StrContains(t, out, "Resource")
must.StrContains(t, out, "Value")
must.StrContains(t, out, "CPU")
} else {
must.One(t, code)
must.StrContains(t, ui.ErrorWriter.String(), "Nomad Enterprise only endpoint")
}
}
func TestRecommendationListCommand_Sort(t *testing.T) {
ci.Parallel(t)
testCases := []struct {
inputRecommendationList []*api.Recommendation
expectedOutputList []*api.Recommendation
name string
}{
{
inputRecommendationList: []*api.Recommendation{
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
},
expectedOutputList: []*api.Recommendation{
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
},
name: "single job with both resources",
},
{
inputRecommendationList: []*api.Recommendation{
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "MemoryMB"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "CPU"},
},
expectedOutputList: []*api.Recommendation{
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "CPU"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "MemoryMB"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
},
name: "single job with multiple groups",
},
{
inputRecommendationList: []*api.Recommendation{
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "MemoryMB"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "MemoryMB"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "CPU"},
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "CPU"},
},
expectedOutputList: []*api.Recommendation{
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "CPU"},
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "MemoryMB"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "CPU"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "MemoryMB"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
},
name: "multiple jobs",
},
{
inputRecommendationList: []*api.Recommendation{
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
{Namespace: "cefault", JobID: "distro", Group: "cache", Task: "redis", Resource: "MemoryMB"},
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "MemoryMB"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "MemoryMB"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "CPU"},
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "CPU"},
{Namespace: "cefault", JobID: "distro", Group: "cache", Task: "redis", Resource: "CPU"},
},
expectedOutputList: []*api.Recommendation{
{Namespace: "cefault", JobID: "distro", Group: "cache", Task: "redis", Resource: "CPU"},
{Namespace: "cefault", JobID: "distro", Group: "cache", Task: "redis", Resource: "MemoryMB"},
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "CPU"},
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "MemoryMB"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "CPU"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "MemoryMB"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
},
name: "multiple namespaces",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
sortedRecs := recommendationList{r: tc.inputRecommendationList}
sort.Sort(sortedRecs)
must.Eq(t, tc.expectedOutputList, sortedRecs.r)
})
}
}