mirror of
https://github.com/DeBrosOfficial/network.git
synced 2026-01-30 21:13:03 +00:00
224 lines
6.8 KiB
Go
224 lines
6.8 KiB
Go
//go:build e2e
|
|
|
|
package deployments_test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/DeBrosOfficial/network/e2e"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestDeploy_InvalidTarball verifies that uploading an invalid/corrupt tarball
|
|
// returns a clean error (not a 500 or panic).
|
|
func TestDeploy_InvalidTarball(t *testing.T) {
|
|
env, err := e2e.LoadTestEnv()
|
|
require.NoError(t, err)
|
|
|
|
deploymentName := fmt.Sprintf("invalid-tar-%d", time.Now().Unix())
|
|
|
|
body := &bytes.Buffer{}
|
|
boundary := "----WebKitFormBoundary7MA4YWxkTrZu0gW"
|
|
|
|
body.WriteString("--" + boundary + "\r\n")
|
|
body.WriteString("Content-Disposition: form-data; name=\"name\"\r\n\r\n")
|
|
body.WriteString(deploymentName + "\r\n")
|
|
|
|
// Write invalid tarball data (random bytes, not a real gzip)
|
|
body.WriteString("--" + boundary + "\r\n")
|
|
body.WriteString("Content-Disposition: form-data; name=\"tarball\"; filename=\"app.tar.gz\"\r\n")
|
|
body.WriteString("Content-Type: application/gzip\r\n\r\n")
|
|
body.WriteString("this is not a valid tarball content at all!!!")
|
|
body.WriteString("\r\n--" + boundary + "--\r\n")
|
|
|
|
req, err := http.NewRequest("POST", env.GatewayURL+"/v1/deployments/static/upload", body)
|
|
require.NoError(t, err)
|
|
req.Header.Set("Content-Type", "multipart/form-data; boundary="+boundary)
|
|
req.Header.Set("Authorization", "Bearer "+env.APIKey)
|
|
|
|
resp, err := env.HTTPClient.Do(req)
|
|
require.NoError(t, err)
|
|
defer resp.Body.Close()
|
|
|
|
respBody, _ := io.ReadAll(resp.Body)
|
|
t.Logf("Status: %d, Body: %s", resp.StatusCode, string(respBody))
|
|
|
|
// Should return an error, not 2xx (ideally 400, but server currently returns 500)
|
|
assert.True(t, resp.StatusCode >= 400,
|
|
"Invalid tarball should return error (got %d)", resp.StatusCode)
|
|
}
|
|
|
|
// TestDeploy_EmptyTarball verifies that uploading an empty file returns an error.
|
|
func TestDeploy_EmptyTarball(t *testing.T) {
|
|
env, err := e2e.LoadTestEnv()
|
|
require.NoError(t, err)
|
|
|
|
deploymentName := fmt.Sprintf("empty-tar-%d", time.Now().Unix())
|
|
|
|
body := &bytes.Buffer{}
|
|
boundary := "----WebKitFormBoundary7MA4YWxkTrZu0gW"
|
|
|
|
body.WriteString("--" + boundary + "\r\n")
|
|
body.WriteString("Content-Disposition: form-data; name=\"name\"\r\n\r\n")
|
|
body.WriteString(deploymentName + "\r\n")
|
|
|
|
// Empty tarball
|
|
body.WriteString("--" + boundary + "\r\n")
|
|
body.WriteString("Content-Disposition: form-data; name=\"tarball\"; filename=\"app.tar.gz\"\r\n")
|
|
body.WriteString("Content-Type: application/gzip\r\n\r\n")
|
|
body.WriteString("\r\n--" + boundary + "--\r\n")
|
|
|
|
req, err := http.NewRequest("POST", env.GatewayURL+"/v1/deployments/static/upload", body)
|
|
require.NoError(t, err)
|
|
req.Header.Set("Content-Type", "multipart/form-data; boundary="+boundary)
|
|
req.Header.Set("Authorization", "Bearer "+env.APIKey)
|
|
|
|
resp, err := env.HTTPClient.Do(req)
|
|
require.NoError(t, err)
|
|
defer resp.Body.Close()
|
|
|
|
respBody, _ := io.ReadAll(resp.Body)
|
|
t.Logf("Status: %d, Body: %s", resp.StatusCode, string(respBody))
|
|
|
|
assert.True(t, resp.StatusCode >= 400,
|
|
"Empty tarball should return error (got %d)", resp.StatusCode)
|
|
}
|
|
|
|
// TestDeploy_MissingName verifies that deploying without a name returns an error.
|
|
func TestDeploy_MissingName(t *testing.T) {
|
|
env, err := e2e.LoadTestEnv()
|
|
require.NoError(t, err)
|
|
|
|
tarballPath := filepath.Join("../../testdata/apps/react-app")
|
|
|
|
body := &bytes.Buffer{}
|
|
boundary := "----WebKitFormBoundary7MA4YWxkTrZu0gW"
|
|
|
|
// No name field
|
|
body.WriteString("--" + boundary + "\r\n")
|
|
body.WriteString("Content-Disposition: form-data; name=\"tarball\"; filename=\"app.tar.gz\"\r\n")
|
|
body.WriteString("Content-Type: application/gzip\r\n\r\n")
|
|
|
|
// Create tarball from directory for the "no name" test
|
|
tarData, err := exec.Command("tar", "-czf", "-", "-C", tarballPath, ".").Output()
|
|
if err != nil {
|
|
t.Skip("Failed to create tarball from test app")
|
|
}
|
|
body.Write(tarData)
|
|
body.WriteString("\r\n--" + boundary + "--\r\n")
|
|
|
|
req, err := http.NewRequest("POST", env.GatewayURL+"/v1/deployments/static/upload", body)
|
|
require.NoError(t, err)
|
|
req.Header.Set("Content-Type", "multipart/form-data; boundary="+boundary)
|
|
req.Header.Set("Authorization", "Bearer "+env.APIKey)
|
|
|
|
resp, err := env.HTTPClient.Do(req)
|
|
require.NoError(t, err)
|
|
defer resp.Body.Close()
|
|
|
|
assert.True(t, resp.StatusCode >= 400,
|
|
"Missing name should return error (got %d)", resp.StatusCode)
|
|
}
|
|
|
|
// TestDeploy_ConcurrentSameName verifies that deploying two apps with the same
|
|
// name concurrently doesn't cause data corruption.
|
|
func TestDeploy_ConcurrentSameName(t *testing.T) {
|
|
env, err := e2e.LoadTestEnv()
|
|
require.NoError(t, err)
|
|
|
|
deploymentName := fmt.Sprintf("concurrent-%d", time.Now().Unix())
|
|
tarballPath := filepath.Join("../../testdata/apps/react-app")
|
|
|
|
var wg sync.WaitGroup
|
|
results := make([]int, 2)
|
|
ids := make([]string, 2)
|
|
|
|
// Pre-create tarball once for both goroutines
|
|
tarData, err := exec.Command("tar", "-czf", "-", "-C", tarballPath, ".").Output()
|
|
if err != nil {
|
|
t.Skip("Failed to create tarball from test app")
|
|
}
|
|
|
|
for i := 0; i < 2; i++ {
|
|
wg.Add(1)
|
|
go func(idx int) {
|
|
defer wg.Done()
|
|
|
|
body := &bytes.Buffer{}
|
|
boundary := "----WebKitFormBoundary7MA4YWxkTrZu0gW"
|
|
|
|
body.WriteString("--" + boundary + "\r\n")
|
|
body.WriteString("Content-Disposition: form-data; name=\"name\"\r\n\r\n")
|
|
body.WriteString(deploymentName + "\r\n")
|
|
|
|
body.WriteString("--" + boundary + "\r\n")
|
|
body.WriteString("Content-Disposition: form-data; name=\"tarball\"; filename=\"app.tar.gz\"\r\n")
|
|
body.WriteString("Content-Type: application/gzip\r\n\r\n")
|
|
body.Write(tarData)
|
|
body.WriteString("\r\n--" + boundary + "--\r\n")
|
|
|
|
req, _ := http.NewRequest("POST", env.GatewayURL+"/v1/deployments/static/upload", body)
|
|
req.Header.Set("Content-Type", "multipart/form-data; boundary="+boundary)
|
|
req.Header.Set("Authorization", "Bearer "+env.APIKey)
|
|
|
|
resp, err := env.HTTPClient.Do(req)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
results[idx] = resp.StatusCode
|
|
|
|
var result map[string]interface{}
|
|
json.NewDecoder(resp.Body).Decode(&result)
|
|
if id, ok := result["deployment_id"].(string); ok {
|
|
ids[idx] = id
|
|
} else if id, ok := result["id"].(string); ok {
|
|
ids[idx] = id
|
|
}
|
|
}(i)
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
t.Logf("Concurrent deploy results: status1=%d status2=%d id1=%s id2=%s",
|
|
results[0], results[1], ids[0], ids[1])
|
|
|
|
// At least one should succeed
|
|
successCount := 0
|
|
for _, status := range results {
|
|
if status == http.StatusCreated {
|
|
successCount++
|
|
}
|
|
}
|
|
assert.GreaterOrEqual(t, successCount, 1,
|
|
"At least one concurrent deploy should succeed")
|
|
|
|
// Cleanup
|
|
for _, id := range ids {
|
|
if id != "" {
|
|
e2e.DeleteDeployment(t, env, id)
|
|
}
|
|
}
|
|
}
|
|
|
|
func readFileBytes(path string) ([]byte, error) {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
return io.ReadAll(f)
|
|
}
|