Skip to content

Commit 0c3b294

Browse files
committed
Add HTTP integration test for remote message routing.
1 parent 89efb90 commit 0c3b294

File tree

1 file changed

+157
-38
lines changed

1 file changed

+157
-38
lines changed

glia/http_test.go

+157-38
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
"testing"
1414

1515
"github.com/libp2p/go-libp2p"
16+
"github.com/libp2p/go-libp2p/core/host"
17+
"github.com/libp2p/go-libp2p/core/peer"
1618
inproc "github.com/lthibault/go-libp2p-inproc-transport"
1719
"github.com/stretchr/testify/require"
1820
"github.com/tetratelabs/wazero"
@@ -41,6 +43,107 @@ func newTestEnv(t *testing.T) *testEnv {
4143
}
4244
}
4345

46+
type testFixture struct {
47+
t *testing.T
48+
ctx context.Context
49+
rt wazero.Runtime
50+
module wazero.CompiledModule
51+
host host.Host
52+
server *httptest.Server
53+
}
54+
55+
func newTestFixture(t *testing.T) *testFixture {
56+
t.Helper()
57+
58+
// Create host with inproc transport
59+
h, err := libp2p.New(
60+
libp2p.NoTransports,
61+
libp2p.NoListenAddrs,
62+
libp2p.Transport(inproc.New()),
63+
libp2p.ListenAddrStrings("/inproc/~"))
64+
require.NoError(t, err)
65+
66+
// Set up wazero runtime
67+
ctx := context.Background()
68+
rt := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfig().
69+
WithCloseOnContextDone(true))
70+
wasi_snapshot_preview1.MustInstantiate(ctx, rt)
71+
72+
// Load echo module
73+
bytecode, err := os.ReadFile("../examples/echo/main.wasm")
74+
require.NoError(t, err)
75+
76+
module, err := rt.CompileModule(ctx, bytecode)
77+
require.NoError(t, err)
78+
79+
return &testFixture{
80+
t: t,
81+
ctx: ctx,
82+
rt: rt,
83+
module: module,
84+
host: h,
85+
}
86+
}
87+
88+
func (f *testFixture) Close() {
89+
if f.server != nil {
90+
f.server.Close()
91+
}
92+
if f.module != nil {
93+
f.module.Close(f.ctx)
94+
}
95+
if f.rt != nil {
96+
f.rt.Close(f.ctx)
97+
}
98+
}
99+
100+
func (f *testFixture) NewProcess() (*proc.P, string) {
101+
f.t.Helper()
102+
pid := proc.NewPID()
103+
p, err := proc.Command{
104+
PID: pid,
105+
Stderr: os.Stderr,
106+
}.Instantiate(f.ctx, f.rt, f.module)
107+
require.NoError(f.t, err)
108+
return p, pid.String()
109+
}
110+
111+
func (f *testFixture) NewHTTPServer(p *proc.P) *httptest.Server {
112+
f.t.Helper()
113+
h := &glia.HTTP{
114+
Env: &system.Env{
115+
Host: f.host,
116+
},
117+
Router: mockRouter{P: p},
118+
}
119+
h.Init()
120+
f.server = httptest.NewServer(h.Handler)
121+
return f.server
122+
}
123+
124+
func (f *testFixture) NewPeerWithProcess() (host.Host, *proc.P, string) {
125+
f.t.Helper()
126+
peer, err := libp2p.New(
127+
libp2p.NoTransports,
128+
libp2p.NoListenAddrs,
129+
libp2p.Transport(inproc.New()),
130+
libp2p.ListenAddrStrings("/inproc/~"))
131+
require.NoError(f.t, err)
132+
133+
p, pid := f.NewProcess()
134+
return peer, p, pid
135+
}
136+
137+
func (f *testFixture) ConnectToPeer(h host.Host) {
138+
f.t.Helper()
139+
info := peer.AddrInfo{
140+
ID: h.ID(),
141+
Addrs: h.Addrs(),
142+
}
143+
err := f.host.Connect(f.ctx, info)
144+
require.NoError(f.t, err)
145+
}
146+
44147
func TestHTTP(t *testing.T) {
45148
t.Parallel()
46149

@@ -158,42 +261,15 @@ func TestHTTPStream(t *testing.T) {
158261
}
159262

160263
func TestHTTPIntegration(t *testing.T) {
161-
host, err := libp2p.New(libp2p.NoTransports, libp2p.NoListenAddrs)
162-
require.NoError(t, err)
264+
f := newTestFixture(t)
265+
defer f.Close()
163266

164-
// Set up wazero runtime and load echo module
165-
r := wazero.NewRuntimeWithConfig(context.Background(), wazero.NewRuntimeConfig().
166-
WithCloseOnContextDone(true))
167-
defer r.Close(context.Background())
168-
wasi_snapshot_preview1.MustInstantiate(context.Background(), r)
169-
170-
bytecode, err := os.ReadFile("../examples/echo/main.wasm")
171-
require.NoError(t, err)
172-
173-
cm, err := r.CompileModule(context.Background(), bytecode)
174-
require.NoError(t, err)
175-
defer cm.Close(context.Background())
176-
177-
const expectedProc = "Wt9hMLbqHmNuCsvqCW8AuKxUjwL"
178-
pid, err := proc.ParsePID(expectedProc)
179-
require.NoError(t, err)
180-
181-
p, err := proc.Command{
182-
PID: pid,
183-
Stderr: os.Stderr,
184-
}.Instantiate(context.Background(), r, cm)
185-
require.NoError(t, err)
186-
defer p.Close(context.Background())
187-
188-
h := &glia.HTTP{
189-
Env: &system.Env{
190-
Host: host,
191-
},
192-
Router: mockRouter{P: p},
193-
}
194-
h.Init()
267+
// Create local process
268+
p, pid := f.NewProcess()
269+
defer p.Close(f.ctx)
195270

196-
server := httptest.NewServer(h.Handler)
271+
// Set up HTTP server
272+
server := f.NewHTTPServer(p)
197273
defer server.Close()
198274

199275
t.Run("status endpoint", func(t *testing.T) {
@@ -217,16 +293,14 @@ func TestHTTPIntegration(t *testing.T) {
217293
})
218294

219295
t.Run("glia endpoint", func(t *testing.T) {
220-
// Test POST request
221296
resp, err := http.Post(server.URL+"/ipfs/v0/host123/proc456/method789", "", nil)
222297
require.NoError(t, err, "Failed to post to glia endpoint")
223298
defer resp.Body.Close()
224299

225-
require.NotEqual(t, http.StatusMethodNotAllowed, resp.StatusCode, "Expected endpoint to be found, got method not allowed")
300+
require.NotEqual(t, http.StatusMethodNotAllowed, resp.StatusCode)
226301
})
227302

228303
t.Run("method not allowed", func(t *testing.T) {
229-
// Test wrong methods on endpoints
230304
endpoints := []string{"/status", "/version"}
231305
for _, endpoint := range endpoints {
232306
resp, err := http.Post(server.URL+endpoint, "", nil)
@@ -241,7 +315,7 @@ func TestHTTPIntegration(t *testing.T) {
241315
t.Run("echo endpoint", func(t *testing.T) {
242316
const message = "Hello, Wetware!"
243317
resp, err := http.Post(
244-
server.URL+path.Join("/ipfs/v0", host.ID().String(), expectedProc, "echo"),
318+
server.URL+path.Join("/", system.Proto.String(), f.host.ID().String(), pid, "echo"),
245319
"text/plain",
246320
strings.NewReader(message))
247321
require.NoError(t, err, "Failed to post to echo endpoint")
@@ -253,4 +327,49 @@ func TestHTTPIntegration(t *testing.T) {
253327
require.NoError(t, err, "Failed to read response body")
254328
require.Equal(t, message, string(body), "Echo response should match input")
255329
})
330+
331+
t.Run("remote echo endpoint", func(t *testing.T) {
332+
// Create peer B with its own process
333+
peerB, pB, pidB := f.NewPeerWithProcess()
334+
defer pB.Close(f.ctx)
335+
336+
// Set up P2P handlers on both hosts
337+
p2pA := &glia.P2P{
338+
Env: &system.Env{
339+
Host: f.host,
340+
},
341+
Router: mockRouter{P: p},
342+
}
343+
go p2pA.Serve(f.ctx)
344+
345+
p2pB := &glia.P2P{
346+
Env: &system.Env{
347+
Host: peerB,
348+
},
349+
Router: mockRouter{P: pB},
350+
}
351+
go p2pB.Serve(f.ctx)
352+
353+
// Create HTTP handler for host A that will route to host B
354+
serverA := f.NewHTTPServer(pB)
355+
defer serverA.Close()
356+
357+
// Connect host A to host B
358+
f.ConnectToPeer(peerB)
359+
360+
// Send request to host A that should be routed to process on host B
361+
const message = "Hello from remote ww host!"
362+
resp, err := http.Post(
363+
serverA.URL+path.Join("/", system.Proto.String(), peerB.ID().String(), pidB, "echo"),
364+
"text/plain",
365+
strings.NewReader(message))
366+
require.NoError(t, err, "failed to post to remote echo endpoint")
367+
defer resp.Body.Close()
368+
369+
require.Equal(t, http.StatusOK, resp.StatusCode)
370+
371+
body, err := io.ReadAll(resp.Body)
372+
require.NoError(t, err, "failed to read response body")
373+
require.Equal(t, message, string(body), "remote echo response should match input")
374+
})
256375
}

0 commit comments

Comments
 (0)