@@ -13,6 +13,8 @@ import (
13
13
"testing"
14
14
15
15
"github.com/libp2p/go-libp2p"
16
+ "github.com/libp2p/go-libp2p/core/host"
17
+ "github.com/libp2p/go-libp2p/core/peer"
16
18
inproc "github.com/lthibault/go-libp2p-inproc-transport"
17
19
"github.com/stretchr/testify/require"
18
20
"github.com/tetratelabs/wazero"
@@ -41,6 +43,107 @@ func newTestEnv(t *testing.T) *testEnv {
41
43
}
42
44
}
43
45
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
+
44
147
func TestHTTP (t * testing.T ) {
45
148
t .Parallel ()
46
149
@@ -158,42 +261,15 @@ func TestHTTPStream(t *testing.T) {
158
261
}
159
262
160
263
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 ( )
163
266
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 )
195
270
196
- server := httptest .NewServer (h .Handler )
271
+ // Set up HTTP server
272
+ server := f .NewHTTPServer (p )
197
273
defer server .Close ()
198
274
199
275
t .Run ("status endpoint" , func (t * testing.T ) {
@@ -217,16 +293,14 @@ func TestHTTPIntegration(t *testing.T) {
217
293
})
218
294
219
295
t .Run ("glia endpoint" , func (t * testing.T ) {
220
- // Test POST request
221
296
resp , err := http .Post (server .URL + "/ipfs/v0/host123/proc456/method789" , "" , nil )
222
297
require .NoError (t , err , "Failed to post to glia endpoint" )
223
298
defer resp .Body .Close ()
224
299
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 )
226
301
})
227
302
228
303
t .Run ("method not allowed" , func (t * testing.T ) {
229
- // Test wrong methods on endpoints
230
304
endpoints := []string {"/status" , "/version" }
231
305
for _ , endpoint := range endpoints {
232
306
resp , err := http .Post (server .URL + endpoint , "" , nil )
@@ -241,7 +315,7 @@ func TestHTTPIntegration(t *testing.T) {
241
315
t .Run ("echo endpoint" , func (t * testing.T ) {
242
316
const message = "Hello, Wetware!"
243
317
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" ),
245
319
"text/plain" ,
246
320
strings .NewReader (message ))
247
321
require .NoError (t , err , "Failed to post to echo endpoint" )
@@ -253,4 +327,49 @@ func TestHTTPIntegration(t *testing.T) {
253
327
require .NoError (t , err , "Failed to read response body" )
254
328
require .Equal (t , message , string (body ), "Echo response should match input" )
255
329
})
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
+ })
256
375
}
0 commit comments