mirror of
https://github.com/DeBrosOfficial/network.git
synced 2025-12-11 07:38:49 +00:00
- Added new E2E tests for authentication, cache operations, and IPFS interactions to improve coverage and reliability. - Introduced concurrency tests for cache operations to validate performance under load. - Updated `go.mod` to include `github.com/mattn/go-sqlite3` as a dependency for database interactions. - Refined Makefile to simplify E2E test execution and configuration discovery. - Removed outdated client E2E tests and consolidated related functionality for better maintainability.
447 lines
11 KiB
Go
447 lines
11 KiB
Go
//go:build e2e
|
|
|
|
package e2e
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestRQLite_CreateTable(t *testing.T) {
|
|
SkipIfMissingGateway(t)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
table := GenerateTableName()
|
|
schema := fmt.Sprintf(
|
|
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP)",
|
|
table,
|
|
)
|
|
|
|
req := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
|
Body: map[string]interface{}{
|
|
"schema": schema,
|
|
},
|
|
}
|
|
|
|
body, status, err := req.Do(ctx)
|
|
if err != nil {
|
|
t.Fatalf("create table request failed: %v", err)
|
|
}
|
|
|
|
if status != http.StatusCreated && status != http.StatusOK {
|
|
t.Fatalf("expected status 201 or 200, got %d: %s", status, string(body))
|
|
}
|
|
}
|
|
|
|
func TestRQLite_InsertQuery(t *testing.T) {
|
|
SkipIfMissingGateway(t)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
table := GenerateTableName()
|
|
schema := fmt.Sprintf(
|
|
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)",
|
|
table,
|
|
)
|
|
|
|
// Create table
|
|
createReq := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
|
Body: map[string]interface{}{
|
|
"schema": schema,
|
|
},
|
|
}
|
|
|
|
_, status, err := createReq.Do(ctx)
|
|
if err != nil || (status != http.StatusCreated && status != http.StatusOK) {
|
|
t.Fatalf("create table failed: status %d, err %v", status, err)
|
|
}
|
|
|
|
// Insert rows
|
|
insertReq := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
|
Body: map[string]interface{}{
|
|
"statements": []string{
|
|
fmt.Sprintf("INSERT INTO %s(name) VALUES ('alice')", table),
|
|
fmt.Sprintf("INSERT INTO %s(name) VALUES ('bob')", table),
|
|
},
|
|
},
|
|
}
|
|
|
|
_, status, err = insertReq.Do(ctx)
|
|
if err != nil || status != http.StatusOK {
|
|
t.Fatalf("insert failed: status %d, err %v", status, err)
|
|
}
|
|
|
|
// Query rows
|
|
queryReq := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/query",
|
|
Body: map[string]interface{}{
|
|
"sql": fmt.Sprintf("SELECT name FROM %s ORDER BY id", table),
|
|
},
|
|
}
|
|
|
|
body, status, err := queryReq.Do(ctx)
|
|
if err != nil {
|
|
t.Fatalf("query failed: %v", err)
|
|
}
|
|
|
|
if status != http.StatusOK {
|
|
t.Fatalf("expected status 200, got %d", status)
|
|
}
|
|
|
|
var queryResp map[string]interface{}
|
|
if err := DecodeJSON(body, &queryResp); err != nil {
|
|
t.Fatalf("failed to decode response: %v", err)
|
|
}
|
|
|
|
if queryResp["count"].(float64) < 2 {
|
|
t.Fatalf("expected at least 2 rows, got %v", queryResp["count"])
|
|
}
|
|
}
|
|
|
|
func TestRQLite_DropTable(t *testing.T) {
|
|
SkipIfMissingGateway(t)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
table := GenerateTableName()
|
|
schema := fmt.Sprintf(
|
|
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, note TEXT)",
|
|
table,
|
|
)
|
|
|
|
// Create table
|
|
createReq := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
|
Body: map[string]interface{}{
|
|
"schema": schema,
|
|
},
|
|
}
|
|
|
|
_, status, err := createReq.Do(ctx)
|
|
if err != nil || (status != http.StatusCreated && status != http.StatusOK) {
|
|
t.Fatalf("create table failed: status %d, err %v", status, err)
|
|
}
|
|
|
|
// Drop table
|
|
dropReq := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/drop-table",
|
|
Body: map[string]interface{}{
|
|
"table": table,
|
|
},
|
|
}
|
|
|
|
_, status, err = dropReq.Do(ctx)
|
|
if err != nil {
|
|
t.Fatalf("drop table request failed: %v", err)
|
|
}
|
|
|
|
if status != http.StatusOK {
|
|
t.Fatalf("expected status 200, got %d", status)
|
|
}
|
|
|
|
// Verify table doesn't exist via schema
|
|
schemaReq := &HTTPRequest{
|
|
Method: http.MethodGet,
|
|
URL: GetGatewayURL() + "/v1/rqlite/schema",
|
|
}
|
|
|
|
body, status, err := schemaReq.Do(ctx)
|
|
if err != nil || status != http.StatusOK {
|
|
t.Logf("warning: failed to verify schema after drop: status %d, err %v", status, err)
|
|
return
|
|
}
|
|
|
|
var schemaResp map[string]interface{}
|
|
if err := DecodeJSON(body, &schemaResp); err != nil {
|
|
t.Logf("warning: failed to decode schema response: %v", err)
|
|
return
|
|
}
|
|
|
|
if tables, ok := schemaResp["tables"].([]interface{}); ok {
|
|
for _, tbl := range tables {
|
|
tblMap := tbl.(map[string]interface{})
|
|
if tblMap["name"] == table {
|
|
t.Fatalf("table %s still present after drop", table)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRQLite_Schema(t *testing.T) {
|
|
SkipIfMissingGateway(t)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
req := &HTTPRequest{
|
|
Method: http.MethodGet,
|
|
URL: GetGatewayURL() + "/v1/rqlite/schema",
|
|
}
|
|
|
|
body, status, err := req.Do(ctx)
|
|
if err != nil {
|
|
t.Fatalf("schema request failed: %v", err)
|
|
}
|
|
|
|
if status != http.StatusOK {
|
|
t.Fatalf("expected status 200, got %d", status)
|
|
}
|
|
|
|
var resp map[string]interface{}
|
|
if err := DecodeJSON(body, &resp); err != nil {
|
|
t.Fatalf("failed to decode response: %v", err)
|
|
}
|
|
|
|
if _, ok := resp["tables"]; !ok {
|
|
t.Fatalf("expected 'tables' field in response")
|
|
}
|
|
}
|
|
|
|
func TestRQLite_MalformedSQL(t *testing.T) {
|
|
SkipIfMissingGateway(t)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
req := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/query",
|
|
Body: map[string]interface{}{
|
|
"sql": "SELECT * FROM nonexistent_table WHERE invalid syntax",
|
|
},
|
|
}
|
|
|
|
_, status, err := req.Do(ctx)
|
|
if err != nil {
|
|
t.Fatalf("request failed: %v", err)
|
|
}
|
|
|
|
// Should get an error response
|
|
if status == http.StatusOK {
|
|
t.Fatalf("expected error for malformed SQL, got status 200")
|
|
}
|
|
}
|
|
|
|
func TestRQLite_LargeTransaction(t *testing.T) {
|
|
SkipIfMissingGateway(t)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
defer cancel()
|
|
|
|
table := GenerateTableName()
|
|
schema := fmt.Sprintf(
|
|
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY AUTOINCREMENT, value INTEGER)",
|
|
table,
|
|
)
|
|
|
|
// Create table
|
|
createReq := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
|
Body: map[string]interface{}{
|
|
"schema": schema,
|
|
},
|
|
}
|
|
|
|
_, status, err := createReq.Do(ctx)
|
|
if err != nil || (status != http.StatusCreated && status != http.StatusOK) {
|
|
t.Fatalf("create table failed: status %d, err %v", status, err)
|
|
}
|
|
|
|
// Generate large transaction (50 inserts)
|
|
var statements []string
|
|
for i := 0; i < 50; i++ {
|
|
statements = append(statements, fmt.Sprintf("INSERT INTO %s(value) VALUES (%d)", table, i))
|
|
}
|
|
|
|
txReq := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
|
Body: map[string]interface{}{
|
|
"statements": statements,
|
|
},
|
|
}
|
|
|
|
_, status, err = txReq.Do(ctx)
|
|
if err != nil || status != http.StatusOK {
|
|
t.Fatalf("large transaction failed: status %d, err %v", status, err)
|
|
}
|
|
|
|
// Verify all rows were inserted
|
|
queryReq := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/query",
|
|
Body: map[string]interface{}{
|
|
"sql": fmt.Sprintf("SELECT COUNT(*) as count FROM %s", table),
|
|
},
|
|
}
|
|
|
|
body, status, err := queryReq.Do(ctx)
|
|
if err != nil || status != http.StatusOK {
|
|
t.Fatalf("count query failed: status %d, err %v", status, err)
|
|
}
|
|
|
|
var countResp map[string]interface{}
|
|
if err := DecodeJSON(body, &countResp); err != nil {
|
|
t.Fatalf("failed to decode response: %v", err)
|
|
}
|
|
|
|
// Extract count from result
|
|
if rows, ok := countResp["rows"].([]interface{}); ok && len(rows) > 0 {
|
|
row := rows[0].([]interface{})
|
|
if row[0].(float64) != 50 {
|
|
t.Fatalf("expected 50 rows, got %v", row[0])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRQLite_ForeignKeyMigration(t *testing.T) {
|
|
SkipIfMissingGateway(t)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
defer cancel()
|
|
|
|
orgsTable := GenerateTableName()
|
|
usersTable := GenerateTableName()
|
|
|
|
// Create base tables
|
|
createOrgsReq := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
|
Body: map[string]interface{}{
|
|
"schema": fmt.Sprintf(
|
|
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, name TEXT)",
|
|
orgsTable,
|
|
),
|
|
},
|
|
}
|
|
|
|
_, status, err := createOrgsReq.Do(ctx)
|
|
if err != nil || (status != http.StatusCreated && status != http.StatusOK) {
|
|
t.Fatalf("create orgs table failed: status %d, err %v", status, err)
|
|
}
|
|
|
|
createUsersReq := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/create-table",
|
|
Body: map[string]interface{}{
|
|
"schema": fmt.Sprintf(
|
|
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, name TEXT, org_id INTEGER, age TEXT)",
|
|
usersTable,
|
|
),
|
|
},
|
|
}
|
|
|
|
_, status, err = createUsersReq.Do(ctx)
|
|
if err != nil || (status != http.StatusCreated && status != http.StatusOK) {
|
|
t.Fatalf("create users table failed: status %d, err %v", status, err)
|
|
}
|
|
|
|
// Seed data
|
|
seedReq := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
|
Body: map[string]interface{}{
|
|
"statements": []string{
|
|
fmt.Sprintf("INSERT INTO %s(id,name) VALUES (1,'org')", orgsTable),
|
|
fmt.Sprintf("INSERT INTO %s(id,name,org_id,age) VALUES (1,'alice',1,'30')", usersTable),
|
|
},
|
|
},
|
|
}
|
|
|
|
_, status, err = seedReq.Do(ctx)
|
|
if err != nil || status != http.StatusOK {
|
|
t.Fatalf("seed transaction failed: status %d, err %v", status, err)
|
|
}
|
|
|
|
// Migrate: change age type and add FK
|
|
migrationReq := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/transaction",
|
|
Body: map[string]interface{}{
|
|
"statements": []string{
|
|
fmt.Sprintf(
|
|
"CREATE TABLE %s_new (id INTEGER PRIMARY KEY, name TEXT, org_id INTEGER, age INTEGER, FOREIGN KEY(org_id) REFERENCES %s(id) ON DELETE CASCADE)",
|
|
usersTable, orgsTable,
|
|
),
|
|
fmt.Sprintf(
|
|
"INSERT INTO %s_new (id,name,org_id,age) SELECT id,name,org_id, CAST(age AS INTEGER) FROM %s",
|
|
usersTable, usersTable,
|
|
),
|
|
fmt.Sprintf("DROP TABLE %s", usersTable),
|
|
fmt.Sprintf("ALTER TABLE %s_new RENAME TO %s", usersTable, usersTable),
|
|
},
|
|
},
|
|
}
|
|
|
|
_, status, err = migrationReq.Do(ctx)
|
|
if err != nil || status != http.StatusOK {
|
|
t.Fatalf("migration transaction failed: status %d, err %v", status, err)
|
|
}
|
|
|
|
// Verify data is intact
|
|
queryReq := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/query",
|
|
Body: map[string]interface{}{
|
|
"sql": fmt.Sprintf("SELECT name, org_id, age FROM %s", usersTable),
|
|
},
|
|
}
|
|
|
|
body, status, err := queryReq.Do(ctx)
|
|
if err != nil || status != http.StatusOK {
|
|
t.Fatalf("query after migration failed: status %d, err %v", status, err)
|
|
}
|
|
|
|
var queryResp map[string]interface{}
|
|
if err := DecodeJSON(body, &queryResp); err != nil {
|
|
t.Fatalf("failed to decode response: %v", err)
|
|
}
|
|
|
|
if queryResp["count"].(float64) != 1 {
|
|
t.Fatalf("expected 1 row after migration, got %v", queryResp["count"])
|
|
}
|
|
}
|
|
|
|
func TestRQLite_DropNonexistentTable(t *testing.T) {
|
|
SkipIfMissingGateway(t)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
dropReq := &HTTPRequest{
|
|
Method: http.MethodPost,
|
|
URL: GetGatewayURL() + "/v1/rqlite/drop-table",
|
|
Body: map[string]interface{}{
|
|
"table": "nonexistent_table_xyz_" + fmt.Sprintf("%d", time.Now().UnixNano()),
|
|
},
|
|
}
|
|
|
|
_, status, err := dropReq.Do(ctx)
|
|
if err != nil {
|
|
t.Logf("warning: drop nonexistent table request failed: %v", err)
|
|
return
|
|
}
|
|
|
|
// Should get an error (400 or 404)
|
|
if status == http.StatusOK {
|
|
t.Logf("warning: expected error for dropping nonexistent table, got status 200")
|
|
}
|
|
}
|