github.com/janelia-flyem/dvid@v1.0.0/datatype/roi/roi_test.go (about) 1 package roi 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "log" 9 "net/http" 10 "net/http/httptest" 11 "reflect" 12 "sync" 13 "testing" 14 15 "github.com/janelia-flyem/dvid/datastore" 16 "github.com/janelia-flyem/dvid/dvid" 17 "github.com/janelia-flyem/dvid/server" 18 ) 19 20 var ( 21 roitype datastore.TypeService 22 testMu sync.Mutex 23 ) 24 25 var testSpans = []dvid.Span{ 26 dvid.Span{100, 101, 200, 210}, dvid.Span{100, 102, 200, 210}, dvid.Span{100, 103, 201, 212}, 27 dvid.Span{101, 101, 201, 213}, dvid.Span{101, 102, 202, 215}, dvid.Span{101, 103, 202, 216}, 28 dvid.Span{102, 101, 200, 210}, dvid.Span{102, 103, 201, 216}, dvid.Span{102, 104, 203, 217}, 29 dvid.Span{103, 101, 200, 210}, dvid.Span{103, 103, 200, 210}, dvid.Span{103, 105, 201, 212}, 30 } 31 32 func TestVoxelBoundsInside(t *testing.T) { 33 size := dvid.Point3d{10, 10, 10} 34 ext := dvid.Extents3d{dvid.Point3d{2030, 1010, 990}, dvid.Point3d{2040, 1040, 990}} 35 if inside, err := VoxelBoundsInside(ext, size, testSpans); err != nil || inside { 36 t.Errorf("Bad intersection of ext %v and test spans: err %v\n", ext, err) 37 } 38 ext = dvid.Extents3d{dvid.Point3d{2030, 1010, 1000}, dvid.Point3d{2040, 1040, 1000}} 39 if inside, err := VoxelBoundsInside(ext, size, testSpans); err != nil || !inside { 40 t.Errorf("Bad intersection of ext %v and test spans: err %v\n", ext, err) 41 } 42 ext = dvid.Extents3d{dvid.Point3d{2130, 1010, 1000}, dvid.Point3d{2900, 1040, 1000}} 43 if inside, err := VoxelBoundsInside(ext, size, testSpans); err != nil || inside { 44 t.Errorf("Bad intersection of ext %v and test spans: err %v\n", ext, err) 45 } 46 ext = dvid.Extents3d{dvid.Point3d{2129, 1030, 1000}, dvid.Point3d{2900, 1040, 1000}} 47 if inside, err := VoxelBoundsInside(ext, size, testSpans); err != nil || !inside { 48 t.Errorf("Bad intersection of ext %v and test spans: err %v\n", ext, err) 49 } 50 ext = dvid.Extents3d{dvid.Point3d{2130, 1010, 200}, dvid.Point3d{2130, 1040, 900}} 51 if inside, err := VoxelBoundsInside(ext, size, testSpans); err != nil || inside { 52 t.Errorf("Bad intersection of ext %v and test spans: err %v\n", ext, err) 53 } 54 ext = dvid.Extents3d{dvid.Point3d{2130, 1040, 1000}, dvid.Point3d{2900, 1040, 2000}} 55 if inside, err := VoxelBoundsInside(ext, size, testSpans); err != nil || !inside { 56 t.Errorf("Bad intersection of ext %v and test spans: err %v\n", ext, err) 57 } 58 } 59 60 func getSpansJSON(spans []dvid.Span) io.Reader { 61 jsonBytes, err := json.Marshal(spans) 62 if err != nil { 63 log.Fatalf("Can't encode spans into JSON: %v\n", err) 64 } 65 return bytes.NewReader(jsonBytes) 66 } 67 68 func putSpansJSON(data []byte) ([]dvid.Span, error) { 69 var spans []dvid.Span 70 if err := json.Unmarshal(data, &spans); err != nil { 71 return nil, err 72 } 73 return spans, nil 74 } 75 76 var testPoints = []dvid.Point3d{ 77 dvid.Point3d{6400, 3232, 3167}, // false 78 dvid.Point3d{6400, 3232, 3200}, // true 79 dvid.Point3d{6719, 3232, 3200}, // true 80 dvid.Point3d{6720, 3232, 3200}, // true 81 dvid.Point3d{6720, 4100, 3263}, // false 82 dvid.Point3d{6720, 3233, 3201}, // true 83 dvid.Point3d{6720, 3234, 3200}, // true 84 } 85 86 var expectedInclusions = []bool{ 87 false, 88 true, 89 true, 90 true, 91 false, 92 true, 93 true, 94 } 95 96 func getPointsJSON(pts []dvid.Point3d) io.Reader { 97 jsonBytes, err := json.Marshal(pts) 98 if err != nil { 99 log.Fatalf("Can't encode points into JSON: %v\n", err) 100 } 101 return bytes.NewReader(jsonBytes) 102 } 103 104 func putInclusionJSON(data []byte) ([]bool, error) { 105 var inclusions []bool 106 if err := json.Unmarshal(data, &inclusions); err != nil { 107 return nil, err 108 } 109 return inclusions, nil 110 } 111 112 // Sets package-level testRepo and TestVersionID 113 func initTestRepo() (dvid.UUID, dvid.VersionID) { 114 testMu.Lock() 115 defer testMu.Unlock() 116 if roitype == nil { 117 var err error 118 roitype, err = datastore.TypeServiceByName(TypeName) 119 if err != nil { 120 log.Fatalf("Can't get ROI type: %v\n", err) 121 } 122 } 123 return datastore.NewTestRepo() 124 } 125 126 func TestTuples(t *testing.T) { 127 tup := dvid.Span{10, 11, 20, 30} 128 if tup.LessChunkPoint3d(dvid.ChunkPoint3d{20, 11, 10}) { 129 t.Errorf("Bad tuple.Less()\n") 130 } 131 if tup.LessChunkPoint3d(dvid.ChunkPoint3d{30, 11, 10}) { 132 t.Errorf("Bad tuple.Less()\n") 133 } 134 if !tup.LessChunkPoint3d(dvid.ChunkPoint3d{31, 11, 10}) { 135 t.Errorf("Bad tuple.Less()\n") 136 } 137 if !tup.LessChunkPoint3d(dvid.ChunkPoint3d{20, 11, 11}) { 138 t.Errorf("Bad tuple.Less()\n") 139 } 140 if tup.LessChunkPoint3d(dvid.ChunkPoint3d{20, 11, 9}) { 141 t.Errorf("Bad tuple.Less()\n") 142 } 143 if !tup.LessChunkPoint3d(dvid.ChunkPoint3d{20, 11, 11}) { 144 t.Errorf("Bad tuple.Less()\n") 145 } 146 147 if tup.Includes(dvid.ChunkPoint3d{19, 11, 10}) { 148 t.Errorf("Bad tuple.Includes()\n") 149 } 150 if !tup.Includes(dvid.ChunkPoint3d{20, 11, 10}) { 151 t.Errorf("Bad tuple.Includes()\n") 152 } 153 if !tup.Includes(dvid.ChunkPoint3d{30, 11, 10}) { 154 t.Errorf("Bad tuple.Includes()\n") 155 } 156 if tup.Includes(dvid.ChunkPoint3d{31, 11, 10}) { 157 t.Errorf("Bad tuple.Includes()\n") 158 } 159 if tup.Includes(dvid.ChunkPoint3d{25, 11, 11}) { 160 t.Errorf("Bad tuple.Includes()\n") 161 } 162 if tup.Includes(dvid.ChunkPoint3d{25, 11, 9}) { 163 t.Errorf("Bad tuple.Includes()\n") 164 } 165 if tup.Includes(dvid.ChunkPoint3d{25, 10, 10}) { 166 t.Errorf("Bad tuple.Includes()\n") 167 } 168 if tup.Includes(dvid.ChunkPoint3d{25, 12, 10}) { 169 t.Errorf("Bad tuple.Includes()\n") 170 } 171 } 172 173 func TestROIRequests(t *testing.T) { 174 if err := server.OpenTest(); err != nil { 175 t.Fatalf("can't open test server: %v\n", err) 176 } 177 defer server.CloseTest() 178 179 // Create the ROI dataservice. 180 uuid, _ := initTestRepo() 181 182 config := dvid.NewConfig() 183 dataservice, err := datastore.NewData(uuid, roitype, "roi", config) 184 if err != nil { 185 t.Errorf("Error creating new roi instance: %v\n", err) 186 } 187 data, ok := dataservice.(*Data) 188 if !ok { 189 t.Errorf("Returned new data instance is not roi.Data\n") 190 } 191 192 // PUT an ROI 193 roiRequest := fmt.Sprintf("%snode/%s/%s/roi", server.WebAPIPath, uuid, data.DataName()) 194 server.TestHTTP(t, "POST", roiRequest, getSpansJSON(testSpans)) 195 196 // Get back the ROI 197 returnedData := server.TestHTTP(t, "GET", roiRequest, nil) 198 spans, err := putSpansJSON(returnedData) 199 if err != nil { 200 t.Errorf("Error on getting back JSON from roi GET: %v\n", err) 201 } 202 203 // Make sure the two are the same. 204 if !reflect.DeepEqual(spans, testSpans) { 205 t.Errorf("Bad PUT/GET ROI roundtrip\nOriginal:\n%s\nReturned:\n%s\n", testSpans, spans) 206 } 207 208 // Test the ptquery 209 ptqueryRequest := fmt.Sprintf("%snode/%s/%s/ptquery", server.WebAPIPath, uuid, data.DataName()) 210 returnedData = server.TestHTTP(t, "POST", ptqueryRequest, getPointsJSON(testPoints)) 211 inclusions, err := putInclusionJSON(returnedData) 212 if err != nil { 213 t.Fatalf("Error on getting back JSON from ptquery: %v\n", err) 214 } 215 216 // Make sure the two are the same. 217 if !reflect.DeepEqual(inclusions, expectedInclusions) { 218 t.Errorf("Bad ptquery results\nOriginal:\n%v\nReturned:\n%v\n", expectedInclusions, inclusions) 219 } 220 221 // Test ROI mask out of range -- should be all 0. 222 maskRequest := fmt.Sprintf("%snode/%s/%s/mask/0_1_2/100_100_100/10_40_70", server.WebAPIPath, uuid, data.DataName()) 223 returnedData = server.TestHTTP(t, "GET", maskRequest, nil) 224 if len(returnedData) != 100*100*100 { 225 t.Errorf("Expected mask volume of %d bytes, got %d bytes instead\n", 100*100*100, len(returnedData)) 226 } 227 for i, value := range returnedData { 228 if value != 0 { 229 t.Errorf("Expected all-zero mask, got %d at index %d\n", value, i) 230 break 231 } 232 } 233 234 // Test ROI mask within range. 235 maskRequest = fmt.Sprintf("%snode/%s/%s/mask/0_1_2/100_100_100/6350_3232_3200", server.WebAPIPath, uuid, data.DataName()) 236 returnedData = server.TestHTTP(t, "GET", maskRequest, nil) 237 if len(returnedData) != 100*100*100 { 238 t.Errorf("Expected mask volume of %d bytes, got %d bytes instead\n", 100*100*100, len(returnedData)) 239 } 240 // Check first block plane 241 for y := 0; y < 100; y++ { 242 for x := 0; x < 100; x++ { 243 value := returnedData[y*100+x] 244 if x < 50 && value != 0 { 245 t.Errorf("Expected mask to be zero at (%d, %d) before ROI, got %d instead\n", x, y, value) 246 break 247 } 248 if x >= 50 && y < 64 && value != 1 { 249 t.Errorf("Expected mask to be 1 at (%d, %d) within ROI, got %d instead\n", x, y, value) 250 break 251 } 252 // tuple{100, 103, 201, 212} 253 if x <= 81 && y >= 64 && y < 96 && value != 0 { 254 t.Errorf("Expected mask to be zero at (%d, %d) before ROI, got %d instead\n", x, y, value) 255 break 256 } 257 if x > 81 && y >= 64 && y < 96 && value != 1 { 258 t.Errorf("Expected mask to be 1 at (%d, %d) within ROI, got %d instead\n", x, y, value) 259 break 260 } 261 } 262 } 263 // Check second block plane 264 offset := 32 * 100 * 100 // moves to next block in Z 265 for y := 0; y < 100; y++ { 266 for x := 0; x < 100; x++ { 267 value := returnedData[offset+y*100+x] 268 if x < 50 && value != 0 { 269 t.Errorf("Expected mask to be zero at (%d, %d) before ROI, got %d instead\n", x, y, value) 270 break 271 } 272 if x <= 81 && y < 32 && value != 0 { 273 t.Errorf("Expected mask to be zero at (%d, %d) before ROI, got %d instead\n", x, y, value) 274 break 275 } 276 if x > 81 && y < 32 && value != 1 { 277 t.Errorf("Expected mask to be 1 at (%d, %d) within ROI, got %d instead\n", x, y, value) 278 break 279 } 280 if y >= 32 && value != 0 { 281 t.Errorf("Expected mask to be zero at (%d, %d) before ROI, got %d instead\n", x, y, value) 282 break 283 } 284 } 285 } 286 // Check last block plane 287 offset = 96 * 100 * 100 // moves to last ROI layer in Z 288 for y := 0; y < 100; y++ { 289 for x := 0; x < 100; x++ { 290 value := returnedData[offset+y*100+x] 291 if x < 50 && value != 0 { 292 t.Errorf("Expected mask to be zero at (%d, %d) before ROI, got %d instead\n", x, y, value) 293 break 294 } 295 if x >= 50 && y < 32 && value != 1 { 296 t.Errorf("Expected mask to be 1 at (%d, %d) within ROI, got %d instead\n", x, y, value) 297 break 298 } 299 if y >= 32 && y < 64 && value != 0 { 300 t.Errorf("Expected mask to be zero at (%d, %d) before ROI, got %d instead\n", x, y, value) 301 break 302 } 303 if x >= 50 && y >= 64 && y < 96 && value != 1 { 304 t.Errorf("Expected mask to be 1 at (%d, %d) within ROI, got %d instead\n", x, y, value) 305 break 306 } 307 if y >= 96 && value != 0 { 308 t.Errorf("Expected mask to be zero at (%d, %d) before ROI, got %d instead\n", x, y, value) 309 break 310 } 311 } 312 } 313 } 314 315 func TestROIPostAndDelete(t *testing.T) { 316 if err := server.OpenTest(); err != nil { 317 t.Fatalf("can't open test server: %v\n", err) 318 } 319 defer server.CloseTest() 320 321 // Create the ROI dataservice. 322 uuid, _ := initTestRepo() 323 324 config := dvid.NewConfig() 325 dataservice, err := datastore.NewData(uuid, roitype, "roi", config) 326 if err != nil { 327 t.Errorf("Error creating new roi instance: %v\n", err) 328 } 329 data, ok := dataservice.(*Data) 330 if !ok { 331 t.Errorf("Returned new data instance is not roi.Data\n") 332 } 333 334 // PUT an ROI 335 roiRequest := fmt.Sprintf("%snode/%s/%s/roi", server.WebAPIPath, uuid, data.DataName()) 336 server.TestHTTP(t, "POST", roiRequest, getSpansJSON(testSpans)) 337 338 // Get back the ROI 339 returnedData := server.TestHTTP(t, "GET", roiRequest, nil) 340 spans, err := putSpansJSON(returnedData) 341 if err != nil { 342 t.Errorf("Error on getting back JSON from roi GET: %v\n", err) 343 } 344 if !reflect.DeepEqual(spans, testSpans) { 345 t.Errorf("Bad PUT/GET ROI roundtrip\nOriginal:\n%s\nReturned:\n%s\n", testSpans, spans) 346 } 347 348 // Make a new version 349 reqStr := fmt.Sprintf("%snode/%s/commit", server.WebAPIPath, uuid) 350 server.TestHTTP(t, "POST", reqStr, nil) 351 versionReq := fmt.Sprintf("%snode/%s/newversion", server.WebAPIPath, uuid) 352 respData := server.TestHTTP(t, "POST", versionReq, nil) 353 resp := struct { 354 Child string `json:"child"` 355 }{} 356 if err := json.Unmarshal(respData, &resp); err != nil { 357 t.Errorf("Expected 'child' JSON response. Got %s\n", string(respData)) 358 } 359 child := dvid.UUID(resp.Child) 360 361 // Delete the ROI 362 roiRequest2 := fmt.Sprintf("%snode/%s/%s/roi", server.WebAPIPath, child, data.DataName()) 363 _ = server.TestHTTP(t, "DELETE", roiRequest2, nil) 364 365 // ROI in past version should still be there 366 returnedData = server.TestHTTP(t, "GET", roiRequest, nil) 367 spans, err = putSpansJSON(returnedData) 368 if err != nil { 369 t.Errorf("Error on getting back JSON from roi GET: %v\n", err) 370 } 371 if !reflect.DeepEqual(spans, testSpans) { 372 t.Errorf("Bad PUT/GET ROI roundtrip\nOriginal:\n%s\nReturned:\n%s\n", testSpans, spans) 373 } 374 375 // ROI should now be empty for leaf 376 returnedData = server.TestHTTP(t, "GET", roiRequest2, nil) 377 if string(returnedData) != "[]" { 378 t.Errorf("Bad ROI after ROI delete. Should be [ ] got: %s\n", string(returnedData)) 379 } 380 leafRequest := fmt.Sprintf("%snode/%s:master/%s/roi", server.WebAPIPath, uuid[:8], data.DataName()) 381 returnedData = server.TestHTTP(t, "GET", leafRequest, nil) 382 if string(returnedData) != "[]" { 383 t.Errorf("Bad ROI after ROI delete. Should be [ ] got: %s\n", string(returnedData)) 384 } 385 } 386 387 func TestROICreateAndSerialize(t *testing.T) { 388 if err := server.OpenTest(); err != nil { 389 t.Fatalf("can't open test server: %v\n", err) 390 } 391 defer server.CloseTest() 392 393 uuid, _ := initTestRepo() 394 395 // Add data 396 config := dvid.NewConfig() 397 dataservice1, err := datastore.NewData(uuid, roitype, "myroi", config) 398 if err != nil { 399 t.Errorf("Error creating new roi instance: %v\n", err) 400 } 401 roi1, ok := dataservice1.(*Data) 402 if !ok { 403 t.Errorf("Returned new data instance 1 is not roi.Data\n") 404 } 405 if roi1.DataName() != "myroi" { 406 t.Errorf("New roi data instance name set incorrectly: %q != %q\n", 407 roi1.DataName(), "myroi") 408 } 409 410 config.Set("BlockSize", "15,16,17") 411 dataservice2, err := datastore.NewData(uuid, roitype, "myroi2", config) 412 if err != nil { 413 t.Errorf("Error creating new roi instance: %v\n", err) 414 } 415 roi2, ok := dataservice2.(*Data) 416 if !ok { 417 t.Errorf("Returned new data instance 2 is not roi.Data\n") 418 } 419 420 if roi1.InstanceID() == roi2.InstanceID() { 421 t.Errorf("Instance IDs should be different: %d == %d\n", 422 roi1.InstanceID(), roi2.InstanceID()) 423 } 424 425 // Test persistence of storage. 426 roi2.MinZ = 13 427 roi2.MaxZ = 3098 428 gobBytes, err := roi2.GobEncode() 429 if err != nil { 430 t.Fatalf("Could not Gob encode roi: %v\n", err) 431 } 432 433 var received Data 434 if err = received.GobDecode(gobBytes); err != nil { 435 t.Fatalf("Could not decode Gob-encoded roi: %v\n", err) 436 } 437 438 if !roi2.Data.Equals(received.Data) { 439 t.Errorf("ROI base Data has bad roundtrip:\nOriginal:\n%v\nReceived:\n%v\n", 440 *(roi2.Data), *(received.Data)) 441 } 442 443 if !reflect.DeepEqual(roi2.Properties, received.Properties) { 444 t.Errorf("ROI extended properties has bad roundtrip:\nOriginal:\n%v\nReceived:\n%v\n", 445 roi2.Properties, received.Properties) 446 } 447 } 448 449 func TestROIPartition(t *testing.T) { 450 if err := server.OpenTest(); err != nil { 451 t.Fatalf("can't open test server: %v\n", err) 452 } 453 defer server.CloseTest() 454 455 // Create the ROI dataservice. 456 uuid, versionID := initTestRepo() 457 458 config := dvid.NewConfig() 459 dataservice, err := datastore.NewData(uuid, roitype, "roi", config) 460 if err != nil { 461 t.Errorf("Error creating new roi instance: %v\n", err) 462 } 463 data, ok := dataservice.(*Data) 464 if !ok { 465 t.Errorf("Returned new data instance is not roi.Data\n") 466 } 467 468 // PUT an ROI 469 roiRequest := fmt.Sprintf("%snode/%s/%s/roi", server.WebAPIPath, uuid, data.DataName()) 470 req, err := http.NewRequest("POST", roiRequest, getSpansJSON(testSpans)) 471 if err != nil { 472 t.Errorf("Unsuccessful POST request (%s): %v\n", roiRequest, err) 473 } 474 ctx := datastore.NewVersionedCtx(data, versionID) 475 w := httptest.NewRecorder() 476 data.ServeHTTP(uuid, ctx, w, req) 477 if w.Code != http.StatusOK { 478 t.Errorf("Bad server response roi POST, status %d, for roi %q\n", w.Code, data.DataName()) 479 } 480 481 // Request the standard subvolume partitioning 482 partitionReq := fmt.Sprintf("%snode/%s/%s/partition?batchsize=5&optimized=true", server.WebAPIPath, uuid, 483 data.DataName()) 484 req, err = http.NewRequest("GET", partitionReq, nil) 485 if err != nil { 486 t.Errorf("Unsuccessful GET request (%s): %v\n", partitionReq, err) 487 } 488 w = httptest.NewRecorder() 489 data.ServeHTTP(uuid, ctx, w, req) 490 if w.Code != http.StatusOK { 491 t.Errorf("Bad server response roi GET, status %d, for roi %q\n", w.Code, data.DataName()) 492 } 493 var subvolJSON, expectedJSON interface{} 494 response := w.Body.Bytes() 495 if err := json.Unmarshal(response, &subvolJSON); err != nil { 496 t.Errorf("Can't unmarshal JSON: %s\n", w.Body.Bytes()) 497 } 498 json.Unmarshal([]byte(expectedPartition), &expectedJSON) 499 if !reflect.DeepEqual(subvolJSON, expectedJSON) { 500 t.Errorf("Error doing optimized subvolume partitioning. Got bad result:\n%s\n", 501 string(response)) 502 } 503 } 504 505 func TestROISimplePartition(t *testing.T) { 506 if err := server.OpenTest(); err != nil { 507 t.Fatalf("can't open test server: %v\n", err) 508 } 509 defer server.CloseTest() 510 511 // Create the ROI dataservice. 512 uuid, versionID := initTestRepo() 513 514 config := dvid.NewConfig() 515 dataservice, err := datastore.NewData(uuid, roitype, "roi", config) 516 if err != nil { 517 t.Errorf("Error creating new roi instance: %v\n", err) 518 } 519 data, ok := dataservice.(*Data) 520 if !ok { 521 t.Errorf("Returned new data instance is not roi.Data\n") 522 } 523 524 // PUT an ROI 525 roiRequest := fmt.Sprintf("%snode/%s/%s/roi", server.WebAPIPath, uuid, data.DataName()) 526 req, err := http.NewRequest("POST", roiRequest, getSpansJSON(testSpans)) 527 if err != nil { 528 t.Errorf("Unsuccessful POST request (%s): %v\n", roiRequest, err) 529 } 530 ctx := datastore.NewVersionedCtx(data, versionID) 531 w := httptest.NewRecorder() 532 data.ServeHTTP(uuid, ctx, w, req) 533 if w.Code != http.StatusOK { 534 t.Errorf("Bad server response roi POST, status %d, for roi %q\n", w.Code, data.DataName()) 535 } 536 537 // Request the standard subvolume partitioning 538 partitionReq := fmt.Sprintf("%snode/%s/%s/partition?batchsize=5", server.WebAPIPath, uuid, 539 data.DataName()) 540 req, err = http.NewRequest("GET", partitionReq, nil) 541 if err != nil { 542 t.Errorf("Unsuccessful GET request (%s): %v\n", partitionReq, err) 543 } 544 w = httptest.NewRecorder() 545 data.ServeHTTP(uuid, ctx, w, req) 546 if w.Code != http.StatusOK { 547 t.Errorf("Bad server response roi GET, status %d, for roi %q\n", w.Code, data.DataName()) 548 } 549 var subvolJSON, expectedJSON interface{} 550 response := w.Body.Bytes() 551 if err := json.Unmarshal(response, &subvolJSON); err != nil { 552 t.Errorf("Can't unmarshal JSON: %s\n", w.Body.Bytes()) 553 } 554 json.Unmarshal([]byte(expectedSimplePartition), &expectedJSON) 555 if !reflect.DeepEqual(subvolJSON, expectedJSON) { 556 t.Errorf("Error doing simple subvolume partitioning. Got bad result:\n%s\n", string(response)) 557 } 558 } 559 560 const expectedPartition = ` 561 { 562 "NumTotalBlocks": 450, 563 "NumActiveBlocks": 152, 564 "NumSubvolumes": 3, 565 "ROI": { 566 "MinChunk": [ 567 0, 568 0, 569 100 570 ], 571 "MaxChunk": [ 572 217, 573 105, 574 103 575 ] 576 }, 577 "Subvolumes": [ 578 { 579 "MinPoint": [ 580 6400, 581 3232, 582 3200 583 ], 584 "MaxPoint": [ 585 6591, 586 3391, 587 3359 588 ], 589 "MinChunk": [ 590 200, 591 101, 592 100 593 ], 594 "MaxChunk": [ 595 205, 596 105, 597 104 598 ], 599 "TotalBlocks": 150, 600 "ActiveBlocks": 61 601 }, 602 { 603 "MinPoint": [ 604 6592, 605 3232, 606 3200 607 ], 608 "MaxPoint": [ 609 6783, 610 3391, 611 3359 612 ], 613 "MinChunk": [ 614 206, 615 101, 616 100 617 ], 618 "MaxChunk": [ 619 211, 620 105, 621 104 622 ], 623 "TotalBlocks": 150, 624 "ActiveBlocks": 67 625 }, 626 { 627 "MinPoint": [ 628 6784, 629 3232, 630 3200 631 ], 632 "MaxPoint": [ 633 6975, 634 3391, 635 3359 636 ], 637 "MinChunk": [ 638 212, 639 101, 640 100 641 ], 642 "MaxChunk": [ 643 217, 644 105, 645 104 646 ], 647 "TotalBlocks": 150, 648 "ActiveBlocks": 24 649 } 650 ] 651 } 652 ` 653 654 const expectedSimplePartition = ` 655 { 656 "NumTotalBlocks": 1375, 657 "NumActiveBlocks": 152, 658 "NumSubvolumes": 10, 659 "ROI": { 660 "MinChunk": [ 661 0, 662 0, 663 100 664 ], 665 "MaxChunk": [ 666 217, 667 105, 668 103 669 ] 670 }, 671 "Subvolumes": [ 672 { 673 "MinPoint": [ 674 6368, 675 3168, 676 3136 677 ], 678 "MaxPoint": [ 679 6527, 680 3327, 681 3295 682 ], 683 "MinChunk": [ 684 199, 685 99, 686 98 687 ], 688 "MaxChunk": [ 689 203, 690 103, 691 102 692 ], 693 "TotalBlocks": 125, 694 "ActiveBlocks": 25 695 }, 696 { 697 "MinPoint": [ 698 6528, 699 3168, 700 3136 701 ], 702 "MaxPoint": [ 703 6687, 704 3327, 705 3295 706 ], 707 "MinChunk": [ 708 204, 709 99, 710 98 711 ], 712 "MaxChunk": [ 713 208, 714 103, 715 102 716 ], 717 "TotalBlocks": 125, 718 "ActiveBlocks": 40 719 }, 720 { 721 "MinPoint": [ 722 6688, 723 3168, 724 3136 725 ], 726 "MaxPoint": [ 727 6847, 728 3327, 729 3295 730 ], 731 "MinChunk": [ 732 209, 733 99, 734 98 735 ], 736 "MaxChunk": [ 737 213, 738 103, 739 102 740 ], 741 "TotalBlocks": 125, 742 "ActiveBlocks": 30 743 }, 744 { 745 "MinPoint": [ 746 6848, 747 3168, 748 3136 749 ], 750 "MaxPoint": [ 751 7007, 752 3327, 753 3295 754 ], 755 "MinChunk": [ 756 214, 757 99, 758 98 759 ], 760 "MaxChunk": [ 761 218, 762 103, 763 102 764 ], 765 "TotalBlocks": 125, 766 "ActiveBlocks": 8 767 }, 768 { 769 "MinPoint": [ 770 6496, 771 3328, 772 3136 773 ], 774 "MaxPoint": [ 775 6655, 776 3487, 777 3295 778 ], 779 "MinChunk": [ 780 203, 781 104, 782 98 783 ], 784 "MaxChunk": [ 785 207, 786 108, 787 102 788 ], 789 "TotalBlocks": 125, 790 "ActiveBlocks": 5 791 }, 792 { 793 "MinPoint": [ 794 6656, 795 3328, 796 3136 797 ], 798 "MaxPoint": [ 799 6815, 800 3487, 801 3295 802 ], 803 "MinChunk": [ 804 208, 805 104, 806 98 807 ], 808 "MaxChunk": [ 809 212, 810 108, 811 102 812 ], 813 "TotalBlocks": 125, 814 "ActiveBlocks": 5 815 }, 816 { 817 "MinPoint": [ 818 6816, 819 3328, 820 3136 821 ], 822 "MaxPoint": [ 823 6975, 824 3487, 825 3295 826 ], 827 "MinChunk": [ 828 213, 829 104, 830 98 831 ], 832 "MaxChunk": [ 833 217, 834 108, 835 102 836 ], 837 "TotalBlocks": 125, 838 "ActiveBlocks": 5 839 }, 840 { 841 "MinPoint": [ 842 6368, 843 3232, 844 3296 845 ], 846 "MaxPoint": [ 847 6527, 848 3391, 849 3455 850 ], 851 "MinChunk": [ 852 199, 853 101, 854 103 855 ], 856 "MaxChunk": [ 857 203, 858 105, 859 107 860 ], 861 "TotalBlocks": 125, 862 "ActiveBlocks": 11 863 }, 864 { 865 "MinPoint": [ 866 6528, 867 3232, 868 3296 869 ], 870 "MaxPoint": [ 871 6687, 872 3391, 873 3455 874 ], 875 "MinChunk": [ 876 204, 877 101, 878 103 879 ], 880 "MaxChunk": [ 881 208, 882 105, 883 107 884 ], 885 "TotalBlocks": 125, 886 "ActiveBlocks": 15 887 }, 888 { 889 "MinPoint": [ 890 6688, 891 3232, 892 3296 893 ], 894 "MaxPoint": [ 895 6847, 896 3391, 897 3455 898 ], 899 "MinChunk": [ 900 209, 901 101, 902 103 903 ], 904 "MaxChunk": [ 905 213, 906 105, 907 107 908 ], 909 "TotalBlocks": 125, 910 "ActiveBlocks": 8 911 } 912 ] 913 } 914 ` 915 916 func TestROIRepoPersistence(t *testing.T) { 917 if err := server.OpenTest(); err != nil { 918 t.Fatalf("can't open test server: %v\n", err) 919 } 920 defer server.CloseTest() 921 922 uuid, _ := initTestRepo() 923 924 // Add data 925 config := dvid.NewConfig() 926 dataservice1, err := datastore.NewData(uuid, roitype, "myroi", config) 927 if err != nil { 928 t.Errorf("Error creating new roi instance: %v\n", err) 929 } 930 roi1, ok := dataservice1.(*Data) 931 if !ok { 932 t.Errorf("Returned new data instance 1 is not roi.Data\n") 933 } 934 if roi1.DataName() != "myroi" { 935 t.Errorf("New roi data instance name set incorrectly: %q != %q\n", 936 roi1.DataName(), "myroi") 937 } 938 939 config.Set("BlockSize", "15,16,17") 940 dataservice2, err := datastore.NewData(uuid, roitype, "myroi2", config) 941 if err != nil { 942 t.Errorf("Error creating new roi instance: %v\n", err) 943 } 944 roi2, ok := dataservice2.(*Data) 945 if !ok { 946 t.Errorf("Returned new data instance 2 is not roi.Data\n") 947 } 948 roi2.MinZ = 13 949 roi2.MaxZ = 3098 950 oldData := *roi2 951 952 // Check instance IDs 953 if roi1.InstanceID() == roi2.InstanceID() { 954 t.Errorf("Instance IDs should be different: %d == %d\n", 955 roi1.InstanceID(), roi2.InstanceID()) 956 } 957 958 // Restart test datastore and see if datasets are still there. 959 if err = datastore.SaveDataByUUID(uuid, dataservice1); err != nil { 960 t.Fatalf("Unable to save data1 during ROI persistence test: %v\n", err) 961 } 962 if err = datastore.SaveDataByUUID(uuid, dataservice2); err != nil { 963 t.Fatalf("Unable to save data2 during ROI persistence test: %v\n", err) 964 } 965 966 datastore.CloseReopenTest() 967 968 dataservice3, err := datastore.GetDataByUUIDName(uuid, "myroi2") 969 if err != nil { 970 t.Fatalf("Can't get first ROI instance from reloaded test db: %v\n", err) 971 } 972 roi2new, ok := dataservice3.(*Data) 973 if !ok { 974 t.Errorf("Returned new data instance 3 is not roi.Data\n") 975 } 976 if !oldData.Equals(roi2new) { 977 t.Errorf("Expected %v, got %v\n", oldData, *roi2new) 978 } 979 }