// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package command import ( "testing" "github.com/hashicorp/nomad/api" "github.com/hashicorp/nomad/ci" "github.com/hashicorp/nomad/helper/pointer" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestDeviceQualifiedID(t *testing.T) { ci.Parallel(t) require := require.New(t) require.Equal("vendor/type/name[id]", deviceQualifiedID("vendor", "type", "name", "id")) require.Equal("vendor/type[id]", deviceQualifiedID("vendor", "type", "", "id")) require.Equal("vendor[id]", deviceQualifiedID("vendor", "", "", "id")) } func TestBuildDeviceStatsSummaryMap(t *testing.T) { ci.Parallel(t) hostDeviceStats := []*api.DeviceGroupStats{ { Vendor: "vendor1", Type: "type1", Name: "name1", InstanceStats: map[string]*api.DeviceStats{ "id1": { Summary: &api.StatValue{ StringVal: pointer.Of("stat1"), }, }, "id2": { Summary: &api.StatValue{ IntNumeratorVal: pointer.Of(int64(2)), }, }, }, }, { Vendor: "vendor2", Type: "type2", InstanceStats: map[string]*api.DeviceStats{ "id1": { Summary: &api.StatValue{ StringVal: pointer.Of("stat3"), }, }, "id2": { Summary: &api.StatValue{ IntNumeratorVal: pointer.Of(int64(4)), }, }, }, }, } expected := map[string]*api.StatValue{ "vendor1/type1/name1[id1]": { StringVal: pointer.Of("stat1"), }, "vendor1/type1/name1[id2]": { IntNumeratorVal: pointer.Of(int64(2)), }, "vendor2/type2[id1]": { StringVal: pointer.Of("stat3"), }, "vendor2/type2[id2]": { IntNumeratorVal: pointer.Of(int64(4)), }, } require.EqualValues(t, expected, buildDeviceStatsSummaryMap(hostDeviceStats)) } func TestFormatDeviceStats(t *testing.T) { ci.Parallel(t) statValue := func(v string) *api.StatValue { return &api.StatValue{ StringVal: pointer.Of(v), } } stat := &api.StatObject{ Attributes: map[string]*api.StatValue{ "a0": statValue("va0"), "k0": statValue("v0"), }, Nested: map[string]*api.StatObject{ "nested1": { Attributes: map[string]*api.StatValue{ "k1_0": statValue("v1_0"), "k1_1": statValue("v1_1"), }, Nested: map[string]*api.StatObject{ "nested1_1": { Attributes: map[string]*api.StatValue{ "k11_0": statValue("v11_0"), "k11_1": statValue("v11_1"), }, }, }, }, "nested2": { Attributes: map[string]*api.StatValue{ "k2": statValue("v2"), }, }, }, } result := formatDeviceStats("TestDeviceID", stat) // check that device id always appears first require.Equal(t, "Device|TestDeviceID", result[0]) // check rest of values expected := []string{ "Device|TestDeviceID", "a0|va0", "k0|v0", "nested1.k1_0|v1_0", "nested1.k1_1|v1_1", "nested1.nested1_1.k11_0|v11_0", "nested1.nested1_1.k11_1|v11_1", "nested2.k2|v2", } require.Equal(t, expected, result) } func TestNodeStatusCommand_GetDeviceResourcesForNode(t *testing.T) { ci.Parallel(t) hostDeviceStats := []*api.DeviceGroupStats{ { Vendor: "vendor1", Type: "type1", Name: "name1", InstanceStats: map[string]*api.DeviceStats{ "id1": { Summary: &api.StatValue{ StringVal: pointer.Of("stat1"), }, }, "id2": { Summary: &api.StatValue{ IntNumeratorVal: pointer.Of(int64(2)), }, }, }, }, { Vendor: "vendor2", Type: "type2", InstanceStats: map[string]*api.DeviceStats{ "id1": { Summary: &api.StatValue{ StringVal: pointer.Of("stat3"), }, }, "id2": { Summary: &api.StatValue{ IntNumeratorVal: pointer.Of(int64(4)), }, }, }, }, } node := &api.Node{ NodeResources: &api.NodeResources{ Devices: []*api.NodeDeviceResource{ { Vendor: "vendor2", Type: "type2", Instances: []*api.NodeDevice{ {ID: "id1"}, {ID: "id2"}, }, }, { Vendor: "vendor1", Type: "type1", Name: "name1", Instances: []*api.NodeDevice{ {ID: "id1"}, {ID: "id2"}, }, }, }, }, } formattedDevices := getDeviceResourcesForNode(hostDeviceStats, node) expected := []string{ "vendor1/type1/name1[id1]|stat1", "vendor1/type1/name1[id2]|2", "vendor2/type2[id1]|stat3", "vendor2/type2[id2]|4", } assert.Equal(t, expected, formattedDevices) } func TestNodeStatusCommand_GetDeviceResources(t *testing.T) { ci.Parallel(t) hostDeviceStats := []*api.DeviceGroupStats{ { Vendor: "vendor1", Type: "type1", Name: "name1", InstanceStats: map[string]*api.DeviceStats{ "id1": { Summary: &api.StatValue{ StringVal: pointer.Of("stat1"), }, }, "id2": { Summary: &api.StatValue{ IntNumeratorVal: pointer.Of(int64(2)), }, }, }, }, { Vendor: "vendor2", Type: "type2", InstanceStats: map[string]*api.DeviceStats{ "id1": { Summary: &api.StatValue{ StringVal: pointer.Of("stat3"), }, }, "id2": { Summary: &api.StatValue{ IntNumeratorVal: pointer.Of(int64(4)), }, }, }, }, } formattedDevices := getDeviceResources(hostDeviceStats) expected := []string{ "vendor1/type1/name1[id1]|stat1", "vendor1/type1/name1[id2]|2", "vendor2/type2[id1]|stat3", "vendor2/type2[id2]|4", } assert.Equal(t, expected, formattedDevices) } func TestGetDeviceAttributes(t *testing.T) { ci.Parallel(t) d := &api.NodeDeviceResource{ Vendor: "Vendor", Type: "Type", Name: "Name", Attributes: map[string]*api.Attribute{ "utilization": { FloatVal: pointer.Of(float64(0.78)), Unit: "%", }, "filesystem": { StringVal: pointer.Of("ext4"), }, }, } formattedDevices := getDeviceAttributes(d) expected := []string{ "Device Group|Vendor/Type/Name", "filesystem|ext4", "utilization|0.78 %", } assert.Equal(t, expected, formattedDevices) }