| 1 | package ipfsfetcher |
| 2 | |
| 3 | import ( |
| 4 | "bufio" |
| 5 | "bytes" |
| 6 | "fmt" |
| 7 | "os" |
| 8 | "path/filepath" |
| 9 | "testing" |
| 10 | |
| 11 | "github.com/ipfs/kubo/plugin/loader" |
| 12 | "github.com/ipfs/kubo/repo/fsrepo/migrations" |
| 13 | ) |
| 14 | |
| 15 | func init() { |
| 16 | err := setupPlugins() |
| 17 | if err != nil { |
| 18 | panic(err) |
| 19 | } |
| 20 | } |
| 21 | |
| 22 | func TestIpfsFetcher(t *testing.T) { |
| 23 | skipUnlessEpic(t) |
| 24 | |
| 25 | ctx := t.Context() |
| 26 | |
| 27 | fetcher := NewIpfsFetcher("", 0, nil, "") |
| 28 | defer fetcher.Close() |
| 29 | |
| 30 | out, err := fetcher.Fetch(ctx, "go-ipfs/versions") |
| 31 | if err != nil { |
| 32 | t.Fatal(err) |
| 33 | } |
| 34 | |
| 35 | var lines []string |
| 36 | scan := bufio.NewScanner(bytes.NewReader(out)) |
| 37 | for scan.Scan() { |
| 38 | lines = append(lines, scan.Text()) |
| 39 | } |
| 40 | err = scan.Err() |
| 41 | if err != nil { |
| 42 | t.Fatal("could not read versions:", err) |
| 43 | } |
| 44 | |
| 45 | if len(lines) < 6 { |
| 46 | t.Fatal("do not get all expected data") |
| 47 | } |
| 48 | if lines[0] != "v0.3.2" { |
| 49 | t.Fatal("expected v1.0.0 as first line, got", lines[0]) |
| 50 | } |
| 51 | |
| 52 | // Check not found |
| 53 | if _, err = fetcher.Fetch(ctx, "/no_such_file"); err == nil { |
| 54 | t.Fatal("expected error 404") |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | func TestInitIpfsFetcher(t *testing.T) { |
| 59 | ctx := t.Context() |
| 60 | |
| 61 | f := NewIpfsFetcher("", 0, nil, "") |
| 62 | defer f.Close() |
| 63 | |
| 64 | // Init ipfs repo |
| 65 | f.ipfsTmpDir, f.openErr = initTempNode(ctx, nil, nil) |
| 66 | if f.openErr != nil { |
| 67 | t.Fatalf("failed to initialize ipfs node: %s", f.openErr) |
| 68 | } |
| 69 | |
| 70 | // Start ipfs node |
| 71 | f.openErr = f.startTempNode(ctx) |
| 72 | if f.openErr != nil { |
| 73 | t.Errorf("failed to start ipfs node: %s", f.openErr) |
| 74 | return |
| 75 | } |
| 76 | |
| 77 | var stopFuncCalled bool |
| 78 | stopFunc := f.ipfsStopFunc |
| 79 | f.ipfsStopFunc = func() { |
| 80 | stopFuncCalled = true |
| 81 | stopFunc() |
| 82 | } |
| 83 | |
| 84 | addrInfo := f.AddrInfo() |
| 85 | if string(addrInfo.ID) == "" { |
| 86 | t.Error("AddInfo ID not set") |
| 87 | } |
| 88 | if len(addrInfo.Addrs) == 0 { |
| 89 | t.Error("AddInfo Addrs not set") |
| 90 | } |
| 91 | t.Log("Temp node listening on:", addrInfo.Addrs) |
| 92 | |
| 93 | err := f.Close() |
| 94 | if err != nil { |
| 95 | t.Fatalf("failed to close fetcher: %s", err) |
| 96 | } |
| 97 | |
| 98 | if stopFunc != nil && !stopFuncCalled { |
| 99 | t.Error("Close did not call stop function") |
| 100 | } |
| 101 | |
| 102 | err = f.Close() |
| 103 | if err != nil { |
| 104 | t.Fatalf("failed to close fetcher 2nd time: %s", err) |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | func TestReadIpfsConfig(t *testing.T) { |
| 109 | testConfig := ` |
| 110 | { |
| 111 | "Bootstrap": [ |
| 112 | "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", |
| 113 | "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ" |
| 114 | ], |
| 115 | "Migration": { |
| 116 | "DownloadSources": ["IPFS", "HTTP", "127.0.0.1", "https://127.0.1.1"], |
| 117 | "Keep": "cache" |
| 118 | }, |
| 119 | "Peering": { |
| 120 | "Peers": [ |
| 121 | { |
| 122 | "ID": "12D3KooWGC6TvWhfapngX6wvJHMYvKpDMXPb3ZnCZ6dMoaMtimQ5", |
| 123 | "Addrs": ["/ip4/127.0.0.1/tcp/4001", "/ip4/127.0.0.1/udp/4001/quic"] |
| 124 | } |
| 125 | ] |
| 126 | } |
| 127 | } |
| 128 | ` |
| 129 | |
| 130 | noSuchDir := "no_such_dir-5953aa51-1145-4efd-afd1-a069075fcf76" |
| 131 | bootstrap, peers := readIpfsConfig(&noSuchDir, "") |
| 132 | if bootstrap != nil { |
| 133 | t.Error("expected nil bootstrap") |
| 134 | } |
| 135 | if peers != nil { |
| 136 | t.Error("expected nil peers") |
| 137 | } |
| 138 | |
| 139 | tmpDir := makeConfig(t, testConfig) |
| 140 | |
| 141 | bootstrap, peers = readIpfsConfig(nil, "") |
| 142 | if bootstrap != nil || peers != nil { |
| 143 | t.Fatal("expected nil ipfs config items") |
| 144 | } |
| 145 | |
| 146 | bootstrap, peers = readIpfsConfig(&tmpDir, "") |
| 147 | if len(bootstrap) != 2 { |
| 148 | t.Fatal("wrong number of bootstrap addresses") |
| 149 | } |
| 150 | if bootstrap[0] != "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt" { |
| 151 | t.Fatal("wrong bootstrap address") |
| 152 | } |
| 153 | |
| 154 | if len(peers) != 1 { |
| 155 | t.Fatal("wrong number of peers") |
| 156 | } |
| 157 | |
| 158 | peer := peers[0] |
| 159 | if peer.ID.String() != "12D3KooWGC6TvWhfapngX6wvJHMYvKpDMXPb3ZnCZ6dMoaMtimQ5" { |
| 160 | t.Errorf("wrong ID for first peer") |
| 161 | } |
| 162 | if len(peer.Addrs) != 2 { |
| 163 | t.Error("wrong number of addrs for first peer") |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | func TestBadBootstrappingIpfsConfig(t *testing.T) { |
| 168 | const configBadBootstrap = ` |
| 169 | { |
| 170 | "Bootstrap": "unreadable", |
| 171 | "Migration": { |
| 172 | "DownloadSources": ["IPFS", "HTTP", "127.0.0.1"], |
| 173 | "Keep": "cache" |
| 174 | }, |
| 175 | "Peering": { |
| 176 | "Peers": [ |
| 177 | { |
| 178 | "ID": "12D3KooWGC6TvWhfapngX6wvJHMYvKpDMXPb3ZnCZ6dMoaMtimQ5", |
| 179 | "Addrs": ["/ip4/127.0.0.1/tcp/4001", "/ip4/127.0.0.1/udp/4001/quic"] |
| 180 | } |
| 181 | ] |
| 182 | } |
| 183 | } |
| 184 | ` |
| 185 | |
| 186 | tmpDir := makeConfig(t, configBadBootstrap) |
| 187 | |
| 188 | bootstrap, peers := readIpfsConfig(&tmpDir, "") |
| 189 | if bootstrap != nil { |
| 190 | t.Fatal("expected nil bootstrap") |
| 191 | } |
| 192 | if len(peers) != 1 { |
| 193 | t.Fatal("wrong number of peers") |
| 194 | } |
| 195 | if len(peers[0].Addrs) != 2 { |
| 196 | t.Error("wrong number of addrs for first peer") |
| 197 | } |
| 198 | os.RemoveAll(tmpDir) |
| 199 | } |
| 200 | |
| 201 | func TestBadPeersIpfsConfig(t *testing.T) { |
| 202 | const configBadPeers = ` |
| 203 | { |
| 204 | "Bootstrap": [ |
| 205 | "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", |
| 206 | "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ" |
| 207 | ], |
| 208 | "Migration": { |
| 209 | "DownloadSources": ["IPFS", "HTTP", "127.0.0.1"], |
| 210 | "Keep": "cache" |
| 211 | }, |
| 212 | "Peering": "Unreadable-data" |
| 213 | } |
| 214 | ` |
| 215 | |
| 216 | tmpDir := makeConfig(t, configBadPeers) |
| 217 | |
| 218 | bootstrap, peers := readIpfsConfig(&tmpDir, "") |
| 219 | if peers != nil { |
| 220 | t.Fatal("expected nil peers") |
| 221 | } |
| 222 | if len(bootstrap) != 2 { |
| 223 | t.Fatal("wrong number of bootstrap addresses") |
| 224 | } |
| 225 | if bootstrap[0] != "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt" { |
| 226 | t.Fatal("wrong bootstrap address") |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | func makeConfig(t *testing.T, configData string) string { |
| 231 | tmpDir := t.TempDir() |
| 232 | |
| 233 | cfgFile, err := os.Create(filepath.Join(tmpDir, "config")) |
| 234 | if err != nil { |
| 235 | t.Fatal(err) |
| 236 | } |
| 237 | if _, err = cfgFile.Write([]byte(configData)); err != nil { |
| 238 | t.Fatal(err) |
| 239 | } |
| 240 | if err = cfgFile.Close(); err != nil { |
| 241 | t.Fatal(err) |
| 242 | } |
| 243 | return tmpDir |
| 244 | } |
| 245 | |
| 246 | func skipUnlessEpic(t *testing.T) { |
| 247 | if os.Getenv("IPFS_EPIC_TEST") == "" { |
| 248 | t.SkipNow() |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | func setupPlugins() error { |
| 253 | defaultPath, err := migrations.IpfsDir("") |
| 254 | if err != nil { |
| 255 | return err |
| 256 | } |
| 257 | |
| 258 | // Load plugins. This will skip the repo if not available. |
| 259 | plugins, err := loader.NewPluginLoader(filepath.Join(defaultPath, "plugins")) |
| 260 | if err != nil { |
| 261 | return fmt.Errorf("error loading plugins: %w", err) |
| 262 | } |
| 263 | |
| 264 | if err := plugins.Initialize(); err != nil { |
| 265 | // Need to ignore errors here because plugins may already be loaded when |
| 266 | // run from ipfs daemon. |
| 267 | return fmt.Errorf("error initializing plugins: %w", err) |
| 268 | } |
| 269 | |
| 270 | if err := plugins.Inject(); err != nil { |
| 271 | // Need to ignore errors here because plugins may already be loaded when |
| 272 | // run from ipfs daemon. |
| 273 | return fmt.Errorf("error injecting plugins: %w", err) |
| 274 | } |
| 275 | |
| 276 | return nil |
| 277 | } |