master
go 104 lines 2.94 KB
Raw
1 package cli
2
3 import (
4 "net/http"
5 "os"
6 "os/exec"
7 "path/filepath"
8 "strings"
9 "testing"
10 "time"
11
12 "github.com/ipfs/kubo/test/cli/harness"
13 "github.com/stretchr/testify/require"
14 )
15
16 // TestAddressFileReady verifies that when address files ($IPFS_PATH/api and
17 // $IPFS_PATH/gateway) are created, the corresponding HTTP servers are ready
18 // to accept connections immediately. This prevents race conditions for tools
19 // like systemd path units that start services when these files appear.
20 func TestAddressFileReady(t *testing.T) {
21 t.Parallel()
22
23 t.Run("api file", func(t *testing.T) {
24 t.Parallel()
25 h := harness.NewT(t)
26 node := h.NewNode().Init()
27
28 // Start daemon in background (don't use StartDaemon which waits for API)
29 res := node.Runner.MustRun(harness.RunRequest{
30 Path: node.IPFSBin,
31 Args: []string{"daemon"},
32 RunFunc: (*exec.Cmd).Start,
33 })
34 node.Daemon = res
35 defer node.StopDaemon()
36
37 // Poll for api file to appear
38 apiFile := filepath.Join(node.Dir, "api")
39 var fileExists bool
40 for range 100 {
41 if _, err := os.Stat(apiFile); err == nil {
42 fileExists = true
43 break
44 }
45 time.Sleep(100 * time.Millisecond)
46 }
47 require.True(t, fileExists, "api file should be created")
48
49 // Read the api file to get the address
50 apiAddr, err := node.TryAPIAddr()
51 require.NoError(t, err)
52
53 // Extract IP and port from multiaddr
54 ip, err := apiAddr.ValueForProtocol(4) // P_IP4
55 require.NoError(t, err)
56 port, err := apiAddr.ValueForProtocol(6) // P_TCP
57 require.NoError(t, err)
58
59 // Immediately try to use the API - should work on first attempt
60 url := "http://" + ip + ":" + port + "/api/v0/id"
61 resp, err := http.Post(url, "", nil)
62 require.NoError(t, err, "RPC API should be ready immediately when api file exists")
63 defer resp.Body.Close()
64 require.Equal(t, http.StatusOK, resp.StatusCode)
65 })
66
67 t.Run("gateway file", func(t *testing.T) {
68 t.Parallel()
69 h := harness.NewT(t)
70 node := h.NewNode().Init()
71
72 // Start daemon in background
73 res := node.Runner.MustRun(harness.RunRequest{
74 Path: node.IPFSBin,
75 Args: []string{"daemon"},
76 RunFunc: (*exec.Cmd).Start,
77 })
78 node.Daemon = res
79 defer node.StopDaemon()
80
81 // Poll for gateway file to appear
82 gatewayFile := filepath.Join(node.Dir, "gateway")
83 var fileExists bool
84 for range 100 {
85 if _, err := os.Stat(gatewayFile); err == nil {
86 fileExists = true
87 break
88 }
89 time.Sleep(100 * time.Millisecond)
90 }
91 require.True(t, fileExists, "gateway file should be created")
92
93 // Read the gateway file to get the URL (already includes http:// prefix)
94 gatewayURL, err := os.ReadFile(gatewayFile)
95 require.NoError(t, err)
96
97 // Immediately try to use the Gateway - should work on first attempt
98 url := strings.TrimSpace(string(gatewayURL)) + "/ipfs/bafkqaaa" // empty file CID
99 resp, err := http.Get(url)
100 require.NoError(t, err, "Gateway should be ready immediately when gateway file exists")
101 defer resp.Body.Close()
102 require.Equal(t, http.StatusOK, resp.StatusCode)
103 })
104 }