mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-21 10:27:46 +08:00
Some checks failed
CodeQL / codeql (push) Has been cancelled
Docker Build / docker-build (push) Has been cancelled
Gateway Conformance / gateway-conformance (push) Has been cancelled
Gateway Conformance / gateway-conformance-libp2p-experiment (push) Has been cancelled
Go Build / go-build (push) Has been cancelled
Go Check / go-check (push) Has been cancelled
Go Lint / go-lint (push) Has been cancelled
Go Test / go-test (push) Has been cancelled
Interop / interop-prep (push) Has been cancelled
Sharness / sharness-test (push) Has been cancelled
Spell Check / spellcheck (push) Has been cancelled
Interop / helia-interop (push) Has been cancelled
Interop / ipfs-webui (push) Has been cancelled
https://github.com/ipfs/kubo/pull/10883 https://github.com/ipshipyard/config.ipfs-mainnet.org/issues/3 --------- Co-authored-by: gammazero <gammazero@users.noreply.github.com>
393 lines
9.1 KiB
Go
393 lines
9.1 KiB
Go
package migrations
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
config "github.com/ipfs/kubo/config"
|
|
)
|
|
|
|
func TestFindMigrations(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
migs, bins, err := findMigrations(ctx, 0, 5)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(migs) != 5 {
|
|
t.Fatal("expected 5 migrations")
|
|
}
|
|
if len(bins) != 0 {
|
|
t.Fatal("should not have found migrations")
|
|
}
|
|
|
|
for i := 1; i < 6; i++ {
|
|
createFakeBin(i-1, i, tmpDir)
|
|
}
|
|
|
|
origPath := os.Getenv("PATH")
|
|
os.Setenv("PATH", tmpDir)
|
|
defer os.Setenv("PATH", origPath)
|
|
|
|
migs, bins, err = findMigrations(ctx, 0, 5)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(migs) != 5 {
|
|
t.Fatal("expected 5 migrations")
|
|
}
|
|
if len(bins) != len(migs) {
|
|
t.Fatal("missing", len(migs)-len(bins), "migrations")
|
|
}
|
|
|
|
os.Remove(bins[migs[2]])
|
|
|
|
migs, bins, err = findMigrations(ctx, 0, 5)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(bins) != len(migs)-1 {
|
|
t.Fatal("should be missing one migration bin")
|
|
}
|
|
}
|
|
|
|
func TestFindMigrationsReverse(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
migs, bins, err := findMigrations(ctx, 5, 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(migs) != 5 {
|
|
t.Fatal("expected 5 migrations")
|
|
}
|
|
if len(bins) != 0 {
|
|
t.Fatal("should not have found migrations")
|
|
}
|
|
|
|
for i := 1; i < 6; i++ {
|
|
createFakeBin(i-1, i, tmpDir)
|
|
}
|
|
|
|
origPath := os.Getenv("PATH")
|
|
os.Setenv("PATH", tmpDir)
|
|
defer os.Setenv("PATH", origPath)
|
|
|
|
migs, bins, err = findMigrations(ctx, 5, 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(migs) != 5 {
|
|
t.Fatal("expected 5 migrations")
|
|
}
|
|
if len(bins) != len(migs) {
|
|
t.Fatal("missing", len(migs)-len(bins), "migrations:", migs)
|
|
}
|
|
|
|
os.Remove(bins[migs[2]])
|
|
|
|
migs, bins, err = findMigrations(ctx, 5, 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(bins) != len(migs)-1 {
|
|
t.Fatal("should be missing one migration bin")
|
|
}
|
|
}
|
|
|
|
func TestFetchMigrations(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
fetcher := NewHttpFetcher(testIpfsDist, testServer.URL, "", 0)
|
|
|
|
tmpDir := t.TempDir()
|
|
|
|
needed := []string{"fs-repo-1-to-2", "fs-repo-2-to-3"}
|
|
buf := new(strings.Builder)
|
|
buf.Grow(256)
|
|
logger := log.New(buf, "", 0)
|
|
fetched, err := fetchMigrations(ctx, fetcher, needed, tmpDir, logger)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
for _, bin := range fetched {
|
|
_, err = os.Stat(bin)
|
|
if os.IsNotExist(err) {
|
|
t.Error("expected file to exist:", bin)
|
|
}
|
|
}
|
|
|
|
// Check expected log output
|
|
for _, mig := range needed {
|
|
logOut := fmt.Sprintf("Downloading migration: %s", mig)
|
|
if !strings.Contains(buf.String(), logOut) {
|
|
t.Fatalf("did not find expected log output %q", logOut)
|
|
}
|
|
logOut = fmt.Sprintf("Downloaded and unpacked migration: %s", filepath.Join(tmpDir, mig))
|
|
if !strings.Contains(buf.String(), logOut) {
|
|
t.Fatalf("did not find expected log output %q", logOut)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRunMigrations(t *testing.T) {
|
|
fakeHome := t.TempDir()
|
|
|
|
os.Setenv("HOME", fakeHome)
|
|
fakeIpfs := filepath.Join(fakeHome, ".ipfs")
|
|
|
|
err := os.Mkdir(fakeIpfs, os.ModePerm)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
testVer := 11
|
|
err = WriteRepoVersion(fakeIpfs, testVer)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
fetcher := NewHttpFetcher(testIpfsDist, testServer.URL, "", 0)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
targetVer := 9
|
|
|
|
err = RunMigration(ctx, fetcher, targetVer, fakeIpfs, false)
|
|
if err == nil || !strings.HasPrefix(err.Error(), "downgrade not allowed") {
|
|
t.Fatal("expected 'downgrade not allowed' error")
|
|
}
|
|
|
|
err = RunMigration(ctx, fetcher, targetVer, fakeIpfs, true)
|
|
if err != nil {
|
|
if !strings.HasPrefix(err.Error(), "migration fs-repo-10-to-11 failed") {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func createFakeBin(from, to int, tmpDir string) {
|
|
migPath := filepath.Join(tmpDir, ExeName(migrationName(from, to)))
|
|
emptyFile, err := os.Create(migPath)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
emptyFile.Close()
|
|
err = os.Chmod(migPath, 0o755)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
var testConfig = `
|
|
{
|
|
"Bootstrap": [
|
|
"/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt",
|
|
"/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ"
|
|
],
|
|
"Migration": {
|
|
"DownloadSources": ["IPFS", "HTTP", "127.0.0.1", "https://127.0.1.1"],
|
|
"Keep": "cache"
|
|
},
|
|
"Peering": {
|
|
"Peers": [
|
|
{
|
|
"ID": "12D3KooWGC6TvWhfapngX6wvJHMYvKpDMXPb3ZnCZ6dMoaMtimQ5",
|
|
"Addrs": ["/ip4/127.0.0.1/tcp/4001", "/ip4/127.0.0.1/udp/4001/quic"]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
`
|
|
|
|
func TestReadMigrationConfigDefaults(t *testing.T) {
|
|
tmpDir := makeConfig(t, "{}")
|
|
|
|
cfg, err := ReadMigrationConfig(tmpDir, "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if cfg.Keep != config.DefaultMigrationKeep {
|
|
t.Error("expected default value for Keep")
|
|
}
|
|
|
|
if len(cfg.DownloadSources) != len(config.DefaultMigrationDownloadSources) {
|
|
t.Fatal("expected default number of download sources")
|
|
}
|
|
for i, src := range config.DefaultMigrationDownloadSources {
|
|
if cfg.DownloadSources[i] != src {
|
|
t.Errorf("wrong DownloadSource: %s", cfg.DownloadSources[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestReadMigrationConfigErrors(t *testing.T) {
|
|
tmpDir := makeConfig(t, `{"Migration": {"Keep": "badvalue"}}`)
|
|
|
|
_, err := ReadMigrationConfig(tmpDir, "")
|
|
if err == nil {
|
|
t.Fatal("expected error")
|
|
}
|
|
if !strings.HasPrefix(err.Error(), "unknown") {
|
|
t.Fatal("did not get expected error:", err)
|
|
}
|
|
|
|
os.RemoveAll(tmpDir)
|
|
_, err = ReadMigrationConfig(tmpDir, "")
|
|
if err == nil {
|
|
t.Fatal("expected error")
|
|
}
|
|
|
|
tmpDir = makeConfig(t, `}{`)
|
|
_, err = ReadMigrationConfig(tmpDir, "")
|
|
if err == nil {
|
|
t.Fatal("expected error")
|
|
}
|
|
}
|
|
|
|
func TestReadMigrationConfig(t *testing.T) {
|
|
tmpDir := makeConfig(t, testConfig)
|
|
|
|
cfg, err := ReadMigrationConfig(tmpDir, "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(cfg.DownloadSources) != 4 {
|
|
t.Fatal("wrong number of DownloadSources")
|
|
}
|
|
expect := []string{"IPFS", "HTTP", "127.0.0.1", "https://127.0.1.1"}
|
|
for i := range expect {
|
|
if cfg.DownloadSources[i] != expect[i] {
|
|
t.Errorf("wrong DownloadSource at %d", i)
|
|
}
|
|
}
|
|
|
|
if cfg.Keep != "cache" {
|
|
t.Error("wrong value for Keep")
|
|
}
|
|
}
|
|
|
|
type mockIpfsFetcher struct{}
|
|
|
|
var _ Fetcher = (*mockIpfsFetcher)(nil)
|
|
|
|
func (m *mockIpfsFetcher) Fetch(ctx context.Context, filePath string) ([]byte, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockIpfsFetcher) Close() error {
|
|
return nil
|
|
}
|
|
|
|
func TestGetMigrationFetcher(t *testing.T) {
|
|
var f Fetcher
|
|
var err error
|
|
|
|
newIpfsFetcher := func(distPath string) Fetcher {
|
|
return &mockIpfsFetcher{}
|
|
}
|
|
|
|
downloadSources := []string{"ftp://bad.gateway.io"}
|
|
_, err = GetMigrationFetcher(downloadSources, "", newIpfsFetcher)
|
|
if err == nil || !strings.HasPrefix(err.Error(), "bad gateway addr") {
|
|
t.Fatal("Expected bad gateway address error, got:", err)
|
|
}
|
|
|
|
downloadSources = []string{"::bad.gateway.io"}
|
|
_, err = GetMigrationFetcher(downloadSources, "", newIpfsFetcher)
|
|
if err == nil || !strings.HasPrefix(err.Error(), "bad gateway addr") {
|
|
t.Fatal("Expected bad gateway address error, got:", err)
|
|
}
|
|
|
|
downloadSources = []string{"http://localhost"}
|
|
f, err = GetMigrationFetcher(downloadSources, "", newIpfsFetcher)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if rf, ok := f.(*RetryFetcher); !ok {
|
|
t.Fatal("expected RetryFetcher")
|
|
} else if _, ok := rf.Fetcher.(*HttpFetcher); !ok {
|
|
t.Fatal("expected HttpFetcher")
|
|
}
|
|
|
|
downloadSources = []string{"ipfs"}
|
|
_, err = GetMigrationFetcher(downloadSources, "", newIpfsFetcher)
|
|
if err == nil || !strings.Contains(err.Error(), "IPFS downloads are not supported for legacy migrations") {
|
|
t.Fatal("Expected IPFS downloads error, got:", err)
|
|
}
|
|
|
|
downloadSources = []string{"http"}
|
|
f, err = GetMigrationFetcher(downloadSources, "", newIpfsFetcher)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if rf, ok := f.(*RetryFetcher); !ok {
|
|
t.Fatal("expected RetryFetcher")
|
|
} else if _, ok := rf.Fetcher.(*HttpFetcher); !ok {
|
|
t.Fatal("expected HttpFetcher")
|
|
}
|
|
|
|
downloadSources = []string{"IPFS", "HTTPS"}
|
|
_, err = GetMigrationFetcher(downloadSources, "", newIpfsFetcher)
|
|
if err == nil || !strings.Contains(err.Error(), "IPFS downloads are not supported for legacy migrations") {
|
|
t.Fatal("Expected IPFS downloads error, got:", err)
|
|
}
|
|
|
|
downloadSources = []string{"https", "some.domain.io"}
|
|
f, err = GetMigrationFetcher(downloadSources, "", newIpfsFetcher)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
mf, ok := f.(*MultiFetcher)
|
|
if !ok {
|
|
t.Fatal("expected MultiFetcher")
|
|
}
|
|
if mf.Len() != 2 {
|
|
t.Fatal("expected 2 fetchers in MultiFetcher")
|
|
}
|
|
|
|
downloadSources = nil
|
|
_, err = GetMigrationFetcher(downloadSources, "", newIpfsFetcher)
|
|
if err == nil {
|
|
t.Fatal("expected error when no sources specified")
|
|
}
|
|
|
|
downloadSources = []string{"", ""}
|
|
_, err = GetMigrationFetcher(downloadSources, "", newIpfsFetcher)
|
|
if err == nil {
|
|
t.Fatal("expected error when empty string fetchers specified")
|
|
}
|
|
}
|
|
|
|
func makeConfig(t *testing.T, configData string) string {
|
|
tmpDir := t.TempDir()
|
|
|
|
cfgFile, err := os.Create(filepath.Join(tmpDir, "config"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err = cfgFile.Write([]byte(configData)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = cfgFile.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return tmpDir
|
|
}
|