func TestCommitAndBranch(t *testing.T) { tests.UseStore() defer tests.CloseStore() apiStr := fmt.Sprintf("%srepos", server.WebAPIPath) r := server.TestHTTP(t, "POST", apiStr, nil) var jsonResp map[string]interface{} if err := json.Unmarshal(r, &jsonResp); err != nil { t.Fatalf("Unable to unmarshal repo creation response: %s\n", string(r)) } v, ok := jsonResp["root"] if !ok { t.Fatalf("No 'root' metadata returned: %s\n", string(r)) } uuidStr, ok := v.(string) if !ok { t.Fatalf("Couldn't cast returned 'root' data (%v) into string.\n", v) } uuid := dvid.UUID(uuidStr) // Shouldn't be able to create branch on open node. branchReq := fmt.Sprintf("%snode/%s/branch", server.WebAPIPath, uuid) server.TestBadHTTP(t, "POST", branchReq, nil) // Add a keyvalue instance. server.CreateTestInstance(t, uuid, "keyvalue", "mykv", dvid.Config{}) // Commit it. payload := bytes.NewBufferString(`{"note": "This is my test commit", "log": ["line1", "line2", "some more stuff in a line"]}`) apiStr = fmt.Sprintf("%snode/%s/commit", server.WebAPIPath, uuid) server.TestHTTP(t, "POST", apiStr, payload) // Make sure committed nodes can only be read. // We shouldn't be able to write to keyvalue.. keyReq := fmt.Sprintf("%snode/%s/mykv/key/foo", server.WebAPIPath, uuid) server.TestBadHTTP(t, "POST", keyReq, bytes.NewBufferString("some data")) // Should be able to create branch now that we've committed parent. respData := server.TestHTTP(t, "POST", branchReq, nil) resp := struct { Child dvid.UUID `json:"child"` }{} if err := json.Unmarshal(respData, &resp); err != nil { t.Errorf("Expected 'child' JSON response. Got %s\n", string(respData)) } // We should be able to write to that keyvalue now in the child. keyReq = fmt.Sprintf("%snode/%s/mykv/key/foo", server.WebAPIPath, resp.Child) server.TestHTTP(t, "POST", keyReq, bytes.NewBufferString("some data")) }
func TestDeleteInstance(t *testing.T) { tests.UseStore() defer tests.CloseStore() apiStr := fmt.Sprintf("%srepos", server.WebAPIPath) r := server.TestHTTP(t, "POST", apiStr, nil) var jsonResp map[string]interface{} if err := json.Unmarshal(r, &jsonResp); err != nil { t.Fatalf("Unable to unmarshal repo creation response: %s\n", string(r)) } v, ok := jsonResp["root"] if !ok { t.Fatalf("No 'root' metadata returned: %s\n", string(r)) } uuidStr, ok := v.(string) if !ok { t.Fatalf("Couldn't cast returned 'root' data (%v) into string.\n", v) } uuid := dvid.UUID(uuidStr) // Add a data instance. var config dvid.Config server.CreateTestInstance(t, uuid, "keyvalue", "foo", config) // Make sure it exists. _, err := datastore.GetDataByUUID(uuid, "foo") if err != nil { t.Errorf("Couldn't create data instance 'foo'\n") } // Shouldn't be able to delete instance without "imsure" delReq := fmt.Sprintf("%srepo/%s/%s", server.WebAPIPath, uuid, "foo") server.TestBadHTTP(t, "DELETE", delReq, nil) delReq = fmt.Sprintf("%srepo/%s/%s?imsure=true", server.WebAPIPath, uuid, "foo") server.TestHTTP(t, "DELETE", delReq, nil) // Make sure it no longer exists. _, err = datastore.GetDataByUUID(uuid, "foo") if err == nil { t.Errorf("Shouldn't be able to access a deleted data instance 'foo'\n") } }
func TestKeyvalueVersioning(t *testing.T) { datastore.OpenTest() defer datastore.CloseTest() uuid, _ := initTestRepo() config := dvid.NewConfig() dataservice, err := datastore.NewData(uuid, kvtype, "versiontest", config) if err != nil { t.Fatalf("Error creating new keyvalue instance: %v\n", err) } data, ok := dataservice.(*Data) if !ok { t.Fatalf("Returned new data instance is not roi.Data\n") } // PUT a value key1 := "mykey" value1 := "some stuff" key1req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid, data.DataName(), key1) server.TestHTTP(t, "POST", key1req, strings.NewReader(value1)) // Add 2nd k/v key2 := "my2ndkey" value2 := "more good stuff" key2req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid, data.DataName(), key2) server.TestHTTP(t, "POST", key2req, strings.NewReader(value2)) // Create a new version in repo if err = datastore.Commit(uuid, "my commit msg", []string{"stuff one", "stuff two"}); err != nil { t.Errorf("Unable to lock root node %s: %v\n", uuid, err) } uuid2, err := datastore.NewVersion(uuid, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid, err) } _, err = datastore.VersionFromUUID(uuid2) if err != nil { t.Fatalf("Unable to get version ID from new uuid %s: %v\n", uuid2, err) } // Change the 2nd k/v uuid2val := "this is completely different" uuid2req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid2, data.DataName(), key2) server.TestHTTP(t, "POST", uuid2req, strings.NewReader(uuid2val)) // Get the first version value returnValue := server.TestHTTP(t, "GET", key2req, nil) if string(returnValue) != value2 { t.Errorf("Error on first version, key %q: expected %s, got %s\n", key2, value2, string(returnValue)) } // Get the second version value returnValue = server.TestHTTP(t, "GET", uuid2req, nil) if string(returnValue) != uuid2val { t.Errorf("Error on second version, key %q: expected %s, got %s\n", key2, uuid2val, string(returnValue)) } // Check return of first two keys in range. rangereq := fmt.Sprintf("%snode/%s/%s/keyrange/%s/%s", server.WebAPIPath, uuid, data.DataName(), "my", "zebra") returnValue = server.TestHTTP(t, "GET", rangereq, nil) var retrievedKeys []string if err = json.Unmarshal(returnValue, &retrievedKeys); err != nil { t.Errorf("Bad key range request unmarshal: %v\n", err) } if len(retrievedKeys) != 2 || retrievedKeys[1] != "mykey" && retrievedKeys[0] != "my2ndKey" { t.Errorf("Bad key range request return. Expected: [%q,%q]. Got: %s\n", key1, key2, string(returnValue)) } // Commit the repo if err = datastore.Commit(uuid2, "my 2nd commit msg", []string{"changed 2nd k/v"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid2, err) } // Make grandchild of root uuid3, err := datastore.NewVersion(uuid2, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid2, err) } // Delete the 2nd k/v uuid3req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid3, data.DataName(), key2) server.TestHTTP(t, "DELETE", uuid3req, nil) server.TestBadHTTP(t, "GET", uuid3req, nil) // Make sure the 2nd k/v is correct for each of previous versions. returnValue = server.TestHTTP(t, "GET", key2req, nil) if string(returnValue) != value2 { t.Errorf("Error on first version, key %q: expected %s, got %s\n", key2, value2, string(returnValue)) } returnValue = server.TestHTTP(t, "GET", uuid2req, nil) if string(returnValue) != uuid2val { t.Errorf("Error on second version, key %q: expected %s, got %s\n", key2, uuid2val, string(returnValue)) } // Make a child if err = datastore.Commit(uuid3, "my 3rd commit msg", []string{"deleted 2nd k/v"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid2, err) } uuid4, err := datastore.NewVersion(uuid3, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid3, err) } // Change the 2nd k/v uuid4val := "we are reintroducing this k/v" uuid4req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid4, data.DataName(), key2) server.TestHTTP(t, "POST", uuid4req, strings.NewReader(uuid4val)) if err = datastore.Commit(uuid4, "commit node 4", []string{"we modified stuff"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid4, err) } // Make sure the 2nd k/v is correct for each of previous versions. returnValue = server.TestHTTP(t, "GET", key2req, nil) if string(returnValue) != value2 { t.Errorf("Error on first version, key %q: expected %s, got %s\n", key2, value2, string(returnValue)) } returnValue = server.TestHTTP(t, "GET", uuid2req, nil) if string(returnValue) != uuid2val { t.Errorf("Error on second version, key %q: expected %s, got %s\n", key2, uuid2val, string(returnValue)) } server.TestBadHTTP(t, "GET", uuid3req, nil) returnValue = server.TestHTTP(t, "GET", uuid4req, nil) if string(returnValue) != uuid4val { t.Errorf("Error on fourth version, key %q: expected %s, got %s\n", key2, uuid4val, string(returnValue)) } // Let's try a merge! // Make a child off the 2nd version from root. uuid5, err := datastore.NewVersion(uuid2, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid2, err) } // Store new stuff in 2nd k/v uuid5val := "this is forked value" uuid5req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid5, data.DataName(), key2) server.TestHTTP(t, "POST", uuid5req, strings.NewReader(uuid5val)) returnValue = server.TestHTTP(t, "GET", uuid5req, nil) if string(returnValue) != uuid5val { t.Errorf("Error on merged child, key %q: expected %q, got %q\n", key2, uuid5val, string(returnValue)) } // Commit node if err = datastore.Commit(uuid5, "forked node", []string{"we modified stuff"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid5, err) } // Should be able to merge using conflict-free (disjoint at key level) merge even though // its conflicted. Will get lazy error on request. badChild, err := datastore.Merge([]dvid.UUID{uuid4, uuid5}, "some child", datastore.MergeConflictFree) if err != nil { t.Errorf("Error doing merge: %v\n", err) } childreq := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, badChild, data.DataName(), key2) server.TestBadHTTP(t, "GET", childreq, nil) // Manually fix conflict: Branch, and then delete 2nd k/v and commit. uuid6, err := datastore.NewVersion(uuid5, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid5, err) } uuid6req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid6, data.DataName(), key2) server.TestHTTP(t, "DELETE", uuid6req, nil) server.TestBadHTTP(t, "GET", uuid6req, nil) if err = datastore.Commit(uuid6, "deleted forked node 2nd k/v", []string{"we modified stuff"}); err != nil { t.Errorf("Unable to commit node %s: %s\n", uuid6, err) } // Should now be able to correctly merge the two branches. goodChild, err := datastore.Merge([]dvid.UUID{uuid4, uuid6}, "merging stuff", datastore.MergeConflictFree) if err != nil { t.Errorf("Error doing merge: %v\n", err) } // We should be able to see just the original uuid4 value of the 2nd k/v childreq = fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, goodChild, data.DataName(), key2) returnValue = server.TestHTTP(t, "GET", childreq, nil) if string(returnValue) != uuid4val { t.Errorf("Error on merged child, key %q: expected %q, got %q\n", key2, uuid4val, string(returnValue)) } // Apply the automatic conflict resolution using ordering. payload := fmt.Sprintf(`{"data":["versiontest"],"parents":[%q,%q],"note":"automatic resolved merge"}`, uuid5, uuid4) resolveReq := fmt.Sprintf("%srepo/%s/resolve", server.WebAPIPath, uuid4) returnValue = server.TestHTTP(t, "POST", resolveReq, bytes.NewBufferString(payload)) resolveResp := struct { Child dvid.UUID `json:"child"` }{} if err := json.Unmarshal(returnValue, &resolveResp); err != nil { t.Fatalf("Can't parse return of resolve request: %s\n", string(returnValue)) } // We should now see the uuid5 version of the 2nd k/v in the returned merged node. childreq = fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, resolveResp.Child, data.DataName(), key2) returnValue = server.TestHTTP(t, "GET", childreq, nil) if string(returnValue) != uuid5val { t.Errorf("Error on auto merged child, key %q: expected %q, got %q\n", key2, uuid5val, string(returnValue)) } // Introduce a child off root but don't add 2nd k/v to it. uuid7, err := datastore.NewVersion(uuid, "2nd child off root", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid, err) } if err = datastore.Commit(uuid7, "useless node", []string{"we modified nothing!"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid7, err) } // Now merge the previously merged node with the newly created "blank" child off root. if err = datastore.Commit(goodChild, "this was a good merge", []string{}); err != nil { t.Errorf("Unable to commit node %s: %v\n", goodChild, err) } merge2, err := datastore.Merge([]dvid.UUID{goodChild, uuid7}, "merging a useless path", datastore.MergeConflictFree) if err != nil { t.Errorf("Error doing merge: %v\n", err) } merge3, err := datastore.Merge([]dvid.UUID{uuid7, goodChild}, "merging a useless path in reverse order", datastore.MergeConflictFree) if err != nil { t.Errorf("Error doing merge: %v\n", err) } // We should still be conflict free since 2nd key in left parent path will take precedent over shared 2nd key // in root. This tests our invalidation of ancestors. toughreq := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, merge2, data.DataName(), key2) returnValue = server.TestHTTP(t, "GET", toughreq, nil) if string(returnValue) != uuid4val { t.Errorf("Error on merged child, key %q: expected %q, got %q\n", key2, uuid4val, string(returnValue)) } toughreq = fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, merge3, data.DataName(), key2) returnValue = server.TestHTTP(t, "GET", toughreq, nil) if string(returnValue) != uuid4val { t.Errorf("Error on merged child, key %q: expected %q, got %q\n", key2, uuid4val, string(returnValue)) } }
func TestKeyvalueUnversioned(t *testing.T) { datastore.OpenTest() defer datastore.CloseTest() uuid, _ := initTestRepo() config := dvid.NewConfig() config.Set("versioned", "false") dataservice, err := datastore.NewData(uuid, kvtype, "unversiontest", config) if err != nil { t.Fatalf("Error creating new keyvalue instance: %v\n", err) } data, ok := dataservice.(*Data) if !ok { t.Fatalf("Returned new data instance is not roi.Data\n") } // PUT a value key1 := "mykey" value1 := "some stuff" key1req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid, data.DataName(), key1) server.TestHTTP(t, "POST", key1req, strings.NewReader(value1)) // Add 2nd k/v key2 := "my2ndkey" value2 := "more good stuff" key2req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid, data.DataName(), key2) server.TestHTTP(t, "POST", key2req, strings.NewReader(value2)) // Create a new version in repo if err = datastore.Commit(uuid, "my commit msg", []string{"stuff one", "stuff two"}); err != nil { t.Errorf("Unable to lock root node %s: %v\n", uuid, err) } uuid2, err := datastore.NewVersion(uuid, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid, err) } _, err = datastore.VersionFromUUID(uuid2) if err != nil { t.Fatalf("Unable to get version ID from new uuid %s: %v\n", uuid2, err) } // Change the 2nd k/v uuid2val := "this is completely different" uuid2req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid2, data.DataName(), key2) server.TestHTTP(t, "POST", uuid2req, strings.NewReader(uuid2val)) // Now the first version value should equal the new value returnValue := server.TestHTTP(t, "GET", key2req, nil) if string(returnValue) != uuid2val { t.Errorf("Error on unversioned key %q: expected %s, got %s\n", key2, uuid2val, string(returnValue)) } // Get the second version value returnValue = server.TestHTTP(t, "GET", uuid2req, nil) if string(returnValue) != uuid2val { t.Errorf("Error on unversioned key %q: expected %s, got %s\n", key2, uuid2val, string(returnValue)) } // Check return of first two keys in range. rangereq := fmt.Sprintf("%snode/%s/%s/keyrange/%s/%s", server.WebAPIPath, uuid, data.DataName(), "my", "zebra") returnValue = server.TestHTTP(t, "GET", rangereq, nil) var retrievedKeys []string if err = json.Unmarshal(returnValue, &retrievedKeys); err != nil { t.Errorf("Bad key range request unmarshal: %v\n", err) } if len(retrievedKeys) != 2 || retrievedKeys[1] != "mykey" && retrievedKeys[0] != "my2ndKey" { t.Errorf("Bad key range request return. Expected: [%q,%q]. Got: %s\n", key1, key2, string(returnValue)) } // Commit the repo if err = datastore.Commit(uuid2, "my 2nd commit msg", []string{"changed 2nd k/v"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid2, err) } // Make grandchild of root uuid3, err := datastore.NewVersion(uuid2, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid2, err) } // Delete the 2nd k/v uuid3req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid3, data.DataName(), key2) server.TestHTTP(t, "DELETE", uuid3req, nil) server.TestBadHTTP(t, "GET", uuid3req, nil) // Make sure the 2nd k/v is now missing for previous versions. server.TestBadHTTP(t, "GET", key2req, nil) server.TestBadHTTP(t, "GET", uuid2req, nil) // Make a child if err = datastore.Commit(uuid3, "my 3rd commit msg", []string{"deleted 2nd k/v"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid2, err) } uuid4, err := datastore.NewVersion(uuid3, "some child", nil) if err != nil { t.Fatalf("Unable to create new version off node %s: %v\n", uuid3, err) } // Change the 2nd k/v uuid4val := "we are reintroducing this k/v" uuid4req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid4, data.DataName(), key2) server.TestHTTP(t, "POST", uuid4req, strings.NewReader(uuid4val)) if err = datastore.Commit(uuid4, "commit node 4", []string{"we modified stuff"}); err != nil { t.Errorf("Unable to commit node %s: %v\n", uuid4, err) } // Make sure the 2nd k/v is correct for each of previous versions. returnValue = server.TestHTTP(t, "GET", key2req, nil) if string(returnValue) != uuid4val { t.Errorf("Error on first version, key %q: expected %s, got %s\n", key2, uuid4val, string(returnValue)) } returnValue = server.TestHTTP(t, "GET", uuid2req, nil) if string(returnValue) != uuid4val { t.Errorf("Error on second version, key %q: expected %s, got %s\n", key2, uuid4val, string(returnValue)) } returnValue = server.TestHTTP(t, "GET", uuid3req, nil) if string(returnValue) != uuid4val { t.Errorf("Error on third version, key %q: expected %s, got %s\n", key2, uuid4val, string(returnValue)) } returnValue = server.TestHTTP(t, "GET", uuid4req, nil) if string(returnValue) != uuid4val { t.Errorf("Error on fourth version, key %q: expected %s, got %s\n", key2, uuid4val, string(returnValue)) } }
func testRequest(t *testing.T, uuid dvid.UUID, versionID dvid.VersionID, name dvid.InstanceName) { config := dvid.NewConfig() dataservice, err := datastore.NewData(uuid, kvtype, name, config) if err != nil { t.Fatalf("Error creating new keyvalue instance: %v\n", err) } data, ok := dataservice.(*Data) if !ok { t.Fatalf("Returned new data instance is not roi.Data\n") } // PUT a value key1 := "mykey" value1 := "some stuff" key1req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid, data.DataName(), key1) server.TestHTTP(t, "POST", key1req, strings.NewReader(value1)) // Get back k/v returnValue := server.TestHTTP(t, "GET", key1req, nil) if string(returnValue) != value1 { t.Errorf("Error on key %q: expected %s, got %s\n", key1, value1, string(returnValue)) } // Expect error if no key used. badrequest := fmt.Sprintf("%snode/%s/%s/key/", server.WebAPIPath, uuid, data.DataName()) server.TestBadHTTP(t, "GET", badrequest, nil) // Add 2nd k/v key2 := "my2ndkey" value2 := "more good stuff" key2req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid, data.DataName(), key2) server.TestHTTP(t, "POST", key2req, strings.NewReader(value2)) // Add 3rd k/v key3 := "heresanotherkey" value3 := "my 3rd value" key3req := fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid, data.DataName(), key3) server.TestHTTP(t, "POST", key3req, strings.NewReader(value3)) // Check return of first two keys in range. rangereq := fmt.Sprintf("%snode/%s/%s/keyrange/%s/%s", server.WebAPIPath, uuid, data.DataName(), "my", "zebra") returnValue = server.TestHTTP(t, "GET", rangereq, nil) var retrievedKeys []string if err = json.Unmarshal(returnValue, &retrievedKeys); err != nil { t.Errorf("Bad key range request unmarshal: %v\n", err) } if len(retrievedKeys) != 2 || retrievedKeys[1] != "mykey" && retrievedKeys[0] != "my2ndKey" { t.Errorf("Bad key range request return. Expected: [%q,%q]. Got: %s\n", key2, key1, string(returnValue)) } // Check return of all keys allkeyreq := fmt.Sprintf("%snode/%s/%s/keys", server.WebAPIPath, uuid, data.DataName()) returnValue = server.TestHTTP(t, "GET", allkeyreq, nil) if err = json.Unmarshal(returnValue, &retrievedKeys); err != nil { t.Errorf("Bad key range request unmarshal: %v\n", err) } if len(retrievedKeys) != 3 || retrievedKeys[0] != "heresanotherkey" && retrievedKeys[1] != "my2ndKey" && retrievedKeys[2] != "mykey" { t.Errorf("Bad all key request return. Expected: [%q,%q,%q]. Got: %s\n", key3, key2, key1, string(returnValue)) } }
func TestLabels(t *testing.T) { datastore.OpenTest() defer datastore.CloseTest() // Create testbed volume and data instances uuid, _ := initTestRepo() var config dvid.Config server.CreateTestInstance(t, uuid, "labelblk", "labels", config) server.CreateTestInstance(t, uuid, "labelvol", "bodies", config) // Establish syncs server.CreateTestSync(t, uuid, "labels", "bodies") server.CreateTestSync(t, uuid, "bodies", "labels") // Populate the labels, which should automatically populate the labelvol _ = createLabelTestVolume(t, uuid, "labels") if err := datastore.BlockOnUpdating(uuid, "labels"); err != nil { t.Fatalf("Error blocking on sync of labels: %v\n", err) } // Add annotations syncing with "labels" instance checking for deduplication. server.CreateTestInstance(t, uuid, "annotation", "mysynapses", config) server.CreateTestSync(t, uuid, "mysynapses", "labels,bodies,labels,bodies,labels,bodies") dataservice, err := datastore.GetDataByUUIDName(uuid, "mysynapses") if err != nil { t.Fatal(err) } data, ok := dataservice.(*Data) if !ok { t.Fatalf("Can't convert dataservice %v into datastore.Data\n", dataservice) } if len(data.SyncedData()) != 2 { t.Fatalf("Expected 2 syncs (uuids for labels and bodies], got %v\n", data.SyncedData()) } // PUT first batch of synapses testJSON, err := json.Marshal(testData) if err != nil { t.Fatal(err) } url1 := fmt.Sprintf("%snode/%s/mysynapses/elements", server.WebAPIPath, uuid) server.TestHTTP(t, "POST", url1, strings.NewReader(string(testJSON))) // Test if labels were properly denormalized. For the POST we have synchronized label denormalization. // If this were to become asynchronous, we'd want to block on updating like the labelblk<->labelvol sync. testResponseLabel(t, expectedLabel1, "%snode/%s/mysynapses/label/1?relationships=true", server.WebAPIPath, uuid) testResponseLabel(t, expectedLabel2, "%snode/%s/mysynapses/label/2?relationships=true", server.WebAPIPath, uuid) testResponseLabel(t, expectedLabel3, "%snode/%s/mysynapses/label/3?relationships=true", server.WebAPIPath, uuid) testResponseLabel(t, expectedLabel3NoRel, "%snode/%s/mysynapses/label/3", server.WebAPIPath, uuid) testResponseLabel(t, expectedLabel4, "%snode/%s/mysynapses/label/4?relationships=true", server.WebAPIPath, uuid) // Make change to labelblk and make sure our label synapses have been adjusted (case A) _ = modifyLabelTestVolume(t, uuid, "labels") if err := datastore.BlockOnUpdating(uuid, "mysynapses"); err != nil { t.Fatalf("Error blocking on sync of labels->annotations: %v\n", err) } testResponseLabel(t, expectedLabel1, "%snode/%s/mysynapses/label/1?relationships=true", server.WebAPIPath, uuid) testResponseLabel(t, expectedLabel2a, "%snode/%s/mysynapses/label/2?relationships=true", server.WebAPIPath, uuid) testResponseLabel(t, expectedLabel3a, "%snode/%s/mysynapses/label/3?relationships=true", server.WebAPIPath, uuid) testResponseLabel(t, expectedLabel4, "%snode/%s/mysynapses/label/4?relationships=true", server.WebAPIPath, uuid) testResponseLabel(t, expectedLabel4NoRel, "%snode/%s/mysynapses/label/4", server.WebAPIPath, uuid) // Make change to labelvol and make sure our label synapses have been adjusted (case B). // Merge 3a into 2a. testMerge := mergeJSON(`[2, 3]`) testMerge.send(t, uuid, "bodies") if err := datastore.BlockOnUpdating(uuid, "labels"); err != nil { t.Fatalf("Error blocking on sync of labels: %v\n", err) } if err := datastore.BlockOnUpdating(uuid, "mysynapses"); err != nil { t.Fatalf("Error blocking on sync of synapses: %v\n", err) } testResponseLabel(t, expectedLabel1, "%snode/%s/mysynapses/label/1?relationships=true", server.WebAPIPath, uuid) testResponseLabel(t, expectedLabel2b, "%snode/%s/mysynapses/label/2?relationships=true", server.WebAPIPath, uuid) testResponseLabel(t, nil, "%snode/%s/mysynapses/label/3?relationships=true", server.WebAPIPath, uuid) testResponseLabel(t, expectedLabel4, "%snode/%s/mysynapses/label/4?relationships=true", server.WebAPIPath, uuid) // Now split label 2b off and check if annotations also split // Create the sparsevol encoding for split area numspans := len(bodysplit.voxelSpans) rles := make(dvid.RLEs, numspans, numspans) for i, span := range bodysplit.voxelSpans { start := dvid.Point3d{span[2], span[1], span[0]} length := span[3] - span[2] + 1 rles[i] = dvid.NewRLE(start, length) } buf := getBytesRLE(t, rles) // Submit the split sparsevol reqStr := fmt.Sprintf("%snode/%s/%s/split/%d?splitlabel=7", server.WebAPIPath, uuid, "bodies", 2) r := server.TestHTTP(t, "POST", reqStr, buf) jsonVal := make(map[string]uint64) if err := json.Unmarshal(r, &jsonVal); err != nil { t.Errorf("Unable to get new label from split. Instead got: %v\n", jsonVal) } // Verify that the annotations are correct. if err := datastore.BlockOnUpdating(uuid, "mysynapses"); err != nil { t.Fatalf("Error blocking on sync of split->annotations: %v\n", err) } testResponseLabel(t, expectedLabel2c, "%snode/%s/mysynapses/label/2?relationships=true", server.WebAPIPath, uuid) url2 := fmt.Sprintf("%snode/%s/mysynapses/label/7?relationships=true", server.WebAPIPath, uuid) testResponseLabel(t, expectedLabel7, url2) // Change the name of the annotations. if err = datastore.RenameData(uuid, "mysynapses", "bodies", "foobar"); err == nil { t.Fatalf("Should have been prevented from renaming data 'mysynapses' to existing data 'bodies'!\n") } if err = datastore.RenameData(uuid, "mysynapses", "renamedData", "foobar"); err != nil { t.Fatalf("Error renaming annotations: %v\n", err) } // Make sure the old name is no longer there and the new one is. server.TestBadHTTP(t, "GET", url2, nil) testResponseLabel(t, expectedLabel2c, "%snode/%s/renamedData/label/2?relationships=true", server.WebAPIPath, uuid) // Try a coarse split. // Create the encoding for split area in block coordinates. rles = dvid.RLEs{ dvid.NewRLE(dvid.Point3d{3, 1, 3}, 1), } buf = getBytesRLE(t, rles) // Submit the coarse split reqStr = fmt.Sprintf("%snode/%s/%s/split-coarse/2?splitlabel=8", server.WebAPIPath, uuid, "bodies") r = server.TestHTTP(t, "POST", reqStr, buf) jsonVal = make(map[string]uint64) if err := json.Unmarshal(r, &jsonVal); err != nil { t.Errorf("Unable to get new label from split. Instead got: %v\n", jsonVal) } // Verify that the annotations are correct. if err := datastore.BlockOnUpdating(uuid, "renamedData"); err != nil { t.Fatalf("Error blocking on sync of split->annotations: %v\n", err) } testResponseLabel(t, expectedLabel2c, "%snode/%s/renamedData/label/8?relationships=true", server.WebAPIPath, uuid) testResponseLabel(t, nil, "%snode/%s/renamedData/label/2?relationships=true", server.WebAPIPath, uuid) // Delete a labeled annotation and make sure it's not in label delurl := fmt.Sprintf("%snode/%s/%s/element/20_30_40", server.WebAPIPath, uuid, "renamedData") server.TestHTTP(t, "DELETE", delurl, nil) testResponseLabel(t, afterDeleteOn7, "%snode/%s/%s/label/7?relationships=true", server.WebAPIPath, uuid, "renamedData") }
func TestCommitAndBranch(t *testing.T) { datastore.OpenTest() defer datastore.CloseTest() apiStr := fmt.Sprintf("%srepos", server.WebAPIPath) r := server.TestHTTP(t, "POST", apiStr, nil) var jsonResp map[string]interface{} if err := json.Unmarshal(r, &jsonResp); err != nil { t.Fatalf("Unable to unmarshal repo creation response: %s\n", string(r)) } v, ok := jsonResp["root"] if !ok { t.Fatalf("No 'root' metadata returned: %s\n", string(r)) } uuidStr, ok := v.(string) if !ok { t.Fatalf("Couldn't cast returned 'root' data (%v) into string.\n", v) } uuid := dvid.UUID(uuidStr) // Shouldn't be able to create branch on open node. branchReq := fmt.Sprintf("%snode/%s/branch", server.WebAPIPath, uuid) server.TestBadHTTP(t, "POST", branchReq, nil) // Add a keyvalue instance. server.CreateTestInstance(t, uuid, "keyvalue", "mykv", dvid.Config{}) // Commit it. payload := bytes.NewBufferString(`{"note": "This is my test commit", "log": ["line1", "line2", "some more stuff in a line"]}`) apiStr = fmt.Sprintf("%snode/%s/commit", server.WebAPIPath, uuid) server.TestHTTP(t, "POST", apiStr, payload) // Make sure committed nodes can only be read. // We shouldn't be able to write to keyvalue. keyReq := fmt.Sprintf("%snode/%s/mykv/key/foo", server.WebAPIPath, uuid) server.TestBadHTTP(t, "POST", keyReq, bytes.NewBufferString("some data")) // Create a ROI with an immutable POST request via ptquery. Should be able to still POST to it. server.CreateTestInstance(t, uuid, "roi", "myroi", dvid.Config{}) apiStr = fmt.Sprintf("%snode/%s/myroi/ptquery", server.WebAPIPath, uuid) queryJSON := "[[10, 10, 10], [20, 20, 20], [30, 30, 30], [40, 40, 40], [50, 50, 50]]" server.TestHTTP(t, "POST", apiStr, bytes.NewReader([]byte(queryJSON))) // we have no ROI so just testing HTTP. // Should be able to create branch now that we've committed parent. respData := server.TestHTTP(t, "POST", branchReq, nil) resp := struct { Child dvid.UUID `json:"child"` }{} if err := json.Unmarshal(respData, &resp); err != nil { t.Errorf("Expected 'child' JSON response. Got %s\n", string(respData)) } // We should be able to write to that keyvalue now in the child. keyReq = fmt.Sprintf("%snode/%s/mykv/key/foo", server.WebAPIPath, resp.Child) server.TestHTTP(t, "POST", keyReq, bytes.NewBufferString("some data")) // We should also be able to write to the repo-wide log. logReq := fmt.Sprintf("%srepo/%s/log", server.WebAPIPath, uuid) server.TestHTTP(t, "POST", logReq, bytes.NewBufferString(`{"log": ["a log mesage"]}`)) }