test: fix flaky content routing over HTTP test (#9772)
Gus Eggert committed
Apr 5, 2023 at 07:10 UTC
fd830b3c1a1aeda55504f28fe6a268e92cc30225
2 files changed
+104
-61
test/cli/content_routing_http_test.go
new
+104
@@ -0,0 +1,104 @@
1
+package cli
2
+
3
+import (
4
+ "context"
5
+ "net/http"
6
+ "net/http/httptest"
7
+ "os/exec"
8
+ "sync"
9
+ "testing"
10
+ "time"
11
+
12
+ "github.com/ipfs/boxo/routing/http/server"
13
+ "github.com/ipfs/boxo/routing/http/types"
14
+ "github.com/ipfs/go-cid"
15
+ "github.com/ipfs/kubo/test/cli/harness"
16
+ "github.com/ipfs/kubo/test/cli/testutils"
17
+ "github.com/stretchr/testify/assert"
18
+)
19
+
20
+type fakeHTTPContentRouter struct {
21
+ m sync.Mutex
22
+ findProvidersCalls int
23
+ provideCalls int
24
+}
25
+
26
+func (r *fakeHTTPContentRouter) FindProviders(ctx context.Context, key cid.Cid) ([]types.ProviderResponse, error) {
27
+ r.m.Lock()
28
+ defer r.m.Unlock()
29
+ r.findProvidersCalls++
30
+ return []types.ProviderResponse{}, nil
31
+}
32
+
33
+func (r *fakeHTTPContentRouter) ProvideBitswap(ctx context.Context, req *server.BitswapWriteProvideRequest) (time.Duration, error) {
34
+ r.m.Lock()
35
+ defer r.m.Unlock()
36
+ r.provideCalls++
37
+ return 0, nil
38
+}
39
+func (r *fakeHTTPContentRouter) Provide(ctx context.Context, req *server.WriteProvideRequest) (types.ProviderResponse, error) {
40
+ r.m.Lock()
41
+ defer r.m.Unlock()
42
+ r.provideCalls++
43
+ return nil, nil
44
+}
45
+
46
+func (r *fakeHTTPContentRouter) numFindProvidersCalls() int {
47
+ r.m.Lock()
48
+ defer r.m.Unlock()
49
+ return r.findProvidersCalls
50
+}
51
+
52
+// userAgentRecorder records the user agent of every HTTP request
53
+type userAgentRecorder struct {
54
+ delegate http.Handler
55
+ userAgents []string
56
+}
57
+
58
+func (r *userAgentRecorder) ServeHTTP(w http.ResponseWriter, req *http.Request) {
59
+ r.userAgents = append(r.userAgents, req.UserAgent())
60
+ r.delegate.ServeHTTP(w, req)
61
+}
62
+
63
+func TestContentRoutingHTTP(t *testing.T) {
64
+ cr := &fakeHTTPContentRouter{}
65
+
66
+ // run the content routing HTTP server
67
+ userAgentRecorder := &userAgentRecorder{delegate: server.Handler(cr)}
68
+ server := httptest.NewServer(userAgentRecorder)
69
+ t.Cleanup(func() { server.Close() })
70
+
71
+ // setup the node
72
+ node := harness.NewT(t).NewNode().Init()
73
+ node.Runner.Env["IPFS_HTTP_ROUTERS"] = server.URL
74
+ node.StartDaemon()
75
+
76
+ // compute a random CID
77
+ randStr := string(testutils.RandomBytes(100))
78
+ res := node.PipeStrToIPFS(randStr, "add", "-qn")
79
+ wantCIDStr := res.Stdout.Trimmed()
80
+
81
+ t.Run("fetching an uncached block results in an HTTP lookup", func(t *testing.T) {
82
+ statRes := node.Runner.Run(harness.RunRequest{
83
+ Path: node.IPFSBin,
84
+ Args: []string{"block", "stat", wantCIDStr},
85
+ RunFunc: (*exec.Cmd).Start,
86
+ })
87
+ defer func() {
88
+ if err := statRes.Cmd.Process.Kill(); err != nil {
89
+ t.Logf("error killing 'block stat' cmd: %s", err)
90
+ }
91
+ }()
92
+
93
+ // verify the content router was called
94
+ assert.Eventually(t, func() bool {
95
+ return cr.numFindProvidersCalls() > 0
96
+ }, time.Minute, 10*time.Millisecond)
97
+
98
+ assert.NotEmpty(t, userAgentRecorder.userAgents)
99
+ version := node.IPFS("id", "-f", "<aver>").Stdout.Trimmed()
100
+ for _, userAgent := range userAgentRecorder.userAgents {
101
+ assert.Equal(t, version, userAgent)
102
+ }
103
+ })
104
+}
test/sharness/t0172-content-routing-over-http.sh
deleted
-61
@@ -1,61 +0,0 @@
1
-#!/usr/bin/env bash
2
-
3
-test_description="Test content routing over HTTP"
4
-
5
-. lib/test-lib.sh
6
-
7
-
8
-if ! test_have_prereq SOCAT; then
9
- skip_all="skipping '$test_description': socat is not available"
10
- test_done
11
-fi
12
-
13
-test_init_ipfs
14
-
15
-# Run listener on a free port to log HTTP requests sent by Kubo in Routing.Type=auto mode
16
-export ROUTER_PORT=$(comm -23 <(seq 49152 65535 | sort) <(ss -Htan | awk '{print $4}' | cut -d':' -f2) | head -n 1)
17
-export IPFS_HTTP_ROUTERS="http://127.0.0.1:$ROUTER_PORT"
18
-
19
-test_launch_ipfs_daemon
20
-
21
-test_expect_success "start HTTP router proxy" '
22
- touch http_requests
23
- socat -u TCP-LISTEN:$ROUTER_PORT,reuseaddr,fork,bind=127.0.0.1,retry=10 CREATE:http_requests &
24
- NCPID=$!
25
-'
26
-
27
-## HTTP GETs
28
-
29
-test_expect_success 'create unique CID without adding it to the local datastore' '
30
- WANT_CID=$(date +"%FT%T.%N%z" | ipfs add -qn)
31
-'
32
-
33
-test_expect_success 'expect HTTP lookup when CID is not in the local datastore' '
34
- ipfs block stat "$WANT_CID" &
35
- test_wait_output_n_lines http_requests 4 &&
36
- test_should_contain "GET /routing/v1/providers/$WANT_CID" http_requests
37
-'
38
-
39
-test_expect_success 'expect HTTP request User-Agent to match Kubo version' '
40
- test_should_contain "User-Agent: $(ipfs id -f "<aver>")" http_requests
41
-'
42
-
43
-## HTTP PUTs
44
-
45
-test_expect_success 'add new CID to the local datastore' '
46
- ADD_CID=$(date +"%FT%T.%N%z" | ipfs add -q)
47
-'
48
-
49
-# cid.contact supports GET-only: https://github.com/ipfs/kubo/issues/9504
50
-# which means no announcements over HTTP should be made.
51
-test_expect_success 'expect no HTTP requests to be sent with locally added CID' '
52
- test_should_not_contain "$ADD_CID" http_requests
53
-'
54
-
55
-test_expect_success "stop nc" '
56
- kill "$NCPID" && wait "$NCPID" || true
57
- rm -f http_requests || true
58
-'
59
-
60
-test_kill_ipfs_daemon
61
-test_done