mirror of
https://github.com/DeBrosOfficial/network.git
synced 2026-01-30 13:23:03 +00:00
refactored all e2e tests
This commit is contained in:
parent
81414722cd
commit
29581bec51
37
Makefile
37
Makefile
@ -8,7 +8,7 @@ test:
|
|||||||
# Gateway-focused E2E tests assume gateway and nodes are already running
|
# Gateway-focused E2E tests assume gateway and nodes are already running
|
||||||
# Auto-discovers configuration from ~/.orama and queries database for API key
|
# Auto-discovers configuration from ~/.orama and queries database for API key
|
||||||
# No environment variables required
|
# No environment variables required
|
||||||
.PHONY: test-e2e test-e2e-deployments test-e2e-fullstack test-e2e-https test-e2e-quick test-e2e-local test-e2e-prod
|
.PHONY: test-e2e test-e2e-deployments test-e2e-fullstack test-e2e-https test-e2e-quick test-e2e-local test-e2e-prod test-e2e-shared test-e2e-cluster test-e2e-integration test-e2e-production
|
||||||
|
|
||||||
# Check if gateway is running (helper)
|
# Check if gateway is running (helper)
|
||||||
.PHONY: check-gateway
|
.PHONY: check-gateway
|
||||||
@ -32,15 +32,15 @@ test-e2e-local: check-gateway
|
|||||||
@echo "Running E2E tests against local dev environment..."
|
@echo "Running E2E tests against local dev environment..."
|
||||||
go test -v -tags e2e -timeout 30m ./e2e/...
|
go test -v -tags e2e -timeout 30m ./e2e/...
|
||||||
|
|
||||||
# Production E2E tests - requires ORAMA_GATEWAY_URL to be set
|
# Production E2E tests - includes production-only tests
|
||||||
test-e2e-prod:
|
test-e2e-prod:
|
||||||
@if [ -z "$$ORAMA_GATEWAY_URL" ]; then \
|
@if [ -z "$$ORAMA_GATEWAY_URL" ]; then \
|
||||||
echo "❌ ORAMA_GATEWAY_URL not set"; \
|
echo "❌ ORAMA_GATEWAY_URL not set"; \
|
||||||
echo "Usage: ORAMA_GATEWAY_URL=http://VPS-IP:6001 make test-e2e-prod"; \
|
echo "Usage: ORAMA_GATEWAY_URL=http://VPS-IP:6001 make test-e2e-prod"; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
@echo "Running E2E tests against $$ORAMA_GATEWAY_URL..."
|
@echo "Running E2E tests (including production-only) against $$ORAMA_GATEWAY_URL..."
|
||||||
go test -v -tags e2e -timeout 30m ./e2e/...
|
go test -v -tags "e2e production" -timeout 30m ./e2e/...
|
||||||
|
|
||||||
# Generic e2e target (works with both local and production)
|
# Generic e2e target (works with both local and production)
|
||||||
test-e2e:
|
test-e2e:
|
||||||
@ -61,6 +61,22 @@ test-e2e-https:
|
|||||||
@echo "Running HTTPS/external access E2E tests..."
|
@echo "Running HTTPS/external access E2E tests..."
|
||||||
go test -v -tags e2e -timeout 10m -run "TestHTTPS" ./e2e/...
|
go test -v -tags e2e -timeout 10m -run "TestHTTPS" ./e2e/...
|
||||||
|
|
||||||
|
test-e2e-shared:
|
||||||
|
@echo "Running shared E2E tests..."
|
||||||
|
go test -v -tags e2e -timeout 10m ./e2e/shared/...
|
||||||
|
|
||||||
|
test-e2e-cluster:
|
||||||
|
@echo "Running cluster E2E tests..."
|
||||||
|
go test -v -tags e2e -timeout 15m ./e2e/cluster/...
|
||||||
|
|
||||||
|
test-e2e-integration:
|
||||||
|
@echo "Running integration E2E tests..."
|
||||||
|
go test -v -tags e2e -timeout 20m ./e2e/integration/...
|
||||||
|
|
||||||
|
test-e2e-production:
|
||||||
|
@echo "Running production-only E2E tests..."
|
||||||
|
go test -v -tags "e2e production" -timeout 15m ./e2e/production/...
|
||||||
|
|
||||||
test-e2e-quick:
|
test-e2e-quick:
|
||||||
@echo "Running quick E2E smoke tests..."
|
@echo "Running quick E2E smoke tests..."
|
||||||
go test -v -tags e2e -timeout 5m -run "TestStatic|TestHealth" ./e2e/...
|
go test -v -tags e2e -timeout 5m -run "TestStatic|TestHealth" ./e2e/...
|
||||||
@ -155,10 +171,15 @@ help:
|
|||||||
@echo " make kill - Force kill all development services (use if stop fails)"
|
@echo " make kill - Force kill all development services (use if stop fails)"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "E2E Testing:"
|
@echo "E2E Testing:"
|
||||||
@echo " make test-e2e-local - Run E2E tests against local dev (checks gateway first)"
|
@echo " make test-e2e-local - Run E2E tests against local dev (checks gateway first)"
|
||||||
@echo " make test-e2e-prod - Run E2E tests against production (needs ORAMA_GATEWAY_URL)"
|
@echo " make test-e2e-prod - Run all E2E tests incl. production-only (needs ORAMA_GATEWAY_URL)"
|
||||||
@echo " make test-e2e-quick - Quick smoke tests (static deploys, health checks)"
|
@echo " make test-e2e-shared - Run shared E2E tests (cache, storage, pubsub, auth)"
|
||||||
@echo " make test-e2e - Generic E2E tests (auto-discovers config)"
|
@echo " make test-e2e-cluster - Run cluster E2E tests (libp2p, olric, rqlite, namespace)"
|
||||||
|
@echo " make test-e2e-integration - Run integration E2E tests (fullstack, persistence, concurrency)"
|
||||||
|
@echo " make test-e2e-deployments - Run deployment E2E tests"
|
||||||
|
@echo " make test-e2e-production - Run production-only E2E tests (DNS, HTTPS, cross-node)"
|
||||||
|
@echo " make test-e2e-quick - Quick smoke tests (static deploys, health checks)"
|
||||||
|
@echo " make test-e2e - Generic E2E tests (auto-discovers config)"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo " Example production test:"
|
@echo " Example production test:"
|
||||||
@echo " ORAMA_GATEWAY_URL=http://141.227.165.168:6001 make test-e2e-prod"
|
@echo " ORAMA_GATEWAY_URL=http://141.227.165.168:6001 make test-e2e-prod"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package cluster_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/DeBrosOfficial/network/e2e"
|
||||||
"github.com/DeBrosOfficial/network/pkg/ipfs"
|
"github.com/DeBrosOfficial/network/pkg/ipfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,13 +19,13 @@ import (
|
|||||||
// For production testing, use storage_http_test.go which uses gateway endpoints.
|
// For production testing, use storage_http_test.go which uses gateway endpoints.
|
||||||
|
|
||||||
func TestIPFSCluster_Health(t *testing.T) {
|
func TestIPFSCluster_Health(t *testing.T) {
|
||||||
SkipIfProduction(t) // Direct IPFS connection not available in production
|
e2e.SkipIfProduction(t) // Direct IPFS connection not available in production
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
logger := NewTestLogger(t)
|
logger := e2e.NewTestLogger(t)
|
||||||
cfg := ipfs.Config{
|
cfg := ipfs.Config{
|
||||||
ClusterAPIURL: GetIPFSClusterURL(),
|
ClusterAPIURL: e2e.GetIPFSClusterURL(),
|
||||||
Timeout: 10 * time.Second,
|
Timeout: 10 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,13 +41,13 @@ func TestIPFSCluster_Health(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIPFSCluster_GetPeerCount(t *testing.T) {
|
func TestIPFSCluster_GetPeerCount(t *testing.T) {
|
||||||
SkipIfProduction(t)
|
e2e.SkipIfProduction(t)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
logger := NewTestLogger(t)
|
logger := e2e.NewTestLogger(t)
|
||||||
cfg := ipfs.Config{
|
cfg := ipfs.Config{
|
||||||
ClusterAPIURL: GetIPFSClusterURL(),
|
ClusterAPIURL: e2e.GetIPFSClusterURL(),
|
||||||
Timeout: 10 * time.Second,
|
Timeout: 10 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,13 +69,13 @@ func TestIPFSCluster_GetPeerCount(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIPFSCluster_AddFile(t *testing.T) {
|
func TestIPFSCluster_AddFile(t *testing.T) {
|
||||||
SkipIfProduction(t)
|
e2e.SkipIfProduction(t)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
logger := NewTestLogger(t)
|
logger := e2e.NewTestLogger(t)
|
||||||
cfg := ipfs.Config{
|
cfg := ipfs.Config{
|
||||||
ClusterAPIURL: GetIPFSClusterURL(),
|
ClusterAPIURL: e2e.GetIPFSClusterURL(),
|
||||||
Timeout: 30 * time.Second,
|
Timeout: 30 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,13 +102,13 @@ func TestIPFSCluster_AddFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIPFSCluster_PinFile(t *testing.T) {
|
func TestIPFSCluster_PinFile(t *testing.T) {
|
||||||
SkipIfProduction(t)
|
e2e.SkipIfProduction(t)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
logger := NewTestLogger(t)
|
logger := e2e.NewTestLogger(t)
|
||||||
cfg := ipfs.Config{
|
cfg := ipfs.Config{
|
||||||
ClusterAPIURL: GetIPFSClusterURL(),
|
ClusterAPIURL: e2e.GetIPFSClusterURL(),
|
||||||
Timeout: 30 * time.Second,
|
Timeout: 30 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,13 +140,13 @@ func TestIPFSCluster_PinFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIPFSCluster_PinStatus(t *testing.T) {
|
func TestIPFSCluster_PinStatus(t *testing.T) {
|
||||||
SkipIfProduction(t)
|
e2e.SkipIfProduction(t)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
logger := NewTestLogger(t)
|
logger := e2e.NewTestLogger(t)
|
||||||
cfg := ipfs.Config{
|
cfg := ipfs.Config{
|
||||||
ClusterAPIURL: GetIPFSClusterURL(),
|
ClusterAPIURL: e2e.GetIPFSClusterURL(),
|
||||||
Timeout: 30 * time.Second,
|
Timeout: 30 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +174,7 @@ func TestIPFSCluster_PinStatus(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Give pin time to propagate
|
// Give pin time to propagate
|
||||||
Delay(1000)
|
e2e.Delay(1000)
|
||||||
|
|
||||||
// Get status
|
// Get status
|
||||||
status, err := client.PinStatus(ctx, cid)
|
status, err := client.PinStatus(ctx, cid)
|
||||||
@ -197,13 +198,13 @@ func TestIPFSCluster_PinStatus(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIPFSCluster_UnpinFile(t *testing.T) {
|
func TestIPFSCluster_UnpinFile(t *testing.T) {
|
||||||
SkipIfProduction(t)
|
e2e.SkipIfProduction(t)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
logger := NewTestLogger(t)
|
logger := e2e.NewTestLogger(t)
|
||||||
cfg := ipfs.Config{
|
cfg := ipfs.Config{
|
||||||
ClusterAPIURL: GetIPFSClusterURL(),
|
ClusterAPIURL: e2e.GetIPFSClusterURL(),
|
||||||
Timeout: 30 * time.Second,
|
Timeout: 30 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,13 +237,13 @@ func TestIPFSCluster_UnpinFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIPFSCluster_GetFile(t *testing.T) {
|
func TestIPFSCluster_GetFile(t *testing.T) {
|
||||||
SkipIfProduction(t)
|
e2e.SkipIfProduction(t)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
logger := NewTestLogger(t)
|
logger := e2e.NewTestLogger(t)
|
||||||
cfg := ipfs.Config{
|
cfg := ipfs.Config{
|
||||||
ClusterAPIURL: GetIPFSClusterURL(),
|
ClusterAPIURL: e2e.GetIPFSClusterURL(),
|
||||||
Timeout: 30 * time.Second,
|
Timeout: 30 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,10 +262,10 @@ func TestIPFSCluster_GetFile(t *testing.T) {
|
|||||||
cid := addResult.Cid
|
cid := addResult.Cid
|
||||||
|
|
||||||
// Give time for propagation
|
// Give time for propagation
|
||||||
Delay(1000)
|
e2e.Delay(1000)
|
||||||
|
|
||||||
// Get file
|
// Get file
|
||||||
rc, err := client.Get(ctx, cid, GetIPFSAPIURL())
|
rc, err := client.Get(ctx, cid, e2e.GetIPFSAPIURL())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("get file failed: %v", err)
|
t.Fatalf("get file failed: %v", err)
|
||||||
}
|
}
|
||||||
@ -283,13 +284,13 @@ func TestIPFSCluster_GetFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIPFSCluster_LargeFile(t *testing.T) {
|
func TestIPFSCluster_LargeFile(t *testing.T) {
|
||||||
SkipIfProduction(t)
|
e2e.SkipIfProduction(t)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
logger := NewTestLogger(t)
|
logger := e2e.NewTestLogger(t)
|
||||||
cfg := ipfs.Config{
|
cfg := ipfs.Config{
|
||||||
ClusterAPIURL: GetIPFSClusterURL(),
|
ClusterAPIURL: e2e.GetIPFSClusterURL(),
|
||||||
Timeout: 60 * time.Second,
|
Timeout: 60 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,13 +318,13 @@ func TestIPFSCluster_LargeFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIPFSCluster_ReplicationFactor(t *testing.T) {
|
func TestIPFSCluster_ReplicationFactor(t *testing.T) {
|
||||||
SkipIfProduction(t) // Direct IPFS connection not available in production
|
e2e.SkipIfProduction(t) // Direct IPFS connection not available in production
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
logger := NewTestLogger(t)
|
logger := e2e.NewTestLogger(t)
|
||||||
cfg := ipfs.Config{
|
cfg := ipfs.Config{
|
||||||
ClusterAPIURL: GetIPFSClusterURL(),
|
ClusterAPIURL: e2e.GetIPFSClusterURL(),
|
||||||
Timeout: 30 * time.Second,
|
Timeout: 30 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,7 +354,7 @@ func TestIPFSCluster_ReplicationFactor(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Give time for replication
|
// Give time for replication
|
||||||
Delay(2000)
|
e2e.Delay(2000)
|
||||||
|
|
||||||
// Check status
|
// Check status
|
||||||
status, err := client.PinStatus(ctx, cid)
|
status, err := client.PinStatus(ctx, cid)
|
||||||
@ -365,13 +366,13 @@ func TestIPFSCluster_ReplicationFactor(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIPFSCluster_MultipleFiles(t *testing.T) {
|
func TestIPFSCluster_MultipleFiles(t *testing.T) {
|
||||||
SkipIfProduction(t) // Direct IPFS connection not available in production
|
e2e.SkipIfProduction(t) // Direct IPFS connection not available in production
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
logger := NewTestLogger(t)
|
logger := e2e.NewTestLogger(t)
|
||||||
cfg := ipfs.Config{
|
cfg := ipfs.Config{
|
||||||
ClusterAPIURL: GetIPFSClusterURL(),
|
ClusterAPIURL: e2e.GetIPFSClusterURL(),
|
||||||
Timeout: 30 * time.Second,
|
Timeout: 30 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package cluster_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -8,25 +8,27 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/DeBrosOfficial/network/e2e"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLibP2P_PeerConnectivity(t *testing.T) {
|
func TestLibP2P_PeerConnectivity(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Create and connect client
|
// Create and connect client
|
||||||
c := NewNetworkClient(t)
|
c := e2e.NewNetworkClient(t)
|
||||||
if err := c.Connect(); err != nil {
|
if err := c.Connect(); err != nil {
|
||||||
t.Fatalf("connect failed: %v", err)
|
t.Fatalf("connect failed: %v", err)
|
||||||
}
|
}
|
||||||
defer c.Disconnect()
|
defer c.Disconnect()
|
||||||
|
|
||||||
// Verify peer connectivity through the gateway
|
// Verify peer connectivity through the gateway
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/network/peers",
|
URL: e2e.GetGatewayURL() + "/v1/network/peers",
|
||||||
}
|
}
|
||||||
|
|
||||||
body, status, err := req.Do(ctx)
|
body, status, err := req.Do(ctx)
|
||||||
@ -39,7 +41,7 @@ func TestLibP2P_PeerConnectivity(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resp map[string]interface{}
|
var resp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &resp); err != nil {
|
if err := e2e.DecodeJSON(body, &resp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,30 +52,30 @@ func TestLibP2P_PeerConnectivity(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLibP2P_BootstrapPeers(t *testing.T) {
|
func TestLibP2P_BootstrapPeers(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
bootstrapPeers := GetBootstrapPeers()
|
bootstrapPeers := e2e.GetBootstrapPeers()
|
||||||
if len(bootstrapPeers) == 0 {
|
if len(bootstrapPeers) == 0 {
|
||||||
t.Skipf("E2E_BOOTSTRAP_PEERS not set; skipping")
|
t.Skipf("E2E_BOOTSTRAP_PEERS not set; skipping")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create client with bootstrap peers explicitly set
|
// Create client with bootstrap peers explicitly set
|
||||||
c := NewNetworkClient(t)
|
c := e2e.NewNetworkClient(t)
|
||||||
if err := c.Connect(); err != nil {
|
if err := c.Connect(); err != nil {
|
||||||
t.Fatalf("connect failed: %v", err)
|
t.Fatalf("connect failed: %v", err)
|
||||||
}
|
}
|
||||||
defer c.Disconnect()
|
defer c.Disconnect()
|
||||||
|
|
||||||
// Give peer discovery time
|
// Give peer discovery time
|
||||||
Delay(2000)
|
e2e.Delay(2000)
|
||||||
|
|
||||||
// Verify we're connected (check via gateway status)
|
// Verify we're connected (check via gateway status)
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/network/status",
|
URL: e2e.GetGatewayURL() + "/v1/network/status",
|
||||||
}
|
}
|
||||||
|
|
||||||
body, status, err := req.Do(ctx)
|
body, status, err := req.Do(ctx)
|
||||||
@ -86,7 +88,7 @@ func TestLibP2P_BootstrapPeers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resp map[string]interface{}
|
var resp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &resp); err != nil {
|
if err := e2e.DecodeJSON(body, &resp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,15 +98,15 @@ func TestLibP2P_BootstrapPeers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLibP2P_MultipleClientConnections(t *testing.T) {
|
func TestLibP2P_MultipleClientConnections(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Create multiple clients
|
// Create multiple clients
|
||||||
c1 := NewNetworkClient(t)
|
c1 := e2e.NewNetworkClient(t)
|
||||||
c2 := NewNetworkClient(t)
|
c2 := e2e.NewNetworkClient(t)
|
||||||
c3 := NewNetworkClient(t)
|
c3 := e2e.NewNetworkClient(t)
|
||||||
|
|
||||||
if err := c1.Connect(); err != nil {
|
if err := c1.Connect(); err != nil {
|
||||||
t.Fatalf("c1 connect failed: %v", err)
|
t.Fatalf("c1 connect failed: %v", err)
|
||||||
@ -122,12 +124,12 @@ func TestLibP2P_MultipleClientConnections(t *testing.T) {
|
|||||||
defer c3.Disconnect()
|
defer c3.Disconnect()
|
||||||
|
|
||||||
// Give peer discovery time
|
// Give peer discovery time
|
||||||
Delay(2000)
|
e2e.Delay(2000)
|
||||||
|
|
||||||
// Verify gateway sees multiple peers
|
// Verify gateway sees multiple peers
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/network/peers",
|
URL: e2e.GetGatewayURL() + "/v1/network/peers",
|
||||||
}
|
}
|
||||||
|
|
||||||
body, status, err := req.Do(ctx)
|
body, status, err := req.Do(ctx)
|
||||||
@ -140,7 +142,7 @@ func TestLibP2P_MultipleClientConnections(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resp map[string]interface{}
|
var resp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &resp); err != nil {
|
if err := e2e.DecodeJSON(body, &resp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,12 +153,12 @@ func TestLibP2P_MultipleClientConnections(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLibP2P_ReconnectAfterDisconnect(t *testing.T) {
|
func TestLibP2P_ReconnectAfterDisconnect(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := NewNetworkClient(t)
|
c := e2e.NewNetworkClient(t)
|
||||||
|
|
||||||
// Connect
|
// Connect
|
||||||
if err := c.Connect(); err != nil {
|
if err := c.Connect(); err != nil {
|
||||||
@ -164,9 +166,9 @@ func TestLibP2P_ReconnectAfterDisconnect(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify connected via gateway
|
// Verify connected via gateway
|
||||||
req1 := &HTTPRequest{
|
req1 := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/network/status",
|
URL: e2e.GetGatewayURL() + "/v1/network/status",
|
||||||
}
|
}
|
||||||
|
|
||||||
_, status1, err := req1.Do(ctx)
|
_, status1, err := req1.Do(ctx)
|
||||||
@ -180,7 +182,7 @@ func TestLibP2P_ReconnectAfterDisconnect(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Give time for disconnect to propagate
|
// Give time for disconnect to propagate
|
||||||
Delay(500)
|
e2e.Delay(500)
|
||||||
|
|
||||||
// Reconnect
|
// Reconnect
|
||||||
if err := c.Connect(); err != nil {
|
if err := c.Connect(); err != nil {
|
||||||
@ -189,9 +191,9 @@ func TestLibP2P_ReconnectAfterDisconnect(t *testing.T) {
|
|||||||
defer c.Disconnect()
|
defer c.Disconnect()
|
||||||
|
|
||||||
// Verify connected via gateway again
|
// Verify connected via gateway again
|
||||||
req2 := &HTTPRequest{
|
req2 := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/network/status",
|
URL: e2e.GetGatewayURL() + "/v1/network/status",
|
||||||
}
|
}
|
||||||
|
|
||||||
_, status2, err := req2.Do(ctx)
|
_, status2, err := req2.Do(ctx)
|
||||||
@ -201,25 +203,25 @@ func TestLibP2P_ReconnectAfterDisconnect(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLibP2P_PeerDiscovery(t *testing.T) {
|
func TestLibP2P_PeerDiscovery(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Create client
|
// Create client
|
||||||
c := NewNetworkClient(t)
|
c := e2e.NewNetworkClient(t)
|
||||||
if err := c.Connect(); err != nil {
|
if err := c.Connect(); err != nil {
|
||||||
t.Fatalf("connect failed: %v", err)
|
t.Fatalf("connect failed: %v", err)
|
||||||
}
|
}
|
||||||
defer c.Disconnect()
|
defer c.Disconnect()
|
||||||
|
|
||||||
// Give peer discovery time
|
// Give peer discovery time
|
||||||
Delay(3000)
|
e2e.Delay(3000)
|
||||||
|
|
||||||
// Get peer list
|
// Get peer list
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/network/peers",
|
URL: e2e.GetGatewayURL() + "/v1/network/peers",
|
||||||
}
|
}
|
||||||
|
|
||||||
body, status, err := req.Do(ctx)
|
body, status, err := req.Do(ctx)
|
||||||
@ -232,7 +234,7 @@ func TestLibP2P_PeerDiscovery(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resp map[string]interface{}
|
var resp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &resp); err != nil {
|
if err := e2e.DecodeJSON(body, &resp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,22 +253,22 @@ func TestLibP2P_PeerDiscovery(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLibP2P_PeerAddressFormat(t *testing.T) {
|
func TestLibP2P_PeerAddressFormat(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Create client
|
// Create client
|
||||||
c := NewNetworkClient(t)
|
c := e2e.NewNetworkClient(t)
|
||||||
if err := c.Connect(); err != nil {
|
if err := c.Connect(); err != nil {
|
||||||
t.Fatalf("connect failed: %v", err)
|
t.Fatalf("connect failed: %v", err)
|
||||||
}
|
}
|
||||||
defer c.Disconnect()
|
defer c.Disconnect()
|
||||||
|
|
||||||
// Get peer list
|
// Get peer list
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/network/peers",
|
URL: e2e.GetGatewayURL() + "/v1/network/peers",
|
||||||
}
|
}
|
||||||
|
|
||||||
body, status, err := req.Do(ctx)
|
body, status, err := req.Do(ctx)
|
||||||
@ -279,7 +281,7 @@ func TestLibP2P_PeerAddressFormat(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resp map[string]interface{}
|
var resp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &resp); err != nil {
|
if err := e2e.DecodeJSON(body, &resp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package cluster_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -16,6 +16,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/DeBrosOfficial/network/e2e"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ func TestNamespaceCluster_FullProvisioning(t *testing.T) {
|
|||||||
// Generate unique namespace name
|
// Generate unique namespace name
|
||||||
newNamespace := fmt.Sprintf("e2e-cluster-%d", time.Now().UnixNano())
|
newNamespace := fmt.Sprintf("e2e-cluster-%d", time.Now().UnixNano())
|
||||||
|
|
||||||
env, err := LoadTestEnvWithNamespace(newNamespace)
|
env, err := e2e.LoadTestEnvWithNamespace(newNamespace)
|
||||||
require.NoError(t, err, "FATAL: Failed to create test environment for namespace %s", newNamespace)
|
require.NoError(t, err, "FATAL: Failed to create test environment for namespace %s", newNamespace)
|
||||||
require.NotEmpty(t, env.APIKey, "FATAL: No API key received - namespace provisioning failed")
|
require.NotEmpty(t, env.APIKey, "FATAL: No API key received - namespace provisioning failed")
|
||||||
|
|
||||||
@ -70,7 +71,7 @@ func TestNamespaceCluster_FullProvisioning(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deploymentName := fmt.Sprintf("cluster-test-%d", time.Now().Unix())
|
deploymentName := fmt.Sprintf("cluster-test-%d", time.Now().Unix())
|
||||||
deploymentID := CreateTestDeployment(t, env, deploymentName, tarballPath)
|
deploymentID := e2e.CreateTestDeployment(t, env, deploymentName, tarballPath)
|
||||||
require.NotEmpty(t, deploymentID, "FAIL: Deployment creation failed on namespace cluster")
|
require.NotEmpty(t, deploymentID, "FAIL: Deployment creation failed on namespace cluster")
|
||||||
|
|
||||||
t.Logf("Created deployment %s (ID: %s) on namespace %s", deploymentName, deploymentID, newNamespace)
|
t.Logf("Created deployment %s (ID: %s) on namespace %s", deploymentName, deploymentID, newNamespace)
|
||||||
@ -78,7 +79,7 @@ func TestNamespaceCluster_FullProvisioning(t *testing.T) {
|
|||||||
// Cleanup
|
// Cleanup
|
||||||
defer func() {
|
defer func() {
|
||||||
if !env.SkipCleanup {
|
if !env.SkipCleanup {
|
||||||
DeleteDeployment(t, env, deploymentID)
|
e2e.DeleteDeployment(t, env, deploymentID)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -246,7 +247,7 @@ func TestNamespaceCluster_ProvisioningCreatesProcesses(t *testing.T) {
|
|||||||
t.Logf("Ports in use before provisioning: %v", portsBefore)
|
t.Logf("Ports in use before provisioning: %v", portsBefore)
|
||||||
|
|
||||||
// Create namespace
|
// Create namespace
|
||||||
env, err := LoadTestEnvWithNamespace(newNamespace)
|
env, err := e2e.LoadTestEnvWithNamespace(newNamespace)
|
||||||
require.NoError(t, err, "FATAL: Failed to create namespace")
|
require.NoError(t, err, "FATAL: Failed to create namespace")
|
||||||
require.NotEmpty(t, env.APIKey, "FATAL: No API key - provisioning failed")
|
require.NotEmpty(t, env.APIKey, "FATAL: No API key - provisioning failed")
|
||||||
|
|
||||||
@ -330,7 +331,7 @@ func TestNamespaceCluster_ProvisioningCreatesProcesses(t *testing.T) {
|
|||||||
|
|
||||||
// TestNamespaceCluster_StatusEndpoint tests the /v1/namespace/status endpoint
|
// TestNamespaceCluster_StatusEndpoint tests the /v1/namespace/status endpoint
|
||||||
func TestNamespaceCluster_StatusEndpoint(t *testing.T) {
|
func TestNamespaceCluster_StatusEndpoint(t *testing.T) {
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "Failed to load test environment")
|
require.NoError(t, err, "Failed to load test environment")
|
||||||
|
|
||||||
t.Run("Status endpoint returns 404 for non-existent cluster", func(t *testing.T) {
|
t.Run("Status endpoint returns 404 for non-existent cluster", func(t *testing.T) {
|
||||||
@ -351,10 +352,10 @@ func TestNamespaceCluster_CrossNamespaceAccess(t *testing.T) {
|
|||||||
nsA := fmt.Sprintf("ns-a-%d", time.Now().Unix())
|
nsA := fmt.Sprintf("ns-a-%d", time.Now().Unix())
|
||||||
nsB := fmt.Sprintf("ns-b-%d", time.Now().Unix())
|
nsB := fmt.Sprintf("ns-b-%d", time.Now().Unix())
|
||||||
|
|
||||||
envA, err := LoadTestEnvWithNamespace(nsA)
|
envA, err := e2e.LoadTestEnvWithNamespace(nsA)
|
||||||
require.NoError(t, err, "FAIL: Cannot create namespace A")
|
require.NoError(t, err, "FAIL: Cannot create namespace A")
|
||||||
|
|
||||||
envB, err := LoadTestEnvWithNamespace(nsB)
|
envB, err := e2e.LoadTestEnvWithNamespace(nsB)
|
||||||
require.NoError(t, err, "FAIL: Cannot create namespace B")
|
require.NoError(t, err, "FAIL: Cannot create namespace B")
|
||||||
|
|
||||||
// Verify both namespaces have different API keys
|
// Verify both namespaces have different API keys
|
||||||
@ -392,7 +393,7 @@ func TestNamespaceCluster_CrossNamespaceAccess(t *testing.T) {
|
|||||||
|
|
||||||
// TestDeployment_SubdomainFormat tests deployment subdomain format
|
// TestDeployment_SubdomainFormat tests deployment subdomain format
|
||||||
func TestDeployment_SubdomainFormat(t *testing.T) {
|
func TestDeployment_SubdomainFormat(t *testing.T) {
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "Failed to load test environment")
|
require.NoError(t, err, "Failed to load test environment")
|
||||||
|
|
||||||
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
||||||
@ -401,12 +402,12 @@ func TestDeployment_SubdomainFormat(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deploymentName := fmt.Sprintf("subdomain-test-%d", time.Now().UnixNano())
|
deploymentName := fmt.Sprintf("subdomain-test-%d", time.Now().UnixNano())
|
||||||
deploymentID := CreateTestDeployment(t, env, deploymentName, tarballPath)
|
deploymentID := e2e.CreateTestDeployment(t, env, deploymentName, tarballPath)
|
||||||
require.NotEmpty(t, deploymentID, "FAIL: Deployment creation failed")
|
require.NotEmpty(t, deploymentID, "FAIL: Deployment creation failed")
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if !env.SkipCleanup {
|
if !env.SkipCleanup {
|
||||||
DeleteDeployment(t, env, deploymentID)
|
e2e.DeleteDeployment(t, env, deploymentID)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package cluster_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -12,35 +12,36 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/DeBrosOfficial/network/e2e"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNamespaceIsolation_Deployments(t *testing.T) {
|
func TestNamespaceIsolation_Deployments(t *testing.T) {
|
||||||
// Setup two test environments with different namespaces
|
// Setup two test environments with different namespaces
|
||||||
envA, err := LoadTestEnvWithNamespace("namespace-a-" + fmt.Sprintf("%d", time.Now().Unix()))
|
envA, err := e2e.LoadTestEnvWithNamespace("namespace-a-" + fmt.Sprintf("%d", time.Now().Unix()))
|
||||||
require.NoError(t, err, "Failed to create namespace A environment")
|
require.NoError(t, err, "Failed to create namespace A environment")
|
||||||
|
|
||||||
envB, err := LoadTestEnvWithNamespace("namespace-b-" + fmt.Sprintf("%d", time.Now().Unix()))
|
envB, err := e2e.LoadTestEnvWithNamespace("namespace-b-" + fmt.Sprintf("%d", time.Now().Unix()))
|
||||||
require.NoError(t, err, "Failed to create namespace B environment")
|
require.NoError(t, err, "Failed to create namespace B environment")
|
||||||
|
|
||||||
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
||||||
|
|
||||||
// Create deployment in namespace-a
|
// Create deployment in namespace-a
|
||||||
deploymentNameA := "test-app-ns-a"
|
deploymentNameA := "test-app-ns-a"
|
||||||
deploymentIDA := CreateTestDeployment(t, envA, deploymentNameA, tarballPath)
|
deploymentIDA := e2e.CreateTestDeployment(t, envA, deploymentNameA, tarballPath)
|
||||||
defer func() {
|
defer func() {
|
||||||
if !envA.SkipCleanup {
|
if !envA.SkipCleanup {
|
||||||
DeleteDeployment(t, envA, deploymentIDA)
|
e2e.DeleteDeployment(t, envA, deploymentIDA)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Create deployment in namespace-b
|
// Create deployment in namespace-b
|
||||||
deploymentNameB := "test-app-ns-b"
|
deploymentNameB := "test-app-ns-b"
|
||||||
deploymentIDB := CreateTestDeployment(t, envB, deploymentNameB, tarballPath)
|
deploymentIDB := e2e.CreateTestDeployment(t, envB, deploymentNameB, tarballPath)
|
||||||
defer func() {
|
defer func() {
|
||||||
if !envB.SkipCleanup {
|
if !envB.SkipCleanup {
|
||||||
DeleteDeployment(t, envB, deploymentIDB)
|
e2e.DeleteDeployment(t, envB, deploymentIDB)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -112,27 +113,27 @@ func TestNamespaceIsolation_Deployments(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNamespaceIsolation_SQLiteDatabases(t *testing.T) {
|
func TestNamespaceIsolation_SQLiteDatabases(t *testing.T) {
|
||||||
envA, err := LoadTestEnvWithNamespace("namespace-a-" + fmt.Sprintf("%d", time.Now().Unix()))
|
envA, err := e2e.LoadTestEnvWithNamespace("namespace-a-" + fmt.Sprintf("%d", time.Now().Unix()))
|
||||||
require.NoError(t, err, "Should create test environment for namespace-a")
|
require.NoError(t, err, "Should create test environment for namespace-a")
|
||||||
|
|
||||||
envB, err := LoadTestEnvWithNamespace("namespace-b-" + fmt.Sprintf("%d", time.Now().Unix()))
|
envB, err := e2e.LoadTestEnvWithNamespace("namespace-b-" + fmt.Sprintf("%d", time.Now().Unix()))
|
||||||
require.NoError(t, err, "Should create test environment for namespace-b")
|
require.NoError(t, err, "Should create test environment for namespace-b")
|
||||||
|
|
||||||
// Create database in namespace-a
|
// Create database in namespace-a
|
||||||
dbNameA := "users-db-a"
|
dbNameA := "users-db-a"
|
||||||
CreateSQLiteDB(t, envA, dbNameA)
|
e2e.CreateSQLiteDB(t, envA, dbNameA)
|
||||||
defer func() {
|
defer func() {
|
||||||
if !envA.SkipCleanup {
|
if !envA.SkipCleanup {
|
||||||
DeleteSQLiteDB(t, envA, dbNameA)
|
e2e.DeleteSQLiteDB(t, envA, dbNameA)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Create database in namespace-b
|
// Create database in namespace-b
|
||||||
dbNameB := "users-db-b"
|
dbNameB := "users-db-b"
|
||||||
CreateSQLiteDB(t, envB, dbNameB)
|
e2e.CreateSQLiteDB(t, envB, dbNameB)
|
||||||
defer func() {
|
defer func() {
|
||||||
if !envB.SkipCleanup {
|
if !envB.SkipCleanup {
|
||||||
DeleteSQLiteDB(t, envB, dbNameB)
|
e2e.DeleteSQLiteDB(t, envB, dbNameB)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -201,17 +202,17 @@ func TestNamespaceIsolation_SQLiteDatabases(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNamespaceIsolation_IPFSContent(t *testing.T) {
|
func TestNamespaceIsolation_IPFSContent(t *testing.T) {
|
||||||
envA, err := LoadTestEnvWithNamespace("namespace-a-" + fmt.Sprintf("%d", time.Now().Unix()))
|
envA, err := e2e.LoadTestEnvWithNamespace("namespace-a-" + fmt.Sprintf("%d", time.Now().Unix()))
|
||||||
require.NoError(t, err, "Should create test environment for namespace-a")
|
require.NoError(t, err, "Should create test environment for namespace-a")
|
||||||
|
|
||||||
envB, err := LoadTestEnvWithNamespace("namespace-b-" + fmt.Sprintf("%d", time.Now().Unix()))
|
envB, err := e2e.LoadTestEnvWithNamespace("namespace-b-" + fmt.Sprintf("%d", time.Now().Unix()))
|
||||||
require.NoError(t, err, "Should create test environment for namespace-b")
|
require.NoError(t, err, "Should create test environment for namespace-b")
|
||||||
|
|
||||||
// Upload file in namespace-a
|
// Upload file in namespace-a
|
||||||
cidA := UploadTestFile(t, envA, "test-file-a.txt", "Content from namespace A")
|
cidA := e2e.UploadTestFile(t, envA, "test-file-a.txt", "Content from namespace A")
|
||||||
defer func() {
|
defer func() {
|
||||||
if !envA.SkipCleanup {
|
if !envA.SkipCleanup {
|
||||||
UnpinFile(t, envA, cidA)
|
e2e.UnpinFile(t, envA, cidA)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -273,10 +274,10 @@ func TestNamespaceIsolation_IPFSContent(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNamespaceIsolation_OlricCache(t *testing.T) {
|
func TestNamespaceIsolation_OlricCache(t *testing.T) {
|
||||||
envA, err := LoadTestEnvWithNamespace("namespace-a-" + fmt.Sprintf("%d", time.Now().Unix()))
|
envA, err := e2e.LoadTestEnvWithNamespace("namespace-a-" + fmt.Sprintf("%d", time.Now().Unix()))
|
||||||
require.NoError(t, err, "Should create test environment for namespace-a")
|
require.NoError(t, err, "Should create test environment for namespace-a")
|
||||||
|
|
||||||
envB, err := LoadTestEnvWithNamespace("namespace-b-" + fmt.Sprintf("%d", time.Now().Unix()))
|
envB, err := e2e.LoadTestEnvWithNamespace("namespace-b-" + fmt.Sprintf("%d", time.Now().Unix()))
|
||||||
require.NoError(t, err, "Should create test environment for namespace-b")
|
require.NoError(t, err, "Should create test environment for namespace-b")
|
||||||
|
|
||||||
dmap := "test-cache"
|
dmap := "test-cache"
|
||||||
@ -1,17 +1,17 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package cluster_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/DeBrosOfficial/network/e2e"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,86 +31,10 @@ func getOlricNodeAddresses() []string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// putToOlric stores a key-value pair in Olric via HTTP API
|
|
||||||
func putToOlric(gatewayURL, apiKey, dmap, key, value string) error {
|
|
||||||
reqBody := map[string]interface{}{
|
|
||||||
"dmap": dmap,
|
|
||||||
"key": key,
|
|
||||||
"value": value,
|
|
||||||
}
|
|
||||||
bodyBytes, _ := json.Marshal(reqBody)
|
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", gatewayURL+"/v1/cache/put", strings.NewReader(string(bodyBytes)))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
req.Header.Set("Authorization", "Bearer "+apiKey)
|
|
||||||
|
|
||||||
client := &http.Client{Timeout: 10 * time.Second}
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
|
|
||||||
body, _ := io.ReadAll(resp.Body)
|
|
||||||
return fmt.Errorf("put failed with status %d: %s", resp.StatusCode, string(body))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getFromOlric retrieves a value from Olric via HTTP API
|
|
||||||
func getFromOlric(gatewayURL, apiKey, dmap, key string) (string, error) {
|
|
||||||
reqBody := map[string]interface{}{
|
|
||||||
"dmap": dmap,
|
|
||||||
"key": key,
|
|
||||||
}
|
|
||||||
bodyBytes, _ := json.Marshal(reqBody)
|
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", gatewayURL+"/v1/cache/get", strings.NewReader(string(bodyBytes)))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
req.Header.Set("Authorization", "Bearer "+apiKey)
|
|
||||||
|
|
||||||
client := &http.Client{Timeout: 10 * time.Second}
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
if resp.StatusCode == http.StatusNotFound {
|
|
||||||
return "", fmt.Errorf("key not found")
|
|
||||||
}
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
body, _ := io.ReadAll(resp.Body)
|
|
||||||
return "", fmt.Errorf("get failed with status %d: %s", resp.StatusCode, string(body))
|
|
||||||
}
|
|
||||||
|
|
||||||
body, _ := io.ReadAll(resp.Body)
|
|
||||||
var result map[string]interface{}
|
|
||||||
if err := json.Unmarshal(body, &result); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if value, ok := result["value"].(string); ok {
|
|
||||||
return value, nil
|
|
||||||
}
|
|
||||||
// Value might be in a different format
|
|
||||||
if value, ok := result["value"]; ok {
|
|
||||||
return fmt.Sprintf("%v", value), nil
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf("value not found in response")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestOlric_BasicDistribution verifies cache operations work across the cluster.
|
// TestOlric_BasicDistribution verifies cache operations work across the cluster.
|
||||||
func TestOlric_BasicDistribution(t *testing.T) {
|
func TestOlric_BasicDistribution(t *testing.T) {
|
||||||
// Note: Not using SkipIfMissingGateway() since LoadTestEnv() creates its own API key
|
// Note: Not using SkipIfMissingGateway() since LoadTestEnv() creates its own API key
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "FAIL: Could not load test environment")
|
require.NoError(t, err, "FAIL: Could not load test environment")
|
||||||
require.NotEmpty(t, env.APIKey, "FAIL: No API key available")
|
require.NotEmpty(t, env.APIKey, "FAIL: No API key available")
|
||||||
|
|
||||||
@ -121,11 +45,11 @@ func TestOlric_BasicDistribution(t *testing.T) {
|
|||||||
value := fmt.Sprintf("value_%d", time.Now().UnixNano())
|
value := fmt.Sprintf("value_%d", time.Now().UnixNano())
|
||||||
|
|
||||||
// Put
|
// Put
|
||||||
err := putToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
err := e2e.PutToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
||||||
require.NoError(t, err, "FAIL: Could not put value to cache")
|
require.NoError(t, err, "FAIL: Could not put value to cache")
|
||||||
|
|
||||||
// Get
|
// Get
|
||||||
retrieved, err := getFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
retrieved, err := e2e.GetFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
||||||
require.NoError(t, err, "FAIL: Could not get value from cache")
|
require.NoError(t, err, "FAIL: Could not get value from cache")
|
||||||
require.Equal(t, value, retrieved, "FAIL: Retrieved value doesn't match")
|
require.Equal(t, value, retrieved, "FAIL: Retrieved value doesn't match")
|
||||||
|
|
||||||
@ -140,7 +64,7 @@ func TestOlric_BasicDistribution(t *testing.T) {
|
|||||||
value := fmt.Sprintf("dist_value_%d", i)
|
value := fmt.Sprintf("dist_value_%d", i)
|
||||||
keys[key] = value
|
keys[key] = value
|
||||||
|
|
||||||
err := putToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
err := e2e.PutToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
||||||
require.NoError(t, err, "FAIL: Could not put key %s", key)
|
require.NoError(t, err, "FAIL: Could not put key %s", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +72,7 @@ func TestOlric_BasicDistribution(t *testing.T) {
|
|||||||
|
|
||||||
// Verify all keys are retrievable
|
// Verify all keys are retrievable
|
||||||
for key, expectedValue := range keys {
|
for key, expectedValue := range keys {
|
||||||
retrieved, err := getFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
retrieved, err := e2e.GetFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
||||||
require.NoError(t, err, "FAIL: Could not get key %s", key)
|
require.NoError(t, err, "FAIL: Could not get key %s", key)
|
||||||
require.Equal(t, expectedValue, retrieved, "FAIL: Value mismatch for key %s", key)
|
require.Equal(t, expectedValue, retrieved, "FAIL: Value mismatch for key %s", key)
|
||||||
}
|
}
|
||||||
@ -159,7 +83,7 @@ func TestOlric_BasicDistribution(t *testing.T) {
|
|||||||
|
|
||||||
// TestOlric_ConcurrentAccess verifies cache handles concurrent operations correctly.
|
// TestOlric_ConcurrentAccess verifies cache handles concurrent operations correctly.
|
||||||
func TestOlric_ConcurrentAccess(t *testing.T) {
|
func TestOlric_ConcurrentAccess(t *testing.T) {
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "FAIL: Could not load test environment")
|
require.NoError(t, err, "FAIL: Could not load test environment")
|
||||||
|
|
||||||
dmap := fmt.Sprintf("concurrent_test_%d", time.Now().UnixNano())
|
dmap := fmt.Sprintf("concurrent_test_%d", time.Now().UnixNano())
|
||||||
@ -172,7 +96,7 @@ func TestOlric_ConcurrentAccess(t *testing.T) {
|
|||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
go func(idx int) {
|
go func(idx int) {
|
||||||
value := fmt.Sprintf("concurrent_value_%d", idx)
|
value := fmt.Sprintf("concurrent_value_%d", idx)
|
||||||
err := putToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
err := e2e.PutToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
||||||
done <- err
|
done <- err
|
||||||
}(i)
|
}(i)
|
||||||
}
|
}
|
||||||
@ -188,7 +112,7 @@ func TestOlric_ConcurrentAccess(t *testing.T) {
|
|||||||
require.Empty(t, errors, "FAIL: %d concurrent writes failed: %v", len(errors), errors)
|
require.Empty(t, errors, "FAIL: %d concurrent writes failed: %v", len(errors), errors)
|
||||||
|
|
||||||
// The key should have ONE of the values (last write wins)
|
// The key should have ONE of the values (last write wins)
|
||||||
retrieved, err := getFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
retrieved, err := e2e.GetFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
||||||
require.NoError(t, err, "FAIL: Could not get key after concurrent writes")
|
require.NoError(t, err, "FAIL: Could not get key after concurrent writes")
|
||||||
require.Contains(t, retrieved, "concurrent_value_", "FAIL: Value doesn't match expected pattern")
|
require.Contains(t, retrieved, "concurrent_value_", "FAIL: Value doesn't match expected pattern")
|
||||||
|
|
||||||
@ -200,7 +124,7 @@ func TestOlric_ConcurrentAccess(t *testing.T) {
|
|||||||
initialValue := "initial_value"
|
initialValue := "initial_value"
|
||||||
|
|
||||||
// Set initial value
|
// Set initial value
|
||||||
err := putToOlric(env.GatewayURL, env.APIKey, dmap, key, initialValue)
|
err := e2e.PutToOlric(env.GatewayURL, env.APIKey, dmap, key, initialValue)
|
||||||
require.NoError(t, err, "FAIL: Could not set initial value")
|
require.NoError(t, err, "FAIL: Could not set initial value")
|
||||||
|
|
||||||
// Launch concurrent readers and writers
|
// Launch concurrent readers and writers
|
||||||
@ -209,7 +133,7 @@ func TestOlric_ConcurrentAccess(t *testing.T) {
|
|||||||
// 10 readers
|
// 10 readers
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
go func() {
|
go func() {
|
||||||
_, err := getFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
_, err := e2e.GetFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
||||||
done <- err
|
done <- err
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
@ -218,7 +142,7 @@ func TestOlric_ConcurrentAccess(t *testing.T) {
|
|||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
go func(idx int) {
|
go func(idx int) {
|
||||||
value := fmt.Sprintf("updated_value_%d", idx)
|
value := fmt.Sprintf("updated_value_%d", idx)
|
||||||
err := putToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
err := e2e.PutToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
||||||
done <- err
|
done <- err
|
||||||
}(i)
|
}(i)
|
||||||
}
|
}
|
||||||
@ -247,7 +171,7 @@ func TestOlric_NamespaceClusterCache(t *testing.T) {
|
|||||||
// Create a new namespace
|
// Create a new namespace
|
||||||
namespace := fmt.Sprintf("cache-test-%d", time.Now().UnixNano())
|
namespace := fmt.Sprintf("cache-test-%d", time.Now().UnixNano())
|
||||||
|
|
||||||
env, err := LoadTestEnvWithNamespace(namespace)
|
env, err := e2e.LoadTestEnvWithNamespace(namespace)
|
||||||
require.NoError(t, err, "FAIL: Could not create namespace for cache test")
|
require.NoError(t, err, "FAIL: Could not create namespace for cache test")
|
||||||
require.NotEmpty(t, env.APIKey, "FAIL: No API key")
|
require.NotEmpty(t, env.APIKey, "FAIL: No API key")
|
||||||
|
|
||||||
@ -260,11 +184,11 @@ func TestOlric_NamespaceClusterCache(t *testing.T) {
|
|||||||
value := fmt.Sprintf("ns_value_%d", time.Now().UnixNano())
|
value := fmt.Sprintf("ns_value_%d", time.Now().UnixNano())
|
||||||
|
|
||||||
// Put using namespace API key
|
// Put using namespace API key
|
||||||
err := putToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
err := e2e.PutToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
||||||
require.NoError(t, err, "FAIL: Could not put value in namespace cache")
|
require.NoError(t, err, "FAIL: Could not put value in namespace cache")
|
||||||
|
|
||||||
// Get
|
// Get
|
||||||
retrieved, err := getFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
retrieved, err := e2e.GetFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
||||||
require.NoError(t, err, "FAIL: Could not get value from namespace cache")
|
require.NoError(t, err, "FAIL: Could not get value from namespace cache")
|
||||||
require.Equal(t, value, retrieved, "FAIL: Value mismatch in namespace cache")
|
require.Equal(t, value, retrieved, "FAIL: Value mismatch in namespace cache")
|
||||||
|
|
||||||
@ -298,7 +222,7 @@ func TestOlric_NamespaceClusterCache(t *testing.T) {
|
|||||||
|
|
||||||
// TestOlric_DataConsistency verifies data remains consistent across operations.
|
// TestOlric_DataConsistency verifies data remains consistent across operations.
|
||||||
func TestOlric_DataConsistency(t *testing.T) {
|
func TestOlric_DataConsistency(t *testing.T) {
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "FAIL: Could not load test environment")
|
require.NoError(t, err, "FAIL: Could not load test environment")
|
||||||
|
|
||||||
dmap := fmt.Sprintf("consistency_test_%d", time.Now().UnixNano())
|
dmap := fmt.Sprintf("consistency_test_%d", time.Now().UnixNano())
|
||||||
@ -309,12 +233,12 @@ func TestOlric_DataConsistency(t *testing.T) {
|
|||||||
// Write multiple times
|
// Write multiple times
|
||||||
for i := 1; i <= 5; i++ {
|
for i := 1; i <= 5; i++ {
|
||||||
value := fmt.Sprintf("version_%d", i)
|
value := fmt.Sprintf("version_%d", i)
|
||||||
err := putToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
err := e2e.PutToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
||||||
require.NoError(t, err, "FAIL: Could not update key to version %d", i)
|
require.NoError(t, err, "FAIL: Could not update key to version %d", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final read should return latest version
|
// Final read should return latest version
|
||||||
retrieved, err := getFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
retrieved, err := e2e.GetFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
||||||
require.NoError(t, err, "FAIL: Could not read final value")
|
require.NoError(t, err, "FAIL: Could not read final value")
|
||||||
require.Equal(t, "version_5", retrieved, "FAIL: Latest version not preserved")
|
require.Equal(t, "version_5", retrieved, "FAIL: Latest version not preserved")
|
||||||
|
|
||||||
@ -326,11 +250,11 @@ func TestOlric_DataConsistency(t *testing.T) {
|
|||||||
value := "to_be_deleted"
|
value := "to_be_deleted"
|
||||||
|
|
||||||
// Put
|
// Put
|
||||||
err := putToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
err := e2e.PutToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
||||||
require.NoError(t, err, "FAIL: Could not put value")
|
require.NoError(t, err, "FAIL: Could not put value")
|
||||||
|
|
||||||
// Verify it exists
|
// Verify it exists
|
||||||
retrieved, err := getFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
retrieved, err := e2e.GetFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
||||||
require.NoError(t, err, "FAIL: Could not get value before delete")
|
require.NoError(t, err, "FAIL: Could not get value before delete")
|
||||||
require.Equal(t, value, retrieved)
|
require.Equal(t, value, retrieved)
|
||||||
|
|
||||||
@ -351,7 +275,7 @@ func TestOlric_DataConsistency(t *testing.T) {
|
|||||||
"FAIL: Delete returned unexpected status %d", resp.StatusCode)
|
"FAIL: Delete returned unexpected status %d", resp.StatusCode)
|
||||||
|
|
||||||
// Verify key is gone
|
// Verify key is gone
|
||||||
_, err = getFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
_, err = e2e.GetFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
||||||
require.Error(t, err, "FAIL: Key should not exist after delete")
|
require.Error(t, err, "FAIL: Key should not exist after delete")
|
||||||
require.Contains(t, err.Error(), "not found", "FAIL: Expected 'not found' error")
|
require.Contains(t, err.Error(), "not found", "FAIL: Expected 'not found' error")
|
||||||
|
|
||||||
@ -365,7 +289,7 @@ func TestOlric_DataConsistency(t *testing.T) {
|
|||||||
func TestOlric_TTLExpiration(t *testing.T) {
|
func TestOlric_TTLExpiration(t *testing.T) {
|
||||||
t.Skip("TTL support not yet implemented in cache handler - see set_handler.go lines 88-98")
|
t.Skip("TTL support not yet implemented in cache handler - see set_handler.go lines 88-98")
|
||||||
|
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "FAIL: Could not load test environment")
|
require.NoError(t, err, "FAIL: Could not load test environment")
|
||||||
|
|
||||||
dmap := fmt.Sprintf("ttl_test_%d", time.Now().UnixNano())
|
dmap := fmt.Sprintf("ttl_test_%d", time.Now().UnixNano())
|
||||||
@ -396,7 +320,7 @@ func TestOlric_TTLExpiration(t *testing.T) {
|
|||||||
"FAIL: Put returned status %d", resp.StatusCode)
|
"FAIL: Put returned status %d", resp.StatusCode)
|
||||||
|
|
||||||
// Verify key exists immediately
|
// Verify key exists immediately
|
||||||
retrieved, err := getFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
retrieved, err := e2e.GetFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
||||||
require.NoError(t, err, "FAIL: Could not get key immediately after put")
|
require.NoError(t, err, "FAIL: Could not get key immediately after put")
|
||||||
require.Equal(t, value, retrieved)
|
require.Equal(t, value, retrieved)
|
||||||
t.Logf(" Key exists immediately after put")
|
t.Logf(" Key exists immediately after put")
|
||||||
@ -405,7 +329,7 @@ func TestOlric_TTLExpiration(t *testing.T) {
|
|||||||
time.Sleep(time.Duration(ttlSeconds+2) * time.Second)
|
time.Sleep(time.Duration(ttlSeconds+2) * time.Second)
|
||||||
|
|
||||||
// Key should be gone
|
// Key should be gone
|
||||||
_, err = getFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
_, err = e2e.GetFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
||||||
require.Error(t, err, "FAIL: Key should have expired after %d seconds", ttlSeconds)
|
require.Error(t, err, "FAIL: Key should have expired after %d seconds", ttlSeconds)
|
||||||
require.Contains(t, err.Error(), "not found", "FAIL: Expected 'not found' error after TTL")
|
require.Contains(t, err.Error(), "not found", "FAIL: Expected 'not found' error after TTL")
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package cluster_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/DeBrosOfficial/network/e2e"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,15 +22,15 @@ import (
|
|||||||
|
|
||||||
// TestRQLite_ClusterHealth verifies the RQLite cluster is healthy and operational.
|
// TestRQLite_ClusterHealth verifies the RQLite cluster is healthy and operational.
|
||||||
func TestRQLite_ClusterHealth(t *testing.T) {
|
func TestRQLite_ClusterHealth(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Check RQLite schema endpoint (proves cluster is reachable)
|
// Check RQLite schema endpoint (proves cluster is reachable)
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/schema",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/schema",
|
||||||
}
|
}
|
||||||
|
|
||||||
body, status, err := req.Do(ctx)
|
body, status, err := req.Do(ctx)
|
||||||
@ -37,7 +38,7 @@ func TestRQLite_ClusterHealth(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: RQLite schema endpoint returned %d: %s", status, string(body))
|
require.Equal(t, http.StatusOK, status, "FAIL: RQLite schema endpoint returned %d: %s", status, string(body))
|
||||||
|
|
||||||
var schemaResp map[string]interface{}
|
var schemaResp map[string]interface{}
|
||||||
err = DecodeJSON(body, &schemaResp)
|
err = e2e.DecodeJSON(body, &schemaResp)
|
||||||
require.NoError(t, err, "FAIL: Could not decode RQLite schema response")
|
require.NoError(t, err, "FAIL: Could not decode RQLite schema response")
|
||||||
|
|
||||||
// Schema endpoint should return tables array
|
// Schema endpoint should return tables array
|
||||||
@ -49,27 +50,27 @@ func TestRQLite_ClusterHealth(t *testing.T) {
|
|||||||
|
|
||||||
// TestRQLite_WriteReadConsistency verifies data written can be read back consistently.
|
// TestRQLite_WriteReadConsistency verifies data written can be read back consistently.
|
||||||
func TestRQLite_WriteReadConsistency(t *testing.T) {
|
func TestRQLite_WriteReadConsistency(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
table := GenerateTableName()
|
table := e2e.GenerateTableName()
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
defer func() {
|
defer func() {
|
||||||
dropReq := &HTTPRequest{
|
dropReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/drop-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/drop-table",
|
||||||
Body: map[string]interface{}{"table": table},
|
Body: map[string]interface{}{"table": table},
|
||||||
}
|
}
|
||||||
dropReq.Do(context.Background())
|
dropReq.Do(context.Background())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Create table
|
// Create table
|
||||||
createReq := &HTTPRequest{
|
createReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/create-table",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"schema": fmt.Sprintf(
|
"schema": fmt.Sprintf(
|
||||||
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, value TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP)",
|
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, value TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP)",
|
||||||
@ -88,9 +89,9 @@ func TestRQLite_WriteReadConsistency(t *testing.T) {
|
|||||||
uniqueValue := fmt.Sprintf("test_value_%d", time.Now().UnixNano())
|
uniqueValue := fmt.Sprintf("test_value_%d", time.Now().UnixNano())
|
||||||
|
|
||||||
// Insert
|
// Insert
|
||||||
insertReq := &HTTPRequest{
|
insertReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/transaction",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"statements": []string{
|
"statements": []string{
|
||||||
fmt.Sprintf("INSERT INTO %s (value) VALUES ('%s')", table, uniqueValue),
|
fmt.Sprintf("INSERT INTO %s (value) VALUES ('%s')", table, uniqueValue),
|
||||||
@ -103,9 +104,9 @@ func TestRQLite_WriteReadConsistency(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Insert returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Insert returned status %d", status)
|
||||||
|
|
||||||
// Read back
|
// Read back
|
||||||
queryReq := &HTTPRequest{
|
queryReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/query",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/query",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"sql": fmt.Sprintf("SELECT value FROM %s WHERE value = '%s'", table, uniqueValue),
|
"sql": fmt.Sprintf("SELECT value FROM %s WHERE value = '%s'", table, uniqueValue),
|
||||||
},
|
},
|
||||||
@ -116,7 +117,7 @@ func TestRQLite_WriteReadConsistency(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Query returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Query returned status %d", status)
|
||||||
|
|
||||||
var queryResp map[string]interface{}
|
var queryResp map[string]interface{}
|
||||||
err = DecodeJSON(body, &queryResp)
|
err = e2e.DecodeJSON(body, &queryResp)
|
||||||
require.NoError(t, err, "FAIL: Could not decode query response")
|
require.NoError(t, err, "FAIL: Could not decode query response")
|
||||||
|
|
||||||
// Verify we got our value back
|
// Verify we got our value back
|
||||||
@ -135,9 +136,9 @@ func TestRQLite_WriteReadConsistency(t *testing.T) {
|
|||||||
fmt.Sprintf("INSERT INTO %s (value) VALUES ('batch_%d')", table, i))
|
fmt.Sprintf("INSERT INTO %s (value) VALUES ('batch_%d')", table, i))
|
||||||
}
|
}
|
||||||
|
|
||||||
insertReq := &HTTPRequest{
|
insertReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/transaction",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"statements": statements,
|
"statements": statements,
|
||||||
},
|
},
|
||||||
@ -148,9 +149,9 @@ func TestRQLite_WriteReadConsistency(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Batch insert returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Batch insert returned status %d", status)
|
||||||
|
|
||||||
// Count all batch rows
|
// Count all batch rows
|
||||||
queryReq := &HTTPRequest{
|
queryReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/query",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/query",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"sql": fmt.Sprintf("SELECT COUNT(*) as cnt FROM %s WHERE value LIKE 'batch_%%'", table),
|
"sql": fmt.Sprintf("SELECT COUNT(*) as cnt FROM %s WHERE value LIKE 'batch_%%'", table),
|
||||||
},
|
},
|
||||||
@ -161,7 +162,7 @@ func TestRQLite_WriteReadConsistency(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Count query returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Count query returned status %d", status)
|
||||||
|
|
||||||
var queryResp map[string]interface{}
|
var queryResp map[string]interface{}
|
||||||
DecodeJSON(body, &queryResp)
|
e2e.DecodeJSON(body, &queryResp)
|
||||||
|
|
||||||
if rows, ok := queryResp["rows"].([]interface{}); ok && len(rows) > 0 {
|
if rows, ok := queryResp["rows"].([]interface{}); ok && len(rows) > 0 {
|
||||||
row := rows[0].([]interface{})
|
row := rows[0].([]interface{})
|
||||||
@ -175,27 +176,27 @@ func TestRQLite_WriteReadConsistency(t *testing.T) {
|
|||||||
|
|
||||||
// TestRQLite_TransactionAtomicity verifies transactions are atomic.
|
// TestRQLite_TransactionAtomicity verifies transactions are atomic.
|
||||||
func TestRQLite_TransactionAtomicity(t *testing.T) {
|
func TestRQLite_TransactionAtomicity(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
table := GenerateTableName()
|
table := e2e.GenerateTableName()
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
defer func() {
|
defer func() {
|
||||||
dropReq := &HTTPRequest{
|
dropReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/drop-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/drop-table",
|
||||||
Body: map[string]interface{}{"table": table},
|
Body: map[string]interface{}{"table": table},
|
||||||
}
|
}
|
||||||
dropReq.Do(context.Background())
|
dropReq.Do(context.Background())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Create table
|
// Create table
|
||||||
createReq := &HTTPRequest{
|
createReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/create-table",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"schema": fmt.Sprintf(
|
"schema": fmt.Sprintf(
|
||||||
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, value TEXT UNIQUE)",
|
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, value TEXT UNIQUE)",
|
||||||
@ -210,9 +211,9 @@ func TestRQLite_TransactionAtomicity(t *testing.T) {
|
|||||||
"FAIL: Create table returned status %d", status)
|
"FAIL: Create table returned status %d", status)
|
||||||
|
|
||||||
t.Run("Successful_transaction_commits_all", func(t *testing.T) {
|
t.Run("Successful_transaction_commits_all", func(t *testing.T) {
|
||||||
txReq := &HTTPRequest{
|
txReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/transaction",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"statements": []string{
|
"statements": []string{
|
||||||
fmt.Sprintf("INSERT INTO %s (value) VALUES ('tx_val_1')", table),
|
fmt.Sprintf("INSERT INTO %s (value) VALUES ('tx_val_1')", table),
|
||||||
@ -227,9 +228,9 @@ func TestRQLite_TransactionAtomicity(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Transaction returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Transaction returned status %d", status)
|
||||||
|
|
||||||
// Verify all 3 rows exist
|
// Verify all 3 rows exist
|
||||||
queryReq := &HTTPRequest{
|
queryReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/query",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/query",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"sql": fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE value LIKE 'tx_val_%%'", table),
|
"sql": fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE value LIKE 'tx_val_%%'", table),
|
||||||
},
|
},
|
||||||
@ -237,7 +238,7 @@ func TestRQLite_TransactionAtomicity(t *testing.T) {
|
|||||||
|
|
||||||
body, _, _ := queryReq.Do(ctx)
|
body, _, _ := queryReq.Do(ctx)
|
||||||
var queryResp map[string]interface{}
|
var queryResp map[string]interface{}
|
||||||
DecodeJSON(body, &queryResp)
|
e2e.DecodeJSON(body, &queryResp)
|
||||||
|
|
||||||
if rows, ok := queryResp["rows"].([]interface{}); ok && len(rows) > 0 {
|
if rows, ok := queryResp["rows"].([]interface{}); ok && len(rows) > 0 {
|
||||||
row := rows[0].([]interface{})
|
row := rows[0].([]interface{})
|
||||||
@ -250,9 +251,9 @@ func TestRQLite_TransactionAtomicity(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Updates_preserve_consistency", func(t *testing.T) {
|
t.Run("Updates_preserve_consistency", func(t *testing.T) {
|
||||||
// Update a value
|
// Update a value
|
||||||
updateReq := &HTTPRequest{
|
updateReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/transaction",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"statements": []string{
|
"statements": []string{
|
||||||
fmt.Sprintf("UPDATE %s SET value = 'tx_val_1_updated' WHERE value = 'tx_val_1'", table),
|
fmt.Sprintf("UPDATE %s SET value = 'tx_val_1_updated' WHERE value = 'tx_val_1'", table),
|
||||||
@ -265,9 +266,9 @@ func TestRQLite_TransactionAtomicity(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Update returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Update returned status %d", status)
|
||||||
|
|
||||||
// Verify update took effect
|
// Verify update took effect
|
||||||
queryReq := &HTTPRequest{
|
queryReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/query",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/query",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"sql": fmt.Sprintf("SELECT value FROM %s WHERE value = 'tx_val_1_updated'", table),
|
"sql": fmt.Sprintf("SELECT value FROM %s WHERE value = 'tx_val_1_updated'", table),
|
||||||
},
|
},
|
||||||
@ -275,7 +276,7 @@ func TestRQLite_TransactionAtomicity(t *testing.T) {
|
|||||||
|
|
||||||
body, _, _ := queryReq.Do(ctx)
|
body, _, _ := queryReq.Do(ctx)
|
||||||
var queryResp map[string]interface{}
|
var queryResp map[string]interface{}
|
||||||
DecodeJSON(body, &queryResp)
|
e2e.DecodeJSON(body, &queryResp)
|
||||||
|
|
||||||
count, _ := queryResp["count"].(float64)
|
count, _ := queryResp["count"].(float64)
|
||||||
require.Equal(t, float64(1), count, "FAIL: Update didn't take effect")
|
require.Equal(t, float64(1), count, "FAIL: Update didn't take effect")
|
||||||
@ -286,27 +287,27 @@ func TestRQLite_TransactionAtomicity(t *testing.T) {
|
|||||||
|
|
||||||
// TestRQLite_ConcurrentWrites verifies the cluster handles concurrent writes correctly.
|
// TestRQLite_ConcurrentWrites verifies the cluster handles concurrent writes correctly.
|
||||||
func TestRQLite_ConcurrentWrites(t *testing.T) {
|
func TestRQLite_ConcurrentWrites(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
table := GenerateTableName()
|
table := e2e.GenerateTableName()
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
defer func() {
|
defer func() {
|
||||||
dropReq := &HTTPRequest{
|
dropReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/drop-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/drop-table",
|
||||||
Body: map[string]interface{}{"table": table},
|
Body: map[string]interface{}{"table": table},
|
||||||
}
|
}
|
||||||
dropReq.Do(context.Background())
|
dropReq.Do(context.Background())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Create table
|
// Create table
|
||||||
createReq := &HTTPRequest{
|
createReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/create-table",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"schema": fmt.Sprintf(
|
"schema": fmt.Sprintf(
|
||||||
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, worker INTEGER, seq INTEGER)",
|
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, worker INTEGER, seq INTEGER)",
|
||||||
@ -333,9 +334,9 @@ func TestRQLite_ConcurrentWrites(t *testing.T) {
|
|||||||
go func(workerID int) {
|
go func(workerID int) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
for i := 0; i < insertsPerWorker; i++ {
|
for i := 0; i < insertsPerWorker; i++ {
|
||||||
insertReq := &HTTPRequest{
|
insertReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/transaction",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"statements": []string{
|
"statements": []string{
|
||||||
fmt.Sprintf("INSERT INTO %s (worker, seq) VALUES (%d, %d)", table, workerID, i),
|
fmt.Sprintf("INSERT INTO %s (worker, seq) VALUES (%d, %d)", table, workerID, i),
|
||||||
@ -367,9 +368,9 @@ func TestRQLite_ConcurrentWrites(t *testing.T) {
|
|||||||
require.Empty(t, errors, "FAIL: %d concurrent inserts failed: %v", len(errors), errors)
|
require.Empty(t, errors, "FAIL: %d concurrent inserts failed: %v", len(errors), errors)
|
||||||
|
|
||||||
// Verify total count
|
// Verify total count
|
||||||
queryReq := &HTTPRequest{
|
queryReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/query",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/query",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"sql": fmt.Sprintf("SELECT COUNT(*) FROM %s", table),
|
"sql": fmt.Sprintf("SELECT COUNT(*) FROM %s", table),
|
||||||
},
|
},
|
||||||
@ -377,7 +378,7 @@ func TestRQLite_ConcurrentWrites(t *testing.T) {
|
|||||||
|
|
||||||
body, _, _ := queryReq.Do(ctx)
|
body, _, _ := queryReq.Do(ctx)
|
||||||
var queryResp map[string]interface{}
|
var queryResp map[string]interface{}
|
||||||
DecodeJSON(body, &queryResp)
|
e2e.DecodeJSON(body, &queryResp)
|
||||||
|
|
||||||
if rows, ok := queryResp["rows"].([]interface{}); ok && len(rows) > 0 {
|
if rows, ok := queryResp["rows"].([]interface{}); ok && len(rows) > 0 {
|
||||||
row := rows[0].([]interface{})
|
row := rows[0].([]interface{})
|
||||||
@ -395,7 +396,7 @@ func TestRQLite_NamespaceClusterOperations(t *testing.T) {
|
|||||||
// Create a new namespace
|
// Create a new namespace
|
||||||
namespace := fmt.Sprintf("rqlite-test-%d", time.Now().UnixNano())
|
namespace := fmt.Sprintf("rqlite-test-%d", time.Now().UnixNano())
|
||||||
|
|
||||||
env, err := LoadTestEnvWithNamespace(namespace)
|
env, err := e2e.LoadTestEnvWithNamespace(namespace)
|
||||||
require.NoError(t, err, "FAIL: Could not create namespace for RQLite test")
|
require.NoError(t, err, "FAIL: Could not create namespace for RQLite test")
|
||||||
require.NotEmpty(t, env.APIKey, "FAIL: No API key - namespace provisioning failed")
|
require.NotEmpty(t, env.APIKey, "FAIL: No API key - namespace provisioning failed")
|
||||||
|
|
||||||
@ -404,11 +405,11 @@ func TestRQLite_NamespaceClusterOperations(t *testing.T) {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
table := GenerateTableName()
|
table := e2e.GenerateTableName()
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
defer func() {
|
defer func() {
|
||||||
dropReq := &HTTPRequest{
|
dropReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: env.GatewayURL + "/v1/rqlite/drop-table",
|
URL: env.GatewayURL + "/v1/rqlite/drop-table",
|
||||||
Body: map[string]interface{}{"table": table},
|
Body: map[string]interface{}{"table": table},
|
||||||
@ -419,7 +420,7 @@ func TestRQLite_NamespaceClusterOperations(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Namespace_RQLite_create_insert_query", func(t *testing.T) {
|
t.Run("Namespace_RQLite_create_insert_query", func(t *testing.T) {
|
||||||
// Create table in namespace cluster
|
// Create table in namespace cluster
|
||||||
createReq := &HTTPRequest{
|
createReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: env.GatewayURL + "/v1/rqlite/create-table",
|
URL: env.GatewayURL + "/v1/rqlite/create-table",
|
||||||
Headers: map[string]string{"Authorization": "Bearer " + env.APIKey},
|
Headers: map[string]string{"Authorization": "Bearer " + env.APIKey},
|
||||||
@ -438,7 +439,7 @@ func TestRQLite_NamespaceClusterOperations(t *testing.T) {
|
|||||||
|
|
||||||
// Insert data
|
// Insert data
|
||||||
uniqueValue := fmt.Sprintf("ns_value_%d", time.Now().UnixNano())
|
uniqueValue := fmt.Sprintf("ns_value_%d", time.Now().UnixNano())
|
||||||
insertReq := &HTTPRequest{
|
insertReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: env.GatewayURL + "/v1/rqlite/transaction",
|
URL: env.GatewayURL + "/v1/rqlite/transaction",
|
||||||
Headers: map[string]string{"Authorization": "Bearer " + env.APIKey},
|
Headers: map[string]string{"Authorization": "Bearer " + env.APIKey},
|
||||||
@ -454,7 +455,7 @@ func TestRQLite_NamespaceClusterOperations(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Insert returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Insert returned status %d", status)
|
||||||
|
|
||||||
// Query data
|
// Query data
|
||||||
queryReq := &HTTPRequest{
|
queryReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: env.GatewayURL + "/v1/rqlite/query",
|
URL: env.GatewayURL + "/v1/rqlite/query",
|
||||||
Headers: map[string]string{"Authorization": "Bearer " + env.APIKey},
|
Headers: map[string]string{"Authorization": "Bearer " + env.APIKey},
|
||||||
@ -468,7 +469,7 @@ func TestRQLite_NamespaceClusterOperations(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Query returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Query returned status %d", status)
|
||||||
|
|
||||||
var queryResp map[string]interface{}
|
var queryResp map[string]interface{}
|
||||||
DecodeJSON(body, &queryResp)
|
e2e.DecodeJSON(body, &queryResp)
|
||||||
|
|
||||||
count, _ := queryResp["count"].(float64)
|
count, _ := queryResp["count"].(float64)
|
||||||
require.Equal(t, float64(1), count, "FAIL: Data not found in namespace cluster")
|
require.Equal(t, float64(1), count, "FAIL: Data not found in namespace cluster")
|
||||||
75
e2e/env.go
75
e2e/env.go
@ -1536,6 +1536,81 @@ func TestDeploymentWithHostHeader(t *testing.T, env *E2ETestEnv, host, path stri
|
|||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PutToOlric stores a key-value pair in Olric via the gateway HTTP API
|
||||||
|
func PutToOlric(gatewayURL, apiKey, dmap, key, value string) error {
|
||||||
|
reqBody := map[string]interface{}{
|
||||||
|
"dmap": dmap,
|
||||||
|
"key": key,
|
||||||
|
"value": value,
|
||||||
|
}
|
||||||
|
bodyBytes, _ := json.Marshal(reqBody)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", gatewayURL+"/v1/cache/put", strings.NewReader(string(bodyBytes)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
|
|
||||||
|
client := &http.Client{Timeout: 10 * time.Second}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
return fmt.Errorf("put failed with status %d: %s", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFromOlric retrieves a value from Olric via the gateway HTTP API
|
||||||
|
func GetFromOlric(gatewayURL, apiKey, dmap, key string) (string, error) {
|
||||||
|
reqBody := map[string]interface{}{
|
||||||
|
"dmap": dmap,
|
||||||
|
"key": key,
|
||||||
|
}
|
||||||
|
bodyBytes, _ := json.Marshal(reqBody)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", gatewayURL+"/v1/cache/get", strings.NewReader(string(bodyBytes)))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
|
|
||||||
|
client := &http.Client{Timeout: 10 * time.Second}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusNotFound {
|
||||||
|
return "", fmt.Errorf("key not found")
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
return "", fmt.Errorf("get failed with status %d: %s", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
var result map[string]interface{}
|
||||||
|
if err := json.Unmarshal(body, &result); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if value, ok := result["value"].(string); ok {
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
if value, ok := result["value"]; ok {
|
||||||
|
return fmt.Sprintf("%v", value), nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("value not found in response")
|
||||||
|
}
|
||||||
|
|
||||||
// WaitForHealthy waits for a deployment to become healthy
|
// WaitForHealthy waits for a deployment to become healthy
|
||||||
func WaitForHealthy(t *testing.T, env *E2ETestEnv, deploymentID string, timeout time.Duration) bool {
|
func WaitForHealthy(t *testing.T, env *E2ETestEnv, deploymentID string, timeout time.Duration) bool {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package integration_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -10,16 +10,18 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/DeBrosOfficial/network/e2e"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestCache_ConcurrentWrites tests concurrent cache writes
|
// TestCache_ConcurrentWrites tests concurrent cache writes
|
||||||
func TestCache_ConcurrentWrites(t *testing.T) {
|
func TestCache_ConcurrentWrites(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
dmap := GenerateDMapName()
|
dmap := e2e.GenerateDMapName()
|
||||||
numGoroutines := 10
|
numGoroutines := 10
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
var errorCount int32
|
var errorCount int32
|
||||||
@ -32,9 +34,9 @@ func TestCache_ConcurrentWrites(t *testing.T) {
|
|||||||
key := fmt.Sprintf("key-%d", idx)
|
key := fmt.Sprintf("key-%d", idx)
|
||||||
value := fmt.Sprintf("value-%d", idx)
|
value := fmt.Sprintf("value-%d", idx)
|
||||||
|
|
||||||
putReq := &HTTPRequest{
|
putReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/put",
|
URL: e2e.GetGatewayURL() + "/v1/cache/put",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -56,9 +58,9 @@ func TestCache_ConcurrentWrites(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify all values exist
|
// Verify all values exist
|
||||||
scanReq := &HTTPRequest{
|
scanReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/scan",
|
URL: e2e.GetGatewayURL() + "/v1/cache/scan",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
},
|
},
|
||||||
@ -70,7 +72,7 @@ func TestCache_ConcurrentWrites(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var scanResp map[string]interface{}
|
var scanResp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &scanResp); err != nil {
|
if err := e2e.DecodeJSON(body, &scanResp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,19 +84,19 @@ func TestCache_ConcurrentWrites(t *testing.T) {
|
|||||||
|
|
||||||
// TestCache_ConcurrentReads tests concurrent cache reads
|
// TestCache_ConcurrentReads tests concurrent cache reads
|
||||||
func TestCache_ConcurrentReads(t *testing.T) {
|
func TestCache_ConcurrentReads(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
dmap := GenerateDMapName()
|
dmap := e2e.GenerateDMapName()
|
||||||
key := "shared-key"
|
key := "shared-key"
|
||||||
value := "shared-value"
|
value := "shared-value"
|
||||||
|
|
||||||
// Put value first
|
// Put value first
|
||||||
putReq := &HTTPRequest{
|
putReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/put",
|
URL: e2e.GetGatewayURL() + "/v1/cache/put",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -117,9 +119,9 @@ func TestCache_ConcurrentReads(t *testing.T) {
|
|||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
getReq := &HTTPRequest{
|
getReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/get",
|
URL: e2e.GetGatewayURL() + "/v1/cache/get",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -133,7 +135,7 @@ func TestCache_ConcurrentReads(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var getResp map[string]interface{}
|
var getResp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &getResp); err != nil {
|
if err := e2e.DecodeJSON(body, &getResp); err != nil {
|
||||||
atomic.AddInt32(&errorCount, 1)
|
atomic.AddInt32(&errorCount, 1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -153,12 +155,12 @@ func TestCache_ConcurrentReads(t *testing.T) {
|
|||||||
|
|
||||||
// TestCache_ConcurrentDeleteAndWrite tests concurrent delete and write
|
// TestCache_ConcurrentDeleteAndWrite tests concurrent delete and write
|
||||||
func TestCache_ConcurrentDeleteAndWrite(t *testing.T) {
|
func TestCache_ConcurrentDeleteAndWrite(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
dmap := GenerateDMapName()
|
dmap := e2e.GenerateDMapName()
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
var errorCount int32
|
var errorCount int32
|
||||||
|
|
||||||
@ -174,9 +176,9 @@ func TestCache_ConcurrentDeleteAndWrite(t *testing.T) {
|
|||||||
key := fmt.Sprintf("key-%d", idx)
|
key := fmt.Sprintf("key-%d", idx)
|
||||||
value := fmt.Sprintf("value-%d", idx)
|
value := fmt.Sprintf("value-%d", idx)
|
||||||
|
|
||||||
putReq := &HTTPRequest{
|
putReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/put",
|
URL: e2e.GetGatewayURL() + "/v1/cache/put",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -201,9 +203,9 @@ func TestCache_ConcurrentDeleteAndWrite(t *testing.T) {
|
|||||||
|
|
||||||
key := fmt.Sprintf("key-%d", idx)
|
key := fmt.Sprintf("key-%d", idx)
|
||||||
|
|
||||||
deleteReq := &HTTPRequest{
|
deleteReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/delete",
|
URL: e2e.GetGatewayURL() + "/v1/cache/delete",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -226,18 +228,18 @@ func TestCache_ConcurrentDeleteAndWrite(t *testing.T) {
|
|||||||
|
|
||||||
// TestRQLite_ConcurrentInserts tests concurrent database inserts
|
// TestRQLite_ConcurrentInserts tests concurrent database inserts
|
||||||
func TestRQLite_ConcurrentInserts(t *testing.T) {
|
func TestRQLite_ConcurrentInserts(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
table := GenerateTableName()
|
table := e2e.GenerateTableName()
|
||||||
|
|
||||||
// Cleanup table after test
|
// Cleanup table after test
|
||||||
defer func() {
|
defer func() {
|
||||||
dropReq := &HTTPRequest{
|
dropReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/drop-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/drop-table",
|
||||||
Body: map[string]interface{}{"table": table},
|
Body: map[string]interface{}{"table": table},
|
||||||
}
|
}
|
||||||
dropReq.Do(context.Background())
|
dropReq.Do(context.Background())
|
||||||
@ -249,9 +251,9 @@ func TestRQLite_ConcurrentInserts(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Create table
|
// Create table
|
||||||
createReq := &HTTPRequest{
|
createReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/create-table",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"schema": schema,
|
"schema": schema,
|
||||||
},
|
},
|
||||||
@ -272,9 +274,9 @@ func TestRQLite_ConcurrentInserts(t *testing.T) {
|
|||||||
go func(idx int) {
|
go func(idx int) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
txReq := &HTTPRequest{
|
txReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/transaction",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"statements": []string{
|
"statements": []string{
|
||||||
fmt.Sprintf("INSERT INTO %s(value) VALUES (%d)", table, idx),
|
fmt.Sprintf("INSERT INTO %s(value) VALUES (%d)", table, idx),
|
||||||
@ -296,9 +298,9 @@ func TestRQLite_ConcurrentInserts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify count
|
// Verify count
|
||||||
queryReq := &HTTPRequest{
|
queryReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/query",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/query",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"sql": fmt.Sprintf("SELECT COUNT(*) as count FROM %s", table),
|
"sql": fmt.Sprintf("SELECT COUNT(*) as count FROM %s", table),
|
||||||
},
|
},
|
||||||
@ -310,7 +312,7 @@ func TestRQLite_ConcurrentInserts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var countResp map[string]interface{}
|
var countResp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &countResp); err != nil {
|
if err := e2e.DecodeJSON(body, &countResp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,18 +327,18 @@ func TestRQLite_ConcurrentInserts(t *testing.T) {
|
|||||||
|
|
||||||
// TestRQLite_LargeBatchTransaction tests a large transaction with many statements
|
// TestRQLite_LargeBatchTransaction tests a large transaction with many statements
|
||||||
func TestRQLite_LargeBatchTransaction(t *testing.T) {
|
func TestRQLite_LargeBatchTransaction(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
table := GenerateTableName()
|
table := e2e.GenerateTableName()
|
||||||
|
|
||||||
// Cleanup table after test
|
// Cleanup table after test
|
||||||
defer func() {
|
defer func() {
|
||||||
dropReq := &HTTPRequest{
|
dropReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/drop-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/drop-table",
|
||||||
Body: map[string]interface{}{"table": table},
|
Body: map[string]interface{}{"table": table},
|
||||||
}
|
}
|
||||||
dropReq.Do(context.Background())
|
dropReq.Do(context.Background())
|
||||||
@ -348,9 +350,9 @@ func TestRQLite_LargeBatchTransaction(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Create table
|
// Create table
|
||||||
createReq := &HTTPRequest{
|
createReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/create-table",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"schema": schema,
|
"schema": schema,
|
||||||
},
|
},
|
||||||
@ -370,9 +372,9 @@ func TestRQLite_LargeBatchTransaction(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
txReq := &HTTPRequest{
|
txReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/transaction",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"ops": ops,
|
"ops": ops,
|
||||||
},
|
},
|
||||||
@ -384,9 +386,9 @@ func TestRQLite_LargeBatchTransaction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify count
|
// Verify count
|
||||||
queryReq := &HTTPRequest{
|
queryReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/query",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/query",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"sql": fmt.Sprintf("SELECT COUNT(*) as count FROM %s", table),
|
"sql": fmt.Sprintf("SELECT COUNT(*) as count FROM %s", table),
|
||||||
},
|
},
|
||||||
@ -398,7 +400,7 @@ func TestRQLite_LargeBatchTransaction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var countResp map[string]interface{}
|
var countResp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &countResp); err != nil {
|
if err := e2e.DecodeJSON(body, &countResp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,19 +414,19 @@ func TestRQLite_LargeBatchTransaction(t *testing.T) {
|
|||||||
|
|
||||||
// TestCache_TTLExpiryWithSleep tests TTL expiry with a controlled sleep
|
// TestCache_TTLExpiryWithSleep tests TTL expiry with a controlled sleep
|
||||||
func TestCache_TTLExpiryWithSleep(t *testing.T) {
|
func TestCache_TTLExpiryWithSleep(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
dmap := GenerateDMapName()
|
dmap := e2e.GenerateDMapName()
|
||||||
key := "ttl-expiry-key"
|
key := "ttl-expiry-key"
|
||||||
value := "ttl-expiry-value"
|
value := "ttl-expiry-value"
|
||||||
|
|
||||||
// Put value with 2 second TTL
|
// Put value with 2 second TTL
|
||||||
putReq := &HTTPRequest{
|
putReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/put",
|
URL: e2e.GetGatewayURL() + "/v1/cache/put",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -439,9 +441,9 @@ func TestCache_TTLExpiryWithSleep(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify exists immediately
|
// Verify exists immediately
|
||||||
getReq := &HTTPRequest{
|
getReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/get",
|
URL: e2e.GetGatewayURL() + "/v1/cache/get",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -454,7 +456,7 @@ func TestCache_TTLExpiryWithSleep(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sleep for TTL duration + buffer
|
// Sleep for TTL duration + buffer
|
||||||
Delay(2500)
|
e2e.Delay(2500)
|
||||||
|
|
||||||
// Try to get after TTL expires
|
// Try to get after TTL expires
|
||||||
_, status, err = getReq.Do(ctx)
|
_, status, err = getReq.Do(ctx)
|
||||||
@ -465,21 +467,21 @@ func TestCache_TTLExpiryWithSleep(t *testing.T) {
|
|||||||
|
|
||||||
// TestCache_ConcurrentWriteAndDelete tests concurrent writes and deletes on same key
|
// TestCache_ConcurrentWriteAndDelete tests concurrent writes and deletes on same key
|
||||||
func TestCache_ConcurrentWriteAndDelete(t *testing.T) {
|
func TestCache_ConcurrentWriteAndDelete(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
dmap := GenerateDMapName()
|
dmap := e2e.GenerateDMapName()
|
||||||
key := "contested-key"
|
key := "contested-key"
|
||||||
|
|
||||||
// Alternate between writes and deletes
|
// Alternate between writes and deletes
|
||||||
numIterations := 5
|
numIterations := 5
|
||||||
for i := 0; i < numIterations; i++ {
|
for i := 0; i < numIterations; i++ {
|
||||||
// Write
|
// Write
|
||||||
putReq := &HTTPRequest{
|
putReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/put",
|
URL: e2e.GetGatewayURL() + "/v1/cache/put",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -493,9 +495,9 @@ func TestCache_ConcurrentWriteAndDelete(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read
|
// Read
|
||||||
getReq := &HTTPRequest{
|
getReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/get",
|
URL: e2e.GetGatewayURL() + "/v1/cache/get",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -508,9 +510,9 @@ func TestCache_ConcurrentWriteAndDelete(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
deleteReq := &HTTPRequest{
|
deleteReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/delete",
|
URL: e2e.GetGatewayURL() + "/v1/cache/delete",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package integration_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -12,6 +12,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/DeBrosOfficial/network/e2e"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ import (
|
|||||||
|
|
||||||
// TestRQLite_DataPersistence verifies that RQLite data is persisted through the gateway.
|
// TestRQLite_DataPersistence verifies that RQLite data is persisted through the gateway.
|
||||||
func TestRQLite_DataPersistence(t *testing.T) {
|
func TestRQLite_DataPersistence(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -32,18 +33,18 @@ func TestRQLite_DataPersistence(t *testing.T) {
|
|||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
defer func() {
|
defer func() {
|
||||||
dropReq := &HTTPRequest{
|
dropReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/drop-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/drop-table",
|
||||||
Body: map[string]interface{}{"table": tableName},
|
Body: map[string]interface{}{"table": tableName},
|
||||||
}
|
}
|
||||||
dropReq.Do(context.Background())
|
dropReq.Do(context.Background())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Create table
|
// Create table
|
||||||
createReq := &HTTPRequest{
|
createReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/create-table",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"schema": fmt.Sprintf(
|
"schema": fmt.Sprintf(
|
||||||
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, value TEXT, version INTEGER)",
|
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, value TEXT, version INTEGER)",
|
||||||
@ -65,9 +66,9 @@ func TestRQLite_DataPersistence(t *testing.T) {
|
|||||||
fmt.Sprintf("INSERT INTO %s (value, version) VALUES ('item_%d', %d)", tableName, i, i))
|
fmt.Sprintf("INSERT INTO %s (value, version) VALUES ('item_%d', %d)", tableName, i, i))
|
||||||
}
|
}
|
||||||
|
|
||||||
insertReq := &HTTPRequest{
|
insertReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/transaction",
|
||||||
Body: map[string]interface{}{"statements": statements},
|
Body: map[string]interface{}{"statements": statements},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,9 +77,9 @@ func TestRQLite_DataPersistence(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Insert returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Insert returned status %d", status)
|
||||||
|
|
||||||
// Verify all data exists
|
// Verify all data exists
|
||||||
queryReq := &HTTPRequest{
|
queryReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/query",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/query",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"sql": fmt.Sprintf("SELECT COUNT(*) FROM %s", tableName),
|
"sql": fmt.Sprintf("SELECT COUNT(*) FROM %s", tableName),
|
||||||
},
|
},
|
||||||
@ -89,7 +90,7 @@ func TestRQLite_DataPersistence(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Count query returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Count query returned status %d", status)
|
||||||
|
|
||||||
var queryResp map[string]interface{}
|
var queryResp map[string]interface{}
|
||||||
DecodeJSON(body, &queryResp)
|
e2e.DecodeJSON(body, &queryResp)
|
||||||
|
|
||||||
if rows, ok := queryResp["rows"].([]interface{}); ok && len(rows) > 0 {
|
if rows, ok := queryResp["rows"].([]interface{}); ok && len(rows) > 0 {
|
||||||
row := rows[0].([]interface{})
|
row := rows[0].([]interface{})
|
||||||
@ -98,9 +99,9 @@ func TestRQLite_DataPersistence(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update data
|
// Update data
|
||||||
updateReq := &HTTPRequest{
|
updateReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/transaction",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"statements": []string{
|
"statements": []string{
|
||||||
fmt.Sprintf("UPDATE %s SET version = version + 100 WHERE version <= 5", tableName),
|
fmt.Sprintf("UPDATE %s SET version = version + 100 WHERE version <= 5", tableName),
|
||||||
@ -113,9 +114,9 @@ func TestRQLite_DataPersistence(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Update returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Update returned status %d", status)
|
||||||
|
|
||||||
// Verify updates persisted
|
// Verify updates persisted
|
||||||
queryUpdatedReq := &HTTPRequest{
|
queryUpdatedReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/query",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/query",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"sql": fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE version > 100", tableName),
|
"sql": fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE version > 100", tableName),
|
||||||
},
|
},
|
||||||
@ -125,7 +126,7 @@ func TestRQLite_DataPersistence(t *testing.T) {
|
|||||||
require.NoError(t, err, "FAIL: Could not count updated rows")
|
require.NoError(t, err, "FAIL: Could not count updated rows")
|
||||||
require.Equal(t, http.StatusOK, status, "FAIL: Count updated query returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Count updated query returned status %d", status)
|
||||||
|
|
||||||
DecodeJSON(body, &queryResp)
|
e2e.DecodeJSON(body, &queryResp)
|
||||||
if rows, ok := queryResp["rows"].([]interface{}); ok && len(rows) > 0 {
|
if rows, ok := queryResp["rows"].([]interface{}); ok && len(rows) > 0 {
|
||||||
row := rows[0].([]interface{})
|
row := rows[0].([]interface{})
|
||||||
count := int(row[0].(float64))
|
count := int(row[0].(float64))
|
||||||
@ -137,9 +138,9 @@ func TestRQLite_DataPersistence(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Deletes_are_persisted", func(t *testing.T) {
|
t.Run("Deletes_are_persisted", func(t *testing.T) {
|
||||||
// Delete some rows
|
// Delete some rows
|
||||||
deleteReq := &HTTPRequest{
|
deleteReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/transaction",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"statements": []string{
|
"statements": []string{
|
||||||
fmt.Sprintf("DELETE FROM %s WHERE version > 100", tableName),
|
fmt.Sprintf("DELETE FROM %s WHERE version > 100", tableName),
|
||||||
@ -152,9 +153,9 @@ func TestRQLite_DataPersistence(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Delete returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Delete returned status %d", status)
|
||||||
|
|
||||||
// Verify deletes persisted
|
// Verify deletes persisted
|
||||||
queryReq := &HTTPRequest{
|
queryReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/query",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/query",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"sql": fmt.Sprintf("SELECT COUNT(*) FROM %s", tableName),
|
"sql": fmt.Sprintf("SELECT COUNT(*) FROM %s", tableName),
|
||||||
},
|
},
|
||||||
@ -165,7 +166,7 @@ func TestRQLite_DataPersistence(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Count query returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Count query returned status %d", status)
|
||||||
|
|
||||||
var queryResp map[string]interface{}
|
var queryResp map[string]interface{}
|
||||||
DecodeJSON(body, &queryResp)
|
e2e.DecodeJSON(body, &queryResp)
|
||||||
|
|
||||||
if rows, ok := queryResp["rows"].([]interface{}); ok && len(rows) > 0 {
|
if rows, ok := queryResp["rows"].([]interface{}); ok && len(rows) > 0 {
|
||||||
row := rows[0].([]interface{})
|
row := rows[0].([]interface{})
|
||||||
@ -213,7 +214,7 @@ func TestRQLite_DataFilesExist(t *testing.T) {
|
|||||||
// TestOlric_DataPersistence verifies Olric cache data persistence.
|
// TestOlric_DataPersistence verifies Olric cache data persistence.
|
||||||
// Note: Olric is an in-memory cache, so this tests data survival during runtime.
|
// Note: Olric is an in-memory cache, so this tests data survival during runtime.
|
||||||
func TestOlric_DataPersistence(t *testing.T) {
|
func TestOlric_DataPersistence(t *testing.T) {
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "FAIL: Could not load test environment")
|
require.NoError(t, err, "FAIL: Could not load test environment")
|
||||||
|
|
||||||
dmap := fmt.Sprintf("persist_cache_%d", time.Now().UnixNano())
|
dmap := fmt.Sprintf("persist_cache_%d", time.Now().UnixNano())
|
||||||
@ -226,17 +227,17 @@ func TestOlric_DataPersistence(t *testing.T) {
|
|||||||
value := fmt.Sprintf("persist_value_%d", i)
|
value := fmt.Sprintf("persist_value_%d", i)
|
||||||
keys[key] = value
|
keys[key] = value
|
||||||
|
|
||||||
err := putToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
err := e2e.PutToOlric(env.GatewayURL, env.APIKey, dmap, key, value)
|
||||||
require.NoError(t, err, "FAIL: Could not put key %s", key)
|
require.NoError(t, err, "FAIL: Could not put key %s", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform other operations
|
// Perform other operations
|
||||||
err := putToOlric(env.GatewayURL, env.APIKey, dmap, "other_key", "other_value")
|
err := e2e.PutToOlric(env.GatewayURL, env.APIKey, dmap, "other_key", "other_value")
|
||||||
require.NoError(t, err, "FAIL: Could not put other key")
|
require.NoError(t, err, "FAIL: Could not put other key")
|
||||||
|
|
||||||
// Verify original keys still exist
|
// Verify original keys still exist
|
||||||
for key, expectedValue := range keys {
|
for key, expectedValue := range keys {
|
||||||
retrieved, err := getFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
retrieved, err := e2e.GetFromOlric(env.GatewayURL, env.APIKey, dmap, key)
|
||||||
require.NoError(t, err, "FAIL: Key %s not found after other operations", key)
|
require.NoError(t, err, "FAIL: Key %s not found after other operations", key)
|
||||||
require.Equal(t, expectedValue, retrieved, "FAIL: Value mismatch for key %s", key)
|
require.Equal(t, expectedValue, retrieved, "FAIL: Value mismatch for key %s", key)
|
||||||
}
|
}
|
||||||
@ -249,7 +250,7 @@ func TestOlric_DataPersistence(t *testing.T) {
|
|||||||
func TestNamespaceCluster_DataPersistence(t *testing.T) {
|
func TestNamespaceCluster_DataPersistence(t *testing.T) {
|
||||||
// Create namespace
|
// Create namespace
|
||||||
namespace := fmt.Sprintf("persist-ns-%d", time.Now().UnixNano())
|
namespace := fmt.Sprintf("persist-ns-%d", time.Now().UnixNano())
|
||||||
env, err := LoadTestEnvWithNamespace(namespace)
|
env, err := e2e.LoadTestEnvWithNamespace(namespace)
|
||||||
require.NoError(t, err, "FAIL: Could not create namespace")
|
require.NoError(t, err, "FAIL: Could not create namespace")
|
||||||
|
|
||||||
t.Logf("Created namespace: %s", namespace)
|
t.Logf("Created namespace: %s", namespace)
|
||||||
@ -261,7 +262,7 @@ func TestNamespaceCluster_DataPersistence(t *testing.T) {
|
|||||||
// Create data via gateway API
|
// Create data via gateway API
|
||||||
tableName := fmt.Sprintf("ns_data_%d", time.Now().UnixNano())
|
tableName := fmt.Sprintf("ns_data_%d", time.Now().UnixNano())
|
||||||
|
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: env.GatewayURL + "/v1/rqlite/create-table",
|
URL: env.GatewayURL + "/v1/rqlite/create-table",
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
@ -278,7 +279,7 @@ func TestNamespaceCluster_DataPersistence(t *testing.T) {
|
|||||||
"FAIL: Create table returned status %d", status)
|
"FAIL: Create table returned status %d", status)
|
||||||
|
|
||||||
// Insert data
|
// Insert data
|
||||||
insertReq := &HTTPRequest{
|
insertReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: env.GatewayURL + "/v1/rqlite/transaction",
|
URL: env.GatewayURL + "/v1/rqlite/transaction",
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
@ -296,7 +297,7 @@ func TestNamespaceCluster_DataPersistence(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Insert returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Insert returned status %d", status)
|
||||||
|
|
||||||
// Verify data exists
|
// Verify data exists
|
||||||
queryReq := &HTTPRequest{
|
queryReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: env.GatewayURL + "/v1/rqlite/query",
|
URL: env.GatewayURL + "/v1/rqlite/query",
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
@ -323,7 +324,7 @@ func TestNamespaceCluster_DataPersistence(t *testing.T) {
|
|||||||
// TestIPFS_DataPersistence verifies IPFS content is persisted and pinned.
|
// TestIPFS_DataPersistence verifies IPFS content is persisted and pinned.
|
||||||
// Note: Detailed IPFS tests are in storage_http_test.go. This test uses the helper from env.go.
|
// Note: Detailed IPFS tests are in storage_http_test.go. This test uses the helper from env.go.
|
||||||
func TestIPFS_DataPersistence(t *testing.T) {
|
func TestIPFS_DataPersistence(t *testing.T) {
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "FAIL: Could not load test environment")
|
require.NoError(t, err, "FAIL: Could not load test environment")
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
@ -332,12 +333,12 @@ func TestIPFS_DataPersistence(t *testing.T) {
|
|||||||
t.Run("Uploaded_content_persists", func(t *testing.T) {
|
t.Run("Uploaded_content_persists", func(t *testing.T) {
|
||||||
// Use helper function to upload content via multipart form
|
// Use helper function to upload content via multipart form
|
||||||
content := fmt.Sprintf("persistent content %d", time.Now().UnixNano())
|
content := fmt.Sprintf("persistent content %d", time.Now().UnixNano())
|
||||||
cid := UploadTestFile(t, env, "persist_test.txt", content)
|
cid := e2e.UploadTestFile(t, env, "persist_test.txt", content)
|
||||||
require.NotEmpty(t, cid, "FAIL: No CID returned from upload")
|
require.NotEmpty(t, cid, "FAIL: No CID returned from upload")
|
||||||
t.Logf(" Uploaded content with CID: %s", cid)
|
t.Logf(" Uploaded content with CID: %s", cid)
|
||||||
|
|
||||||
// Verify content can be retrieved
|
// Verify content can be retrieved
|
||||||
getReq := &HTTPRequest{
|
getReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: env.GatewayURL + "/v1/storage/get/" + cid,
|
URL: env.GatewayURL + "/v1/storage/get/" + cid,
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
@ -357,7 +358,7 @@ func TestIPFS_DataPersistence(t *testing.T) {
|
|||||||
|
|
||||||
// TestSQLite_DataPersistence verifies per-deployment SQLite databases persist.
|
// TestSQLite_DataPersistence verifies per-deployment SQLite databases persist.
|
||||||
func TestSQLite_DataPersistence(t *testing.T) {
|
func TestSQLite_DataPersistence(t *testing.T) {
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "FAIL: Could not load test environment")
|
require.NoError(t, err, "FAIL: Could not load test environment")
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
@ -367,7 +368,7 @@ func TestSQLite_DataPersistence(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("SQLite_database_persists", func(t *testing.T) {
|
t.Run("SQLite_database_persists", func(t *testing.T) {
|
||||||
// Create database
|
// Create database
|
||||||
createReq := &HTTPRequest{
|
createReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: env.GatewayURL + "/v1/db/sqlite/create",
|
URL: env.GatewayURL + "/v1/db/sqlite/create",
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
@ -385,7 +386,7 @@ func TestSQLite_DataPersistence(t *testing.T) {
|
|||||||
t.Logf(" Created SQLite database: %s", dbName)
|
t.Logf(" Created SQLite database: %s", dbName)
|
||||||
|
|
||||||
// Create table and insert data
|
// Create table and insert data
|
||||||
queryReq := &HTTPRequest{
|
queryReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: env.GatewayURL + "/v1/db/sqlite/query",
|
URL: env.GatewayURL + "/v1/db/sqlite/query",
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
@ -402,7 +403,7 @@ func TestSQLite_DataPersistence(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Create table returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Create table returned status %d", status)
|
||||||
|
|
||||||
// Insert data
|
// Insert data
|
||||||
insertReq := &HTTPRequest{
|
insertReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: env.GatewayURL + "/v1/db/sqlite/query",
|
URL: env.GatewayURL + "/v1/db/sqlite/query",
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
@ -419,7 +420,7 @@ func TestSQLite_DataPersistence(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusOK, status, "FAIL: Insert returned status %d", status)
|
require.Equal(t, http.StatusOK, status, "FAIL: Insert returned status %d", status)
|
||||||
|
|
||||||
// Verify data persists
|
// Verify data persists
|
||||||
selectReq := &HTTPRequest{
|
selectReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: env.GatewayURL + "/v1/db/sqlite/query",
|
URL: env.GatewayURL + "/v1/db/sqlite/query",
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
@ -442,7 +443,7 @@ func TestSQLite_DataPersistence(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("SQLite_database_listed", func(t *testing.T) {
|
t.Run("SQLite_database_listed", func(t *testing.T) {
|
||||||
// List databases to verify it was persisted
|
// List databases to verify it was persisted
|
||||||
listReq := &HTTPRequest{
|
listReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: env.GatewayURL + "/v1/db/sqlite/list",
|
URL: env.GatewayURL + "/v1/db/sqlite/list",
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package integration_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -12,21 +12,22 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/DeBrosOfficial/network/e2e"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDomainRouting_BasicRouting(t *testing.T) {
|
func TestDomainRouting_BasicRouting(t *testing.T) {
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "Failed to load test environment")
|
require.NoError(t, err, "Failed to load test environment")
|
||||||
|
|
||||||
deploymentName := fmt.Sprintf("test-routing-%d", time.Now().Unix())
|
deploymentName := fmt.Sprintf("test-routing-%d", time.Now().Unix())
|
||||||
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
||||||
|
|
||||||
deploymentID := CreateTestDeployment(t, env, deploymentName, tarballPath)
|
deploymentID := e2e.CreateTestDeployment(t, env, deploymentName, tarballPath)
|
||||||
defer func() {
|
defer func() {
|
||||||
if !env.SkipCleanup {
|
if !env.SkipCleanup {
|
||||||
DeleteDeployment(t, env, deploymentID)
|
e2e.DeleteDeployment(t, env, deploymentID)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -34,7 +35,7 @@ func TestDomainRouting_BasicRouting(t *testing.T) {
|
|||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
// Get deployment details for debugging
|
// Get deployment details for debugging
|
||||||
deployment := GetDeployment(t, env, deploymentID)
|
deployment := e2e.GetDeployment(t, env, deploymentID)
|
||||||
t.Logf("Deployment created: ID=%s, CID=%s, Name=%s, Status=%s",
|
t.Logf("Deployment created: ID=%s, CID=%s, Name=%s, Status=%s",
|
||||||
deploymentID, deployment["content_cid"], deployment["name"], deployment["status"])
|
deploymentID, deployment["content_cid"], deployment["name"], deployment["status"])
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ func TestDomainRouting_BasicRouting(t *testing.T) {
|
|||||||
// Domain format: {deploymentName}.{baseDomain}
|
// Domain format: {deploymentName}.{baseDomain}
|
||||||
domain := env.BuildDeploymentDomain(deploymentName)
|
domain := env.BuildDeploymentDomain(deploymentName)
|
||||||
|
|
||||||
resp := TestDeploymentWithHostHeader(t, env, domain, "/")
|
resp := e2e.TestDeploymentWithHostHeader(t, env, domain, "/")
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, resp.StatusCode, "Should return 200 OK")
|
assert.Equal(t, http.StatusOK, resp.StatusCode, "Should return 200 OK")
|
||||||
@ -58,7 +59,7 @@ func TestDomainRouting_BasicRouting(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Non-debros domain passes through", func(t *testing.T) {
|
t.Run("Non-debros domain passes through", func(t *testing.T) {
|
||||||
// Request with non-debros domain should not route to deployment
|
// Request with non-debros domain should not route to deployment
|
||||||
resp := TestDeploymentWithHostHeader(t, env, "example.com", "/")
|
resp := e2e.TestDeploymentWithHostHeader(t, env, "example.com", "/")
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
// Should either return 404 or pass to default handler
|
// Should either return 404 or pass to default handler
|
||||||
@ -98,7 +99,7 @@ func TestDomainRouting_BasicRouting(t *testing.T) {
|
|||||||
domain := env.BuildDeploymentDomain(deploymentName)
|
domain := env.BuildDeploymentDomain(deploymentName)
|
||||||
|
|
||||||
// /.well-known/ paths should bypass (used for ACME challenges, etc.)
|
// /.well-known/ paths should bypass (used for ACME challenges, etc.)
|
||||||
resp := TestDeploymentWithHostHeader(t, env, domain, "/.well-known/acme-challenge/test")
|
resp := e2e.TestDeploymentWithHostHeader(t, env, domain, "/.well-known/acme-challenge/test")
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
// Should not serve deployment content
|
// Should not serve deployment content
|
||||||
@ -117,7 +118,7 @@ func TestDomainRouting_BasicRouting(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDomainRouting_MultipleDeployments(t *testing.T) {
|
func TestDomainRouting_MultipleDeployments(t *testing.T) {
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "Failed to load test environment")
|
require.NoError(t, err, "Failed to load test environment")
|
||||||
|
|
||||||
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
||||||
@ -126,14 +127,14 @@ func TestDomainRouting_MultipleDeployments(t *testing.T) {
|
|||||||
deployment1Name := fmt.Sprintf("test-multi-1-%d", time.Now().Unix())
|
deployment1Name := fmt.Sprintf("test-multi-1-%d", time.Now().Unix())
|
||||||
deployment2Name := fmt.Sprintf("test-multi-2-%d", time.Now().Unix())
|
deployment2Name := fmt.Sprintf("test-multi-2-%d", time.Now().Unix())
|
||||||
|
|
||||||
deployment1ID := CreateTestDeployment(t, env, deployment1Name, tarballPath)
|
deployment1ID := e2e.CreateTestDeployment(t, env, deployment1Name, tarballPath)
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
deployment2ID := CreateTestDeployment(t, env, deployment2Name, tarballPath)
|
deployment2ID := e2e.CreateTestDeployment(t, env, deployment2Name, tarballPath)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if !env.SkipCleanup {
|
if !env.SkipCleanup {
|
||||||
DeleteDeployment(t, env, deployment1ID)
|
e2e.DeleteDeployment(t, env, deployment1ID)
|
||||||
DeleteDeployment(t, env, deployment2ID)
|
e2e.DeleteDeployment(t, env, deployment2ID)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -144,13 +145,13 @@ func TestDomainRouting_MultipleDeployments(t *testing.T) {
|
|||||||
domain2 := env.BuildDeploymentDomain(deployment2Name)
|
domain2 := env.BuildDeploymentDomain(deployment2Name)
|
||||||
|
|
||||||
// Test deployment 1
|
// Test deployment 1
|
||||||
resp1 := TestDeploymentWithHostHeader(t, env, domain1, "/")
|
resp1 := e2e.TestDeploymentWithHostHeader(t, env, domain1, "/")
|
||||||
defer resp1.Body.Close()
|
defer resp1.Body.Close()
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, resp1.StatusCode, "Deployment 1 should serve")
|
assert.Equal(t, http.StatusOK, resp1.StatusCode, "Deployment 1 should serve")
|
||||||
|
|
||||||
// Test deployment 2
|
// Test deployment 2
|
||||||
resp2 := TestDeploymentWithHostHeader(t, env, domain2, "/")
|
resp2 := e2e.TestDeploymentWithHostHeader(t, env, domain2, "/")
|
||||||
defer resp2.Body.Close()
|
defer resp2.Body.Close()
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, resp2.StatusCode, "Deployment 2 should serve")
|
assert.Equal(t, http.StatusOK, resp2.StatusCode, "Deployment 2 should serve")
|
||||||
@ -164,7 +165,7 @@ func TestDomainRouting_MultipleDeployments(t *testing.T) {
|
|||||||
// Request with non-existent deployment subdomain
|
// Request with non-existent deployment subdomain
|
||||||
fakeDeploymentDomain := env.BuildDeploymentDomain(fmt.Sprintf("nonexistent-deployment-%d", time.Now().Unix()))
|
fakeDeploymentDomain := env.BuildDeploymentDomain(fmt.Sprintf("nonexistent-deployment-%d", time.Now().Unix()))
|
||||||
|
|
||||||
resp := TestDeploymentWithHostHeader(t, env, fakeDeploymentDomain, "/")
|
resp := e2e.TestDeploymentWithHostHeader(t, env, fakeDeploymentDomain, "/")
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
assert.Equal(t, http.StatusNotFound, resp.StatusCode,
|
assert.Equal(t, http.StatusNotFound, resp.StatusCode,
|
||||||
@ -175,16 +176,16 @@ func TestDomainRouting_MultipleDeployments(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDomainRouting_ContentTypes(t *testing.T) {
|
func TestDomainRouting_ContentTypes(t *testing.T) {
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "Failed to load test environment")
|
require.NoError(t, err, "Failed to load test environment")
|
||||||
|
|
||||||
deploymentName := fmt.Sprintf("test-content-types-%d", time.Now().Unix())
|
deploymentName := fmt.Sprintf("test-content-types-%d", time.Now().Unix())
|
||||||
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
||||||
|
|
||||||
deploymentID := CreateTestDeployment(t, env, deploymentName, tarballPath)
|
deploymentID := e2e.CreateTestDeployment(t, env, deploymentName, tarballPath)
|
||||||
defer func() {
|
defer func() {
|
||||||
if !env.SkipCleanup {
|
if !env.SkipCleanup {
|
||||||
DeleteDeployment(t, env, deploymentID)
|
e2e.DeleteDeployment(t, env, deploymentID)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -203,7 +204,7 @@ func TestDomainRouting_ContentTypes(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range contentTypeTests {
|
for _, test := range contentTypeTests {
|
||||||
t.Run(test.description, func(t *testing.T) {
|
t.Run(test.description, func(t *testing.T) {
|
||||||
resp := TestDeploymentWithHostHeader(t, env, domain, test.path)
|
resp := e2e.TestDeploymentWithHostHeader(t, env, domain, test.path)
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode == http.StatusOK {
|
if resp.StatusCode == http.StatusOK {
|
||||||
@ -220,16 +221,16 @@ func TestDomainRouting_ContentTypes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDomainRouting_SPAFallback(t *testing.T) {
|
func TestDomainRouting_SPAFallback(t *testing.T) {
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "Failed to load test environment")
|
require.NoError(t, err, "Failed to load test environment")
|
||||||
|
|
||||||
deploymentName := fmt.Sprintf("test-spa-%d", time.Now().Unix())
|
deploymentName := fmt.Sprintf("test-spa-%d", time.Now().Unix())
|
||||||
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
||||||
|
|
||||||
deploymentID := CreateTestDeployment(t, env, deploymentName, tarballPath)
|
deploymentID := e2e.CreateTestDeployment(t, env, deploymentName, tarballPath)
|
||||||
defer func() {
|
defer func() {
|
||||||
if !env.SkipCleanup {
|
if !env.SkipCleanup {
|
||||||
DeleteDeployment(t, env, deploymentID)
|
e2e.DeleteDeployment(t, env, deploymentID)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -246,7 +247,7 @@ func TestDomainRouting_SPAFallback(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, path := range unknownPaths {
|
for _, path := range unknownPaths {
|
||||||
resp := TestDeploymentWithHostHeader(t, env, domain, path)
|
resp := e2e.TestDeploymentWithHostHeader(t, env, domain, path)
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
|
|
||||||
@ -266,16 +267,16 @@ func TestDomainRouting_SPAFallback(t *testing.T) {
|
|||||||
// - CORRECT: {name}-{random}.{baseDomain} (e.g., "myapp-f3o4if.dbrs.space")
|
// - CORRECT: {name}-{random}.{baseDomain} (e.g., "myapp-f3o4if.dbrs.space")
|
||||||
// - WRONG: {name}.node-{shortID}.{baseDomain} (should NOT exist)
|
// - WRONG: {name}.node-{shortID}.{baseDomain} (should NOT exist)
|
||||||
func TestDeployment_DomainFormat(t *testing.T) {
|
func TestDeployment_DomainFormat(t *testing.T) {
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "Failed to load test environment")
|
require.NoError(t, err, "Failed to load test environment")
|
||||||
|
|
||||||
deploymentName := fmt.Sprintf("format-test-%d", time.Now().Unix())
|
deploymentName := fmt.Sprintf("format-test-%d", time.Now().Unix())
|
||||||
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
||||||
|
|
||||||
deploymentID := CreateTestDeployment(t, env, deploymentName, tarballPath)
|
deploymentID := e2e.CreateTestDeployment(t, env, deploymentName, tarballPath)
|
||||||
defer func() {
|
defer func() {
|
||||||
if !env.SkipCleanup {
|
if !env.SkipCleanup {
|
||||||
DeleteDeployment(t, env, deploymentID)
|
e2e.DeleteDeployment(t, env, deploymentID)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -283,7 +284,7 @@ func TestDeployment_DomainFormat(t *testing.T) {
|
|||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
t.Run("Deployment URL has correct format", func(t *testing.T) {
|
t.Run("Deployment URL has correct format", func(t *testing.T) {
|
||||||
deployment := GetDeployment(t, env, deploymentID)
|
deployment := e2e.GetDeployment(t, env, deploymentID)
|
||||||
|
|
||||||
// Get the deployment URLs
|
// Get the deployment URLs
|
||||||
urls, ok := deployment["urls"].([]interface{})
|
urls, ok := deployment["urls"].([]interface{})
|
||||||
@ -331,14 +332,14 @@ func TestDeployment_DomainFormat(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Domain resolves via Host header", func(t *testing.T) {
|
t.Run("Domain resolves via Host header", func(t *testing.T) {
|
||||||
// Get the actual subdomain from the deployment
|
// Get the actual subdomain from the deployment
|
||||||
deployment := GetDeployment(t, env, deploymentID)
|
deployment := e2e.GetDeployment(t, env, deploymentID)
|
||||||
subdomain, _ := deployment["subdomain"].(string)
|
subdomain, _ := deployment["subdomain"].(string)
|
||||||
if subdomain == "" {
|
if subdomain == "" {
|
||||||
t.Skip("No subdomain set, skipping host header test")
|
t.Skip("No subdomain set, skipping host header test")
|
||||||
}
|
}
|
||||||
domain := subdomain + "." + env.BaseDomain
|
domain := subdomain + "." + env.BaseDomain
|
||||||
|
|
||||||
resp := TestDeploymentWithHostHeader(t, env, domain, "/")
|
resp := e2e.TestDeploymentWithHostHeader(t, env, domain, "/")
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, resp.StatusCode,
|
assert.Equal(t, http.StatusOK, resp.StatusCode,
|
||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package integration_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -12,12 +12,13 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/DeBrosOfficial/network/e2e"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFullStack_GoAPI_SQLite(t *testing.T) {
|
func TestFullStack_GoAPI_SQLite(t *testing.T) {
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "Failed to load test environment")
|
require.NoError(t, err, "Failed to load test environment")
|
||||||
|
|
||||||
appName := fmt.Sprintf("fullstack-app-%d", time.Now().Unix())
|
appName := fmt.Sprintf("fullstack-app-%d", time.Now().Unix())
|
||||||
@ -29,15 +30,15 @@ func TestFullStack_GoAPI_SQLite(t *testing.T) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
if !env.SkipCleanup {
|
if !env.SkipCleanup {
|
||||||
if backendID != "" {
|
if backendID != "" {
|
||||||
DeleteDeployment(t, env, backendID)
|
e2e.DeleteDeployment(t, env, backendID)
|
||||||
}
|
}
|
||||||
DeleteSQLiteDB(t, env, dbName)
|
e2e.DeleteSQLiteDB(t, env, dbName)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Step 1: Create SQLite database
|
// Step 1: Create SQLite database
|
||||||
t.Run("Create SQLite database", func(t *testing.T) {
|
t.Run("Create SQLite database", func(t *testing.T) {
|
||||||
CreateSQLiteDB(t, env, dbName)
|
e2e.CreateSQLiteDB(t, env, dbName)
|
||||||
|
|
||||||
// Create users table
|
// Create users table
|
||||||
query := `CREATE TABLE users (
|
query := `CREATE TABLE users (
|
||||||
@ -46,11 +47,11 @@ func TestFullStack_GoAPI_SQLite(t *testing.T) {
|
|||||||
email TEXT UNIQUE NOT NULL,
|
email TEXT UNIQUE NOT NULL,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
)`
|
)`
|
||||||
ExecuteSQLQuery(t, env, dbName, query)
|
e2e.ExecuteSQLQuery(t, env, dbName, query)
|
||||||
|
|
||||||
// Insert test data
|
// Insert test data
|
||||||
insertQuery := `INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')`
|
insertQuery := `INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')`
|
||||||
result := ExecuteSQLQuery(t, env, dbName, insertQuery)
|
result := e2e.ExecuteSQLQuery(t, env, dbName, insertQuery)
|
||||||
|
|
||||||
assert.NotNil(t, result, "Should execute INSERT successfully")
|
assert.NotNil(t, result, "Should execute INSERT successfully")
|
||||||
t.Logf("✓ Database created with users table")
|
t.Logf("✓ Database created with users table")
|
||||||
@ -64,7 +65,7 @@ func TestFullStack_GoAPI_SQLite(t *testing.T) {
|
|||||||
|
|
||||||
// Note: In a real implementation, we would pass DATABASE_NAME env var
|
// Note: In a real implementation, we would pass DATABASE_NAME env var
|
||||||
// For now, we just test the deployment mechanism
|
// For now, we just test the deployment mechanism
|
||||||
backendID = CreateTestDeployment(t, env, backendName, tarballPath)
|
backendID = e2e.CreateTestDeployment(t, env, backendName, tarballPath)
|
||||||
|
|
||||||
assert.NotEmpty(t, backendID, "Backend deployment ID should not be empty")
|
assert.NotEmpty(t, backendID, "Backend deployment ID should not be empty")
|
||||||
t.Logf("✓ Go backend deployed: %s", backendName)
|
t.Logf("✓ Go backend deployed: %s", backendName)
|
||||||
@ -77,10 +78,10 @@ func TestFullStack_GoAPI_SQLite(t *testing.T) {
|
|||||||
t.Run("Test database CRUD operations", func(t *testing.T) {
|
t.Run("Test database CRUD operations", func(t *testing.T) {
|
||||||
// INSERT
|
// INSERT
|
||||||
insertQuery := `INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com')`
|
insertQuery := `INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com')`
|
||||||
ExecuteSQLQuery(t, env, dbName, insertQuery)
|
e2e.ExecuteSQLQuery(t, env, dbName, insertQuery)
|
||||||
|
|
||||||
// SELECT
|
// SELECT
|
||||||
users := QuerySQLite(t, env, dbName, "SELECT * FROM users ORDER BY id")
|
users := e2e.QuerySQLite(t, env, dbName, "SELECT * FROM users ORDER BY id")
|
||||||
require.GreaterOrEqual(t, len(users), 2, "Should have at least 2 users")
|
require.GreaterOrEqual(t, len(users), 2, "Should have at least 2 users")
|
||||||
|
|
||||||
assert.Equal(t, "Alice", users[0]["name"], "First user should be Alice")
|
assert.Equal(t, "Alice", users[0]["name"], "First user should be Alice")
|
||||||
@ -91,14 +92,14 @@ func TestFullStack_GoAPI_SQLite(t *testing.T) {
|
|||||||
|
|
||||||
// UPDATE
|
// UPDATE
|
||||||
updateQuery := `UPDATE users SET email = 'alice.new@example.com' WHERE name = 'Alice'`
|
updateQuery := `UPDATE users SET email = 'alice.new@example.com' WHERE name = 'Alice'`
|
||||||
result := ExecuteSQLQuery(t, env, dbName, updateQuery)
|
result := e2e.ExecuteSQLQuery(t, env, dbName, updateQuery)
|
||||||
|
|
||||||
rowsAffected, ok := result["rows_affected"].(float64)
|
rowsAffected, ok := result["rows_affected"].(float64)
|
||||||
require.True(t, ok, "Should have rows_affected")
|
require.True(t, ok, "Should have rows_affected")
|
||||||
assert.Equal(t, float64(1), rowsAffected, "Should update 1 row")
|
assert.Equal(t, float64(1), rowsAffected, "Should update 1 row")
|
||||||
|
|
||||||
// Verify update
|
// Verify update
|
||||||
updated := QuerySQLite(t, env, dbName, "SELECT email FROM users WHERE name = 'Alice'")
|
updated := e2e.QuerySQLite(t, env, dbName, "SELECT email FROM users WHERE name = 'Alice'")
|
||||||
require.Len(t, updated, 1, "Should find Alice")
|
require.Len(t, updated, 1, "Should find Alice")
|
||||||
assert.Equal(t, "alice.new@example.com", updated[0]["email"], "Email should be updated")
|
assert.Equal(t, "alice.new@example.com", updated[0]["email"], "Email should be updated")
|
||||||
|
|
||||||
@ -106,14 +107,14 @@ func TestFullStack_GoAPI_SQLite(t *testing.T) {
|
|||||||
|
|
||||||
// DELETE
|
// DELETE
|
||||||
deleteQuery := `DELETE FROM users WHERE name = 'Bob'`
|
deleteQuery := `DELETE FROM users WHERE name = 'Bob'`
|
||||||
result = ExecuteSQLQuery(t, env, dbName, deleteQuery)
|
result = e2e.ExecuteSQLQuery(t, env, dbName, deleteQuery)
|
||||||
|
|
||||||
rowsAffected, ok = result["rows_affected"].(float64)
|
rowsAffected, ok = result["rows_affected"].(float64)
|
||||||
require.True(t, ok, "Should have rows_affected")
|
require.True(t, ok, "Should have rows_affected")
|
||||||
assert.Equal(t, float64(1), rowsAffected, "Should delete 1 row")
|
assert.Equal(t, float64(1), rowsAffected, "Should delete 1 row")
|
||||||
|
|
||||||
// Verify deletion
|
// Verify deletion
|
||||||
remaining := QuerySQLite(t, env, dbName, "SELECT * FROM users")
|
remaining := e2e.QuerySQLite(t, env, dbName, "SELECT * FROM users")
|
||||||
assert.Equal(t, 1, len(remaining), "Should have 1 user remaining")
|
assert.Equal(t, 1, len(remaining), "Should have 1 user remaining")
|
||||||
|
|
||||||
t.Logf("✓ DELETE operation verified")
|
t.Logf("✓ DELETE operation verified")
|
||||||
@ -121,7 +122,7 @@ func TestFullStack_GoAPI_SQLite(t *testing.T) {
|
|||||||
|
|
||||||
// Step 4: Test backend API endpoints (if deployment is active)
|
// Step 4: Test backend API endpoints (if deployment is active)
|
||||||
t.Run("Test backend API endpoints", func(t *testing.T) {
|
t.Run("Test backend API endpoints", func(t *testing.T) {
|
||||||
deployment := GetDeployment(t, env, backendID)
|
deployment := e2e.GetDeployment(t, env, backendID)
|
||||||
|
|
||||||
status, ok := deployment["status"].(string)
|
status, ok := deployment["status"].(string)
|
||||||
if !ok || status != "active" {
|
if !ok || status != "active" {
|
||||||
@ -132,7 +133,7 @@ func TestFullStack_GoAPI_SQLite(t *testing.T) {
|
|||||||
backendDomain := env.BuildDeploymentDomain(backendName)
|
backendDomain := env.BuildDeploymentDomain(backendName)
|
||||||
|
|
||||||
// Test health endpoint
|
// Test health endpoint
|
||||||
resp := TestDeploymentWithHostHeader(t, env, backendDomain, "/health")
|
resp := e2e.TestDeploymentWithHostHeader(t, env, backendDomain, "/health")
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode == http.StatusOK {
|
if resp.StatusCode == http.StatusOK {
|
||||||
@ -149,7 +150,7 @@ func TestFullStack_GoAPI_SQLite(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test users API endpoint
|
// Test users API endpoint
|
||||||
resp2 := TestDeploymentWithHostHeader(t, env, backendDomain, "/api/users")
|
resp2 := e2e.TestDeploymentWithHostHeader(t, env, backendDomain, "/api/users")
|
||||||
defer resp2.Body.Close()
|
defer resp2.Body.Close()
|
||||||
|
|
||||||
if resp2.StatusCode == http.StatusOK {
|
if resp2.StatusCode == http.StatusOK {
|
||||||
@ -205,7 +206,7 @@ func TestFullStack_GoAPI_SQLite(t *testing.T) {
|
|||||||
|
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; i++ {
|
||||||
go func(idx int) {
|
go func(idx int) {
|
||||||
users := QuerySQLite(t, env, dbName, "SELECT * FROM users")
|
users := e2e.QuerySQLite(t, env, dbName, "SELECT * FROM users")
|
||||||
assert.GreaterOrEqual(t, len(users), 0, "Should query successfully")
|
assert.GreaterOrEqual(t, len(users), 0, "Should query successfully")
|
||||||
done <- true
|
done <- true
|
||||||
}(i)
|
}(i)
|
||||||
@ -226,7 +227,7 @@ func TestFullStack_GoAPI_SQLite(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFullStack_StaticSite_SQLite(t *testing.T) {
|
func TestFullStack_StaticSite_SQLite(t *testing.T) {
|
||||||
env, err := LoadTestEnv()
|
env, err := e2e.LoadTestEnv()
|
||||||
require.NoError(t, err, "Failed to load test environment")
|
require.NoError(t, err, "Failed to load test environment")
|
||||||
|
|
||||||
appName := fmt.Sprintf("fullstack-static-%d", time.Now().Unix())
|
appName := fmt.Sprintf("fullstack-static-%d", time.Now().Unix())
|
||||||
@ -238,21 +239,21 @@ func TestFullStack_StaticSite_SQLite(t *testing.T) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
if !env.SkipCleanup {
|
if !env.SkipCleanup {
|
||||||
if frontendID != "" {
|
if frontendID != "" {
|
||||||
DeleteDeployment(t, env, frontendID)
|
e2e.DeleteDeployment(t, env, frontendID)
|
||||||
}
|
}
|
||||||
DeleteSQLiteDB(t, env, dbName)
|
e2e.DeleteSQLiteDB(t, env, dbName)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
t.Run("Deploy static site and create database", func(t *testing.T) {
|
t.Run("Deploy static site and create database", func(t *testing.T) {
|
||||||
// Create database
|
// Create database
|
||||||
CreateSQLiteDB(t, env, dbName)
|
e2e.CreateSQLiteDB(t, env, dbName)
|
||||||
ExecuteSQLQuery(t, env, dbName, "CREATE TABLE page_views (id INTEGER PRIMARY KEY, page TEXT, count INTEGER)")
|
e2e.ExecuteSQLQuery(t, env, dbName, "CREATE TABLE page_views (id INTEGER PRIMARY KEY, page TEXT, count INTEGER)")
|
||||||
ExecuteSQLQuery(t, env, dbName, "INSERT INTO page_views (page, count) VALUES ('home', 0)")
|
e2e.ExecuteSQLQuery(t, env, dbName, "INSERT INTO page_views (page, count) VALUES ('home', 0)")
|
||||||
|
|
||||||
// Deploy frontend
|
// Deploy frontend
|
||||||
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
tarballPath := filepath.Join("../testdata/tarballs/react-vite.tar.gz")
|
||||||
frontendID = CreateTestDeployment(t, env, frontendName, tarballPath)
|
frontendID = e2e.CreateTestDeployment(t, env, frontendName, tarballPath)
|
||||||
|
|
||||||
assert.NotEmpty(t, frontendID, "Frontend deployment should succeed")
|
assert.NotEmpty(t, frontendID, "Frontend deployment should succeed")
|
||||||
t.Logf("✓ Static site deployed with SQLite backend")
|
t.Logf("✓ Static site deployed with SQLite backend")
|
||||||
@ -265,7 +266,7 @@ func TestFullStack_StaticSite_SQLite(t *testing.T) {
|
|||||||
frontendDomain := env.BuildDeploymentDomain(frontendName)
|
frontendDomain := env.BuildDeploymentDomain(frontendName)
|
||||||
|
|
||||||
// Test frontend
|
// Test frontend
|
||||||
resp := TestDeploymentWithHostHeader(t, env, frontendDomain, "/")
|
resp := e2e.TestDeploymentWithHostHeader(t, env, frontendDomain, "/")
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, resp.StatusCode, "Frontend should serve")
|
assert.Equal(t, http.StatusOK, resp.StatusCode, "Frontend should serve")
|
||||||
@ -274,10 +275,10 @@ func TestFullStack_StaticSite_SQLite(t *testing.T) {
|
|||||||
assert.Contains(t, string(body), "<div id=\"root\">", "Should contain React app")
|
assert.Contains(t, string(body), "<div id=\"root\">", "Should contain React app")
|
||||||
|
|
||||||
// Simulate page view tracking
|
// Simulate page view tracking
|
||||||
ExecuteSQLQuery(t, env, dbName, "UPDATE page_views SET count = count + 1 WHERE page = 'home'")
|
e2e.ExecuteSQLQuery(t, env, dbName, "UPDATE page_views SET count = count + 1 WHERE page = 'home'")
|
||||||
|
|
||||||
// Verify count
|
// Verify count
|
||||||
views := QuerySQLite(t, env, dbName, "SELECT count FROM page_views WHERE page = 'home'")
|
views := e2e.QuerySQLite(t, env, dbName, "SELECT count FROM page_views WHERE page = 'home'")
|
||||||
require.Len(t, views, 1, "Should have page view record")
|
require.Len(t, views, 1, "Should have page view record")
|
||||||
|
|
||||||
count, ok := views[0]["count"].(float64)
|
count, ok := views[0]["count"].(float64)
|
||||||
@ -1,4 +1,4 @@
|
|||||||
//go:build e2e
|
//go:build e2e && production
|
||||||
|
|
||||||
package production
|
package production
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
//go:build e2e
|
//go:build e2e && production
|
||||||
|
|
||||||
package production
|
package production
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
//go:build e2e
|
//go:build e2e && production
|
||||||
|
|
||||||
package production
|
package production
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e && production
|
||||||
|
|
||||||
package deployments_test
|
package production
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
@ -24,7 +24,7 @@ import (
|
|||||||
// This test requires:
|
// This test requires:
|
||||||
// - Orama deployed on a VPS with a real domain
|
// - Orama deployed on a VPS with a real domain
|
||||||
// - DNS properly configured
|
// - DNS properly configured
|
||||||
// - Run with: go test -v -tags e2e -run TestHTTPS ./e2e/deployments/...
|
// - Run with: go test -v -tags "e2e production" -run TestHTTPS ./e2e/production/...
|
||||||
func TestHTTPS_ExternalAccess(t *testing.T) {
|
func TestHTTPS_ExternalAccess(t *testing.T) {
|
||||||
// Skip if not configured for external testing
|
// Skip if not configured for external testing
|
||||||
externalURL := os.Getenv("ORAMA_EXTERNAL_URL")
|
externalURL := os.Getenv("ORAMA_EXTERNAL_URL")
|
||||||
@ -171,3 +171,34 @@ func TestHTTPS_DomainFormat(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func extractNodeURL(t *testing.T, deployment map[string]interface{}) string {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
if urls, ok := deployment["urls"].([]interface{}); ok && len(urls) > 0 {
|
||||||
|
if url, ok := urls[0].(string); ok {
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if urls, ok := deployment["urls"].(map[string]interface{}); ok {
|
||||||
|
if url, ok := urls["node"].(string); ok {
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractDomain(url string) string {
|
||||||
|
domain := url
|
||||||
|
if len(url) > 8 && url[:8] == "https://" {
|
||||||
|
domain = url[8:]
|
||||||
|
} else if len(url) > 7 && url[:7] == "http://" {
|
||||||
|
domain = url[7:]
|
||||||
|
}
|
||||||
|
if len(domain) > 0 && domain[len(domain)-1] == '/' {
|
||||||
|
domain = domain[:len(domain)-1]
|
||||||
|
}
|
||||||
|
return domain
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
//go:build e2e
|
//go:build e2e && production
|
||||||
|
|
||||||
package production
|
package production
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package shared_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -9,6 +9,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
e2e "github.com/DeBrosOfficial/network/e2e"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,10 +25,10 @@ func TestAuth_MissingAPIKey(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Request protected endpoint without auth headers
|
// Request protected endpoint without auth headers
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, GetGatewayURL()+"/v1/cache/health", nil)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, e2e.GetGatewayURL()+"/v1/cache/health", nil)
|
||||||
require.NoError(t, err, "FAIL: Could not create request")
|
require.NoError(t, err, "FAIL: Could not create request")
|
||||||
|
|
||||||
client := NewHTTPClient(30 * time.Second)
|
client := e2e.NewHTTPClient(30 * time.Second)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
require.NoError(t, err, "FAIL: Request failed")
|
require.NoError(t, err, "FAIL: Request failed")
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@ -42,12 +44,12 @@ func TestAuth_InvalidAPIKey(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Request with invalid API key
|
// Request with invalid API key
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, GetGatewayURL()+"/v1/cache/health", nil)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, e2e.GetGatewayURL()+"/v1/cache/health", nil)
|
||||||
require.NoError(t, err, "FAIL: Could not create request")
|
require.NoError(t, err, "FAIL: Could not create request")
|
||||||
|
|
||||||
req.Header.Set("Authorization", "Bearer invalid-key-xyz-123456789")
|
req.Header.Set("Authorization", "Bearer invalid-key-xyz-123456789")
|
||||||
|
|
||||||
client := NewHTTPClient(30 * time.Second)
|
client := e2e.NewHTTPClient(30 * time.Second)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
require.NoError(t, err, "FAIL: Request failed")
|
require.NoError(t, err, "FAIL: Request failed")
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@ -63,9 +65,9 @@ func TestAuth_CacheWithoutAuth(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Request cache endpoint without auth
|
// Request cache endpoint without auth
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/cache/health",
|
URL: e2e.GetGatewayURL() + "/v1/cache/health",
|
||||||
SkipAuth: true,
|
SkipAuth: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,9 +85,9 @@ func TestAuth_StorageWithoutAuth(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Request storage endpoint without auth
|
// Request storage endpoint without auth
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/storage/status/QmTest",
|
URL: e2e.GetGatewayURL() + "/v1/storage/status/QmTest",
|
||||||
SkipAuth: true,
|
SkipAuth: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,9 +105,9 @@ func TestAuth_RQLiteWithoutAuth(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Request rqlite endpoint without auth
|
// Request rqlite endpoint without auth
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/schema",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/schema",
|
||||||
SkipAuth: true,
|
SkipAuth: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,12 +125,12 @@ func TestAuth_MalformedBearerToken(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Request with malformed bearer token (missing "Bearer " prefix)
|
// Request with malformed bearer token (missing "Bearer " prefix)
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, GetGatewayURL()+"/v1/cache/health", nil)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, e2e.GetGatewayURL()+"/v1/cache/health", nil)
|
||||||
require.NoError(t, err, "FAIL: Could not create request")
|
require.NoError(t, err, "FAIL: Could not create request")
|
||||||
|
|
||||||
req.Header.Set("Authorization", "invalid-token-format-no-bearer")
|
req.Header.Set("Authorization", "invalid-token-format-no-bearer")
|
||||||
|
|
||||||
client := NewHTTPClient(30 * time.Second)
|
client := e2e.NewHTTPClient(30 * time.Second)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
require.NoError(t, err, "FAIL: Request failed")
|
require.NoError(t, err, "FAIL: Request failed")
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@ -144,12 +146,12 @@ func TestAuth_ExpiredJWT(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Test with a clearly invalid JWT structure
|
// Test with a clearly invalid JWT structure
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, GetGatewayURL()+"/v1/cache/health", nil)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, e2e.GetGatewayURL()+"/v1/cache/health", nil)
|
||||||
require.NoError(t, err, "FAIL: Could not create request")
|
require.NoError(t, err, "FAIL: Could not create request")
|
||||||
|
|
||||||
req.Header.Set("Authorization", "Bearer expired.jwt.token.invalid")
|
req.Header.Set("Authorization", "Bearer expired.jwt.token.invalid")
|
||||||
|
|
||||||
client := NewHTTPClient(30 * time.Second)
|
client := e2e.NewHTTPClient(30 * time.Second)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
require.NoError(t, err, "FAIL: Request failed")
|
require.NoError(t, err, "FAIL: Request failed")
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@ -165,12 +167,12 @@ func TestAuth_EmptyBearerToken(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Request with empty bearer token
|
// Request with empty bearer token
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, GetGatewayURL()+"/v1/cache/health", nil)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, e2e.GetGatewayURL()+"/v1/cache/health", nil)
|
||||||
require.NoError(t, err, "FAIL: Could not create request")
|
require.NoError(t, err, "FAIL: Could not create request")
|
||||||
|
|
||||||
req.Header.Set("Authorization", "Bearer ")
|
req.Header.Set("Authorization", "Bearer ")
|
||||||
|
|
||||||
client := NewHTTPClient(30 * time.Second)
|
client := e2e.NewHTTPClient(30 * time.Second)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
require.NoError(t, err, "FAIL: Request failed")
|
require.NoError(t, err, "FAIL: Request failed")
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@ -182,7 +184,7 @@ func TestAuth_EmptyBearerToken(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAuth_DuplicateAuthHeaders(t *testing.T) {
|
func TestAuth_DuplicateAuthHeaders(t *testing.T) {
|
||||||
if GetAPIKey() == "" {
|
if e2e.GetAPIKey() == "" {
|
||||||
t.Skip("No API key configured")
|
t.Skip("No API key configured")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,12 +192,12 @@ func TestAuth_DuplicateAuthHeaders(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Request with both valid API key in Authorization header
|
// Request with both valid API key in Authorization header
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/cache/health",
|
URL: e2e.GetGatewayURL() + "/v1/cache/health",
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
"Authorization": "Bearer " + GetAPIKey(),
|
"Authorization": "Bearer " + e2e.GetAPIKey(),
|
||||||
"X-API-Key": GetAPIKey(),
|
"X-API-Key": e2e.GetAPIKey(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +211,7 @@ func TestAuth_DuplicateAuthHeaders(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAuth_CaseSensitiveAPIKey(t *testing.T) {
|
func TestAuth_CaseSensitiveAPIKey(t *testing.T) {
|
||||||
apiKey := GetAPIKey()
|
apiKey := e2e.GetAPIKey()
|
||||||
if apiKey == "" {
|
if apiKey == "" {
|
||||||
t.Skip("No API key configured")
|
t.Skip("No API key configured")
|
||||||
}
|
}
|
||||||
@ -236,12 +238,12 @@ func TestAuth_CaseSensitiveAPIKey(t *testing.T) {
|
|||||||
t.Skip("API key has no letters to change case")
|
t.Skip("API key has no letters to change case")
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, GetGatewayURL()+"/v1/cache/health", nil)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, e2e.GetGatewayURL()+"/v1/cache/health", nil)
|
||||||
require.NoError(t, err, "FAIL: Could not create request")
|
require.NoError(t, err, "FAIL: Could not create request")
|
||||||
|
|
||||||
req.Header.Set("Authorization", "Bearer "+incorrectKey)
|
req.Header.Set("Authorization", "Bearer "+incorrectKey)
|
||||||
|
|
||||||
client := NewHTTPClient(30 * time.Second)
|
client := e2e.NewHTTPClient(30 * time.Second)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
require.NoError(t, err, "FAIL: Request failed")
|
require.NoError(t, err, "FAIL: Request failed")
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@ -257,10 +259,10 @@ func TestAuth_HealthEndpointNoAuth(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Health endpoint at /v1/health should NOT require auth
|
// Health endpoint at /v1/health should NOT require auth
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, GetGatewayURL()+"/v1/health", nil)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, e2e.GetGatewayURL()+"/v1/health", nil)
|
||||||
require.NoError(t, err, "FAIL: Could not create request")
|
require.NoError(t, err, "FAIL: Could not create request")
|
||||||
|
|
||||||
client := NewHTTPClient(30 * time.Second)
|
client := e2e.NewHTTPClient(30 * time.Second)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
require.NoError(t, err, "FAIL: Request failed")
|
require.NoError(t, err, "FAIL: Request failed")
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@ -276,10 +278,10 @@ func TestAuth_StatusEndpointNoAuth(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Status endpoint at /v1/status should NOT require auth
|
// Status endpoint at /v1/status should NOT require auth
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, GetGatewayURL()+"/v1/status", nil)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, e2e.GetGatewayURL()+"/v1/status", nil)
|
||||||
require.NoError(t, err, "FAIL: Could not create request")
|
require.NoError(t, err, "FAIL: Could not create request")
|
||||||
|
|
||||||
client := NewHTTPClient(30 * time.Second)
|
client := e2e.NewHTTPClient(30 * time.Second)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
require.NoError(t, err, "FAIL: Request failed")
|
require.NoError(t, err, "FAIL: Request failed")
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@ -295,9 +297,9 @@ func TestAuth_DeploymentsWithoutAuth(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Request deployments endpoint without auth
|
// Request deployments endpoint without auth
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/deployments/list",
|
URL: e2e.GetGatewayURL() + "/v1/deployments/list",
|
||||||
SkipAuth: true,
|
SkipAuth: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,9 +317,9 @@ func TestAuth_SQLiteWithoutAuth(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Request SQLite endpoint without auth
|
// Request SQLite endpoint without auth
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/db/sqlite/list",
|
URL: e2e.GetGatewayURL() + "/v1/db/sqlite/list",
|
||||||
SkipAuth: true,
|
SkipAuth: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package shared_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -8,17 +8,19 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
e2e "github.com/DeBrosOfficial/network/e2e"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCache_Health(t *testing.T) {
|
func TestCache_Health(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/cache/health",
|
URL: e2e.GetGatewayURL() + "/v1/cache/health",
|
||||||
}
|
}
|
||||||
|
|
||||||
body, status, err := req.Do(ctx)
|
body, status, err := req.Do(ctx)
|
||||||
@ -31,7 +33,7 @@ func TestCache_Health(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resp map[string]interface{}
|
var resp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &resp); err != nil {
|
if err := e2e.DecodeJSON(body, &resp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,19 +47,19 @@ func TestCache_Health(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCache_PutGet(t *testing.T) {
|
func TestCache_PutGet(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
dmap := GenerateDMapName()
|
dmap := e2e.GenerateDMapName()
|
||||||
key := "test-key"
|
key := "test-key"
|
||||||
value := "test-value"
|
value := "test-value"
|
||||||
|
|
||||||
// Put value
|
// Put value
|
||||||
putReq := &HTTPRequest{
|
putReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/put",
|
URL: e2e.GetGatewayURL() + "/v1/cache/put",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -75,9 +77,9 @@ func TestCache_PutGet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get value
|
// Get value
|
||||||
getReq := &HTTPRequest{
|
getReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/get",
|
URL: e2e.GetGatewayURL() + "/v1/cache/get",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -94,7 +96,7 @@ func TestCache_PutGet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var getResp map[string]interface{}
|
var getResp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &getResp); err != nil {
|
if err := e2e.DecodeJSON(body, &getResp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,12 +106,12 @@ func TestCache_PutGet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCache_PutGetJSON(t *testing.T) {
|
func TestCache_PutGetJSON(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
dmap := GenerateDMapName()
|
dmap := e2e.GenerateDMapName()
|
||||||
key := "json-key"
|
key := "json-key"
|
||||||
jsonValue := map[string]interface{}{
|
jsonValue := map[string]interface{}{
|
||||||
"name": "John",
|
"name": "John",
|
||||||
@ -118,9 +120,9 @@ func TestCache_PutGetJSON(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Put JSON value
|
// Put JSON value
|
||||||
putReq := &HTTPRequest{
|
putReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/put",
|
URL: e2e.GetGatewayURL() + "/v1/cache/put",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -138,9 +140,9 @@ func TestCache_PutGetJSON(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get JSON value
|
// Get JSON value
|
||||||
getReq := &HTTPRequest{
|
getReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/get",
|
URL: e2e.GetGatewayURL() + "/v1/cache/get",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -157,7 +159,7 @@ func TestCache_PutGetJSON(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var getResp map[string]interface{}
|
var getResp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &getResp); err != nil {
|
if err := e2e.DecodeJSON(body, &getResp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,19 +173,19 @@ func TestCache_PutGetJSON(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCache_Delete(t *testing.T) {
|
func TestCache_Delete(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
dmap := GenerateDMapName()
|
dmap := e2e.GenerateDMapName()
|
||||||
key := "delete-key"
|
key := "delete-key"
|
||||||
value := "delete-value"
|
value := "delete-value"
|
||||||
|
|
||||||
// Put value
|
// Put value
|
||||||
putReq := &HTTPRequest{
|
putReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/put",
|
URL: e2e.GetGatewayURL() + "/v1/cache/put",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -197,9 +199,9 @@ func TestCache_Delete(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete value
|
// Delete value
|
||||||
deleteReq := &HTTPRequest{
|
deleteReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/delete",
|
URL: e2e.GetGatewayURL() + "/v1/cache/delete",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -216,9 +218,9 @@ func TestCache_Delete(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify deletion
|
// Verify deletion
|
||||||
getReq := &HTTPRequest{
|
getReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/get",
|
URL: e2e.GetGatewayURL() + "/v1/cache/get",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -233,19 +235,19 @@ func TestCache_Delete(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCache_TTL(t *testing.T) {
|
func TestCache_TTL(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
dmap := GenerateDMapName()
|
dmap := e2e.GenerateDMapName()
|
||||||
key := "ttl-key"
|
key := "ttl-key"
|
||||||
value := "ttl-value"
|
value := "ttl-value"
|
||||||
|
|
||||||
// Put value with TTL
|
// Put value with TTL
|
||||||
putReq := &HTTPRequest{
|
putReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/put",
|
URL: e2e.GetGatewayURL() + "/v1/cache/put",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -264,9 +266,9 @@ func TestCache_TTL(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify value exists
|
// Verify value exists
|
||||||
getReq := &HTTPRequest{
|
getReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/get",
|
URL: e2e.GetGatewayURL() + "/v1/cache/get",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -279,7 +281,7 @@ func TestCache_TTL(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait for TTL expiry (2 seconds + buffer)
|
// Wait for TTL expiry (2 seconds + buffer)
|
||||||
Delay(2500)
|
e2e.Delay(2500)
|
||||||
|
|
||||||
// Verify value is expired
|
// Verify value is expired
|
||||||
_, status, err = getReq.Do(ctx)
|
_, status, err = getReq.Do(ctx)
|
||||||
@ -289,19 +291,19 @@ func TestCache_TTL(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCache_Scan(t *testing.T) {
|
func TestCache_Scan(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
dmap := GenerateDMapName()
|
dmap := e2e.GenerateDMapName()
|
||||||
|
|
||||||
// Put multiple keys
|
// Put multiple keys
|
||||||
keys := []string{"user-1", "user-2", "session-1", "session-2"}
|
keys := []string{"user-1", "user-2", "session-1", "session-2"}
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
putReq := &HTTPRequest{
|
putReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/put",
|
URL: e2e.GetGatewayURL() + "/v1/cache/put",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -316,9 +318,9 @@ func TestCache_Scan(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scan all keys
|
// Scan all keys
|
||||||
scanReq := &HTTPRequest{
|
scanReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/scan",
|
URL: e2e.GetGatewayURL() + "/v1/cache/scan",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
},
|
},
|
||||||
@ -334,7 +336,7 @@ func TestCache_Scan(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var scanResp map[string]interface{}
|
var scanResp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &scanResp); err != nil {
|
if err := e2e.DecodeJSON(body, &scanResp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,19 +347,19 @@ func TestCache_Scan(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCache_ScanWithRegex(t *testing.T) {
|
func TestCache_ScanWithRegex(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
dmap := GenerateDMapName()
|
dmap := e2e.GenerateDMapName()
|
||||||
|
|
||||||
// Put keys with different patterns
|
// Put keys with different patterns
|
||||||
keys := []string{"user-1", "user-2", "session-1", "session-2"}
|
keys := []string{"user-1", "user-2", "session-1", "session-2"}
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
putReq := &HTTPRequest{
|
putReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/put",
|
URL: e2e.GetGatewayURL() + "/v1/cache/put",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -372,9 +374,9 @@ func TestCache_ScanWithRegex(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scan with regex pattern
|
// Scan with regex pattern
|
||||||
scanReq := &HTTPRequest{
|
scanReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/scan",
|
URL: e2e.GetGatewayURL() + "/v1/cache/scan",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"pattern": "^user-",
|
"pattern": "^user-",
|
||||||
@ -391,7 +393,7 @@ func TestCache_ScanWithRegex(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var scanResp map[string]interface{}
|
var scanResp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &scanResp); err != nil {
|
if err := e2e.DecodeJSON(body, &scanResp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,19 +404,19 @@ func TestCache_ScanWithRegex(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCache_MultiGet(t *testing.T) {
|
func TestCache_MultiGet(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
dmap := GenerateDMapName()
|
dmap := e2e.GenerateDMapName()
|
||||||
keys := []string{"key-1", "key-2", "key-3"}
|
keys := []string{"key-1", "key-2", "key-3"}
|
||||||
|
|
||||||
// Put values
|
// Put values
|
||||||
for i, key := range keys {
|
for i, key := range keys {
|
||||||
putReq := &HTTPRequest{
|
putReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/put",
|
URL: e2e.GetGatewayURL() + "/v1/cache/put",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": key,
|
"key": key,
|
||||||
@ -429,9 +431,9 @@ func TestCache_MultiGet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Multi-get
|
// Multi-get
|
||||||
multiGetReq := &HTTPRequest{
|
multiGetReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/mget",
|
URL: e2e.GetGatewayURL() + "/v1/cache/mget",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"keys": keys,
|
"keys": keys,
|
||||||
@ -448,7 +450,7 @@ func TestCache_MultiGet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var mgetResp map[string]interface{}
|
var mgetResp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &mgetResp); err != nil {
|
if err := e2e.DecodeJSON(body, &mgetResp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,14 +461,14 @@ func TestCache_MultiGet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCache_MissingDMap(t *testing.T) {
|
func TestCache_MissingDMap(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
getReq := &HTTPRequest{
|
getReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/get",
|
URL: e2e.GetGatewayURL() + "/v1/cache/get",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": "",
|
"dmap": "",
|
||||||
"key": "any-key",
|
"key": "any-key",
|
||||||
@ -484,16 +486,16 @@ func TestCache_MissingDMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCache_MissingKey(t *testing.T) {
|
func TestCache_MissingKey(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
dmap := GenerateDMapName()
|
dmap := e2e.GenerateDMapName()
|
||||||
|
|
||||||
getReq := &HTTPRequest{
|
getReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/cache/get",
|
URL: e2e.GetGatewayURL() + "/v1/cache/get",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"dmap": dmap,
|
"dmap": dmap,
|
||||||
"key": "non-existent-key",
|
"key": "non-existent-key",
|
||||||
@ -1,23 +1,25 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package shared_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
e2e "github.com/DeBrosOfficial/network/e2e"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNetwork_Health(t *testing.T) {
|
func TestNetwork_Health(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/health",
|
URL: e2e.GetGatewayURL() + "/v1/health",
|
||||||
SkipAuth: true,
|
SkipAuth: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +33,7 @@ func TestNetwork_Health(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resp map[string]interface{}
|
var resp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &resp); err != nil {
|
if err := e2e.DecodeJSON(body, &resp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,14 +43,14 @@ func TestNetwork_Health(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNetwork_Status(t *testing.T) {
|
func TestNetwork_Status(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/network/status",
|
URL: e2e.GetGatewayURL() + "/v1/network/status",
|
||||||
}
|
}
|
||||||
|
|
||||||
body, status, err := req.Do(ctx)
|
body, status, err := req.Do(ctx)
|
||||||
@ -61,7 +63,7 @@ func TestNetwork_Status(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resp map[string]interface{}
|
var resp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &resp); err != nil {
|
if err := e2e.DecodeJSON(body, &resp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,14 +77,14 @@ func TestNetwork_Status(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNetwork_Peers(t *testing.T) {
|
func TestNetwork_Peers(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/network/peers",
|
URL: e2e.GetGatewayURL() + "/v1/network/peers",
|
||||||
}
|
}
|
||||||
|
|
||||||
body, status, err := req.Do(ctx)
|
body, status, err := req.Do(ctx)
|
||||||
@ -95,7 +97,7 @@ func TestNetwork_Peers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resp map[string]interface{}
|
var resp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &resp); err != nil {
|
if err := e2e.DecodeJSON(body, &resp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,14 +107,14 @@ func TestNetwork_Peers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNetwork_ProxyAnonSuccess(t *testing.T) {
|
func TestNetwork_ProxyAnonSuccess(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/proxy/anon",
|
URL: e2e.GetGatewayURL() + "/v1/proxy/anon",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"url": "https://httpbin.org/get",
|
"url": "https://httpbin.org/get",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
@ -130,7 +132,7 @@ func TestNetwork_ProxyAnonSuccess(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resp map[string]interface{}
|
var resp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &resp); err != nil {
|
if err := e2e.DecodeJSON(body, &resp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,14 +146,14 @@ func TestNetwork_ProxyAnonSuccess(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNetwork_ProxyAnonBadURL(t *testing.T) {
|
func TestNetwork_ProxyAnonBadURL(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/proxy/anon",
|
URL: e2e.GetGatewayURL() + "/v1/proxy/anon",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"url": "http://localhost:1/nonexistent",
|
"url": "http://localhost:1/nonexistent",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
@ -165,14 +167,14 @@ func TestNetwork_ProxyAnonBadURL(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNetwork_ProxyAnonPostRequest(t *testing.T) {
|
func TestNetwork_ProxyAnonPostRequest(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/proxy/anon",
|
URL: e2e.GetGatewayURL() + "/v1/proxy/anon",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"url": "https://httpbin.org/post",
|
"url": "https://httpbin.org/post",
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
@ -191,7 +193,7 @@ func TestNetwork_ProxyAnonPostRequest(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resp map[string]interface{}
|
var resp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &resp); err != nil {
|
if err := e2e.DecodeJSON(body, &resp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,9 +208,9 @@ func TestNetwork_Unauthorized(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Create request without auth
|
// Create request without auth
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/network/status",
|
URL: e2e.GetGatewayURL() + "/v1/network/status",
|
||||||
SkipAuth: true,
|
SkipAuth: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,40 +1,42 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package shared_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
e2e "github.com/DeBrosOfficial/network/e2e"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestPubSub_SubscribePublish tests basic pub/sub functionality via WebSocket
|
// TestPubSub_SubscribePublish tests basic pub/sub functionality via WebSocket
|
||||||
func TestPubSub_SubscribePublish(t *testing.T) {
|
func TestPubSub_SubscribePublish(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
topic := GenerateTopic()
|
topic := e2e.GenerateTopic()
|
||||||
message := "test-message-from-publisher"
|
message := "test-message-from-publisher"
|
||||||
|
|
||||||
// Create subscriber first
|
// Create subscriber first
|
||||||
subscriber, err := NewWSPubSubClient(t, topic)
|
subscriber, err := e2e.NewWSPubSubClient(t, topic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create subscriber: %v", err)
|
t.Fatalf("failed to create subscriber: %v", err)
|
||||||
}
|
}
|
||||||
defer subscriber.Close()
|
defer subscriber.Close()
|
||||||
|
|
||||||
// Give subscriber time to register
|
// Give subscriber time to register
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Create publisher
|
// Create publisher
|
||||||
publisher, err := NewWSPubSubClient(t, topic)
|
publisher, err := e2e.NewWSPubSubClient(t, topic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create publisher: %v", err)
|
t.Fatalf("failed to create publisher: %v", err)
|
||||||
}
|
}
|
||||||
defer publisher.Close()
|
defer publisher.Close()
|
||||||
|
|
||||||
// Give connections time to stabilize
|
// Give connections time to stabilize
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Publish message
|
// Publish message
|
||||||
if err := publisher.Publish([]byte(message)); err != nil {
|
if err := publisher.Publish([]byte(message)); err != nil {
|
||||||
@ -54,37 +56,37 @@ func TestPubSub_SubscribePublish(t *testing.T) {
|
|||||||
|
|
||||||
// TestPubSub_MultipleSubscribers tests that multiple subscribers receive the same message
|
// TestPubSub_MultipleSubscribers tests that multiple subscribers receive the same message
|
||||||
func TestPubSub_MultipleSubscribers(t *testing.T) {
|
func TestPubSub_MultipleSubscribers(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
topic := GenerateTopic()
|
topic := e2e.GenerateTopic()
|
||||||
message1 := "message-1"
|
message1 := "message-1"
|
||||||
message2 := "message-2"
|
message2 := "message-2"
|
||||||
|
|
||||||
// Create two subscribers
|
// Create two subscribers
|
||||||
sub1, err := NewWSPubSubClient(t, topic)
|
sub1, err := e2e.NewWSPubSubClient(t, topic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create subscriber1: %v", err)
|
t.Fatalf("failed to create subscriber1: %v", err)
|
||||||
}
|
}
|
||||||
defer sub1.Close()
|
defer sub1.Close()
|
||||||
|
|
||||||
sub2, err := NewWSPubSubClient(t, topic)
|
sub2, err := e2e.NewWSPubSubClient(t, topic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create subscriber2: %v", err)
|
t.Fatalf("failed to create subscriber2: %v", err)
|
||||||
}
|
}
|
||||||
defer sub2.Close()
|
defer sub2.Close()
|
||||||
|
|
||||||
// Give subscribers time to register
|
// Give subscribers time to register
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Create publisher
|
// Create publisher
|
||||||
publisher, err := NewWSPubSubClient(t, topic)
|
publisher, err := e2e.NewWSPubSubClient(t, topic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create publisher: %v", err)
|
t.Fatalf("failed to create publisher: %v", err)
|
||||||
}
|
}
|
||||||
defer publisher.Close()
|
defer publisher.Close()
|
||||||
|
|
||||||
// Give connections time to stabilize
|
// Give connections time to stabilize
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Publish first message
|
// Publish first message
|
||||||
if err := publisher.Publish([]byte(message1)); err != nil {
|
if err := publisher.Publish([]byte(message1)); err != nil {
|
||||||
@ -133,30 +135,30 @@ func TestPubSub_MultipleSubscribers(t *testing.T) {
|
|||||||
|
|
||||||
// TestPubSub_Deduplication tests that multiple identical messages are all received
|
// TestPubSub_Deduplication tests that multiple identical messages are all received
|
||||||
func TestPubSub_Deduplication(t *testing.T) {
|
func TestPubSub_Deduplication(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
topic := GenerateTopic()
|
topic := e2e.GenerateTopic()
|
||||||
message := "duplicate-test-message"
|
message := "duplicate-test-message"
|
||||||
|
|
||||||
// Create subscriber
|
// Create subscriber
|
||||||
subscriber, err := NewWSPubSubClient(t, topic)
|
subscriber, err := e2e.NewWSPubSubClient(t, topic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create subscriber: %v", err)
|
t.Fatalf("failed to create subscriber: %v", err)
|
||||||
}
|
}
|
||||||
defer subscriber.Close()
|
defer subscriber.Close()
|
||||||
|
|
||||||
// Give subscriber time to register
|
// Give subscriber time to register
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Create publisher
|
// Create publisher
|
||||||
publisher, err := NewWSPubSubClient(t, topic)
|
publisher, err := e2e.NewWSPubSubClient(t, topic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create publisher: %v", err)
|
t.Fatalf("failed to create publisher: %v", err)
|
||||||
}
|
}
|
||||||
defer publisher.Close()
|
defer publisher.Close()
|
||||||
|
|
||||||
// Give connections time to stabilize
|
// Give connections time to stabilize
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Publish the same message multiple times
|
// Publish the same message multiple times
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
@ -164,7 +166,7 @@ func TestPubSub_Deduplication(t *testing.T) {
|
|||||||
t.Fatalf("publish %d failed: %v", i, err)
|
t.Fatalf("publish %d failed: %v", i, err)
|
||||||
}
|
}
|
||||||
// Small delay between publishes
|
// Small delay between publishes
|
||||||
Delay(50)
|
e2e.Delay(50)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive messages - should get all (no dedup filter)
|
// Receive messages - should get all (no dedup filter)
|
||||||
@ -185,30 +187,30 @@ func TestPubSub_Deduplication(t *testing.T) {
|
|||||||
|
|
||||||
// TestPubSub_ConcurrentPublish tests concurrent message publishing
|
// TestPubSub_ConcurrentPublish tests concurrent message publishing
|
||||||
func TestPubSub_ConcurrentPublish(t *testing.T) {
|
func TestPubSub_ConcurrentPublish(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
topic := GenerateTopic()
|
topic := e2e.GenerateTopic()
|
||||||
numMessages := 10
|
numMessages := 10
|
||||||
|
|
||||||
// Create subscriber
|
// Create subscriber
|
||||||
subscriber, err := NewWSPubSubClient(t, topic)
|
subscriber, err := e2e.NewWSPubSubClient(t, topic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create subscriber: %v", err)
|
t.Fatalf("failed to create subscriber: %v", err)
|
||||||
}
|
}
|
||||||
defer subscriber.Close()
|
defer subscriber.Close()
|
||||||
|
|
||||||
// Give subscriber time to register
|
// Give subscriber time to register
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Create publisher
|
// Create publisher
|
||||||
publisher, err := NewWSPubSubClient(t, topic)
|
publisher, err := e2e.NewWSPubSubClient(t, topic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create publisher: %v", err)
|
t.Fatalf("failed to create publisher: %v", err)
|
||||||
}
|
}
|
||||||
defer publisher.Close()
|
defer publisher.Close()
|
||||||
|
|
||||||
// Give connections time to stabilize
|
// Give connections time to stabilize
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Publish multiple messages concurrently
|
// Publish multiple messages concurrently
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
@ -241,45 +243,45 @@ func TestPubSub_ConcurrentPublish(t *testing.T) {
|
|||||||
|
|
||||||
// TestPubSub_TopicIsolation tests that messages are isolated to their topics
|
// TestPubSub_TopicIsolation tests that messages are isolated to their topics
|
||||||
func TestPubSub_TopicIsolation(t *testing.T) {
|
func TestPubSub_TopicIsolation(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
topic1 := GenerateTopic()
|
topic1 := e2e.GenerateTopic()
|
||||||
topic2 := GenerateTopic()
|
topic2 := e2e.GenerateTopic()
|
||||||
msg1 := "message-on-topic1"
|
msg1 := "message-on-topic1"
|
||||||
msg2 := "message-on-topic2"
|
msg2 := "message-on-topic2"
|
||||||
|
|
||||||
// Create subscriber for topic1
|
// Create subscriber for topic1
|
||||||
sub1, err := NewWSPubSubClient(t, topic1)
|
sub1, err := e2e.NewWSPubSubClient(t, topic1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create subscriber1: %v", err)
|
t.Fatalf("failed to create subscriber1: %v", err)
|
||||||
}
|
}
|
||||||
defer sub1.Close()
|
defer sub1.Close()
|
||||||
|
|
||||||
// Create subscriber for topic2
|
// Create subscriber for topic2
|
||||||
sub2, err := NewWSPubSubClient(t, topic2)
|
sub2, err := e2e.NewWSPubSubClient(t, topic2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create subscriber2: %v", err)
|
t.Fatalf("failed to create subscriber2: %v", err)
|
||||||
}
|
}
|
||||||
defer sub2.Close()
|
defer sub2.Close()
|
||||||
|
|
||||||
// Give subscribers time to register
|
// Give subscribers time to register
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Create publishers
|
// Create publishers
|
||||||
pub1, err := NewWSPubSubClient(t, topic1)
|
pub1, err := e2e.NewWSPubSubClient(t, topic1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create publisher1: %v", err)
|
t.Fatalf("failed to create publisher1: %v", err)
|
||||||
}
|
}
|
||||||
defer pub1.Close()
|
defer pub1.Close()
|
||||||
|
|
||||||
pub2, err := NewWSPubSubClient(t, topic2)
|
pub2, err := e2e.NewWSPubSubClient(t, topic2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create publisher2: %v", err)
|
t.Fatalf("failed to create publisher2: %v", err)
|
||||||
}
|
}
|
||||||
defer pub2.Close()
|
defer pub2.Close()
|
||||||
|
|
||||||
// Give connections time to stabilize
|
// Give connections time to stabilize
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Publish to topic2 first
|
// Publish to topic2 first
|
||||||
if err := pub2.Publish([]byte(msg2)); err != nil {
|
if err := pub2.Publish([]byte(msg2)); err != nil {
|
||||||
@ -312,29 +314,29 @@ func TestPubSub_TopicIsolation(t *testing.T) {
|
|||||||
|
|
||||||
// TestPubSub_EmptyMessage tests sending and receiving empty messages
|
// TestPubSub_EmptyMessage tests sending and receiving empty messages
|
||||||
func TestPubSub_EmptyMessage(t *testing.T) {
|
func TestPubSub_EmptyMessage(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
topic := GenerateTopic()
|
topic := e2e.GenerateTopic()
|
||||||
|
|
||||||
// Create subscriber
|
// Create subscriber
|
||||||
subscriber, err := NewWSPubSubClient(t, topic)
|
subscriber, err := e2e.NewWSPubSubClient(t, topic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create subscriber: %v", err)
|
t.Fatalf("failed to create subscriber: %v", err)
|
||||||
}
|
}
|
||||||
defer subscriber.Close()
|
defer subscriber.Close()
|
||||||
|
|
||||||
// Give subscriber time to register
|
// Give subscriber time to register
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Create publisher
|
// Create publisher
|
||||||
publisher, err := NewWSPubSubClient(t, topic)
|
publisher, err := e2e.NewWSPubSubClient(t, topic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create publisher: %v", err)
|
t.Fatalf("failed to create publisher: %v", err)
|
||||||
}
|
}
|
||||||
defer publisher.Close()
|
defer publisher.Close()
|
||||||
|
|
||||||
// Give connections time to stabilize
|
// Give connections time to stabilize
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Publish empty message
|
// Publish empty message
|
||||||
if err := publisher.Publish([]byte("")); err != nil {
|
if err := publisher.Publish([]byte("")); err != nil {
|
||||||
@ -354,9 +356,9 @@ func TestPubSub_EmptyMessage(t *testing.T) {
|
|||||||
|
|
||||||
// TestPubSub_LargeMessage tests sending and receiving large messages
|
// TestPubSub_LargeMessage tests sending and receiving large messages
|
||||||
func TestPubSub_LargeMessage(t *testing.T) {
|
func TestPubSub_LargeMessage(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
topic := GenerateTopic()
|
topic := e2e.GenerateTopic()
|
||||||
|
|
||||||
// Create a large message (100KB)
|
// Create a large message (100KB)
|
||||||
largeMessage := make([]byte, 100*1024)
|
largeMessage := make([]byte, 100*1024)
|
||||||
@ -365,24 +367,24 @@ func TestPubSub_LargeMessage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create subscriber
|
// Create subscriber
|
||||||
subscriber, err := NewWSPubSubClient(t, topic)
|
subscriber, err := e2e.NewWSPubSubClient(t, topic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create subscriber: %v", err)
|
t.Fatalf("failed to create subscriber: %v", err)
|
||||||
}
|
}
|
||||||
defer subscriber.Close()
|
defer subscriber.Close()
|
||||||
|
|
||||||
// Give subscriber time to register
|
// Give subscriber time to register
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Create publisher
|
// Create publisher
|
||||||
publisher, err := NewWSPubSubClient(t, topic)
|
publisher, err := e2e.NewWSPubSubClient(t, topic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create publisher: %v", err)
|
t.Fatalf("failed to create publisher: %v", err)
|
||||||
}
|
}
|
||||||
defer publisher.Close()
|
defer publisher.Close()
|
||||||
|
|
||||||
// Give connections time to stabilize
|
// Give connections time to stabilize
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Publish large message
|
// Publish large message
|
||||||
if err := publisher.Publish(largeMessage); err != nil {
|
if err := publisher.Publish(largeMessage); err != nil {
|
||||||
@ -409,30 +411,30 @@ func TestPubSub_LargeMessage(t *testing.T) {
|
|||||||
|
|
||||||
// TestPubSub_RapidPublish tests rapid message publishing
|
// TestPubSub_RapidPublish tests rapid message publishing
|
||||||
func TestPubSub_RapidPublish(t *testing.T) {
|
func TestPubSub_RapidPublish(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
topic := GenerateTopic()
|
topic := e2e.GenerateTopic()
|
||||||
numMessages := 50
|
numMessages := 50
|
||||||
|
|
||||||
// Create subscriber
|
// Create subscriber
|
||||||
subscriber, err := NewWSPubSubClient(t, topic)
|
subscriber, err := e2e.NewWSPubSubClient(t, topic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create subscriber: %v", err)
|
t.Fatalf("failed to create subscriber: %v", err)
|
||||||
}
|
}
|
||||||
defer subscriber.Close()
|
defer subscriber.Close()
|
||||||
|
|
||||||
// Give subscriber time to register
|
// Give subscriber time to register
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Create publisher
|
// Create publisher
|
||||||
publisher, err := NewWSPubSubClient(t, topic)
|
publisher, err := e2e.NewWSPubSubClient(t, topic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create publisher: %v", err)
|
t.Fatalf("failed to create publisher: %v", err)
|
||||||
}
|
}
|
||||||
defer publisher.Close()
|
defer publisher.Close()
|
||||||
|
|
||||||
// Give connections time to stabilize
|
// Give connections time to stabilize
|
||||||
Delay(200)
|
e2e.Delay(200)
|
||||||
|
|
||||||
// Publish messages rapidly
|
// Publish messages rapidly
|
||||||
for i := 0; i < numMessages; i++ {
|
for i := 0; i < numMessages; i++ {
|
||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package shared_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -9,17 +9,19 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
e2e "github.com/DeBrosOfficial/network/e2e"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPubSub_Presence(t *testing.T) {
|
func TestPubSub_Presence(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
topic := GenerateTopic()
|
topic := e2e.GenerateTopic()
|
||||||
memberID := "user123"
|
memberID := "user123"
|
||||||
memberMeta := map[string]interface{}{"name": "Alice"}
|
memberMeta := map[string]interface{}{"name": "Alice"}
|
||||||
|
|
||||||
// 1. Subscribe with presence
|
// 1. Subscribe with presence
|
||||||
client1, err := NewWSPubSubPresenceClient(t, topic, memberID, memberMeta)
|
client1, err := e2e.NewWSPubSubPresenceClient(t, topic, memberID, memberMeta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create presence client: %v", err)
|
t.Fatalf("failed to create presence client: %v", err)
|
||||||
}
|
}
|
||||||
@ -48,9 +50,9 @@ func TestPubSub_Presence(t *testing.T) {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: fmt.Sprintf("%s/v1/pubsub/presence?topic=%s", GetGatewayURL(), topic),
|
URL: fmt.Sprintf("%s/v1/pubsub/presence?topic=%s", e2e.GetGatewayURL(), topic),
|
||||||
}
|
}
|
||||||
|
|
||||||
body, status, err := req.Do(ctx)
|
body, status, err := req.Do(ctx)
|
||||||
@ -63,7 +65,7 @@ func TestPubSub_Presence(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resp map[string]interface{}
|
var resp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &resp); err != nil {
|
if err := e2e.DecodeJSON(body, &resp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +85,7 @@ func TestPubSub_Presence(t *testing.T) {
|
|||||||
|
|
||||||
// 3. Subscribe second member
|
// 3. Subscribe second member
|
||||||
memberID2 := "user456"
|
memberID2 := "user456"
|
||||||
client2, err := NewWSPubSubPresenceClient(t, topic, memberID2, nil)
|
client2, err := e2e.NewWSPubSubPresenceClient(t, topic, memberID2, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create second presence client: %v", err)
|
t.Fatalf("failed to create second presence client: %v", err)
|
||||||
}
|
}
|
||||||
@ -119,4 +121,3 @@ func TestPubSub_Presence(t *testing.T) {
|
|||||||
t.Fatalf("expected presence.leave for %s, got %v for %v", memberID2, event["type"], event["member_id"])
|
t.Fatalf("expected presence.leave for %s, got %v for %v", memberID2, event["type"], event["member_id"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package shared_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -8,21 +8,23 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
e2e "github.com/DeBrosOfficial/network/e2e"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRQLite_CreateTable(t *testing.T) {
|
func TestRQLite_CreateTable(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
table := GenerateTableName()
|
table := e2e.GenerateTableName()
|
||||||
|
|
||||||
// Cleanup table after test
|
// Cleanup table after test
|
||||||
defer func() {
|
defer func() {
|
||||||
dropReq := &HTTPRequest{
|
dropReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/drop-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/drop-table",
|
||||||
Body: map[string]interface{}{"table": table},
|
Body: map[string]interface{}{"table": table},
|
||||||
}
|
}
|
||||||
dropReq.Do(context.Background())
|
dropReq.Do(context.Background())
|
||||||
@ -33,9 +35,9 @@ func TestRQLite_CreateTable(t *testing.T) {
|
|||||||
table,
|
table,
|
||||||
)
|
)
|
||||||
|
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/create-table",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"schema": schema,
|
"schema": schema,
|
||||||
},
|
},
|
||||||
@ -52,18 +54,18 @@ func TestRQLite_CreateTable(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRQLite_InsertQuery(t *testing.T) {
|
func TestRQLite_InsertQuery(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
table := GenerateTableName()
|
table := e2e.GenerateTableName()
|
||||||
|
|
||||||
// Cleanup table after test
|
// Cleanup table after test
|
||||||
defer func() {
|
defer func() {
|
||||||
dropReq := &HTTPRequest{
|
dropReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/drop-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/drop-table",
|
||||||
Body: map[string]interface{}{"table": table},
|
Body: map[string]interface{}{"table": table},
|
||||||
}
|
}
|
||||||
dropReq.Do(context.Background())
|
dropReq.Do(context.Background())
|
||||||
@ -75,9 +77,9 @@ func TestRQLite_InsertQuery(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Create table
|
// Create table
|
||||||
createReq := &HTTPRequest{
|
createReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/create-table",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"schema": schema,
|
"schema": schema,
|
||||||
},
|
},
|
||||||
@ -89,9 +91,9 @@ func TestRQLite_InsertQuery(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Insert rows
|
// Insert rows
|
||||||
insertReq := &HTTPRequest{
|
insertReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/transaction",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"statements": []string{
|
"statements": []string{
|
||||||
fmt.Sprintf("INSERT INTO %s(name) VALUES ('alice')", table),
|
fmt.Sprintf("INSERT INTO %s(name) VALUES ('alice')", table),
|
||||||
@ -106,9 +108,9 @@ func TestRQLite_InsertQuery(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Query rows
|
// Query rows
|
||||||
queryReq := &HTTPRequest{
|
queryReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/query",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/query",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"sql": fmt.Sprintf("SELECT name FROM %s ORDER BY id", table),
|
"sql": fmt.Sprintf("SELECT name FROM %s ORDER BY id", table),
|
||||||
},
|
},
|
||||||
@ -124,7 +126,7 @@ func TestRQLite_InsertQuery(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var queryResp map[string]interface{}
|
var queryResp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &queryResp); err != nil {
|
if err := e2e.DecodeJSON(body, &queryResp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,21 +136,21 @@ func TestRQLite_InsertQuery(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRQLite_DropTable(t *testing.T) {
|
func TestRQLite_DropTable(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
table := GenerateTableName()
|
table := e2e.GenerateTableName()
|
||||||
schema := fmt.Sprintf(
|
schema := fmt.Sprintf(
|
||||||
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, note TEXT)",
|
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, note TEXT)",
|
||||||
table,
|
table,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create table
|
// Create table
|
||||||
createReq := &HTTPRequest{
|
createReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/create-table",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"schema": schema,
|
"schema": schema,
|
||||||
},
|
},
|
||||||
@ -160,9 +162,9 @@ func TestRQLite_DropTable(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Drop table
|
// Drop table
|
||||||
dropReq := &HTTPRequest{
|
dropReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/drop-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/drop-table",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"table": table,
|
"table": table,
|
||||||
},
|
},
|
||||||
@ -178,9 +180,9 @@ func TestRQLite_DropTable(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify table doesn't exist via schema
|
// Verify table doesn't exist via schema
|
||||||
schemaReq := &HTTPRequest{
|
schemaReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/schema",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/schema",
|
||||||
}
|
}
|
||||||
|
|
||||||
body, status, err := schemaReq.Do(ctx)
|
body, status, err := schemaReq.Do(ctx)
|
||||||
@ -190,7 +192,7 @@ func TestRQLite_DropTable(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var schemaResp map[string]interface{}
|
var schemaResp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &schemaResp); err != nil {
|
if err := e2e.DecodeJSON(body, &schemaResp); err != nil {
|
||||||
t.Logf("warning: failed to decode schema response: %v", err)
|
t.Logf("warning: failed to decode schema response: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -206,14 +208,14 @@ func TestRQLite_DropTable(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRQLite_Schema(t *testing.T) {
|
func TestRQLite_Schema(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/schema",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/schema",
|
||||||
}
|
}
|
||||||
|
|
||||||
body, status, err := req.Do(ctx)
|
body, status, err := req.Do(ctx)
|
||||||
@ -226,7 +228,7 @@ func TestRQLite_Schema(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resp map[string]interface{}
|
var resp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &resp); err != nil {
|
if err := e2e.DecodeJSON(body, &resp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,14 +238,14 @@ func TestRQLite_Schema(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRQLite_MalformedSQL(t *testing.T) {
|
func TestRQLite_MalformedSQL(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
req := &HTTPRequest{
|
req := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/query",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/query",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"sql": "SELECT * FROM nonexistent_table WHERE invalid syntax",
|
"sql": "SELECT * FROM nonexistent_table WHERE invalid syntax",
|
||||||
},
|
},
|
||||||
@ -261,18 +263,18 @@ func TestRQLite_MalformedSQL(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRQLite_LargeTransaction(t *testing.T) {
|
func TestRQLite_LargeTransaction(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
table := GenerateTableName()
|
table := e2e.GenerateTableName()
|
||||||
|
|
||||||
// Cleanup table after test
|
// Cleanup table after test
|
||||||
defer func() {
|
defer func() {
|
||||||
dropReq := &HTTPRequest{
|
dropReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/drop-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/drop-table",
|
||||||
Body: map[string]interface{}{"table": table},
|
Body: map[string]interface{}{"table": table},
|
||||||
}
|
}
|
||||||
dropReq.Do(context.Background())
|
dropReq.Do(context.Background())
|
||||||
@ -284,9 +286,9 @@ func TestRQLite_LargeTransaction(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Create table
|
// Create table
|
||||||
createReq := &HTTPRequest{
|
createReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/create-table",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"schema": schema,
|
"schema": schema,
|
||||||
},
|
},
|
||||||
@ -303,9 +305,9 @@ func TestRQLite_LargeTransaction(t *testing.T) {
|
|||||||
statements = append(statements, fmt.Sprintf("INSERT INTO %s(value) VALUES (%d)", table, i))
|
statements = append(statements, fmt.Sprintf("INSERT INTO %s(value) VALUES (%d)", table, i))
|
||||||
}
|
}
|
||||||
|
|
||||||
txReq := &HTTPRequest{
|
txReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/transaction",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"statements": statements,
|
"statements": statements,
|
||||||
},
|
},
|
||||||
@ -317,9 +319,9 @@ func TestRQLite_LargeTransaction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify all rows were inserted
|
// Verify all rows were inserted
|
||||||
queryReq := &HTTPRequest{
|
queryReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/query",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/query",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"sql": fmt.Sprintf("SELECT COUNT(*) as count FROM %s", table),
|
"sql": fmt.Sprintf("SELECT COUNT(*) as count FROM %s", table),
|
||||||
},
|
},
|
||||||
@ -331,7 +333,7 @@ func TestRQLite_LargeTransaction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var countResp map[string]interface{}
|
var countResp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &countResp); err != nil {
|
if err := e2e.DecodeJSON(body, &countResp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,35 +347,35 @@ func TestRQLite_LargeTransaction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRQLite_ForeignKeyMigration(t *testing.T) {
|
func TestRQLite_ForeignKeyMigration(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
orgsTable := GenerateTableName()
|
orgsTable := e2e.GenerateTableName()
|
||||||
usersTable := GenerateTableName()
|
usersTable := e2e.GenerateTableName()
|
||||||
|
|
||||||
// Cleanup tables after test
|
// Cleanup tables after test
|
||||||
defer func() {
|
defer func() {
|
||||||
dropUsersReq := &HTTPRequest{
|
dropUsersReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/drop-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/drop-table",
|
||||||
Body: map[string]interface{}{"table": usersTable},
|
Body: map[string]interface{}{"table": usersTable},
|
||||||
}
|
}
|
||||||
dropUsersReq.Do(context.Background())
|
dropUsersReq.Do(context.Background())
|
||||||
|
|
||||||
dropOrgsReq := &HTTPRequest{
|
dropOrgsReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/drop-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/drop-table",
|
||||||
Body: map[string]interface{}{"table": orgsTable},
|
Body: map[string]interface{}{"table": orgsTable},
|
||||||
}
|
}
|
||||||
dropOrgsReq.Do(context.Background())
|
dropOrgsReq.Do(context.Background())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Create base tables
|
// Create base tables
|
||||||
createOrgsReq := &HTTPRequest{
|
createOrgsReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/create-table",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"schema": fmt.Sprintf(
|
"schema": fmt.Sprintf(
|
||||||
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, name TEXT)",
|
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, name TEXT)",
|
||||||
@ -387,9 +389,9 @@ func TestRQLite_ForeignKeyMigration(t *testing.T) {
|
|||||||
t.Fatalf("create orgs table failed: status %d, err %v", status, err)
|
t.Fatalf("create orgs table failed: status %d, err %v", status, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
createUsersReq := &HTTPRequest{
|
createUsersReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/create-table",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"schema": fmt.Sprintf(
|
"schema": fmt.Sprintf(
|
||||||
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, name TEXT, org_id INTEGER, age TEXT)",
|
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, name TEXT, org_id INTEGER, age TEXT)",
|
||||||
@ -404,9 +406,9 @@ func TestRQLite_ForeignKeyMigration(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Seed data
|
// Seed data
|
||||||
seedReq := &HTTPRequest{
|
seedReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/transaction",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"statements": []string{
|
"statements": []string{
|
||||||
fmt.Sprintf("INSERT INTO %s(id,name) VALUES (1,'org')", orgsTable),
|
fmt.Sprintf("INSERT INTO %s(id,name) VALUES (1,'org')", orgsTable),
|
||||||
@ -421,9 +423,9 @@ func TestRQLite_ForeignKeyMigration(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Migrate: change age type and add FK
|
// Migrate: change age type and add FK
|
||||||
migrationReq := &HTTPRequest{
|
migrationReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/transaction",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"statements": []string{
|
"statements": []string{
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
@ -446,9 +448,9 @@ func TestRQLite_ForeignKeyMigration(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify data is intact
|
// Verify data is intact
|
||||||
queryReq := &HTTPRequest{
|
queryReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/query",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/query",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"sql": fmt.Sprintf("SELECT name, org_id, age FROM %s", usersTable),
|
"sql": fmt.Sprintf("SELECT name, org_id, age FROM %s", usersTable),
|
||||||
},
|
},
|
||||||
@ -460,7 +462,7 @@ func TestRQLite_ForeignKeyMigration(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var queryResp map[string]interface{}
|
var queryResp map[string]interface{}
|
||||||
if err := DecodeJSON(body, &queryResp); err != nil {
|
if err := e2e.DecodeJSON(body, &queryResp); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,14 +472,14 @@ func TestRQLite_ForeignKeyMigration(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRQLite_DropNonexistentTable(t *testing.T) {
|
func TestRQLite_DropNonexistentTable(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
dropReq := &HTTPRequest{
|
dropReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/rqlite/drop-table",
|
URL: e2e.GetGatewayURL() + "/v1/rqlite/drop-table",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"table": "nonexistent_table_xyz_" + fmt.Sprintf("%d", time.Now().UnixNano()),
|
"table": "nonexistent_table_xyz_" + fmt.Sprintf("%d", time.Now().UnixNano()),
|
||||||
},
|
},
|
||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package shared_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -11,10 +11,12 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
e2e "github.com/DeBrosOfficial/network/e2e"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestServerless_DeployAndInvoke(t *testing.T) {
|
func TestServerless_DeployAndInvoke(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -53,14 +55,14 @@ func TestServerless_DeployAndInvoke(t *testing.T) {
|
|||||||
part.Write(wasmBytes)
|
part.Write(wasmBytes)
|
||||||
writer.Close()
|
writer.Close()
|
||||||
|
|
||||||
deployReq, _ := http.NewRequestWithContext(ctx, "POST", GetGatewayURL()+"/v1/functions", &buf)
|
deployReq, _ := http.NewRequestWithContext(ctx, "POST", e2e.GetGatewayURL()+"/v1/functions", &buf)
|
||||||
deployReq.Header.Set("Content-Type", writer.FormDataContentType())
|
deployReq.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
|
||||||
if apiKey := GetAPIKey(); apiKey != "" {
|
if apiKey := e2e.GetAPIKey(); apiKey != "" {
|
||||||
deployReq.Header.Set("Authorization", "Bearer "+apiKey)
|
deployReq.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := NewHTTPClient(1 * time.Minute)
|
client := e2e.NewHTTPClient(1 * time.Minute)
|
||||||
resp, err := client.Do(deployReq)
|
resp, err := client.Do(deployReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("deploy request failed: %v", err)
|
t.Fatalf("deploy request failed: %v", err)
|
||||||
@ -74,10 +76,10 @@ func TestServerless_DeployAndInvoke(t *testing.T) {
|
|||||||
|
|
||||||
// 2. Invoke function
|
// 2. Invoke function
|
||||||
invokePayload := []byte(`{"name": "E2E Tester"}`)
|
invokePayload := []byte(`{"name": "E2E Tester"}`)
|
||||||
invokeReq, _ := http.NewRequestWithContext(ctx, "POST", GetGatewayURL()+"/v1/functions/"+funcName+"/invoke?namespace="+namespace, bytes.NewReader(invokePayload))
|
invokeReq, _ := http.NewRequestWithContext(ctx, "POST", e2e.GetGatewayURL()+"/v1/functions/"+funcName+"/invoke?namespace="+namespace, bytes.NewReader(invokePayload))
|
||||||
invokeReq.Header.Set("Content-Type", "application/json")
|
invokeReq.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
if apiKey := GetAPIKey(); apiKey != "" {
|
if apiKey := e2e.GetAPIKey(); apiKey != "" {
|
||||||
invokeReq.Header.Set("Authorization", "Bearer "+apiKey)
|
invokeReq.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,8 +101,8 @@ func TestServerless_DeployAndInvoke(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3. List functions
|
// 3. List functions
|
||||||
listReq, _ := http.NewRequestWithContext(ctx, "GET", GetGatewayURL()+"/v1/functions?namespace="+namespace, nil)
|
listReq, _ := http.NewRequestWithContext(ctx, "GET", e2e.GetGatewayURL()+"/v1/functions?namespace="+namespace, nil)
|
||||||
if apiKey := GetAPIKey(); apiKey != "" {
|
if apiKey := e2e.GetAPIKey(); apiKey != "" {
|
||||||
listReq.Header.Set("Authorization", "Bearer "+apiKey)
|
listReq.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
}
|
}
|
||||||
resp, err = client.Do(listReq)
|
resp, err = client.Do(listReq)
|
||||||
@ -113,8 +115,8 @@ func TestServerless_DeployAndInvoke(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4. Delete function
|
// 4. Delete function
|
||||||
deleteReq, _ := http.NewRequestWithContext(ctx, "DELETE", GetGatewayURL()+"/v1/functions/"+funcName+"?namespace="+namespace, nil)
|
deleteReq, _ := http.NewRequestWithContext(ctx, "DELETE", e2e.GetGatewayURL()+"/v1/functions/"+funcName+"?namespace="+namespace, nil)
|
||||||
if apiKey := GetAPIKey(); apiKey != "" {
|
if apiKey := e2e.GetAPIKey(); apiKey != "" {
|
||||||
deleteReq.Header.Set("Authorization", "Bearer "+apiKey)
|
deleteReq.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
}
|
}
|
||||||
resp, err = client.Do(deleteReq)
|
resp, err = client.Do(deleteReq)
|
||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build e2e
|
//go:build e2e
|
||||||
|
|
||||||
package e2e
|
package shared_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -10,6 +10,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
e2e "github.com/DeBrosOfficial/network/e2e"
|
||||||
)
|
)
|
||||||
|
|
||||||
// uploadFile is a helper to upload a file to storage
|
// uploadFile is a helper to upload a file to storage
|
||||||
@ -34,7 +36,7 @@ func uploadFile(t *testing.T, ctx context.Context, content []byte, filename stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create request
|
// Create request
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, GetGatewayURL()+"/v1/storage/upload", &buf)
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, e2e.GetGatewayURL()+"/v1/storage/upload", &buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create request: %v", err)
|
t.Fatalf("failed to create request: %v", err)
|
||||||
}
|
}
|
||||||
@ -42,13 +44,13 @@ func uploadFile(t *testing.T, ctx context.Context, content []byte, filename stri
|
|||||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
|
||||||
// Add auth headers
|
// Add auth headers
|
||||||
if jwt := GetJWT(); jwt != "" {
|
if jwt := e2e.GetJWT(); jwt != "" {
|
||||||
req.Header.Set("Authorization", "Bearer "+jwt)
|
req.Header.Set("Authorization", "Bearer "+jwt)
|
||||||
} else if apiKey := GetAPIKey(); apiKey != "" {
|
} else if apiKey := e2e.GetAPIKey(); apiKey != "" {
|
||||||
req.Header.Set("Authorization", "Bearer "+apiKey)
|
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := NewHTTPClient(5 * time.Minute)
|
client := e2e.NewHTTPClient(5 * time.Minute)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("upload request failed: %v", err)
|
t.Fatalf("upload request failed: %v", err)
|
||||||
@ -60,28 +62,20 @@ func uploadFile(t *testing.T, ctx context.Context, content []byte, filename stri
|
|||||||
t.Fatalf("upload failed with status %d: %s", resp.StatusCode, string(body))
|
t.Fatalf("upload failed with status %d: %s", resp.StatusCode, string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := DecodeJSONFromReader(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read upload response: %v", err)
|
||||||
|
}
|
||||||
|
var result map[string]interface{}
|
||||||
|
if err := e2e.DecodeJSON(body, &result); err != nil {
|
||||||
t.Fatalf("failed to decode upload response: %v", err)
|
t.Fatalf("failed to decode upload response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result["cid"].(string)
|
return result["cid"].(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeJSON is a helper to decode JSON from io.ReadCloser
|
|
||||||
func DecodeJSONFromReader(rc io.ReadCloser) (map[string]interface{}, error) {
|
|
||||||
defer rc.Close()
|
|
||||||
body, err := io.ReadAll(rc)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var result map[string]interface{}
|
|
||||||
err = DecodeJSON(body, &result)
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStorage_UploadText(t *testing.T) {
|
func TestStorage_UploadText(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -107,18 +101,18 @@ func TestStorage_UploadText(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create request
|
// Create request
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, GetGatewayURL()+"/v1/storage/upload", &buf)
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, e2e.GetGatewayURL()+"/v1/storage/upload", &buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create request: %v", err)
|
t.Fatalf("failed to create request: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
|
||||||
if apiKey := GetAPIKey(); apiKey != "" {
|
if apiKey := e2e.GetAPIKey(); apiKey != "" {
|
||||||
req.Header.Set("Authorization", "Bearer "+apiKey)
|
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := NewHTTPClient(5 * time.Minute)
|
client := e2e.NewHTTPClient(5 * time.Minute)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("upload request failed: %v", err)
|
t.Fatalf("upload request failed: %v", err)
|
||||||
@ -132,7 +126,7 @@ func TestStorage_UploadText(t *testing.T) {
|
|||||||
|
|
||||||
var result map[string]interface{}
|
var result map[string]interface{}
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
if err := DecodeJSON(body, &result); err != nil {
|
if err := e2e.DecodeJSON(body, &result); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +144,7 @@ func TestStorage_UploadText(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestStorage_UploadBinary(t *testing.T) {
|
func TestStorage_UploadBinary(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -177,18 +171,18 @@ func TestStorage_UploadBinary(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create request
|
// Create request
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, GetGatewayURL()+"/v1/storage/upload", &buf)
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, e2e.GetGatewayURL()+"/v1/storage/upload", &buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create request: %v", err)
|
t.Fatalf("failed to create request: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
|
||||||
if apiKey := GetAPIKey(); apiKey != "" {
|
if apiKey := e2e.GetAPIKey(); apiKey != "" {
|
||||||
req.Header.Set("Authorization", "Bearer "+apiKey)
|
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := NewHTTPClient(5 * time.Minute)
|
client := e2e.NewHTTPClient(5 * time.Minute)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("upload request failed: %v", err)
|
t.Fatalf("upload request failed: %v", err)
|
||||||
@ -202,7 +196,7 @@ func TestStorage_UploadBinary(t *testing.T) {
|
|||||||
|
|
||||||
var result map[string]interface{}
|
var result map[string]interface{}
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
if err := DecodeJSON(body, &result); err != nil {
|
if err := e2e.DecodeJSON(body, &result); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +206,7 @@ func TestStorage_UploadBinary(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestStorage_UploadLarge(t *testing.T) {
|
func TestStorage_UploadLarge(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -239,18 +233,18 @@ func TestStorage_UploadLarge(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create request
|
// Create request
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, GetGatewayURL()+"/v1/storage/upload", &buf)
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, e2e.GetGatewayURL()+"/v1/storage/upload", &buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create request: %v", err)
|
t.Fatalf("failed to create request: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
|
||||||
if apiKey := GetAPIKey(); apiKey != "" {
|
if apiKey := e2e.GetAPIKey(); apiKey != "" {
|
||||||
req.Header.Set("Authorization", "Bearer "+apiKey)
|
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := NewHTTPClient(5 * time.Minute)
|
client := e2e.NewHTTPClient(5 * time.Minute)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("upload request failed: %v", err)
|
t.Fatalf("upload request failed: %v", err)
|
||||||
@ -264,7 +258,7 @@ func TestStorage_UploadLarge(t *testing.T) {
|
|||||||
|
|
||||||
var result map[string]interface{}
|
var result map[string]interface{}
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
if err := DecodeJSON(body, &result); err != nil {
|
if err := e2e.DecodeJSON(body, &result); err != nil {
|
||||||
t.Fatalf("failed to decode response: %v", err)
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,7 +268,7 @@ func TestStorage_UploadLarge(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestStorage_PinUnpin(t *testing.T) {
|
func TestStorage_PinUnpin(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -299,18 +293,18 @@ func TestStorage_PinUnpin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create upload request
|
// Create upload request
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, GetGatewayURL()+"/v1/storage/upload", &buf)
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, e2e.GetGatewayURL()+"/v1/storage/upload", &buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create request: %v", err)
|
t.Fatalf("failed to create request: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
|
||||||
if apiKey := GetAPIKey(); apiKey != "" {
|
if apiKey := e2e.GetAPIKey(); apiKey != "" {
|
||||||
req.Header.Set("Authorization", "Bearer "+apiKey)
|
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := NewHTTPClient(5 * time.Minute)
|
client := e2e.NewHTTPClient(5 * time.Minute)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("upload failed: %v", err)
|
t.Fatalf("upload failed: %v", err)
|
||||||
@ -319,7 +313,7 @@ func TestStorage_PinUnpin(t *testing.T) {
|
|||||||
|
|
||||||
var uploadResult map[string]interface{}
|
var uploadResult map[string]interface{}
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
if err := DecodeJSON(body, &uploadResult); err != nil {
|
if err := e2e.DecodeJSON(body, &uploadResult); err != nil {
|
||||||
t.Fatalf("failed to decode upload response: %v", err)
|
t.Fatalf("failed to decode upload response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,9 +327,9 @@ func TestStorage_PinUnpin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pin the file
|
// Pin the file
|
||||||
pinReq := &HTTPRequest{
|
pinReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
URL: GetGatewayURL() + "/v1/storage/pin",
|
URL: e2e.GetGatewayURL() + "/v1/storage/pin",
|
||||||
Body: map[string]interface{}{
|
Body: map[string]interface{}{
|
||||||
"cid": cid,
|
"cid": cid,
|
||||||
"name": "pinned-file",
|
"name": "pinned-file",
|
||||||
@ -352,7 +346,7 @@ func TestStorage_PinUnpin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var pinResult map[string]interface{}
|
var pinResult map[string]interface{}
|
||||||
if err := DecodeJSON(body2, &pinResult); err != nil {
|
if err := e2e.DecodeJSON(body2, &pinResult); err != nil {
|
||||||
t.Fatalf("failed to decode pin response: %v", err)
|
t.Fatalf("failed to decode pin response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,9 +355,9 @@ func TestStorage_PinUnpin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unpin the file
|
// Unpin the file
|
||||||
unpinReq := &HTTPRequest{
|
unpinReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodDelete,
|
Method: http.MethodDelete,
|
||||||
URL: GetGatewayURL() + "/v1/storage/unpin/" + cid,
|
URL: e2e.GetGatewayURL() + "/v1/storage/unpin/" + cid,
|
||||||
}
|
}
|
||||||
|
|
||||||
body3, status, err := unpinReq.Do(ctx)
|
body3, status, err := unpinReq.Do(ctx)
|
||||||
@ -377,7 +371,7 @@ func TestStorage_PinUnpin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestStorage_Status(t *testing.T) {
|
func TestStorage_Status(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -402,18 +396,18 @@ func TestStorage_Status(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create upload request
|
// Create upload request
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, GetGatewayURL()+"/v1/storage/upload", &buf)
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, e2e.GetGatewayURL()+"/v1/storage/upload", &buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create request: %v", err)
|
t.Fatalf("failed to create request: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
|
||||||
if apiKey := GetAPIKey(); apiKey != "" {
|
if apiKey := e2e.GetAPIKey(); apiKey != "" {
|
||||||
req.Header.Set("Authorization", "Bearer "+apiKey)
|
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := NewHTTPClient(5 * time.Minute)
|
client := e2e.NewHTTPClient(5 * time.Minute)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("upload failed: %v", err)
|
t.Fatalf("upload failed: %v", err)
|
||||||
@ -422,16 +416,16 @@ func TestStorage_Status(t *testing.T) {
|
|||||||
|
|
||||||
var uploadResult map[string]interface{}
|
var uploadResult map[string]interface{}
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
if err := DecodeJSON(body, &uploadResult); err != nil {
|
if err := e2e.DecodeJSON(body, &uploadResult); err != nil {
|
||||||
t.Fatalf("failed to decode upload response: %v", err)
|
t.Fatalf("failed to decode upload response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cid := uploadResult["cid"].(string)
|
cid := uploadResult["cid"].(string)
|
||||||
|
|
||||||
// Get status
|
// Get status
|
||||||
statusReq := &HTTPRequest{
|
statusReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/storage/status/" + cid,
|
URL: e2e.GetGatewayURL() + "/v1/storage/status/" + cid,
|
||||||
}
|
}
|
||||||
|
|
||||||
statusBody, status, err := statusReq.Do(ctx)
|
statusBody, status, err := statusReq.Do(ctx)
|
||||||
@ -444,7 +438,7 @@ func TestStorage_Status(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var statusResult map[string]interface{}
|
var statusResult map[string]interface{}
|
||||||
if err := DecodeJSON(statusBody, &statusResult); err != nil {
|
if err := e2e.DecodeJSON(statusBody, &statusResult); err != nil {
|
||||||
t.Fatalf("failed to decode status response: %v", err)
|
t.Fatalf("failed to decode status response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,14 +448,14 @@ func TestStorage_Status(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestStorage_InvalidCID(t *testing.T) {
|
func TestStorage_InvalidCID(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
statusReq := &HTTPRequest{
|
statusReq := &e2e.HTTPRequest{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: GetGatewayURL() + "/v1/storage/status/QmInvalidCID123456789",
|
URL: e2e.GetGatewayURL() + "/v1/storage/status/QmInvalidCID123456789",
|
||||||
}
|
}
|
||||||
|
|
||||||
_, status, err := statusReq.Do(ctx)
|
_, status, err := statusReq.Do(ctx)
|
||||||
@ -475,7 +469,7 @@ func TestStorage_InvalidCID(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestStorage_GetByteRange(t *testing.T) {
|
func TestStorage_GetByteRange(t *testing.T) {
|
||||||
SkipIfMissingGateway(t)
|
e2e.SkipIfMissingGateway(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -500,18 +494,18 @@ func TestStorage_GetByteRange(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create upload request
|
// Create upload request
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, GetGatewayURL()+"/v1/storage/upload", &buf)
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, e2e.GetGatewayURL()+"/v1/storage/upload", &buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create request: %v", err)
|
t.Fatalf("failed to create request: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
|
||||||
if apiKey := GetAPIKey(); apiKey != "" {
|
if apiKey := e2e.GetAPIKey(); apiKey != "" {
|
||||||
req.Header.Set("Authorization", "Bearer "+apiKey)
|
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := NewHTTPClient(5 * time.Minute)
|
client := e2e.NewHTTPClient(5 * time.Minute)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("upload failed: %v", err)
|
t.Fatalf("upload failed: %v", err)
|
||||||
@ -520,19 +514,19 @@ func TestStorage_GetByteRange(t *testing.T) {
|
|||||||
|
|
||||||
var uploadResult map[string]interface{}
|
var uploadResult map[string]interface{}
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
if err := DecodeJSON(body, &uploadResult); err != nil {
|
if err := e2e.DecodeJSON(body, &uploadResult); err != nil {
|
||||||
t.Fatalf("failed to decode upload response: %v", err)
|
t.Fatalf("failed to decode upload response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cid := uploadResult["cid"].(string)
|
cid := uploadResult["cid"].(string)
|
||||||
|
|
||||||
// Get full content
|
// Get full content
|
||||||
getReq, err := http.NewRequestWithContext(ctx, http.MethodGet, GetGatewayURL()+"/v1/storage/get/"+cid, nil)
|
getReq, err := http.NewRequestWithContext(ctx, http.MethodGet, e2e.GetGatewayURL()+"/v1/storage/get/"+cid, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create get request: %v", err)
|
t.Fatalf("failed to create get request: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if apiKey := GetAPIKey(); apiKey != "" {
|
if apiKey := e2e.GetAPIKey(); apiKey != "" {
|
||||||
getReq.Header.Set("Authorization", "Bearer "+apiKey)
|
getReq.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user