Skip to content

Commit edba202

Browse files
committed
chore: adding basic spamoor test
1 parent 269be56 commit edba202

File tree

5 files changed

+180
-770
lines changed

5 files changed

+180
-770
lines changed

test/e2e/evm_spamoor_e2e_test.go

Lines changed: 0 additions & 211 deletions
This file was deleted.

test/e2e/evm_spamoor_smoke_test.go

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
//go:build evm
2+
3+
package e2e
4+
5+
import (
6+
"context"
7+
"fmt"
8+
"net/http"
9+
"path/filepath"
10+
"testing"
11+
"time"
12+
13+
spamoor "github.com/celestiaorg/tastora/framework/docker/evstack/spamoor"
14+
dto "github.com/prometheus/client_model/go"
15+
"github.com/stretchr/testify/require"
16+
)
17+
18+
// TestSpamoorSmoke spins up reth + sequencer and a Spamoor node, starts a few
19+
// basic spammers, waits briefly, then prints a concise metrics summary.
20+
func TestSpamoorSmoke(t *testing.T) {
21+
t.Parallel()
22+
23+
sut := NewSystemUnderTest(t)
24+
// Bring up reth + local DA and start sequencer with default settings.
25+
seqJWT, _, genesisHash, endpoints, rethNode := setupCommonEVMTest(t, sut, false)
26+
sequencerHome := filepath.Join(t.TempDir(), "sequencer")
27+
28+
// In-process OTLP/HTTP collector to capture ev-node spans.
29+
collector := newOTLPCollector(t)
30+
t.Cleanup(collector.close)
31+
32+
// Start sequencer with tracing to our collector.
33+
setupSequencerNode(t, sut, sequencerHome, seqJWT, genesisHash, endpoints,
34+
"--evnode.instrumentation.tracing=true",
35+
"--evnode.instrumentation.tracing_endpoint", collector.endpoint(),
36+
"--evnode.instrumentation.tracing_sample_rate", "1.0",
37+
"--evnode.instrumentation.tracing_service_name", "ev-node-smoke",
38+
)
39+
t.Log("Sequencer node is up")
40+
41+
// Start Spamoor within the same Docker network, targeting reth internal RPC.
42+
ni, err := rethNode.GetNetworkInfo(context.Background())
43+
require.NoError(t, err, "failed to get network info")
44+
45+
internalRPC := "http://" + ni.Internal.RPCAddress()
46+
47+
spBuilder := spamoor.NewNodeBuilder(t.Name()).
48+
WithDockerClient(rethNode.DockerClient).
49+
WithDockerNetworkID(rethNode.NetworkID).
50+
WithLogger(rethNode.Logger).
51+
WithRPCHosts(internalRPC).
52+
WithPrivateKey(TestPrivateKey)
53+
54+
ctx := context.Background()
55+
spNode, err := spBuilder.Build(ctx)
56+
require.NoError(t, err, "failed to build sp node")
57+
58+
t.Cleanup(func() { _ = spNode.Remove(context.Background()) })
59+
require.NoError(t, spNode.Start(ctx), "failed to start spamoor node")
60+
61+
// Wait for daemon readiness.
62+
spInfo, err := spNode.GetNetworkInfo(ctx)
63+
require.NoError(t, err, "failed to get network info")
64+
65+
apiAddr := "http://127.0.0.1:" + spInfo.External.Ports.HTTP
66+
requireHTTP(t, apiAddr+"/api/spammers", 30*time.Second)
67+
api := spNode.API()
68+
69+
// Basic scenarios (structs that YAML-marshal into the daemon config).
70+
eoatx := map[string]any{
71+
"throughput": 100,
72+
"total_count": 3000,
73+
"max_pending": 4000,
74+
"max_wallets": 300,
75+
"amount": 100,
76+
"random_amount": true,
77+
"random_target": true,
78+
"base_fee": 20, // gwei
79+
"tip_fee": 2, // gwei
80+
"refill_amount": "1000000000000000000",
81+
"refill_balance": "500000000000000000",
82+
"refill_interval": 600,
83+
}
84+
85+
gasburner := map[string]any{
86+
"throughput": 25,
87+
"total_count": 2000,
88+
"max_pending": 8000,
89+
"max_wallets": 500,
90+
"gas_units_to_burn": 3000000,
91+
"base_fee": 20,
92+
"tip_fee": 5,
93+
"rebroadcast": 5,
94+
"refill_amount": "5000000000000000000",
95+
"refill_balance": "2000000000000000000",
96+
"refill_interval": 300,
97+
}
98+
99+
var ids []int
100+
id, err := api.CreateSpammer("smoke-eoatx", spamoor.ScenarioEOATX, eoatx, true)
101+
require.NoError(t, err, "failed to create eoatx spammer")
102+
ids = append(ids, id)
103+
id, err = api.CreateSpammer("smoke-gasburner", spamoor.ScenarioGasBurnerTX, gasburner, true)
104+
require.NoError(t, err, "failed to create gasburner spammer")
105+
ids = append(ids, id)
106+
107+
for _, id := range ids {
108+
idToDelete := id
109+
t.Cleanup(func() { _ = api.DeleteSpammer(idToDelete) })
110+
}
111+
112+
// Allow additional time to accumulate activity.
113+
time.Sleep(60 * time.Second)
114+
115+
// Fetch parsed metrics and print a concise summary.
116+
if mfs, err := api.GetMetrics(); err == nil && mfs != nil {
117+
sent := sumCounter(mfs["spamoor_transactions_sent_total"])
118+
fail := sumCounter(mfs["spamoor_transactions_failed_total"])
119+
pend := sumGauge(mfs["spamoor_pending_transactions"])
120+
gas := sumCounter(mfs["spamoor_block_gas_usage"])
121+
t.Logf("Spamoor summary: sent=%.0f failed=%.0f pending=%.0f block_gas=%.0f", sent, fail, pend, gas)
122+
} else {
123+
t.Logf("metrics unavailable or parse error: %v", err)
124+
}
125+
126+
time.Sleep(2 * time.Second)
127+
printCollectedTraceReport(t, collector)
128+
129+
// TODO: test should pass / fail based on results
130+
}
131+
132+
// --- helpers ---
133+
134+
func requireHTTP(t *testing.T, url string, timeout time.Duration) {
135+
t.Helper()
136+
client := &http.Client{Timeout: 200 * time.Millisecond}
137+
deadline := time.Now().Add(timeout)
138+
var lastErr error
139+
for time.Now().Before(deadline) {
140+
resp, err := client.Get(url)
141+
if err == nil {
142+
_ = resp.Body.Close()
143+
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
144+
return
145+
}
146+
lastErr = fmt.Errorf("status %d", resp.StatusCode)
147+
} else {
148+
lastErr = err
149+
}
150+
time.Sleep(100 * time.Millisecond)
151+
}
152+
t.Fatalf("daemon not ready at %s: %v", url, lastErr)
153+
}
154+
155+
// Metric family helpers.
156+
func sumCounter(f *dto.MetricFamily) float64 {
157+
if f == nil || f.GetType() != dto.MetricType_COUNTER {
158+
return 0
159+
}
160+
var sum float64
161+
for _, m := range f.GetMetric() {
162+
if m.GetCounter() != nil && m.GetCounter().Value != nil {
163+
sum += m.GetCounter().GetValue()
164+
}
165+
}
166+
return sum
167+
}
168+
func sumGauge(f *dto.MetricFamily) float64 {
169+
if f == nil || f.GetType() != dto.MetricType_GAUGE {
170+
return 0
171+
}
172+
var sum float64
173+
for _, m := range f.GetMetric() {
174+
if m.GetGauge() != nil && m.GetGauge().Value != nil {
175+
sum += m.GetGauge().GetValue()
176+
}
177+
}
178+
return sum
179+
}

0 commit comments

Comments
 (0)