Browse Source

Add unit tests for Scaleway and OTC NodePricing functions

Add test coverage for the enhanced diagnostic logging in NodePricing()
functions for Scaleway and OTC cloud providers.

Tests cover:
- Successful pricing lookup
- Unknown instance type (triggers logging)
- Unknown zone/region (triggers logging)
- Empty pricing data scenarios

Signed-off-by: Warwick Peatey <warwick.peatey@ibm.com>
Claude 3 months ago
parent
commit
ff24793a49
2 changed files with 232 additions and 0 deletions
  1. 108 0
      pkg/cloud/otc/provider_test.go
  2. 124 0
      pkg/cloud/scaleway/provider_test.go

+ 108 - 0
pkg/cloud/otc/provider_test.go

@@ -0,0 +1,108 @@
+package otc
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+// mockKey implements models.Key for testing
+type mockKey struct {
+	features string
+}
+
+func (m *mockKey) Features() string { return m.features }
+func (m *mockKey) GPUType() string  { return "" }
+func (m *mockKey) GPUCount() int    { return 0 }
+func (m *mockKey) ID() string       { return "" }
+
+func TestNodePricing_Success(t *testing.T) {
+	pricing := map[string]*OTCPricing{
+		"eu-de,s2.large.4,Open Linux": {
+			NodeAttributes: &OTCNodeAttributes{
+				Type:  "s2.large.4",
+				OS:    "Open Linux",
+				Price: "0.05",
+				RAM:   "8",
+				VCPU:  "2",
+			},
+		},
+	}
+
+	otc := &OTC{
+		Pricing:          pricing,
+		ValidPricingKeys: map[string]bool{"eu-de,s2.large.4,Open Linux": true},
+		BaseCPUPrice:     "0.01",
+		BaseRAMPrice:     "0.001",
+		BaseGPUPrice:     "0.1",
+	}
+	key := &mockKey{features: "eu-de,s2.large.4,Open Linux"}
+
+	node, meta, err := otc.NodePricing(key)
+
+	assert.NoError(t, err)
+	assert.NotNil(t, node)
+	assert.NotNil(t, meta)
+	assert.Equal(t, "0.05", node.Cost)
+	assert.Equal(t, "2", node.VCPU)
+	assert.Equal(t, "8", node.RAM)
+}
+
+func TestNodePricing_InvalidKey(t *testing.T) {
+	otc := &OTC{
+		Pricing:          map[string]*OTCPricing{},
+		ValidPricingKeys: map[string]bool{},
+		BaseCPUPrice:     "0.01",
+		BaseRAMPrice:     "0.001",
+		BaseGPUPrice:     "0.1",
+	}
+	key := &mockKey{features: "unknown-region,unknown-type,unknown-os"}
+
+	node, _, err := otc.NodePricing(key)
+
+	assert.Error(t, err)
+	assert.Nil(t, node)
+	assert.Contains(t, err.Error(), "invalid Pricing Key")
+}
+
+func TestNodePricing_ValidKeyButNotLoaded(t *testing.T) {
+	// This tests the case where the key is valid but pricing data is not loaded
+	// In a real scenario, DownloadPricingData would be called, but we can't easily mock that
+	// So we test the error path where download fails
+
+	otc := &OTC{
+		Pricing:          map[string]*OTCPricing{},
+		ValidPricingKeys: map[string]bool{"eu-de,s2.large.4,Open Linux": true},
+		BaseCPUPrice:     "0.01",
+		BaseRAMPrice:     "0.001",
+		BaseGPUPrice:     "0.1",
+	}
+	key := &mockKey{features: "eu-de,s2.large.4,Open Linux"}
+
+	// This will trigger the download path which will fail since we're not in a real environment
+	// but it exercises the logging code path
+	node, _, err := otc.NodePricing(key)
+
+	// The function returns a node with base pricing on error
+	assert.Error(t, err)
+	if node != nil {
+		// If we got a node back, it should have base pricing
+		assert.Equal(t, "0.01", node.BaseCPUPrice)
+	}
+}
+
+func TestNodePricing_EmptyPricing(t *testing.T) {
+	otc := &OTC{
+		Pricing:          map[string]*OTCPricing{},
+		ValidPricingKeys: map[string]bool{},
+		BaseCPUPrice:     "0.01",
+		BaseRAMPrice:     "0.001",
+		BaseGPUPrice:     "0.1",
+	}
+	key := &mockKey{features: "eu-de,s2.large.4,Open Linux"}
+
+	node, _, err := otc.NodePricing(key)
+
+	assert.Error(t, err)
+	assert.Nil(t, node)
+}

+ 124 - 0
pkg/cloud/scaleway/provider_test.go

@@ -0,0 +1,124 @@
+package scaleway
+
+import (
+	"testing"
+
+	"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
+	"github.com/stretchr/testify/assert"
+)
+
+// mockKey implements models.Key for testing
+type mockKey struct {
+	features string
+	gpuType  string
+}
+
+func (m *mockKey) Features() string { return m.features }
+func (m *mockKey) GPUType() string  { return m.gpuType }
+func (m *mockKey) ID() string       { return "" }
+
+func TestNodePricing_Success(t *testing.T) {
+	gpuCount := uint64(0)
+	pricing := map[string]*ScalewayPricing{
+		"fr-par-1": {
+			NodesInfos: map[string]*instance.ServerType{
+				"DEV1-S": {
+					HourlyPrice: 0.01,
+					Ncpus:       2,
+					RAM:         2147483648,
+					Gpu:         &gpuCount,
+					PerVolumeConstraint: &instance.ServerTypeVolumeConstraintsByType{
+						LSSD: &instance.ServerTypeVolumeConstraintSizes{
+							MinSize: 20000000000,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	c := &Scaleway{Pricing: pricing}
+	key := &mockKey{features: "fr-par-1,DEV1-S"}
+
+	node, meta, err := c.NodePricing(key)
+
+	assert.NoError(t, err)
+	assert.NotNil(t, node)
+	assert.NotNil(t, meta)
+	assert.Equal(t, "DEV1-S", node.InstanceType)
+	assert.Equal(t, "fr-par-1", node.Region)
+}
+
+func TestNodePricing_UnknownInstanceType(t *testing.T) {
+	gpuCount := uint64(0)
+	pricing := map[string]*ScalewayPricing{
+		"fr-par-1": {
+			NodesInfos: map[string]*instance.ServerType{
+				"DEV1-S": {
+					HourlyPrice: 0.01,
+					Ncpus:       2,
+					RAM:         2147483648,
+					Gpu:         &gpuCount,
+					PerVolumeConstraint: &instance.ServerTypeVolumeConstraintsByType{
+						LSSD: &instance.ServerTypeVolumeConstraintSizes{
+							MinSize: 20000000000,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	c := &Scaleway{Pricing: pricing}
+	key := &mockKey{features: "fr-par-1,UNKNOWN-TYPE"}
+
+	node, _, err := c.NodePricing(key)
+
+	assert.Error(t, err)
+	assert.Nil(t, node)
+	assert.Contains(t, err.Error(), "Unable to find node pricing")
+}
+
+func TestNodePricing_UnknownZone(t *testing.T) {
+	pricing := map[string]*ScalewayPricing{
+		"fr-par-1": {
+			NodesInfos: map[string]*instance.ServerType{},
+		},
+	}
+
+	c := &Scaleway{Pricing: pricing}
+	key := &mockKey{features: "unknown-zone,DEV1-S"}
+
+	node, _, err := c.NodePricing(key)
+
+	assert.Error(t, err)
+	assert.Nil(t, node)
+	assert.Contains(t, err.Error(), "Unable to find node pricing")
+}
+
+func TestNodePricing_EmptyPricing(t *testing.T) {
+	c := &Scaleway{Pricing: map[string]*ScalewayPricing{}}
+	key := &mockKey{features: "fr-par-1,DEV1-S"}
+
+	node, _, err := c.NodePricing(key)
+
+	assert.Error(t, err)
+	assert.Nil(t, node)
+}
+
+func TestNodePricing_SingleElementFeatures(t *testing.T) {
+	pricing := map[string]*ScalewayPricing{
+		"fr-par-1": {
+			NodesInfos: map[string]*instance.ServerType{},
+		},
+	}
+
+	c := &Scaleway{Pricing: pricing}
+	key := &mockKey{features: "fr-par-1"}
+
+	node, _, err := c.NodePricing(key)
+
+	// Should fail because instance type is empty
+	assert.Error(t, err)
+	assert.Nil(t, node)
+}