From 6cdeea3aa8c3417fa50cb443a5a8eef8f589a101 Mon Sep 17 00:00:00 2001 From: Julian Sommer <115516918+juliansommer@users.noreply.github.com> Date: Fri, 20 Mar 2026 09:27:21 +1000 Subject: [PATCH] chore: more tests --- spinifex/daemon/ownership_test.go | 63 +++++++++++++++++ .../handlers/ec2/key/service_impl_test.go | 67 +++++++++++++++++++ spinifex/services/vpcd/ovn_test.go | 27 ++++++++ 3 files changed, 157 insertions(+) create mode 100644 spinifex/daemon/ownership_test.go diff --git a/spinifex/daemon/ownership_test.go b/spinifex/daemon/ownership_test.go new file mode 100644 index 000000000..d8e29a41e --- /dev/null +++ b/spinifex/daemon/ownership_test.go @@ -0,0 +1,63 @@ +package daemon + +import ( + "testing" + + "github.com/mulgadc/spinifex/spinifex/utils" +) + +func TestIsInstanceVisible(t *testing.T) { + tests := []struct { + name string + callerAccountID string + ownerAccountID string + expected bool + }{ + { + name: "same account", + callerAccountID: "123456789012", + ownerAccountID: "123456789012", + expected: true, + }, + { + name: "different account", + callerAccountID: "123456789012", + ownerAccountID: "999999999999", + expected: false, + }, + { + name: "pre-Phase4 instance visible to root", + callerAccountID: utils.GlobalAccountID, + ownerAccountID: "", + expected: true, + }, + { + name: "pre-Phase4 instance hidden from non-root", + callerAccountID: "123456789012", + ownerAccountID: "", + expected: false, + }, + { + name: "root accessing owned instance", + callerAccountID: utils.GlobalAccountID, + ownerAccountID: utils.GlobalAccountID, + expected: true, + }, + { + name: "root accessing other account instance", + callerAccountID: utils.GlobalAccountID, + ownerAccountID: "123456789012", + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := isInstanceVisible(tt.callerAccountID, tt.ownerAccountID) + if got != tt.expected { + t.Errorf("isInstanceVisible(%q, %q) = %v, want %v", + tt.callerAccountID, tt.ownerAccountID, got, tt.expected) + } + }) + } +} diff --git a/spinifex/handlers/ec2/key/service_impl_test.go b/spinifex/handlers/ec2/key/service_impl_test.go index fbf259115..8277b6c39 100644 --- a/spinifex/handlers/ec2/key/service_impl_test.go +++ b/spinifex/handlers/ec2/key/service_impl_test.go @@ -536,6 +536,73 @@ func TestValidateKeyPairExists_NotFound(t *testing.T) { // formatFingerprint Tests // ============================================================ +// ============================================================ +// getKeyNameFromKeyPairId Tests +// ============================================================ + +func TestGetKeyNameFromKeyPairId_NotFound(t *testing.T) { + svc, _ := newTestKeyService() + + _, err := svc.getKeyNameFromKeyPairId(testAccountID, "key-nonexistent") + require.Error(t, err) + assert.Equal(t, awserrors.ErrorInvalidKeyPairNotFound, err.Error()) +} + +func TestGetKeyNameFromKeyPairId_InvalidJSON(t *testing.T) { + svc, store := newTestKeyService() + + // Seed store with garbage data at the metadata path + metadataPath := "keys/" + testAccountID + "/key-badjson.json" + _, err := store.PutObject(&s3.PutObjectInput{ + Bucket: aws.String(testBucket), + Key: aws.String(metadataPath), + Body: strings.NewReader("this is not valid json{{{"), + }) + require.NoError(t, err) + + _, err = svc.getKeyNameFromKeyPairId(testAccountID, "key-badjson") + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to unmarshal metadata") +} + +func TestGetKeyNameFromKeyPairId_MissingKeyName(t *testing.T) { + svc, store := newTestKeyService() + + // Seed store with valid JSON but missing KeyName field + metadataPath := "keys/" + testAccountID + "/key-noname.json" + jsonData, err := json.Marshal(map[string]string{ + "KeyPairId": "key-noname", + "KeyFingerprint": "SHA256:abc123", + }) + require.NoError(t, err) + + _, err = store.PutObject(&s3.PutObjectInput{ + Bucket: aws.String(testBucket), + Key: aws.String(metadataPath), + Body: strings.NewReader(string(jsonData)), + }) + require.NoError(t, err) + + _, err = svc.getKeyNameFromKeyPairId(testAccountID, "key-noname") + require.Error(t, err) + assert.Contains(t, err.Error(), "invalid metadata: missing KeyName") +} + +func TestGetKeyNameFromKeyPairId_Success(t *testing.T) { + svc, _ := newTestKeyService() + + // Import a key, then look it up by keyPairId + imported := importTestKey(t, svc, "lookup-test") + + keyName, err := svc.getKeyNameFromKeyPairId(testAccountID, *imported.KeyPairId) + require.NoError(t, err) + assert.Equal(t, "lookup-test", keyName) +} + +// ============================================================ +// formatFingerprint Tests +// ============================================================ + func TestFormatFingerprint_MD5(t *testing.T) { hash := []byte{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99} result := formatFingerprint(hash, "MD5") diff --git a/spinifex/services/vpcd/ovn_test.go b/spinifex/services/vpcd/ovn_test.go index 81d1ce3d1..34ae4b0d9 100644 --- a/spinifex/services/vpcd/ovn_test.go +++ b/spinifex/services/vpcd/ovn_test.go @@ -7,6 +7,33 @@ import ( "github.com/mulgadc/spinifex/spinifex/services/vpcd/nbdb" ) +func TestNamedUUID(t *testing.T) { + tests := []struct { + name string + prefix string + input string + expected string + }{ + {"hyphen replacement", "sw_", "vpc-abc123", "sw_vpc_abc123"}, + {"slash and dot replacement", "rp_", "10.0.0.1/24", "rp_10_0_0_1_24"}, + {"no special characters", "lr_", "vpcabc", "lr_vpcabc"}, + {"empty name", "sw_", "", "sw_"}, + {"empty prefix", "", "vpc-1", "vpc_1"}, + {"both empty", "", "", ""}, + {"multiple consecutive hyphens", "x_", "a--b", "x_a__b"}, + {"mixed special chars", "p_", "a.b-c/d", "p_a_b_c_d"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := namedUUID(tt.prefix, tt.input) + if got != tt.expected { + t.Errorf("namedUUID(%q, %q) = %q, want %q", tt.prefix, tt.input, got, tt.expected) + } + }) + } +} + func TestMockOVNClient_Connect(t *testing.T) { mock := NewMockOVNClient() if mock.Connected() {