// ABOUTME: Unit tests for Cloudlet management APIs using httptest mock server // ABOUTME: Tests create, show, list, delete, manifest, and resource usage operations package edgeconnect import ( "context" "encoding/json" "net/http" "net/http/httptest" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestCreateCloudlet(t *testing.T) { tests := []struct { name string input *NewCloudletInput mockStatusCode int mockResponse string expectError bool }{ { name: "successful creation", input: &NewCloudletInput{ Region: "us-west", Cloudlet: Cloudlet{ Key: CloudletKey{ Organization: "cloudletorg", Name: "testcloudlet", }, Location: Location{ Latitude: 37.7749, Longitude: -122.4194, }, IpSupport: "IpSupportDynamic", NumDynamicIps: 10, }, }, mockStatusCode: 200, mockResponse: `{"message": "success"}`, expectError: false, }, { name: "validation error", input: &NewCloudletInput{ Region: "us-west", Cloudlet: Cloudlet{ Key: CloudletKey{ Organization: "", Name: "testcloudlet", }, }, }, mockStatusCode: 400, mockResponse: `{"message": "organization is required"}`, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create mock server server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "POST", r.Method) assert.Equal(t, "/api/v1/auth/ctrl/CreateCloudlet", r.URL.Path) assert.Equal(t, "application/json", r.Header.Get("Content-Type")) w.WriteHeader(tt.mockStatusCode) w.Write([]byte(tt.mockResponse)) })) defer server.Close() // Create client client := NewClient(server.URL, WithHTTPClient(&http.Client{Timeout: 5 * time.Second}), WithAuthProvider(NewStaticTokenProvider("test-token")), ) // Execute test ctx := context.Background() err := client.CreateCloudlet(ctx, tt.input) // Verify results if tt.expectError { assert.Error(t, err) } else { assert.NoError(t, err) } }) } } func TestShowCloudlet(t *testing.T) { tests := []struct { name string cloudletKey CloudletKey region string mockStatusCode int mockResponse string expectError bool expectNotFound bool }{ { name: "successful show", cloudletKey: CloudletKey{ Organization: "cloudletorg", Name: "testcloudlet", }, region: "us-west", mockStatusCode: 200, mockResponse: `{"data": {"key": {"organization": "cloudletorg", "name": "testcloudlet"}, "state": "Ready", "location": {"latitude": 37.7749, "longitude": -122.4194}}} `, expectError: false, expectNotFound: false, }, { name: "cloudlet not found", cloudletKey: CloudletKey{ Organization: "cloudletorg", Name: "nonexistent", }, region: "us-west", mockStatusCode: 404, mockResponse: "", expectError: true, expectNotFound: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create mock server server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "POST", r.Method) assert.Equal(t, "/api/v1/auth/ctrl/ShowCloudlet", r.URL.Path) w.WriteHeader(tt.mockStatusCode) if tt.mockResponse != "" { w.Write([]byte(tt.mockResponse)) } })) defer server.Close() // Create client client := NewClient(server.URL, WithHTTPClient(&http.Client{Timeout: 5 * time.Second}), ) // Execute test ctx := context.Background() cloudlet, err := client.ShowCloudlet(ctx, tt.cloudletKey, tt.region) // Verify results if tt.expectError { assert.Error(t, err) if tt.expectNotFound { assert.Contains(t, err.Error(), "resource not found") } } else { require.NoError(t, err) assert.Equal(t, tt.cloudletKey.Organization, cloudlet.Key.Organization) assert.Equal(t, tt.cloudletKey.Name, cloudlet.Key.Name) assert.Equal(t, "Ready", cloudlet.State) } }) } } func TestShowCloudlets(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "POST", r.Method) assert.Equal(t, "/api/v1/auth/ctrl/ShowCloudlet", r.URL.Path) // Verify request body var filter CloudletFilter err := json.NewDecoder(r.Body).Decode(&filter) require.NoError(t, err) assert.Equal(t, "cloudletorg", filter.Cloudlet.Key.Organization) assert.Equal(t, "us-west", filter.Region) // Return multiple cloudlets response := `{"data": {"key": {"organization": "cloudletorg", "name": "cloudlet1"}, "state": "Ready"}} {"data": {"key": {"organization": "cloudletorg", "name": "cloudlet2"}, "state": "Creating"}} ` w.WriteHeader(200) w.Write([]byte(response)) })) defer server.Close() client := NewClient(server.URL) ctx := context.Background() cloudlets, err := client.ShowCloudlets(ctx, CloudletKey{Organization: "cloudletorg"}, "us-west") require.NoError(t, err) assert.Len(t, cloudlets, 2) assert.Equal(t, "cloudlet1", cloudlets[0].Key.Name) assert.Equal(t, "Ready", cloudlets[0].State) assert.Equal(t, "cloudlet2", cloudlets[1].Key.Name) assert.Equal(t, "Creating", cloudlets[1].State) } func TestDeleteCloudlet(t *testing.T) { tests := []struct { name string cloudletKey CloudletKey region string mockStatusCode int expectError bool }{ { name: "successful deletion", cloudletKey: CloudletKey{ Organization: "cloudletorg", Name: "testcloudlet", }, region: "us-west", mockStatusCode: 200, expectError: false, }, { name: "already deleted (404 ok)", cloudletKey: CloudletKey{ Organization: "cloudletorg", Name: "testcloudlet", }, region: "us-west", mockStatusCode: 404, expectError: false, }, { name: "server error", cloudletKey: CloudletKey{ Organization: "cloudletorg", Name: "testcloudlet", }, region: "us-west", mockStatusCode: 500, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "POST", r.Method) assert.Equal(t, "/api/v1/auth/ctrl/DeleteCloudlet", r.URL.Path) w.WriteHeader(tt.mockStatusCode) })) defer server.Close() client := NewClient(server.URL) ctx := context.Background() err := client.DeleteCloudlet(ctx, tt.cloudletKey, tt.region) if tt.expectError { assert.Error(t, err) } else { assert.NoError(t, err) } }) } } func TestGetCloudletManifest(t *testing.T) { tests := []struct { name string cloudletKey CloudletKey region string mockStatusCode int mockResponse string expectError bool expectNotFound bool }{ { name: "successful manifest retrieval", cloudletKey: CloudletKey{ Organization: "cloudletorg", Name: "testcloudlet", }, region: "us-west", mockStatusCode: 200, mockResponse: `{"manifest": "apiVersion: v1\nkind: Deployment\nmetadata:\n name: test", "last_modified": "2024-01-01T00:00:00Z"}`, expectError: false, expectNotFound: false, }, { name: "manifest not found", cloudletKey: CloudletKey{ Organization: "cloudletorg", Name: "nonexistent", }, region: "us-west", mockStatusCode: 404, mockResponse: "", expectError: true, expectNotFound: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "POST", r.Method) assert.Equal(t, "/api/v1/auth/ctrl/GetCloudletManifest", r.URL.Path) w.WriteHeader(tt.mockStatusCode) if tt.mockResponse != "" { w.Write([]byte(tt.mockResponse)) } })) defer server.Close() client := NewClient(server.URL) ctx := context.Background() manifest, err := client.GetCloudletManifest(ctx, tt.cloudletKey, tt.region) if tt.expectError { assert.Error(t, err) if tt.expectNotFound { assert.Contains(t, err.Error(), "resource not found") } } else { require.NoError(t, err) assert.NotNil(t, manifest) assert.Contains(t, manifest.Manifest, "apiVersion: v1") } }) } } func TestGetCloudletResourceUsage(t *testing.T) { tests := []struct { name string cloudletKey CloudletKey region string mockStatusCode int mockResponse string expectError bool expectNotFound bool }{ { name: "successful usage retrieval", cloudletKey: CloudletKey{ Organization: "cloudletorg", Name: "testcloudlet", }, region: "us-west", mockStatusCode: 200, mockResponse: `{"cloudlet_key": {"organization": "cloudletorg", "name": "testcloudlet"}, "region": "us-west", "usage": {"cpu": "50%", "memory": "30%", "disk": "20%"}}`, expectError: false, expectNotFound: false, }, { name: "usage not found", cloudletKey: CloudletKey{ Organization: "cloudletorg", Name: "nonexistent", }, region: "us-west", mockStatusCode: 404, mockResponse: "", expectError: true, expectNotFound: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "POST", r.Method) assert.Equal(t, "/api/v1/auth/ctrl/GetCloudletResourceUsage", r.URL.Path) w.WriteHeader(tt.mockStatusCode) if tt.mockResponse != "" { w.Write([]byte(tt.mockResponse)) } })) defer server.Close() client := NewClient(server.URL) ctx := context.Background() usage, err := client.GetCloudletResourceUsage(ctx, tt.cloudletKey, tt.region) if tt.expectError { assert.Error(t, err) if tt.expectNotFound { assert.Contains(t, err.Error(), "resource not found") } } else { require.NoError(t, err) assert.NotNil(t, usage) assert.Equal(t, "cloudletorg", usage.CloudletKey.Organization) assert.Equal(t, "testcloudlet", usage.CloudletKey.Name) assert.Equal(t, "us-west", usage.Region) assert.Contains(t, usage.Usage, "cpu") } }) } }