github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/cmd/remove_integration_test.go (about) 1 package cmd 2 3 import ( 4 "os" 5 "path/filepath" 6 "regexp" 7 "strings" 8 "testing" 9 10 "github.com/google/go-cmp/cmp" 11 ) 12 13 func parsePathFromRef(ref string) string { 14 pos := strings.Index(ref, "@") 15 if pos == -1 { 16 return ref 17 } 18 return ref[pos+1:] 19 } 20 21 // Test that adding two versions, then deleting one, ends up with only the first version 22 func TestRemoveOneRevisionFromRepo(t *testing.T) { 23 run := NewTestRunner(t, "test_peer_remote_one_rev_from_repo", "qri_test_remove_one_rev_from_repo") 24 defer run.Delete() 25 26 // Save a dataset containing a body.json, no meta, nothing special. 27 output := run.MustExecCombinedOutErr(t, "qri save --body=testdata/movies/body_two.json me/remove_test") 28 ref1 := parsePathFromRef(parseRefFromSave(output)) 29 dsPath1 := run.GetPathForDataset(t, 0) 30 if ref1 != dsPath1 { 31 t.Fatalf("ref from first save should match what is in qri repo. got %q want %q", ref1, dsPath1) 32 } 33 34 // Save another version 35 output = run.MustExecCombinedOutErr(t, "qri save --body=testdata/movies/body_four.json me/remove_test") 36 ref2 := parsePathFromRef(parseRefFromSave(output)) 37 dsPath2 := run.GetPathForDataset(t, 0) 38 if ref2 != dsPath2 { 39 t.Fatalf("ref from second save should match what is in qri repo. got %q want %q", ref2, dsPath2) 40 } 41 42 // Remove one version 43 run.MustExec(t, "qri remove --revisions=1 me/remove_test") 44 45 // Verify that dsref of HEAD is the same as the result of the first save command 46 dsPath3 := run.GetPathForDataset(t, 0) 47 if ref1 != dsPath3 { 48 t.Errorf("after delete, ref should match the first version, expected: %s\n, got: %s\n", 49 ref1, dsPath3) 50 } 51 } 52 53 // Test that adding two versions, then deleting all will end up with nothing left 54 func TestRemoveAllRevisionsFromRepo(t *testing.T) { 55 run := NewTestRunner(t, "test_peer_remove_all_rev_", "qri_test_remove_all_rev_from_repo") 56 defer run.Delete() 57 58 // Save a dataset containing a body.json, no meta, nothing special. 59 output := run.MustExecCombinedOutErr(t, "qri save --body=testdata/movies/body_two.json me/remove_test") 60 ref1 := parsePathFromRef(parseRefFromSave(output)) 61 dsPath1 := run.GetPathForDataset(t, 0) 62 if ref1 != dsPath1 { 63 t.Fatal("ref from first save should match what is in qri repo") 64 } 65 66 // Save another version 67 output = run.MustExecCombinedOutErr(t, "qri save --body=testdata/movies/body_four.json me/remove_test") 68 ref2 := parsePathFromRef(parseRefFromSave(output)) 69 dsPath2 := run.GetPathForDataset(t, 0) 70 if ref2 != dsPath2 { 71 t.Fatal("ref from second save should match what is in qri repo") 72 } 73 74 // Remove one version 75 run.MustExec(t, "qri remove --all me/remove_test") 76 77 // Verify that dsref of HEAD is the same as the result of the first save command 78 dsPath3 := run.GetPathForDataset(t, 0) 79 if dsPath3 != "" { 80 t.Errorf("after delete, dataset should not exist, got: %s\n", dsPath3) 81 } 82 } 83 84 // Test that a dataset can be removed even if the logbook is missing 85 func TestRemoveEvenIfLogbookGone(t *testing.T) { 86 run := NewTestRunner(t, "test_peer_remove_no_logbook", "qri_test_remove_no_logbook") 87 defer run.Delete() 88 89 // Save the new dataset 90 run.MustExec(t, "qri save --body testdata/movies/body_ten.csv me/movies") 91 92 // Remove the logbook 93 logbookFile := filepath.Join(run.RepoRoot.RootPath, "qri/logbook.qfb") 94 if _, err := os.Stat(logbookFile); os.IsNotExist(err) { 95 t.Fatal("logbook does not exist") 96 } 97 err := os.Remove(logbookFile) 98 if err != nil { 99 t.Fatal(err) 100 } 101 102 // Remove all should still work, even though the logbook is gone. 103 if err := run.ExecCommand("qri remove --revisions=all me/movies"); err != nil { 104 t.Error(err) 105 } 106 } 107 108 // Test that an added dataset can be removed, which removes it from the logbook 109 func TestRemoveEvenIfForeignDataset(t *testing.T) { 110 run := NewTestRunnerWithMockRemoteClient(t, "test_peer_remove_foreign", "remove_foreign") 111 defer run.Delete() 112 113 // Regex that replaces the timestamp with just static text 114 fixTs := regexp.MustCompile(`"(timestamp|commitTime)":\s?"[0-9TZ.:+-]*?"`) 115 116 output := run.MustExec(t, "qri logbook --raw") 117 expectEmpty := `[{"ops":[{"type":"init","model":"user","name":"test_peer_remove_foreign","authorID":"QmeL2mdVka1eahKENjehK6tBxkkpk5dNQ1qMcgWi7Hrb4B","timestamp":"ts"}]}]` 118 actual := string(fixTs.ReplaceAll([]byte(output), []byte(`"timestamp":"ts"`))) 119 if diff := cmp.Diff(expectEmpty, actual); diff != "" { 120 t.Errorf("unexpected (-want +got):\n%s", diff) 121 } 122 123 // Save a foreign dataset 124 run.MustExec(t, "qri add other_peer/their_dataset") 125 126 output = run.MustExec(t, "qri logbook --raw") 127 expectHasForiegn := `[{"ops":[{"type":"init","model":"user","name":"test_peer_remove_foreign","authorID":"QmeL2mdVka1eahKENjehK6tBxkkpk5dNQ1qMcgWi7Hrb4B","timestamp":"ts"}]},{"ops":[{"type":"init","model":"user","name":"other_peer","authorID":"QmWYgD49r9HnuXEppQEq1a7SUUryja4QNs9E6XCH2PayCD","timestamp":"ts"}],"logs":[{"ops":[{"type":"init","model":"dataset","name":"their_dataset","authorID":"xstfcrqf26suws6dnjih4ugvmfk6w5o7e6b7rmflt7aso6htyufa","timestamp":"ts"}],"logs":[{"ops":[{"type":"init","model":"branch","name":"main","authorID":"xstfcrqf26suws6dnjih4ugvmfk6w5o7e6b7rmflt7aso6htyufa","timestamp":"ts"},{"type":"init","model":"commit","timestamp":"ts","size":2,"note":"created dataset"}]}]}]}]` 128 actual = string(fixTs.ReplaceAll([]byte(output), []byte(`"timestamp":"ts"`))) 129 if diff := cmp.Diff(expectHasForiegn, actual); diff != "" { 130 t.Errorf("unexpected (-want +got):\n%s", diff) 131 } 132 133 // Remove all should still work, even though the dataset is foreign 134 if err := run.ExecCommand("qri remove --revisions=all other_peer/their_dataset"); err != nil { 135 t.Error(err) 136 } 137 138 output = run.MustExec(t, "qri logbook --raw") 139 // Log is removed for the database, but author init still remains 140 expectEmptyAuthor := `[{"ops":[{"type":"init","model":"user","name":"test_peer_remove_foreign","authorID":"QmeL2mdVka1eahKENjehK6tBxkkpk5dNQ1qMcgWi7Hrb4B","timestamp":"ts"}]},{"ops":[{"type":"init","model":"user","name":"other_peer","authorID":"QmWYgD49r9HnuXEppQEq1a7SUUryja4QNs9E6XCH2PayCD","timestamp":"ts"}]}]` 141 actual = string(fixTs.ReplaceAll([]byte(output), []byte(`"timestamp":"ts"`))) 142 if diff := cmp.Diff(expectEmptyAuthor, actual); diff != "" { 143 t.Errorf("unexpected (-want +got):\n%s", diff) 144 } 145 } 146 147 // Test that an added dataset can be removed even if the logbook is missing 148 func TestRemoveEvenIfForeignDatasetWithNoOplog(t *testing.T) { 149 run := NewTestRunnerWithMockRemoteClient(t, "test_peer_no_oplog", "remove_no_oplog") 150 defer run.Delete() 151 152 // Save a foreign dataset 153 run.MustExec(t, "qri add other_peer/their_dataset") 154 155 // Remove the logbook 156 logbookFile := filepath.Join(run.RepoRoot.RootPath, "qri/logbook.qfb") 157 if _, err := os.Stat(logbookFile); os.IsNotExist(err) { 158 t.Fatal("logbook does not exist") 159 } 160 err := os.Remove(logbookFile) 161 if err != nil { 162 t.Fatal(err) 163 } 164 165 // Remove all should still work, even though the dataset is foreign with no logbook 166 if err := run.ExecCommand("qri remove --revisions=all other_peer/their_dataset"); err != nil { 167 t.Error(err) 168 } 169 }