e2e/migrate_test.go

f8b976a97290a20d552056a999511f5d27d8e8ec
gitbay/e2e/migrate_test.go history · blame · raw

104 lines · 4727 bytes

  1package e2e
  2
  3import (
  4	"os"
  5	"path/filepath"
  6	"strings"
  7	"testing"
  8)
  9
 10func TestAccountMigration(t *testing.T) {
 11	t.Parallel()
 12	src := startInstance(t)
 13	dst := startInstance(t)
 14	key := src.newKey(t, "alice") // one identity, both instances
 15	src.admin(t, "admin", "user", "create", "alice", "--key", key+".pub")
 16	dst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub")
 17
 18	// Source: profile, a repo with settings/topics, an issue thread, an MR.
 19	if _, _, code := src.ssh(t, key, "", "profile", "set", "--description", "'tinkerer'", "--website", "https://alice.example"); code != 0 {
 20		t.Fatal("profile set failed")
 21	}
 22	if _, _, code := src.ssh(t, key, "", "repo", "create", "alice/tool", "--description", "'a fine tool'"); code != 0 {
 23		t.Fatal("repo create failed")
 24	}
 25	if _, _, code := src.ssh(t, key, "", "repo", "create", "alice/notes", "--private"); code != 0 {
 26		t.Fatal("private repo create failed")
 27	}
 28	src.ssh(t, key, "", "repo", "topics", "add", "alice/tool", "go", "cli")
 29	work := t.TempDir()
 30	env := src.gitEnv(key)
 31	mustGit(t, work, env, "clone", src.sshURL("alice/tool"), "w")
 32	dir := filepath.Join(work, "w")
 33	os.WriteFile(filepath.Join(dir, "main.go"), []byte("package main\n"), 0o644)
 34	mustGit(t, dir, env, "checkout", "-q", "-b", "main")
 35	mustGit(t, dir, env, "add", ".")
 36	mustGit(t, dir, env, "commit", "-q", "-m", "base")
 37	mustGit(t, dir, env, "push", "-q", "origin", "main")
 38	head := strings.TrimSpace(mustGit(t, dir, env, "rev-parse", "HEAD"))
 39	src.ssh(t, key, "", "repo", "settings", "protect", "alice/tool", "main")
 40	src.ssh(t, key, "", "repo", "settings", "require-signed", "alice/tool", "on")
 41	if _, _, code := src.ssh(t, key, "", "issue", "create", "alice/tool", "--title", "'sharpen it'", "--body", "'too dull'"); code != 0 {
 42		t.Fatal("issue create failed")
 43	}
 44	src.ssh(t, key, "", "issue", "label", "alice/tool", "1", "--add", "bug")
 45	src.ssh(t, key, "", "issue", "comment", "alice/tool", "1", "--message", "'on it'")
 46	src.ssh(t, key, "", "issue", "close", "alice/tool", "1")
 47
 48	// Export from the source, replay on the target.
 49	bundleOut, errOut, code := src.ssh(t, key, "", "account", "export")
 50	if code != 0 {
 51		t.Fatalf("export: %s", errOut)
 52	}
 53	if strings.Contains(bundleOut, "ssh-ed25519") || strings.Contains(bundleOut, "PRIVATE") {
 54		t.Fatal("bundle carries key material")
 55	}
 56	out, errOut, code := dst.ssh(t, key, bundleOut, "account", "import-bundle", "--source", "old.example")
 57	if code != 0 {
 58		t.Fatalf("import-bundle: %s", errOut)
 59	}
 60	if !strings.Contains(out, "imported 2 repos, 1 issues, 0 MRs, 1 comments") ||
 61		!strings.Contains(out, "require-signed alice/tool on") ||
 62		!strings.Contains(out, "protect alice/tool main") {
 63		t.Fatalf("import summary: %s", out)
 64	}
 65
 66	// Metadata arrived: issue with state, label, comment, attribution;
 67	// topics, description, visibility.
 68	out, _, _ = dst.ssh(t, key, "", "issue", "show", "alice/tool", "1", "--json")
 69	if !strings.Contains(out, "sharpen it") || !strings.Contains(out, `"state":"closed"`) ||
 70		!strings.Contains(out, `"labels":["bug"]`) || !strings.Contains(out, "on it") ||
 71		!strings.Contains(out, "migrated issue old.example#1") {
 72		t.Fatalf("migrated issue: %s", out)
 73	}
 74	out, _, _ = dst.ssh(t, key, "", "repo", "show", "alice/tool", "--json")
 75	if !strings.Contains(out, `"topics":["cli","go"]`) || !strings.Contains(out, "a fine tool") {
 76		t.Fatalf("migrated repo: %s", out)
 77	}
 78	out, _, _ = dst.ssh(t, key, "", "repo", "show", "alice/notes", "--json")
 79	if !strings.Contains(out, `"visibility":"private"`) {
 80		t.Fatalf("private visibility lost: %s", out)
 81	}
 82	// Deferred policies are NOT applied yet — the push must succeed.
 83	out, _, _ = dst.ssh(t, key, "", "repo", "settings", "show", "alice/tool", "--json")
 84	if strings.Contains(out, `"require_signed_commits":true`) || strings.Contains(out, "protected") {
 85		t.Fatalf("push-blocking settings applied early: %s", out)
 86	}
 87
 88	// Git data client-side: clone from source, push to target (unsigned
 89	// history lands because the policy is deferred).
 90	mirror := t.TempDir()
 91	mustGit(t, mirror, env, "clone", "-q", "--mirror", src.sshURL("alice/tool"), "m")
 92	mdir := filepath.Join(mirror, "m")
 93	mustGit(t, mdir, env, "push", "-q", dst.sshURL("alice/tool"), "+refs/heads/*:refs/heads/*", "+refs/tags/*:refs/tags/*")
 94	out, _, _ = dst.ssh(t, key, "", "repo", "log", "alice/tool", "--json")
 95	if !strings.Contains(out, head) {
 96		t.Fatalf("git data missing on target: %s", out)
 97	}
 98
 99	// Resume: a second replay imports nothing twice.
100	out, _, code = dst.ssh(t, key, bundleOut, "account", "import-bundle", "--source", "old.example")
101	if code != 0 || !strings.Contains(out, "imported 0 repos, 0 issues, 0 MRs, 0 comments (1 already present)") {
102		t.Fatalf("re-import: %s", out)
103	}
104}