mirror of
https://github.com/DeBrosOfficial/network.git
synced 2026-01-30 14:33:03 +00:00
211 lines
6.8 KiB
Go
211 lines
6.8 KiB
Go
//go:build e2e
|
|
|
|
package deployments_test
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/DeBrosOfficial/network/e2e"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestStaticDeployment_FullFlow(t *testing.T) {
|
|
env, err := e2e.LoadTestEnv()
|
|
require.NoError(t, err, "Failed to load test environment")
|
|
|
|
deploymentName := fmt.Sprintf("test-static-%d", time.Now().Unix())
|
|
tarballPath := filepath.Join("../../testdata/apps/react-app")
|
|
var deploymentID string
|
|
|
|
// Cleanup after test
|
|
defer func() {
|
|
if !env.SkipCleanup && deploymentID != "" {
|
|
e2e.DeleteDeployment(t, env, deploymentID)
|
|
}
|
|
}()
|
|
|
|
t.Run("Upload static tarball", func(t *testing.T) {
|
|
deploymentID = e2e.CreateTestDeployment(t, env, deploymentName, tarballPath)
|
|
|
|
assert.NotEmpty(t, deploymentID, "Deployment ID should not be empty")
|
|
t.Logf("✓ Created deployment: %s (ID: %s)", deploymentName, deploymentID)
|
|
})
|
|
|
|
t.Run("Verify deployment in database", func(t *testing.T) {
|
|
deployment := e2e.GetDeployment(t, env, deploymentID)
|
|
|
|
assert.Equal(t, deploymentName, deployment["name"], "Deployment name should match")
|
|
assert.NotEmpty(t, deployment["content_cid"], "Content CID should not be empty")
|
|
|
|
// Status might be "deploying" or "active" depending on timing
|
|
status, ok := deployment["status"].(string)
|
|
require.True(t, ok, "Status should be a string")
|
|
assert.Contains(t, []string{"deploying", "active"}, status, "Status should be deploying or active")
|
|
|
|
t.Logf("✓ Deployment verified in database")
|
|
t.Logf(" - Name: %s", deployment["name"])
|
|
t.Logf(" - Status: %s", status)
|
|
t.Logf(" - CID: %s", deployment["content_cid"])
|
|
})
|
|
|
|
t.Run("Verify DNS record creation", func(t *testing.T) {
|
|
// Wait for deployment to become active
|
|
time.Sleep(2 * time.Second)
|
|
|
|
// Get the actual domain from deployment response
|
|
deployment := e2e.GetDeployment(t, env, deploymentID)
|
|
nodeURL := extractNodeURL(t, deployment)
|
|
require.NotEmpty(t, nodeURL, "Deployment should have a URL")
|
|
expectedDomain := extractDomain(nodeURL)
|
|
|
|
// Make request with Host header (localhost testing)
|
|
resp := e2e.TestDeploymentWithHostHeader(t, env, expectedDomain, "/")
|
|
defer resp.Body.Close()
|
|
|
|
// Should return 200 with React app HTML
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode, "Should return 200 OK")
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err, "Should read response body")
|
|
|
|
bodyStr := string(body)
|
|
|
|
// Verify React app content
|
|
assert.Contains(t, bodyStr, "<div id=\"root\">", "Should contain React root div")
|
|
assert.Contains(t, resp.Header.Get("Content-Type"), "text/html", "Content-Type should be text/html")
|
|
|
|
t.Logf("✓ Domain routing works")
|
|
t.Logf(" - Domain: %s", expectedDomain)
|
|
t.Logf(" - Status: %d", resp.StatusCode)
|
|
t.Logf(" - Content-Type: %s", resp.Header.Get("Content-Type"))
|
|
})
|
|
|
|
t.Run("Verify static assets serve correctly", func(t *testing.T) {
|
|
deployment := e2e.GetDeployment(t, env, deploymentID)
|
|
nodeURL := extractNodeURL(t, deployment)
|
|
require.NotEmpty(t, nodeURL, "Deployment should have a URL")
|
|
expectedDomain := extractDomain(nodeURL)
|
|
|
|
// Test CSS file (exact path depends on Vite build output)
|
|
// We'll just test a few common asset paths
|
|
assetPaths := []struct {
|
|
path string
|
|
contentType string
|
|
}{
|
|
{"/index.html", "text/html"},
|
|
// Note: Asset paths with hashes change on each build
|
|
// We'll test what we can
|
|
}
|
|
|
|
for _, asset := range assetPaths {
|
|
resp := e2e.TestDeploymentWithHostHeader(t, env, expectedDomain, asset.path)
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode == http.StatusOK {
|
|
assert.Contains(t, resp.Header.Get("Content-Type"), asset.contentType,
|
|
"Content-Type should be %s for %s", asset.contentType, asset.path)
|
|
|
|
t.Logf("✓ Asset served correctly: %s (%s)", asset.path, asset.contentType)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Verify SPA fallback routing", func(t *testing.T) {
|
|
deployment := e2e.GetDeployment(t, env, deploymentID)
|
|
nodeURL := extractNodeURL(t, deployment)
|
|
require.NotEmpty(t, nodeURL, "Deployment should have a URL")
|
|
expectedDomain := extractDomain(nodeURL)
|
|
|
|
// Request unknown route (should return index.html for SPA)
|
|
resp := e2e.TestDeploymentWithHostHeader(t, env, expectedDomain, "/about/team")
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode, "SPA fallback should return 200")
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err, "Should read response body")
|
|
|
|
assert.Contains(t, string(body), "<div id=\"root\">", "Should return index.html for unknown paths")
|
|
|
|
t.Logf("✓ SPA fallback routing works")
|
|
})
|
|
|
|
t.Run("List deployments", func(t *testing.T) {
|
|
req, err := http.NewRequest("GET", env.GatewayURL+"/v1/deployments/list", nil)
|
|
require.NoError(t, err, "Should create request")
|
|
|
|
req.Header.Set("Authorization", "Bearer "+env.APIKey)
|
|
|
|
resp, err := env.HTTPClient.Do(req)
|
|
require.NoError(t, err, "Should execute request")
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode, "List deployments should return 200")
|
|
|
|
var result map[string]interface{}
|
|
require.NoError(t, e2e.DecodeJSON(mustReadAll(t, resp.Body), &result), "Should decode JSON")
|
|
|
|
deployments, ok := result["deployments"].([]interface{})
|
|
require.True(t, ok, "Deployments should be an array")
|
|
|
|
assert.GreaterOrEqual(t, len(deployments), 1, "Should have at least one deployment")
|
|
|
|
// Find our deployment
|
|
found := false
|
|
for _, d := range deployments {
|
|
dep, ok := d.(map[string]interface{})
|
|
if !ok {
|
|
continue
|
|
}
|
|
if dep["name"] == deploymentName {
|
|
found = true
|
|
t.Logf("✓ Found deployment in list: %s", deploymentName)
|
|
break
|
|
}
|
|
}
|
|
|
|
assert.True(t, found, "Deployment should be in list")
|
|
})
|
|
|
|
t.Run("Delete deployment", func(t *testing.T) {
|
|
e2e.DeleteDeployment(t, env, deploymentID)
|
|
|
|
// Verify deletion - allow time for replication
|
|
time.Sleep(3 * time.Second)
|
|
|
|
req, _ := http.NewRequest("GET", env.GatewayURL+"/v1/deployments/get?id="+deploymentID, nil)
|
|
req.Header.Set("Authorization", "Bearer "+env.APIKey)
|
|
|
|
resp, err := env.HTTPClient.Do(req)
|
|
require.NoError(t, err, "Should execute request")
|
|
defer resp.Body.Close()
|
|
|
|
body, _ := io.ReadAll(resp.Body)
|
|
t.Logf("Delete verification response: status=%d body=%s", resp.StatusCode, string(body))
|
|
|
|
// After deletion, either 404 (not found) or 200 with empty/error response is acceptable
|
|
if resp.StatusCode == http.StatusOK {
|
|
// If 200, check if the deployment is actually gone
|
|
t.Logf("Got 200 - this may indicate soft delete or eventual consistency")
|
|
}
|
|
|
|
t.Logf("✓ Deployment deleted successfully")
|
|
|
|
// Clear deploymentID so cleanup doesn't try to delete again
|
|
deploymentID = ""
|
|
})
|
|
}
|
|
|
|
func mustReadAll(t *testing.T, r io.Reader) []byte {
|
|
t.Helper()
|
|
data, err := io.ReadAll(r)
|
|
require.NoError(t, err, "Should read all data")
|
|
return data
|
|
}
|