Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions internal/api/catalog_version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package api

import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestGetLatestCatalogVersion_Success(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/v1/license/catalog/aws/version", r.URL.Path)
assert.Equal(t, http.MethodGet, r.Method)
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]string{
"emulator_type": "aws",
"version": "4.14.0",
})
}))
defer srv.Close()

client := NewPlatformClient(srv.URL)
version, err := client.GetLatestCatalogVersion(context.Background(), "aws")

require.NoError(t, err)
assert.Equal(t, "4.14.0", version)
}

func TestGetLatestCatalogVersion_NonOKStatus(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
}))
defer srv.Close()

client := NewPlatformClient(srv.URL)
_, err := client.GetLatestCatalogVersion(context.Background(), "aws")

require.Error(t, err)
assert.Contains(t, err.Error(), "status 400")
}

func TestGetLatestCatalogVersion_EmptyVersion(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]string{
"emulator_type": "aws",
"version": "",
})
}))
defer srv.Close()

client := NewPlatformClient(srv.URL)
_, err := client.GetLatestCatalogVersion(context.Background(), "aws")

require.Error(t, err)
assert.Contains(t, err.Error(), "incomplete catalog response")
}

func TestGetLatestCatalogVersion_MissingVersion(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]string{
"emulator_type": "aws",
})
}))
defer srv.Close()

client := NewPlatformClient(srv.URL)
_, err := client.GetLatestCatalogVersion(context.Background(), "aws")

require.Error(t, err)
assert.Contains(t, err.Error(), "incomplete catalog response")
}

func TestGetLatestCatalogVersion_EmptyEmulatorType(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]string{
"emulator_type": "",
"version": "4.14.0",
})
}))
defer srv.Close()

client := NewPlatformClient(srv.URL)
_, err := client.GetLatestCatalogVersion(context.Background(), "aws")

require.Error(t, err)
assert.Contains(t, err.Error(), "incomplete catalog response")
}

func TestGetLatestCatalogVersion_MismatchedEmulatorType(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]string{
"emulator_type": "azure",
"version": "4.14.0",
})
}))
defer srv.Close()

client := NewPlatformClient(srv.URL)
_, err := client.GetLatestCatalogVersion(context.Background(), "aws")

require.Error(t, err)
assert.Contains(t, err.Error(), "unexpected emulator_type")
}

func TestGetLatestCatalogVersion_Timeout(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// hang until request context is cancelled
<-r.Context().Done()
}))
defer srv.Close()

client := NewPlatformClient(srv.URL)
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()

_, err := client.GetLatestCatalogVersion(ctx, "aws")

require.Error(t, err)
}

func TestGetLatestCatalogVersion_ServerDown(t *testing.T) {
// use a URL with no server behind it
client := NewPlatformClient("http://127.0.0.1:1")
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()

_, err := client.GetLatestCatalogVersion(ctx, "aws")

require.Error(t, err)
}
46 changes: 46 additions & 0 deletions internal/api/client.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package api

//go:generate mockgen -source=client.go -destination=mock_platform_api.go -package=api

import (
"bytes"
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"time"

"github.com/localstack/lstk/internal/version"
Expand All @@ -20,6 +23,7 @@ type PlatformAPI interface {
ExchangeAuthRequest(ctx context.Context, id, exchangeToken string) (string, error)
GetLicenseToken(ctx context.Context, bearerToken string) (string, error)
GetLicense(ctx context.Context, req *LicenseRequest) error
GetLatestCatalogVersion(ctx context.Context, emulatorType string) (string, error)
}

type AuthRequest struct {
Expand Down Expand Up @@ -238,3 +242,45 @@ func (c *PlatformClient) GetLicense(ctx context.Context, licReq *LicenseRequest)
return fmt.Errorf("license request failed with status %d", resp.StatusCode)
}
}

type catalogVersionResponse struct {
EmulatorType string `json:"emulator_type"`
Version string `json:"version"`
}

func (c *PlatformClient) GetLatestCatalogVersion(ctx context.Context, emulatorType string) (string, error) {
reqURL := fmt.Sprintf("%s/v1/license/catalog/%s/version", c.baseURL, url.PathEscape(emulatorType))
req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil)
if err != nil {
return "", fmt.Errorf("failed to create request: %w", err)
}

resp, err := c.httpClient.Do(req)
if err != nil {
return "", fmt.Errorf("failed to get catalog version: %w", err)
}
defer func() {
if err := resp.Body.Close(); err != nil {
log.Printf("failed to close response body: %v", err)
}
}()

if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("failed to get catalog version: status %d", resp.StatusCode)
}

var versionResp catalogVersionResponse
if err := json.NewDecoder(resp.Body).Decode(&versionResp); err != nil {
return "", fmt.Errorf("failed to decode response: %w", err)
}

if versionResp.EmulatorType == "" || versionResp.Version == "" {
return "", fmt.Errorf("incomplete catalog response: emulator_type=%q version=%q", versionResp.EmulatorType, versionResp.Version)
}

if versionResp.EmulatorType != emulatorType {
return "", fmt.Errorf("unexpected emulator_type: got=%q want=%q", versionResp.EmulatorType, emulatorType)
}

return versionResp.Version, nil
}
130 changes: 130 additions & 0 deletions internal/api/mock_platform_api.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading