Skip to content

Commit

Permalink
feat(save): Tests for saving datasets wtih multiple file arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
dustmop committed Mar 25, 2019
1 parent 23735b7 commit 9fe54bc
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 13 deletions.
99 changes: 99 additions & 0 deletions cmd/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,105 @@ func TestSaveThenOverrideMetaComponent(t *testing.T) {
}
}

// Test that saving with two components at once will merge them together.
func TestSaveTwoComponents(t *testing.T) {
if err := confirmQriNotRunning(); err != nil {
t.Skip(err.Error())
}

// To keep hashes consistent, artificially specify the timestamp by overriding
// the dsfs.Timestamp func
prev := dsfs.Timestamp
defer func() { dsfs.Timestamp = prev }()
dsfs.Timestamp = func() time.Time { return time.Date(2001, 01, 01, 01, 01, 01, 01, time.UTC) }

r := NewTestRepoRoot(t, "qri_test_save_then_override_meta")
defer r.Delete()

cmdR := r.CreateCommandRunner()
_, err := executeCommand(cmdR, "qri save --file=testdata/movies/ds_ten.yaml me/test_ds")
if err != nil {
t.Fatalf(err.Error())
}

cmdR = r.CreateCommandRunner()
_, err = executeCommand(cmdR, "qri save --file=testdata/movies/meta_override.yaml --file=testdata/movies/structure_override.json me/test_ds")
if err != nil {
t.Fatalf(err.Error())
}

// Read head from the dataset that was saved, as json string.
dsPath := r.GetPathForDataset(0)
actual := r.DatasetMarshalJSON(dsPath)

// This dataset is ds_ten.yaml, with the meta replaced by meta_override ("different title") and
// the structure replaced by structure_override (lazyQuotes: false && title: "name").
expect := `{"bodyPath":"/ipfs/QmXhsUK6vGZrqarhw9Z8RCXqhmEpvtVByKtaYVarbDZ5zn","commit":{"author":{"id":"QmeL2mdVka1eahKENjehK6tBxkkpk5dNQ1qMcgWi7Hrb4B"},"message":"\t- modified formatConfig\n\t- modified schema\n","path":"/ipfs/QmbrZGpqFJZjW8JPZMZUQ8zDRZU3QakGE6hQ9D4tgvZtYx","qri":"cm:0","signature":"I/nrDkgwt1IPtdFKvgMQAIRYvOqKfqm6x0qfpuJ14rEtO3+uPnY3K5pVDMWJ7K+pYJz6fyguYWgXHKkbo5wZl0ICVyoIiPa9zIVbqc1d6j1v13WqtRb0bn1CXQvuI6HcBhb7+VqkSW1m+ALpxhNQuI4ZfRv8Nm8MbEpL6Ct55fJpWX1zszJ2rQP1LcH2AlEZ8bl0qpcFMk03LENUHSt1DjlaApxrEJzDgAs5drfndxXgGKYjPpkjdF+qGhn2ALV2tC64I5aIn1SJPAQnVwprUr1FmVZjZcF9m9r8WnzQ6ldj29eZIciiFlT4n2Cbw+dgPo/hNRsgzn7Our2a6r5INw==","timestamp":"2001-01-01T01:01:01.000000001Z","title":"Structure: 2 changes"},"meta":{"qri":"md:0","title":"different title"},"path":"/ipfs/QmZCLadp1c2bhZxTyG8BjnxBmm6vdJvYvyD2myJfTTf8yw","peername":"me","previousPath":"/ipfs/QmdFjgWLL5nGdXLb9383x4dNskxQX84iqm7hPJiBCHij1p","qri":"ds:0","structure":{"checksum":"QmcXDEGeWdyzfFRYyPsQVab5qszZfKqxTMEoXRDSZMyrhf","depth":2,"errCount":1,"entries":8,"format":"csv","formatConfig":{"headerRow":true,"lazyQuotes":false},"length":224,"qri":"st:0","schema":{"items":{"items":[{"title":"name","type":"string"},{"title":"duration","type":"integer"}]},"type":"array"}}}`
if actual != expect {
t.Errorf("error, dataset actual:\n%s\nexpect:\n%s\n", actual, expect)
}
}

// Test that saving a full dataset with a component at the same time is an error
func TestSaveDatasetWithComponentError(t *testing.T) {
if err := confirmQriNotRunning(); err != nil {
t.Skip(err.Error())
}

// To keep hashes consistent, artificially specify the timestamp by overriding
// the dsfs.Timestamp func
prev := dsfs.Timestamp
defer func() { dsfs.Timestamp = prev }()
dsfs.Timestamp = func() time.Time { return time.Date(2001, 01, 01, 01, 01, 01, 01, time.UTC) }

r := NewTestRepoRoot(t, "qri_test_save_then_override_meta")
defer r.Delete()

cmdR := r.CreateCommandRunner()
_, err := executeCommand(cmdR, "qri save --file=testdata/movies/ds_ten.yaml --file=testdata/movies/meta_override.yaml me/test_ds")
if err == nil {
t.Errorf("expected error, did not get one")
}

expect := `conflict, cannot save a full dataset with other components`
if err.Error() != expect {
t.Errorf("expected error: \"%s\", got: \"%s\"", expect, err.Error())
}
}

// Test that saving with two components of the same kind is an error
func TestSaveConflictingComponents(t *testing.T) {
if err := confirmQriNotRunning(); err != nil {
t.Skip(err.Error())
}

// To keep hashes consistent, artificially specify the timestamp by overriding
// the dsfs.Timestamp func
prev := dsfs.Timestamp
defer func() { dsfs.Timestamp = prev }()
dsfs.Timestamp = func() time.Time { return time.Date(2001, 01, 01, 01, 01, 01, 01, time.UTC) }

r := NewTestRepoRoot(t, "qri_test_save_then_override_meta")
defer r.Delete()

cmdR := r.CreateCommandRunner()
_, err := executeCommand(cmdR, "qri save --file=testdata/movies/ds_ten.yaml me/test_ds")
if err != nil {
t.Fatalf(err.Error())
}

cmdR = r.CreateCommandRunner()
_, err = executeCommand(cmdR, "qri save --file=testdata/movies/meta_override.yaml --file=testdata/movies/meta_override.yaml me/test_ds")
if err == nil {
t.Errorf("expected error, did not get one")
}

expect := `conflict, multiple components of kind "md"`
if err.Error() != expect {
t.Errorf("expected error: \"%s\", got: \"%s\"", expect, err.Error())
}
}

// TODO: Perhaps this utility should move to a lower package, and be used as a way to validate the
// bodies of dataset in more of our test case. That would require extracting some parts out, like
// pathFactory, which would probably necessitate the pathFactory taking the testRepoRoot as a
Expand Down
2 changes: 1 addition & 1 deletion cmd/save.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func (o *SaveOptions) Complete(f Factory, args []string) (err error) {
// Make all paths absolute. Especially important if we are running
// `qri connect` in a different terminal, and that instance is in a different directory;
// that instance won't correctly find the body file we want to load if it's not absolute.
for i, _ := range o.FilePaths {
for i := range o.FilePaths {
if err := lib.AbsPath(&o.FilePaths[i]); err != nil {
return err
}
Expand Down
7 changes: 0 additions & 7 deletions cmd/save_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,3 @@ func TestSaveRun(t *testing.T) {
}
}
}

// TODO(dlong): Add tests for saving with multiple file compoents. Handle these cases:
// save with a single file, which is a dataset
// save with a single file which is only a meta component
// save with multiple components, meta and structure and title
// error when saving with a dataset and a meta component
// error when saving with a zip file and a meta component
23 changes: 23 additions & 0 deletions cmd/testdata/movies/structure_override.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"qri": "st:0",
"format": "csv",
"formatConfig": {
"headerRow": true,
"lazyQuotes": false
},
"schema": {
"type": "array",
"items": {
"items": [
{
"title": "name",
"type": "string"
},
{
"title": "duration",
"type": "integer"
}
]
}
}
}
12 changes: 7 additions & 5 deletions lib/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func pathKind(path string) string {
func ReadDatasetFiles(pathList []string) (*dataset.Dataset, error) {
// If there's only a single file provided, read it and return the dataset.
if len(pathList) == 1 {
ds, _, err := ReadSingleFile(pathList[0])
ds, _, err := readSingleFile(pathList[0])
return ds, err
}

Expand All @@ -71,16 +71,16 @@ func ReadDatasetFiles(pathList []string) (*dataset.Dataset, error) {
foundKinds := make(map[string]bool)
ds := dataset.Dataset{}
for _, p := range pathList {
component, kind, err := ReadSingleFile(p)
component, kind, err := readSingleFile(p)
if err != nil {
return nil, err
}

if kind == "zip" || kind == "ds" {
return nil, fmt.Errorf("")
return nil, fmt.Errorf("conflict, cannot save a full dataset with other components")
}
if _, ok := foundKinds[kind]; ok {
return nil, fmt.Errorf("conflict, multiple components of kind %s", kind)
return nil, fmt.Errorf("conflict, multiple components of kind \"%s\"", kind)
}
foundKinds[kind] = true

Expand All @@ -90,7 +90,9 @@ func ReadDatasetFiles(pathList []string) (*dataset.Dataset, error) {
return &ds, nil
}

func ReadSingleFile(path string) (*dataset.Dataset, string, error) {
// readSingleFile reads a single file, either a full dataset or component, and returns it as
// a dataset and a string specifying the kind of component that was created
func readSingleFile(path string) (*dataset.Dataset, string, error) {
ds := dataset.Dataset{}
switch pathKind(path) {
case "http":
Expand Down

0 comments on commit 9fe54bc

Please sign in to comment.