github.com/janelia-flyem/dvid@v1.0.0/datatype/labelmap/labelidx_test.go (about) 1 package labelmap 2 3 import ( 4 "bytes" 5 "compress/gzip" 6 "encoding/binary" 7 "encoding/json" 8 "fmt" 9 "strings" 10 "testing" 11 12 pb "google.golang.org/protobuf/proto" 13 14 "github.com/janelia-flyem/dvid/datastore" 15 "github.com/janelia-flyem/dvid/datatype/common/labels" 16 "github.com/janelia-flyem/dvid/datatype/common/proto" 17 "github.com/janelia-flyem/dvid/dvid" 18 "github.com/janelia-flyem/dvid/server" 19 ) 20 21 func checkGetIndices(t *testing.T, uuid dvid.UUID, indices ...*labels.Index) { 22 labelList := make([]uint64, len(indices)) 23 for i, index := range indices { 24 labelList[i] = index.Label 25 } 26 jsonBytes, err := json.Marshal(labelList) 27 if err != nil { 28 t.Fatalf("couldn't marshal labels: %v\n", err) 29 } 30 url := fmt.Sprintf("http://%snode/%s/labels/indices", server.WebAPIPath, uuid) 31 data := server.TestHTTP(t, "GET", url, bytes.NewBuffer(jsonBytes)) 32 if len(data) == 0 { 33 t.Fatalf("Read indices returned no bytes\n") 34 } 35 indicesRet := new(proto.LabelIndices) 36 if err := pb.Unmarshal(data, indicesRet); err != nil { 37 t.Fatalf("couldn't unmarshal indices: %v\n", err) 38 } 39 if len(indicesRet.Indices) != 3 { 40 t.Fatalf("expected 3 returned label indices, got %d\n", len(indicesRet.Indices)) 41 } 42 for i, index := range indices { 43 indexRet := labels.Index{*(indicesRet.Indices[i])} 44 if !index.Equal(indexRet) { 45 t.Fatalf("expected index %d to be\n%v\n but GOT:\n%v\n", i, index, indexRet) 46 } 47 } 48 } 49 50 func TestIngest(t *testing.T) { 51 if err := server.OpenTest(); err != nil { 52 t.Fatalf("can't open test server: %v\n", err) 53 } 54 defer server.CloseTest() 55 56 // Create testbed volume and data instances 57 root, _ := initTestRepo() 58 var config dvid.Config 59 config.Set("MaxDownresLevel", "2") 60 config.Set("BlockSize", "32,32,32") // Previous test data was on 32^3 blocks 61 server.CreateTestInstance(t, root, "labelmap", "labels", config) 62 63 // Post supervoxel volume 64 original := createLabelTestVolume(t, root, "labels") 65 if err := datastore.BlockOnUpdating(root, "labels"); err != nil { 66 t.Fatalf("Error blocking on sync of labels: %v\n", err) 67 } 68 69 for label := uint64(1); label <= 4; label++ { 70 indexURL := fmt.Sprintf("%snode/%s/labels/index/%d", server.WebAPIPath, root, label) 71 serialization := server.TestHTTP(t, "GET", indexURL, nil) 72 idx := new(labels.Index) 73 if err := pb.Unmarshal(serialization, idx); err != nil { 74 t.Fatalf("Unable to GET index/%d: %v\n", label, err) 75 } 76 if idx.Label != label { 77 t.Fatalf("Expected index for label %d, got label %d index\n", label, idx.Label) 78 } 79 supervoxels := idx.GetSupervoxels() 80 if len(supervoxels) != 1 { 81 t.Fatalf("Expected index for label %d to have 1 supervoxel, got %d\n", label, len(supervoxels)) 82 } 83 _, ok := supervoxels[label] 84 if !ok { 85 t.Errorf("Expeced index for label %d to have supervoxel %d, but wasn't present", label, label) 86 } 87 88 indexURL += "?metadata-only=true" 89 respData := server.TestHTTP(t, "GET", indexURL, nil) 90 respJSON := struct { 91 NumVoxels uint64 `json:"num_voxels"` 92 LastMutID uint64 `json:"last_mutid"` 93 LastModTime string `json:"last_mod_time"` 94 LastModUser string `json:"last_mod_user"` 95 LastModApp string `json:"last_mod_app"` 96 }{} 97 if err := json.Unmarshal(respData, &respJSON); err != nil { 98 t.Errorf("Expected JSON response. Got %s\n", string(respData)) 99 } 100 if respJSON.NumVoxels != idx.NumVoxels() { 101 t.Errorf("Expected num voxels %d, got %d\n", idx.NumVoxels(), respJSON.NumVoxels) 102 } 103 } 104 105 checkReq := fmt.Sprintf("%snode/%s/labels/maxlabel", server.WebAPIPath, root) 106 respData := server.TestHTTP(t, "GET", checkReq, nil) 107 respMax := struct { 108 MaxLabel uint64 `json:"maxlabel"` 109 }{} 110 if err := json.Unmarshal(respData, &respMax); err != nil { 111 t.Errorf("Expected 'maxlabel' JSON response. Got %s\n", string(respData)) 112 } 113 if respMax.MaxLabel != 4 { 114 t.Errorf("Expected maxlabel 4, got %d\n", respMax.MaxLabel) 115 } 116 117 checkReq = fmt.Sprintf("%snode/%s/labels/nextlabel", server.WebAPIPath, root) 118 respData = server.TestHTTP(t, "GET", checkReq, nil) 119 respNext := struct { 120 NextLabel uint64 `json:"nextlabel"` 121 }{} 122 if err := json.Unmarshal(respData, &respNext); err != nil { 123 t.Errorf("Expected 'nextlabel' JSON response. Got %s\n", string(respData)) 124 } 125 if respNext.NextLabel != 5 { 126 t.Errorf("Expected nextlabel 5, got %d\n", respNext.NextLabel) 127 } 128 129 // commit and create child version 130 payload := bytes.NewBufferString(`{"note": "Base Supervoxels"}`) 131 commitReq := fmt.Sprintf("%snode/%s/commit", server.WebAPIPath, root) 132 server.TestHTTP(t, "POST", commitReq, payload) 133 134 newVersionReq := fmt.Sprintf("%snode/%s/newversion", server.WebAPIPath, root) 135 respData = server.TestHTTP(t, "POST", newVersionReq, nil) 136 respChild := struct { 137 Child string `json:"child"` 138 }{} 139 if err := json.Unmarshal(respData, &respChild); err != nil { 140 t.Errorf("Expected 'child' JSON response. Got %s\n", string(respData)) 141 } 142 child1 := dvid.UUID(respChild.Child) 143 144 // Test labels in child shouldn't have changed. 145 retrieved := newTestVolume(128, 128, 128) 146 retrieved.get(t, child1, "labels", false) 147 if err := retrieved.equals(original); err != nil { 148 t.Errorf("before mapping: %v\n", err) 149 } 150 151 // POST new mappings and corresponding label indices 152 var m proto.MappingOps 153 m.Mappings = make([]*proto.MappingOp, 2) 154 m.Mappings[0] = &proto.MappingOp{ 155 Mutid: 1, 156 Mapped: 7, 157 Original: []uint64{1, 2}, 158 } 159 m.Mappings[1] = &proto.MappingOp{ 160 Mutid: 2, 161 Mapped: 8, 162 Original: []uint64{3}, 163 } 164 serialization, err := pb.Marshal(&m) 165 if err != nil { 166 t.Fatal(err) 167 } 168 mappingReq := fmt.Sprintf("%snode/%s/labels/mappings", server.WebAPIPath, child1) 169 server.TestHTTP(t, "POST", mappingReq, bytes.NewBuffer(serialization)) 170 171 mappingData := server.TestHTTP(t, "GET", mappingReq, nil) 172 lines := strings.Split(strings.TrimSpace(string(mappingData)), "\n") 173 if len(lines) != 3 { 174 t.Errorf("expected 3 lines for mapping, got %d lines\n", len(lines)) 175 } else { 176 expected := map[uint64]uint64{1: 7, 2: 7, 3: 8} 177 for i, line := range lines { 178 var supervoxel, label uint64 179 fmt.Sscanf(line, "%d %d", &supervoxel, &label) 180 expectedLabel, found := expected[supervoxel] 181 if !found { 182 t.Errorf("got unknown mapping in line %d: %d -> %d\n", i, supervoxel, label) 183 } else if expectedLabel != label { 184 t.Errorf("expected supervoxel %d -> label %d, got %d\n", supervoxel, expectedLabel, label) 185 } 186 } 187 } 188 189 // Same check as above, but with binary format 190 binaryMappingReq := fmt.Sprintf("%snode/%s/labels/mappings?format=binary", server.WebAPIPath, child1) 191 server.TestHTTP(t, "POST", binaryMappingReq, bytes.NewBuffer(serialization)) 192 193 binaryMappingData := server.TestHTTP(t, "GET", binaryMappingReq, nil) 194 if len(binaryMappingData) != 3*8*2 { 195 t.Errorf("expected 3 pairs of uint64 but got %d bytes \n", len(binaryMappingData)) 196 } else { 197 expected := map[uint64]uint64{1: 7, 2: 7, 3: 8} 198 r := bytes.NewReader(binaryMappingData) 199 for i := 0; i < 3; i++ { 200 var supervoxel, label uint64 201 binary.Read(r, binary.LittleEndian, &supervoxel) 202 binary.Read(r, binary.LittleEndian, &label) 203 expectedLabel, found := expected[supervoxel] 204 if !found { 205 t.Errorf("got unknown mapping in pair %d: %d -> %d\n", i, supervoxel, label) 206 } else if expectedLabel != label { 207 t.Errorf("expected supervoxel %d -> label %d, got %d\n", supervoxel, expectedLabel, label) 208 } 209 } 210 } 211 212 idx1 := body1.getIndex(t) 213 idx2 := body2.getIndex(t) 214 idx3 := body3.getIndex(t) 215 checkGetIndices(t, child1, idx1, idx2, idx3) 216 217 if err := idx1.Add(idx2); err != nil { 218 t.Fatal(err) 219 } 220 idx1.Label = 7 221 idx3.Label = 8 222 223 ingestIndex(t, child1, idx1) 224 ingestIndex(t, child1, idx3) 225 226 checkReq = fmt.Sprintf("%snode/%s/labels/maxlabel", server.WebAPIPath, child1) 227 respData = server.TestHTTP(t, "GET", checkReq, nil) 228 if err := json.Unmarshal(respData, &respMax); err != nil { 229 t.Errorf("Expected 'maxlabel' JSON response. Got %s\n", string(respData)) 230 } 231 if respMax.MaxLabel != 8 { 232 t.Errorf("Expected maxlabel 8, got %d\n", respMax.MaxLabel) 233 } 234 235 checkReq = fmt.Sprintf("%snode/%s/labels/nextlabel", server.WebAPIPath, child1) 236 respData = server.TestHTTP(t, "GET", checkReq, nil) 237 if err := json.Unmarshal(respData, &respNext); err != nil { 238 t.Errorf("Expected 'nextlabel' JSON response. Got %s\n", string(respData)) 239 } 240 if respNext.NextLabel != 9 { 241 t.Errorf("Expected nextlabel 9, got %d\n", respNext.NextLabel) 242 } 243 244 blankIdx := new(labels.Index) 245 blankIdx.Label = 2 246 ingestIndex(t, child1, blankIdx) 247 blankIdx.Label = 3 248 ingestIndex(t, child1, blankIdx) 249 250 checkNoSparsevol(t, child1, 2) 251 checkNoSparsevol(t, child1, 3) 252 253 // Test result 254 retrieved.get(t, child1, "labels", false) 255 if err := retrieved.equals(original); err == nil { 256 t.Errorf("expected retrieved labels != original but they are identical after mapping\n") 257 } 258 bodyMerged := body1.add(body2) 259 bodyMerged.checkSparsevolAPIs(t, child1, 7) 260 body3.checkSparsevolAPIs(t, child1, 8) 261 body4.checkSparsevolAPIs(t, child1, 4) 262 263 // Commit and create new version 264 payload = bytes.NewBufferString(`{"note": "First agglo"}`) 265 commitReq = fmt.Sprintf("%snode/%s/commit", server.WebAPIPath, child1) 266 server.TestHTTP(t, "POST", commitReq, payload) 267 268 newVersionReq = fmt.Sprintf("%snode/%s/newversion", server.WebAPIPath, child1) 269 respData = server.TestHTTP(t, "POST", newVersionReq, nil) 270 if err := json.Unmarshal(respData, &respChild); err != nil { 271 t.Errorf("Expected 'child' JSON response. Got %s\n", string(respData)) 272 } 273 child2 := dvid.UUID(respChild.Child) 274 275 // POST second set of mappings to reset supervoxels to original and ingest label indices 276 m.Mappings = make([]*proto.MappingOp, 3) 277 m.Mappings[0] = &proto.MappingOp{ 278 Mutid: 3, 279 Mapped: 1, 280 Original: []uint64{1}, 281 } 282 m.Mappings[1] = &proto.MappingOp{ 283 Mutid: 4, 284 Mapped: 2, 285 Original: []uint64{2}, 286 } 287 m.Mappings[2] = &proto.MappingOp{ 288 Mutid: 5, 289 Mapped: 3, 290 Original: []uint64{3}, 291 } 292 serialization, err = pb.Marshal(&m) 293 if err != nil { 294 t.Fatal(err) 295 } 296 mappingReq = fmt.Sprintf("%snode/%s/labels/mappings", server.WebAPIPath, child2) 297 server.TestHTTP(t, "POST", mappingReq, bytes.NewBuffer(serialization)) 298 299 idx1 = body1.getIndex(t) 300 idx2 = body2.getIndex(t) 301 idx3 = body3.getIndex(t) 302 303 ingestIndex(t, child2, idx1) 304 ingestIndex(t, child2, idx2) 305 ingestIndex(t, child2, idx3) 306 blankIdx.Label = 7 307 ingestIndex(t, child2, blankIdx) 308 blankIdx.Label = 8 309 ingestIndex(t, child2, blankIdx) 310 311 // Test result 312 checkSparsevolAPIs(t, child2) 313 alternateUUID := child1[:8] + ":master" 314 checkSparsevolAPIs(t, alternateUUID) 315 checkNoSparsevol(t, child2, 7) 316 checkNoSparsevol(t, child2, 8) 317 318 retrieved.get(t, child2, "labels", false) 319 if err := retrieved.equals(original); err != nil { 320 t.Errorf("after remapping to original: %v\n", err) 321 } 322 } 323 324 func writeTestBlock(t *testing.T, buf *bytes.Buffer, serialization []byte, blockCoord dvid.Point3d) { 325 var gzipOut bytes.Buffer 326 zw := gzip.NewWriter(&gzipOut) 327 if _, err := zw.Write(serialization); err != nil { 328 t.Fatal(err) 329 } 330 zw.Flush() 331 zw.Close() 332 gzipped := gzipOut.Bytes() 333 writeTestInt32(t, buf, int32(len(gzipped))) 334 n, err := buf.Write(gzipped) 335 if err != nil { 336 t.Fatalf("unable to write gzip block: %v\n", err) 337 } 338 if n != len(gzipped) { 339 t.Fatalf("unable to write %d bytes to buffer, only wrote %d bytes\n", len(gzipped), n) 340 } 341 } 342 343 func TestIngest2(t *testing.T) { 344 if err := server.OpenTest(); err != nil { 345 t.Fatalf("can't open test server: %v\n", err) 346 } 347 defer server.CloseTest() 348 349 uuid, _ := datastore.NewTestRepo() 350 if len(uuid) < 5 { 351 t.Fatalf("Bad root UUID for new repo: %s\n", uuid) 352 } 353 server.CreateTestInstance(t, uuid, "labelmap", "labels", dvid.Config{}) 354 d, err := GetByUUIDName(uuid, "labels") 355 if err != nil { 356 t.Fatal(err) 357 } 358 v, err := datastore.VersionFromUUID(uuid) 359 if err != nil { 360 t.Fatal(err) 361 } 362 if d == nil || v == 0 { 363 t.Fatalf("bad version returned\n") 364 } 365 366 // Exercise POST /blocks using no-indexing. 367 blockCoords := []dvid.Point3d{ 368 {1, 2, 3}, 369 {2, 2, 3}, 370 {1, 3, 4}, 371 {2, 3, 4}, 372 {3, 3, 4}, 373 {4, 3, 5}, 374 } 375 var data [6]testData 376 var buf bytes.Buffer 377 for i, blockCoord := range blockCoords { 378 writeTestInt32(t, &buf, blockCoord[0]) 379 writeTestInt32(t, &buf, blockCoord[1]) 380 writeTestInt32(t, &buf, blockCoord[2]) 381 if i < len(testFiles) { 382 data[i] = loadTestData(t, testFiles[i]) 383 } else { 384 var td testData 385 td.u = make([]uint64, 64*64*64) 386 for i := 0; i < 64*64*64; i++ { 387 td.u[i] = 91748 * uint64(i) 388 } 389 td.b, err = labels.MakeBlock(dvid.AliasUint64ToByte(td.u), dvid.Point3d{64, 64, 64}) 390 if err != nil { 391 t.Fatal(err) 392 } 393 data[i] = td 394 } 395 serialization, err := data[i].b.MarshalBinary() 396 if err != nil { 397 t.Fatalf("unable to MarshalBinary block: %v\n", err) 398 } 399 writeTestBlock(t, &buf, serialization, blockCoord) 400 } 401 402 apiStr := fmt.Sprintf("%snode/%s/labels/blocks?noindexing=true", server.WebAPIPath, uuid) 403 server.TestHTTP(t, "POST", apiStr, &buf) 404 405 if err := datastore.BlockOnUpdating(uuid, "labels"); err != nil { 406 t.Fatalf("Error blocking on sync of labels: %v\n", err) 407 } 408 409 // Add malformed blocks 410 blockCoords = append(blockCoords, dvid.Point3d{5, 3, 5}) 411 blockCoords = append(blockCoords, dvid.Point3d{6, 3, 5}) 412 buf.Reset() 413 prevRecs := len(testFiles) + 2 414 for i, blockCoord := range blockCoords { 415 writeTestInt32(t, &buf, blockCoord[0]) 416 writeTestInt32(t, &buf, blockCoord[1]) 417 writeTestInt32(t, &buf, blockCoord[2]) 418 if i < prevRecs { 419 serialization, err := data[i].b.MarshalBinary() 420 if err != nil { 421 t.Fatalf("unable to MarshalBinary block: %v\n", err) 422 } 423 writeTestBlock(t, &buf, serialization, blockCoord) 424 } else { 425 emptySlice := []byte{38, 247} // random bytes 426 writeTestBlock(t, &buf, emptySlice, blockCoord) 427 } 428 } 429 apiStr = fmt.Sprintf("%snode/%s/labels/blocks?noindexing=true", server.WebAPIPath, uuid) 430 server.TestBadHTTP(t, "POST", apiStr, &buf) 431 432 buf.Reset() 433 for i := int32(0); i < 3; i++ { 434 bcoord := dvid.Point3d{i * 10, i * 11, i * 12} 435 writeTestInt32(t, &buf, bcoord[0]) 436 writeTestInt32(t, &buf, bcoord[1]) 437 writeTestInt32(t, &buf, bcoord[2]) 438 writeTestBlock(t, &buf, []byte{}, bcoord) 439 } 440 apiStr = fmt.Sprintf("%snode/%s/labels/blocks?noindexing=true", server.WebAPIPath, uuid) 441 server.TestBadHTTP(t, "POST", apiStr, &buf) 442 443 buf.Reset() 444 for i := int32(0); i < 3; i++ { 445 bcoord := dvid.Point3d{i * 10, i * 11, i * 12} 446 writeTestInt32(t, &buf, bcoord[0]) 447 writeTestInt32(t, &buf, bcoord[1]) 448 writeTestInt32(t, &buf, bcoord[2]) 449 writeTestInt32(t, &buf, 0) 450 } 451 apiStr = fmt.Sprintf("%snode/%s/labels/blocks?noindexing=true", server.WebAPIPath, uuid) 452 server.TestBadHTTP(t, "POST", apiStr, &buf) 453 }