github.com/janelia-flyem/dvid@v1.0.0/datatype/labelmap/labelmap_test.go (about)

     1  package labelmap
     2  
     3  import (
     4  	"bytes"
     5  	"compress/gzip"
     6  	"encoding/binary"
     7  	"encoding/json"
     8  	"fmt"
     9  	"io"
    10  	"io/ioutil"
    11  	"log"
    12  	"os"
    13  	"path/filepath"
    14  	"reflect"
    15  	"runtime"
    16  	"strings"
    17  	"sync"
    18  	"testing"
    19  
    20  	pb "google.golang.org/protobuf/proto"
    21  
    22  	"github.com/janelia-flyem/dvid/datastore"
    23  	"github.com/janelia-flyem/dvid/datatype/common/downres"
    24  	"github.com/janelia-flyem/dvid/datatype/common/labels"
    25  	"github.com/janelia-flyem/dvid/datatype/common/proto"
    26  	"github.com/janelia-flyem/dvid/dvid"
    27  	"github.com/janelia-flyem/dvid/server"
    28  	lz4 "github.com/janelia-flyem/go/golz4-updated"
    29  )
    30  
    31  var (
    32  	labelsT datastore.TypeService
    33  	testMu  sync.Mutex
    34  )
    35  
    36  // Sets package-level testRepo and TestVersionID
    37  func initTestRepo() (dvid.UUID, dvid.VersionID) {
    38  	testMu.Lock()
    39  	defer testMu.Unlock()
    40  	if labelsT == nil {
    41  		var err error
    42  		labelsT, err = datastore.TypeServiceByName("labelmap")
    43  		if err != nil {
    44  			log.Fatalf("Can't get labelmap type: %s\n", err)
    45  		}
    46  	}
    47  	return datastore.NewTestRepo()
    48  }
    49  
    50  type tuple [4]int32
    51  
    52  var labelsROI = []tuple{
    53  	tuple{3, 3, 2, 4}, tuple{3, 4, 2, 3}, tuple{3, 5, 3, 3},
    54  	tuple{4, 3, 2, 5}, tuple{4, 4, 3, 4}, tuple{4, 5, 2, 4},
    55  	//tuple{5, 2, 3, 4}, tuple{5, 3, 3, 3}, tuple{5, 4, 2, 3}, tuple{5, 5, 2, 2},
    56  }
    57  
    58  func labelsJSON() string {
    59  	b, err := json.Marshal(labelsROI)
    60  	if err != nil {
    61  		return ""
    62  	}
    63  	return string(b)
    64  }
    65  
    66  func inroi(x, y, z int32) bool {
    67  	for _, span := range labelsROI {
    68  		if span[0] != z {
    69  			continue
    70  		}
    71  		if span[1] != y {
    72  			continue
    73  		}
    74  		if span[2] > x || span[3] < x {
    75  			continue
    76  		}
    77  		return true
    78  	}
    79  	return false
    80  }
    81  
    82  // A slice of bytes representing 3d label volume always with first voxel at (0,0,0)
    83  type testVolume struct {
    84  	data []byte
    85  	size dvid.Point3d
    86  }
    87  
    88  func newTestVolume(nx, ny, nz int32) *testVolume {
    89  	return &testVolume{
    90  		data: make([]byte, nx*ny*nz*8),
    91  		size: dvid.Point3d{nx, ny, nz},
    92  	}
    93  }
    94  
    95  // Add a label to a subvolume.
    96  func (v *testVolume) addSubvol(origin, size dvid.Point3d, label uint64) {
    97  	nx := v.size[0]
    98  	nxy := nx * v.size[1]
    99  	spanBytes := size[0] * 8
   100  	buf := make([]byte, spanBytes)
   101  	for x := int32(0); x < size[0]; x++ {
   102  		binary.LittleEndian.PutUint64(buf[x*8:x*8+8], label)
   103  	}
   104  	for z := origin[2]; z < origin[2]+size[2]; z++ {
   105  		for y := origin[1]; y < origin[1]+size[1]; y++ {
   106  			i := (z*nxy + y*nx + origin[0]) * 8
   107  			copy(v.data[i:i+spanBytes], buf)
   108  		}
   109  	}
   110  }
   111  
   112  // add binary blocks, check test volume is sufficient size.
   113  func (v *testVolume) addBlocks(t *testing.T, blocks []labels.BinaryBlock, label uint64) {
   114  	for _, block := range blocks {
   115  		maxx := block.Offset[0] + block.Size[0]
   116  		maxy := block.Offset[1] + block.Size[1]
   117  		maxz := block.Offset[2] + block.Size[2]
   118  		dvid.Infof("Adding block offset %s, size %s, # voxels %d\n", block.Offset, block.Size, len(block.Voxels))
   119  
   120  		if maxx > v.size[0] {
   121  			t.Fatalf("block at offset %s, size %s exceeded test volume size %s\n", block.Offset, block.Size, v.size)
   122  		}
   123  		if maxy > v.size[1] {
   124  			t.Fatalf("block at offset %s, size %s exceeded test volume size %s\n", block.Offset, block.Size, v.size)
   125  		}
   126  		if maxz > v.size[2] {
   127  			t.Fatalf("block at offset %s, size %s exceeded test volume size %s\n", block.Offset, block.Size, v.size)
   128  		}
   129  		if len(block.Voxels) != int(block.Size.Prod()) {
   130  			t.Fatalf("binary block at offset %s, size %s has bad # voxels (%d)\n", block.Offset, block.Size, len(block.Voxels))
   131  		}
   132  		bi := 0
   133  		for z := block.Offset[2]; z < maxz; z++ {
   134  			for y := block.Offset[1]; y < maxy; y++ {
   135  				for x := block.Offset[0]; x < maxx; x++ {
   136  					if block.Voxels[bi] {
   137  						if x == 16 && y == 40 && z == 8 {
   138  							dvid.Infof("voxel found and is indeed on\n")
   139  						}
   140  						i := (z*v.size[0]*v.size[1] + y*v.size[0] + x) * 8
   141  						binary.LittleEndian.PutUint64(v.data[i:i+8], label)
   142  					}
   143  					bi++
   144  				}
   145  			}
   146  		}
   147  	}
   148  }
   149  
   150  // downres assumes only binary volume of some label N or label 0.
   151  func (v *testVolume) downres(scale uint8) {
   152  	sz := int32(1 << scale)
   153  	nx := v.size[0] >> scale
   154  	ny := v.size[1] >> scale
   155  	nz := v.size[2] >> scale
   156  
   157  	var oldpos, x, y, z int32
   158  	for z = 0; z < v.size[2]; z++ {
   159  		newz := z >> scale
   160  		for y = 0; y < v.size[1]; y++ {
   161  			newy := y >> scale
   162  			for x = 0; x < v.size[0]; x++ {
   163  				label := binary.LittleEndian.Uint64(v.data[oldpos*8 : oldpos*8+8])
   164  				oldpos++
   165  				if label != 0 || (x%sz == 0 && y%sz == 0 && z%sz == 0) {
   166  					newx := x >> scale
   167  					newpos := newz*nx*ny + newy*nx + newx
   168  					binary.LittleEndian.PutUint64(v.data[newpos*8:newpos*8+8], label)
   169  				}
   170  			}
   171  		}
   172  	}
   173  	v.size[0] = nx
   174  	v.size[1] = ny
   175  	v.size[2] = nz
   176  	v.data = v.data[:nx*ny*nz*8]
   177  }
   178  
   179  // Put label data into given data instance.
   180  func (v *testVolume) put(t *testing.T, uuid dvid.UUID, name string) {
   181  	apiStr := fmt.Sprintf("%snode/%s/%s/raw/0_1_2/%d_%d_%d/0_0_0", server.WebAPIPath,
   182  		uuid, name, v.size[0], v.size[1], v.size[2])
   183  	server.TestHTTP(t, "POST", apiStr, bytes.NewBuffer(v.data))
   184  }
   185  
   186  func (v *testVolume) putMutable(t *testing.T, uuid dvid.UUID, name string) {
   187  	apiStr := fmt.Sprintf("%snode/%s/%s/raw/0_1_2/%d_%d_%d/0_0_0?mutate=true", server.WebAPIPath,
   188  		uuid, name, v.size[0], v.size[1], v.size[2])
   189  	server.TestHTTP(t, "POST", apiStr, bytes.NewBuffer(v.data))
   190  }
   191  
   192  func (v *testVolume) get(t *testing.T, uuid dvid.UUID, name string, supervoxels bool) {
   193  	apiStr := fmt.Sprintf("%snode/%s/%s/raw/0_1_2/%d_%d_%d/0_0_0", server.WebAPIPath,
   194  		uuid, name, v.size[0], v.size[1], v.size[2])
   195  	if supervoxels {
   196  		apiStr += "?supervoxels=true"
   197  	}
   198  	v.data = server.TestHTTP(t, "GET", apiStr, nil)
   199  }
   200  
   201  func (v *testVolume) getScale(t *testing.T, uuid dvid.UUID, name string, scale uint8, supervoxels bool) {
   202  	apiStr := fmt.Sprintf("%snode/%s/%s/raw/0_1_2/%d_%d_%d/0_0_0?scale=%d", server.WebAPIPath,
   203  		uuid, name, v.size[0], v.size[1], v.size[2], scale)
   204  	if supervoxels {
   205  		apiStr += "&supervoxels=true"
   206  	}
   207  	v.data = server.TestHTTP(t, "GET", apiStr, nil)
   208  }
   209  
   210  func (v *testVolume) containsLabel(label uint64) bool {
   211  	var i uint64
   212  	var x, y, z int32
   213  	for z = 0; z < v.size[2]; z++ {
   214  		for y = 0; y < v.size[1]; y++ {
   215  			for x = 0; x < v.size[0]; x++ {
   216  				val := binary.LittleEndian.Uint64(v.data[i : i+8])
   217  				if val == label {
   218  					return true
   219  				}
   220  				i += 8
   221  			}
   222  		}
   223  	}
   224  	return false
   225  }
   226  
   227  func (v *testVolume) getVoxel(pt dvid.Point3d) uint64 {
   228  	nx := v.size[0]
   229  	nxy := nx * v.size[1]
   230  	i := (pt[2]*nxy + pt[1]*nx + pt[0]) * 8
   231  	return binary.LittleEndian.Uint64(v.data[i : i+8])
   232  }
   233  
   234  func (v *testVolume) verifyLabel(t *testing.T, expected uint64, x, y, z int32) {
   235  	pt := dvid.Point3d{x, y, z}
   236  	label := v.getVoxel(pt)
   237  	if label != expected {
   238  		_, fn, line, _ := runtime.Caller(1)
   239  		t.Errorf("Expected label %d at %s for first downres but got %d instead [%s:%d]\n", expected, pt, label, fn, line)
   240  	}
   241  }
   242  
   243  func (v *testVolume) equals(v2 *testVolume) error {
   244  	if !v.size.Equals(v2.size) {
   245  		return fmt.Errorf("volume sizes are not equal")
   246  	}
   247  	if len(v.data) != len(v2.data) {
   248  		return fmt.Errorf("data lengths are not equal")
   249  	}
   250  	var i uint64
   251  	var x, y, z int32
   252  	for z = 0; z < v.size[2]; z++ {
   253  		for y = 0; y < v.size[1]; y++ {
   254  			for x = 0; x < v.size[0]; x++ {
   255  				val1 := binary.LittleEndian.Uint64(v.data[i : i+8])
   256  				val2 := binary.LittleEndian.Uint64(v2.data[i : i+8])
   257  				i += 8
   258  				if val1 != val2 {
   259  					return fmt.Errorf("For voxel (%d,%d,%d), found value %d != %d\n", x, y, z, val2, val1)
   260  				}
   261  			}
   262  		}
   263  	}
   264  	return nil
   265  }
   266  
   267  func (v *testVolume) equalsDownres(v2 *testVolume) error {
   268  	lores, err := labels.DownresLabels(v2.data, v2.size)
   269  	if err != nil {
   270  		return err
   271  	}
   272  	var i uint64
   273  	var x, y, z int32
   274  	for z = 0; z < v.size[2]; z++ {
   275  		for y = 0; y < v.size[1]; y++ {
   276  			for x = 0; x < v.size[0]; x++ {
   277  				val1 := binary.LittleEndian.Uint64(v.data[i : i+8])
   278  				val2 := binary.LittleEndian.Uint64(lores[i : i+8])
   279  				i += 8
   280  				if val1 != val2 {
   281  					return fmt.Errorf("voxel (%d,%d,%d), expected downres label %d, got %d", x, y, z, val2, val1)
   282  				}
   283  			}
   284  		}
   285  	}
   286  	return nil
   287  }
   288  
   289  func (v *testVolume) testBlock(t *testing.T, context string, bx, by, bz int32, data []byte) {
   290  	if len(data) < int(DefaultBlockSize*DefaultBlockSize*DefaultBlockSize*8) {
   291  		t.Fatalf("[%s] got bad uint64 array of len %d for block (%d, %d, %d)\n", context, len(data), bx, by, bz)
   292  	}
   293  	p := 0
   294  	var x, y, z, numerrors int32
   295  	for z = 0; z < DefaultBlockSize; z++ {
   296  		vz := bz*DefaultBlockSize + z
   297  		for y = 0; y < DefaultBlockSize; y++ {
   298  			vy := by*DefaultBlockSize + y
   299  			for x = 0; x < DefaultBlockSize; x++ {
   300  				vx := bx*DefaultBlockSize + x
   301  				i := (vz*v.size[0]*v.size[1] + vy*v.size[0] + vx) * 8
   302  				label := binary.LittleEndian.Uint64(v.data[i : i+8])
   303  				got := binary.LittleEndian.Uint64(data[p : p+8])
   304  				if label != got && numerrors < 5 {
   305  					t.Errorf("[%s] error block (%d,%d,%d) at voxel (%d,%d,%d): expected %d, got %d\n", context, bx, by, bz, vx, vy, vz, label, got)
   306  					numerrors++
   307  				}
   308  				p += 8
   309  			}
   310  		}
   311  	}
   312  }
   313  
   314  func (v *testVolume) testGetBlocks(t *testing.T, context string, uuid dvid.UUID, name, compression string, scale uint8) {
   315  	apiStr := fmt.Sprintf("%snode/%s/%s/blocks/%d_%d_%d/0_0_0", server.WebAPIPath, uuid, name, v.size[0]+64, v.size[1]+64, v.size[2]+64)
   316  	var qstrs []string
   317  	if compression != "" {
   318  		qstrs = append(qstrs, "compression="+compression)
   319  	}
   320  	if scale > 0 {
   321  		qstrs = append(qstrs, fmt.Sprintf("scale=%d", scale))
   322  	}
   323  	if len(qstrs) > 0 {
   324  		apiStr += "?" + strings.Join(qstrs, "&")
   325  	}
   326  	data := server.TestHTTP(t, "GET", apiStr, nil)
   327  	blockBytes := DefaultBlockSize * DefaultBlockSize * DefaultBlockSize * 8
   328  
   329  	var b int
   330  	for {
   331  		// Get block coord + block size
   332  		if b+16 > len(data) {
   333  			t.Fatalf("Only got %d bytes back from block API call, yet next coord in span would put index @ %d\n", len(data), b+16)
   334  		}
   335  		x := int32(binary.LittleEndian.Uint32(data[b : b+4]))
   336  		b += 4
   337  		y := int32(binary.LittleEndian.Uint32(data[b : b+4]))
   338  		b += 4
   339  		z := int32(binary.LittleEndian.Uint32(data[b : b+4]))
   340  		b += 4
   341  		n := int(binary.LittleEndian.Uint32(data[b : b+4]))
   342  		b += 4
   343  
   344  		var uncompressed []byte
   345  		switch compression {
   346  		case "uncompressed":
   347  			uncompressed = data[b : b+n]
   348  		case "", "lz4":
   349  			uncompressed = make([]byte, blockBytes)
   350  			if err := lz4.Uncompress(data[b:b+n], uncompressed); err != nil {
   351  				t.Fatalf("Unable to uncompress LZ4 data (%s), %d bytes: %v\n", apiStr, n, err)
   352  			}
   353  		case "gzip", "blocks":
   354  			gzipIn := bytes.NewBuffer(data[b : b+n])
   355  			zr, err := gzip.NewReader(gzipIn)
   356  			if err != nil {
   357  				t.Fatalf("can't uncompress gzip block: %v\n", err)
   358  			}
   359  			uncompressed, err = ioutil.ReadAll(zr)
   360  			if err != nil {
   361  				t.Fatalf("can't uncompress gzip block: %v\n", err)
   362  			}
   363  			zr.Close()
   364  
   365  			if compression == "blocks" {
   366  				var block labels.Block
   367  				if err = block.UnmarshalBinary(uncompressed); err != nil {
   368  					t.Errorf("unable to deserialize label block (%d, %d, %d): %v\n", x, y, z, err)
   369  				}
   370  				uint64array, size := block.MakeLabelVolume()
   371  				if !size.Equals(dvid.Point3d{DefaultBlockSize, DefaultBlockSize, DefaultBlockSize}) {
   372  					t.Fatalf("got bad block size from deserialized block (%d, %d, %d): %s\n", x, y, z, size)
   373  				}
   374  				uncompressed = uint64array
   375  			}
   376  		}
   377  		v.testBlock(t, context, x, y, z, uncompressed)
   378  		b += n
   379  		if b == len(data) {
   380  			break
   381  		}
   382  	}
   383  }
   384  
   385  type mergeJSON string
   386  
   387  func (mjson mergeJSON) send(t *testing.T, uuid dvid.UUID, name string) {
   388  	apiStr := fmt.Sprintf("%snode/%s/%s/merge?u=tester", server.WebAPIPath, uuid, name)
   389  	server.TestHTTP(t, "POST", apiStr, bytes.NewBufferString(string(mjson)))
   390  
   391  	if err := datastore.BlockOnUpdating(uuid, dvid.InstanceName(name)); err != nil {
   392  		t.Fatalf("Error blocking on bodies update: %v\n", err)
   393  	}
   394  }
   395  
   396  func (mjson mergeJSON) sendErr(t *testing.T, uuid dvid.UUID, name string) error {
   397  	apiStr := fmt.Sprintf("%snode/%s/%s/merge", server.WebAPIPath, uuid, name)
   398  	_, err := server.TestHTTPError(t, "POST", apiStr, bytes.NewBufferString(string(mjson)))
   399  	return err
   400  }
   401  
   402  type renumberJSON string
   403  
   404  func (mjson renumberJSON) send(t *testing.T, uuid dvid.UUID, name string) {
   405  	apiStr := fmt.Sprintf("%snode/%s/%s/renumber", server.WebAPIPath, uuid, name)
   406  	server.TestHTTP(t, "POST", apiStr, bytes.NewBufferString(string(mjson)))
   407  }
   408  
   409  func checkLabels(t *testing.T, text string, expected, got []byte) {
   410  	if len(expected) != len(got) {
   411  		t.Errorf("%s byte mismatch: expected %d bytes, got %d bytes\n", text, len(expected), len(got))
   412  	}
   413  	expectLabels, err := dvid.AliasByteToUint64(expected)
   414  	if err != nil {
   415  		t.Fatal(err)
   416  	}
   417  	gotLabels, err := dvid.AliasByteToUint64(got)
   418  	if err != nil {
   419  		t.Fatal(err)
   420  	}
   421  	for i, val := range gotLabels {
   422  		if expectLabels[i] != val {
   423  			t.Errorf("%s label mismatch found at index %d, expected %d, got %d\n", text, i, expectLabels[i], val)
   424  			return
   425  		}
   426  	}
   427  	runtime.KeepAlive(&expected)
   428  	runtime.KeepAlive(&got)
   429  }
   430  
   431  type labelVol struct {
   432  	size      dvid.Point3d
   433  	blockSize dvid.Point3d
   434  	offset    dvid.Point3d
   435  	name      string
   436  	data      []byte
   437  
   438  	nx, ny, nz int32
   439  
   440  	startLabel uint64
   441  }
   442  
   443  func (vol *labelVol) makeLabelVolume(t *testing.T, uuid dvid.UUID, startLabel uint64) {
   444  	if vol.startLabel == startLabel && vol.data != nil {
   445  		return
   446  	}
   447  
   448  	vol.startLabel = startLabel
   449  
   450  	vol.nx = vol.size[0] * vol.blockSize[0]
   451  	vol.ny = vol.size[1] * vol.blockSize[1]
   452  	vol.nz = vol.size[2] * vol.blockSize[2]
   453  
   454  	vol.data = make([]byte, vol.numBytes())
   455  	var x, y, z, v int32
   456  	for z = 0; z < vol.nz; z++ {
   457  		lz := z / 3
   458  		for y = 0; y < vol.ny; y++ {
   459  			ly := y / 3
   460  			for x = 0; x < vol.nx; x++ {
   461  				label := startLabel + uint64(x>>2+ly+lz)
   462  				binary.LittleEndian.PutUint64(vol.data[v:v+8], label)
   463  				v += 8
   464  			}
   465  		}
   466  	}
   467  	return
   468  }
   469  
   470  func (vol *labelVol) numBytes() int32 {
   471  	return vol.nx * vol.ny * vol.nz * 8
   472  }
   473  
   474  // Create a new label volume and post it to the test datastore.
   475  // Each voxel in volume has sequential labels in X, Y, then Z order.
   476  func (vol *labelVol) postLabelVolume(t *testing.T, uuid dvid.UUID, compression, roi string, startLabel uint64) {
   477  	vol.makeLabelVolume(t, uuid, startLabel)
   478  
   479  	apiStr := fmt.Sprintf("%snode/%s/%s/raw/0_1_2/%d_%d_%d/%d_%d_%d", server.WebAPIPath,
   480  		uuid, vol.name, vol.nx, vol.ny, vol.nz, vol.offset[0], vol.offset[1], vol.offset[2])
   481  	query := true
   482  
   483  	var data []byte
   484  	var err error
   485  	switch compression {
   486  	case "lz4":
   487  		apiStr += "?compression=lz4"
   488  		compressed := make([]byte, lz4.CompressBound(vol.data))
   489  		var outSize int
   490  		if outSize, err = lz4.Compress(vol.data, compressed); err != nil {
   491  			t.Fatal(err)
   492  		}
   493  		data = compressed[:outSize]
   494  	case "gzip":
   495  		apiStr += "?compression=gzip"
   496  		var buf bytes.Buffer
   497  		gw := gzip.NewWriter(&buf)
   498  		if _, err = gw.Write(vol.data); err != nil {
   499  			t.Fatal(err)
   500  		}
   501  		data = buf.Bytes()
   502  		if err = gw.Close(); err != nil {
   503  			t.Fatal(err)
   504  		}
   505  	default:
   506  		data = vol.data
   507  		query = false
   508  	}
   509  	if roi != "" {
   510  		if query {
   511  			apiStr += "&roi=" + roi
   512  		} else {
   513  			apiStr += "?roi=" + roi
   514  		}
   515  	}
   516  	server.TestHTTP(t, "POST", apiStr, bytes.NewBuffer(data))
   517  }
   518  
   519  func (vol *labelVol) getLabelVolume(t *testing.T, uuid dvid.UUID, compression, roi string) []byte {
   520  	apiStr := fmt.Sprintf("%snode/%s/%s/raw/0_1_2/%d_%d_%d/%d_%d_%d", server.WebAPIPath,
   521  		uuid, vol.name, vol.nx, vol.ny, vol.nz, vol.offset[0], vol.offset[1], vol.offset[2])
   522  	query := true
   523  	switch compression {
   524  	case "lz4":
   525  		apiStr += "?compression=lz4"
   526  	case "gzip":
   527  		apiStr += "?compression=gzip"
   528  	default:
   529  		query = false
   530  	}
   531  	if roi != "" {
   532  		if query {
   533  			apiStr += "&roi=" + roi
   534  		} else {
   535  			apiStr += "?roi=" + roi
   536  		}
   537  	}
   538  	data := server.TestHTTP(t, "GET", apiStr, nil)
   539  	switch compression {
   540  	case "lz4":
   541  		uncompressed := make([]byte, vol.numBytes())
   542  		if err := lz4.Uncompress(data, uncompressed); err != nil {
   543  			t.Fatalf("Unable to uncompress LZ4 data (%s), %d bytes: %v\n", apiStr, len(data), err)
   544  		}
   545  		data = uncompressed
   546  	case "gzip":
   547  		buf := bytes.NewBuffer(data)
   548  		gr, err := gzip.NewReader(buf)
   549  		if err != nil {
   550  			t.Fatalf("Error on gzip new reader: %v\n", err)
   551  		}
   552  		uncompressed, err := ioutil.ReadAll(gr)
   553  		if err != nil {
   554  			t.Fatalf("Error on reading gzip: %v\n", err)
   555  		}
   556  		if err = gr.Close(); err != nil {
   557  			t.Fatalf("Error on closing gzip: %v\n", err)
   558  		}
   559  		data = uncompressed
   560  	default:
   561  	}
   562  	if len(data) != int(vol.numBytes()) {
   563  		t.Errorf("Expected %d uncompressed bytes from 3d labelmap GET.  Got %d instead.", vol.numBytes(), len(data))
   564  	}
   565  	return data
   566  }
   567  
   568  func (vol *labelVol) testGetLabelVolume(t *testing.T, uuid dvid.UUID, compression, roi string) []byte {
   569  	data := vol.getLabelVolume(t, uuid, compression, roi)
   570  
   571  	// run test to make sure it's same volume as we posted.
   572  	var x, y, z, v int32
   573  	for z = 0; z < vol.nz; z++ {
   574  		lz := z / 3
   575  		for y = 0; y < vol.ny; y++ {
   576  			ly := y / 3
   577  			for x = 0; x < vol.nx; x++ {
   578  				label := vol.startLabel + uint64(x>>2+ly+lz)
   579  				got := binary.LittleEndian.Uint64(data[v : v+8])
   580  				if label != got {
   581  					t.Errorf("Error on 3d GET compression (%q): expected %d, got %d\n", compression, label, got)
   582  					goto foundError
   583  				}
   584  				v += 8
   585  			}
   586  		}
   587  	}
   588  
   589  foundError:
   590  
   591  	checkLabels(t, "testing label volume", vol.data, data)
   592  
   593  	return data
   594  }
   595  
   596  func (vol *labelVol) testBlock(t *testing.T, context string, bx, by, bz int32, data []byte) {
   597  	// Get offset of this block in label volume
   598  	ox := bx*vol.blockSize[0] - vol.offset[0]
   599  	oy := by*vol.blockSize[1] - vol.offset[1]
   600  	oz := bz*vol.blockSize[2] - vol.offset[2]
   601  
   602  	if int64(len(data)) < vol.blockSize.Prod()*8 {
   603  		t.Fatalf("[%s] got bad uint64 array of len %d for block (%d, %d, %d)\n", context, len(data), bx, by, bz)
   604  	}
   605  	p := 0
   606  	var x, y, z, numerrors int32
   607  	for z = 0; z < 32; z++ {
   608  		lz := (z + oz) / 3
   609  		for y = 0; y < 32; y++ {
   610  			ly := (y + oy) / 3
   611  			for x = 0; x < 32; x++ {
   612  				lx := x + ox
   613  				label := vol.startLabel + uint64(lx>>2+ly+lz)
   614  				got := binary.LittleEndian.Uint64(data[p : p+8])
   615  				if label != got && numerrors < 5 {
   616  					t.Errorf("[%s] error block (%d,%d,%d) at voxel (%d,%d,%d): expected %d, got %d\n", context, bx, by, bz, x, y, z, label, got)
   617  					numerrors++
   618  				}
   619  				p += 8
   620  			}
   621  		}
   622  	}
   623  }
   624  
   625  func (vol *labelVol) testBlocks(t *testing.T, context string, uuid dvid.UUID, compression string) {
   626  	span := 5
   627  	apiStr := fmt.Sprintf("%snode/%s/%s/blocks/%d_%d_%d/%d_%d_%d", server.WebAPIPath,
   628  		uuid, vol.name, 160, 32, 32, vol.offset[0], vol.offset[1], vol.offset[2])
   629  	var qstrs []string
   630  	if compression != "" {
   631  		qstrs = append(qstrs, "compression="+compression)
   632  	}
   633  	if len(qstrs) > 0 {
   634  		apiStr += "?" + strings.Join(qstrs, "&")
   635  	}
   636  	data := server.TestHTTP(t, "GET", apiStr, nil)
   637  
   638  	blockBytes := int(vol.blockSize.Prod() * 8)
   639  
   640  	// Check if values are what we expect
   641  	b := 0
   642  	for i := 0; i < span; i++ {
   643  		// Get block coord + block size
   644  		if b+16 > len(data) {
   645  			t.Fatalf("Only got %d bytes back from block API call, yet next coord in span would put index @ %d\n", len(data), b+16)
   646  		}
   647  		x := int32(binary.LittleEndian.Uint32(data[b : b+4]))
   648  		b += 4
   649  		y := int32(binary.LittleEndian.Uint32(data[b : b+4]))
   650  		b += 4
   651  		z := int32(binary.LittleEndian.Uint32(data[b : b+4]))
   652  		b += 4
   653  		n := int(binary.LittleEndian.Uint32(data[b : b+4]))
   654  		b += 4
   655  
   656  		// Read in the block data as assumed LZ4 and check it.
   657  		var uncompressed []byte
   658  		switch compression {
   659  		case "uncompressed":
   660  			uncompressed = data[b : b+n]
   661  		case "", "lz4":
   662  			uncompressed = make([]byte, blockBytes)
   663  			if err := lz4.Uncompress(data[b:b+n], uncompressed); err != nil {
   664  				t.Fatalf("Unable to uncompress LZ4 data (%s), %d bytes: %v\n", apiStr, n, err)
   665  			}
   666  		case "gzip", "blocks":
   667  			gzipIn := bytes.NewBuffer(data[b : b+n])
   668  			zr, err := gzip.NewReader(gzipIn)
   669  			if err != nil {
   670  				t.Fatalf("can't uncompress gzip block: %v\n", err)
   671  			}
   672  			uncompressed, err = ioutil.ReadAll(zr)
   673  			if err != nil {
   674  				t.Fatalf("can't uncompress gzip block: %v\n", err)
   675  			}
   676  			zr.Close()
   677  
   678  			if compression == "blocks" {
   679  				var block labels.Block
   680  				if err = block.UnmarshalBinary(uncompressed); err != nil {
   681  					t.Fatalf("unable to deserialize label block (%d, %d, %d): %v\n", x, y, z, err)
   682  				}
   683  				uint64array, size := block.MakeLabelVolume()
   684  				if !size.Equals(vol.blockSize) {
   685  					t.Fatalf("got bad block size from deserialized block (%d, %d, %d): %s\n", x, y, z, size)
   686  				}
   687  				uncompressed = uint64array
   688  			}
   689  		}
   690  		vol.testBlock(t, context, x, y, z, uncompressed)
   691  		b += n
   692  	}
   693  }
   694  
   695  // the label in the test volume should just be the start label + voxel index + 1 when iterating in ZYX order.
   696  // The passed (x,y,z) should be world coordinates, not relative to the volume offset.
   697  func (vol *labelVol) label(x, y, z int32) uint64 {
   698  	if x < vol.offset[0] || x >= vol.offset[0]+vol.size[0]*vol.blockSize[0] {
   699  		return 0
   700  	}
   701  	if y < vol.offset[1] || y >= vol.offset[1]+vol.size[1]*vol.blockSize[1] {
   702  		return 0
   703  	}
   704  	if z < vol.offset[2] || z >= vol.offset[2]+vol.size[2]*vol.blockSize[2] {
   705  		return 0
   706  	}
   707  	x -= vol.offset[0]
   708  	y -= vol.offset[1]
   709  	z -= vol.offset[2]
   710  	return vol.startLabel + uint64(x>>2+y/3+z/3)
   711  }
   712  
   713  type sliceTester struct {
   714  	orient string
   715  	width  int32
   716  	height int32
   717  	offset dvid.Point3d // offset of slice
   718  }
   719  
   720  func (s sliceTester) apiStr(uuid dvid.UUID, name string) string {
   721  	return fmt.Sprintf("%snode/%s/%s/raw/%s/%d_%d/%d_%d_%d", server.WebAPIPath,
   722  		uuid, name, s.orient, s.width, s.height, s.offset[0], s.offset[1], s.offset[2])
   723  }
   724  
   725  // make sure the given labels match what would be expected from the test volume.
   726  func (s sliceTester) testLabel(t *testing.T, vol labelVol, img *dvid.Image) {
   727  	data := img.Data()
   728  	var x, y, z int32
   729  	i := 0
   730  	switch s.orient {
   731  	case "xy":
   732  		for y = 0; y < s.height; y++ {
   733  			for x = 0; x < s.width; x++ {
   734  				label := binary.LittleEndian.Uint64(data[i*8 : (i+1)*8])
   735  				i++
   736  				vx := x + s.offset[0]
   737  				vy := y + s.offset[1]
   738  				vz := s.offset[2]
   739  				expected := vol.label(vx, vy, vz)
   740  				if label != expected {
   741  					t.Errorf("Bad label @ (%d,%d,%d): expected %d, got %d\n", vx, vy, vz, expected, label)
   742  					return
   743  				}
   744  			}
   745  		}
   746  		return
   747  	case "xz":
   748  		for z = 0; z < s.height; z++ {
   749  			for x = 0; x < s.width; x++ {
   750  				label := binary.LittleEndian.Uint64(data[i*8 : (i+1)*8])
   751  				i++
   752  				vx := x + s.offset[0]
   753  				vy := s.offset[1]
   754  				vz := z + s.offset[2]
   755  				expected := vol.label(vx, vy, vz)
   756  				if label != expected {
   757  					t.Errorf("Bad label @ (%d,%d,%d): expected %d, got %d\n", vx, vy, vz, expected, label)
   758  					return
   759  				}
   760  			}
   761  		}
   762  		return
   763  	case "yz":
   764  		for z = 0; z < s.height; z++ {
   765  			for y = 0; y < s.width; y++ {
   766  				label := binary.LittleEndian.Uint64(data[i*8 : (i+1)*8])
   767  				i++
   768  				vx := s.offset[0]
   769  				vy := y + s.offset[1]
   770  				vz := z + s.offset[2]
   771  				expected := vol.label(vx, vy, vz)
   772  				if label != expected {
   773  					t.Errorf("Bad label @ (%d,%d,%d): expected %d, got %d\n", vx, vy, vz, expected, label)
   774  					return
   775  				}
   776  			}
   777  		}
   778  		return
   779  	default:
   780  		t.Fatalf("Unknown slice orientation %q\n", s.orient)
   781  	}
   782  }
   783  
   784  func (vol labelVol) testSlices(t *testing.T, uuid dvid.UUID) {
   785  	// Verify XY slice.
   786  	sliceOffset := vol.offset
   787  	sliceOffset[0] += 51
   788  	sliceOffset[1] += 11
   789  	sliceOffset[2] += 23
   790  	slice := sliceTester{"xy", 67, 83, sliceOffset}
   791  	apiStr := slice.apiStr(uuid, vol.name)
   792  	xy := server.TestHTTP(t, "GET", apiStr, nil)
   793  	img, format, err := dvid.ImageFromBytes(xy, EncodeFormat(), false)
   794  	if err != nil {
   795  		t.Fatalf("Error on XY labels GET: %v\n", err)
   796  	}
   797  	if format != "png" {
   798  		t.Errorf("Expected XY labels GET to return %q image, got %q instead.\n", "png", format)
   799  	}
   800  	if img.NumBytes() != 67*83*8 {
   801  		t.Errorf("Expected %d bytes from XY labelmap GET.  Got %d instead.", 160*160*8, img.NumBytes())
   802  	}
   803  	slice.testLabel(t, vol, img)
   804  
   805  	// Verify XZ slice returns what we expect.
   806  	sliceOffset = vol.offset
   807  	sliceOffset[0] += 11
   808  	sliceOffset[1] += 4
   809  	sliceOffset[2] += 3
   810  	slice = sliceTester{"xz", 67, 83, sliceOffset}
   811  	apiStr = slice.apiStr(uuid, vol.name)
   812  	xz := server.TestHTTP(t, "GET", apiStr, nil)
   813  	img, format, err = dvid.ImageFromBytes(xz, EncodeFormat(), false)
   814  	if err != nil {
   815  		t.Fatalf("Error on XZ labels GET: %v\n", err)
   816  	}
   817  	if format != "png" {
   818  		t.Errorf("Expected XZ labels GET to return %q image, got %q instead.\n", "png", format)
   819  	}
   820  	if img.NumBytes() != 67*83*8 {
   821  		t.Errorf("Expected %d bytes from XZ labelmap GET.  Got %d instead.", 67*83*8, img.NumBytes())
   822  	}
   823  	slice.testLabel(t, vol, img)
   824  
   825  	// Verify YZ slice returns what we expect.
   826  	sliceOffset = vol.offset
   827  	sliceOffset[0] += 7
   828  	sliceOffset[1] += 33
   829  	sliceOffset[2] += 33
   830  	slice = sliceTester{"yz", 67, 83, sliceOffset}
   831  	apiStr = slice.apiStr(uuid, vol.name)
   832  	yz := server.TestHTTP(t, "GET", apiStr, nil)
   833  	img, format, err = dvid.ImageFromBytes(yz, EncodeFormat(), false)
   834  	if err != nil {
   835  		t.Fatalf("Error on YZ labels GET: %v\n", err)
   836  	}
   837  	if format != "png" {
   838  		t.Errorf("Expected YZ labels GET to return %q image, got %q instead.\n", "png", format)
   839  	}
   840  	if img.NumBytes() != 67*83*8 {
   841  		t.Errorf("Expected %d bytes from YZ labelmap GET.  Got %d instead.", 67*83*8, img.NumBytes())
   842  	}
   843  	slice.testLabel(t, vol, img)
   844  }
   845  
   846  type labelResp struct {
   847  	Label uint64
   848  }
   849  
   850  // Data from which to construct repeatable 3d images where adjacent voxels have different values.
   851  var xdata = []uint64{23, 819229, 757, 100303, 9991}
   852  var ydata = []uint64{66599, 201, 881067, 5488, 0}
   853  var zdata = []uint64{1, 734, 43990122, 42, 319596}
   854  
   855  // Make a 2d slice of bytes with top left corner at (ox,oy,oz) and size (nx,ny)
   856  func makeSlice(offset dvid.Point3d, size dvid.Point2d) []byte {
   857  	numBytes := size[0] * size[1] * 8
   858  	slice := make([]byte, numBytes, numBytes)
   859  	i := 0
   860  	modz := offset[2] % int32(len(zdata))
   861  	for y := int32(0); y < size[1]; y++ {
   862  		sy := y + offset[1]
   863  		mody := sy % int32(len(ydata))
   864  		sx := offset[0]
   865  		for x := int32(0); x < size[0]; x++ {
   866  			modx := sx % int32(len(xdata))
   867  			binary.BigEndian.PutUint64(slice[i:i+8], xdata[modx]+ydata[mody]+zdata[modz])
   868  			i += 8
   869  			sx++
   870  		}
   871  	}
   872  	return slice
   873  }
   874  
   875  // Make a 3d volume of bytes with top left corner at (ox,oy,oz) and size (nx, ny, nz)
   876  func makeVolume(offset, size dvid.Point3d) []byte {
   877  	sliceBytes := size[0] * size[1] * 8
   878  	volumeBytes := sliceBytes * size[2]
   879  	volume := make([]byte, volumeBytes, volumeBytes)
   880  	var i int32
   881  	size2d := dvid.Point2d{size[0], size[1]}
   882  	startZ := offset[2]
   883  	endZ := startZ + size[2]
   884  	for z := startZ; z < endZ; z++ {
   885  		offset[2] = z
   886  		copy(volume[i:i+sliceBytes], makeSlice(offset, size2d))
   887  		i += sliceBytes
   888  	}
   889  	return volume
   890  }
   891  
   892  // Creates a new data instance for labelmap
   893  func newDataInstance(uuid dvid.UUID, t *testing.T, name dvid.InstanceName) *Data {
   894  	config := dvid.NewConfig()
   895  	dataservice, err := datastore.NewData(uuid, labelsT, name, config)
   896  	if err != nil {
   897  		t.Fatalf("Unable to create labelmap instance %q: %v\n", name, err)
   898  	}
   899  	labels, ok := dataservice.(*Data)
   900  	if !ok {
   901  		t.Fatalf("Can't cast labels data service into Data\n")
   902  	}
   903  	return labels
   904  }
   905  
   906  func TestLabelarrayDirectAPI(t *testing.T) {
   907  	if err := server.OpenTest(); err != nil {
   908  		t.Fatalf("can't open test server: %v\n", err)
   909  	}
   910  	defer server.CloseTest()
   911  
   912  	uuid, versionID := initTestRepo()
   913  	lbls := newDataInstance(uuid, t, "mylabels")
   914  	labelsCtx := datastore.NewVersionedCtx(lbls, versionID)
   915  
   916  	// Create a fake block-aligned label volume
   917  	offset := dvid.Point3d{DefaultBlockSize, 0, DefaultBlockSize}
   918  	size := dvid.Point3d{2 * DefaultBlockSize, DefaultBlockSize, 3 * DefaultBlockSize}
   919  	subvol := dvid.NewSubvolume(offset, size)
   920  	data := makeVolume(offset, size)
   921  
   922  	// Store it into datastore at root
   923  	v, err := lbls.NewVoxels(subvol, data)
   924  	if err != nil {
   925  		t.Fatalf("Unable to make new labels Voxels: %v\n", err)
   926  	}
   927  	if err = lbls.IngestVoxels(versionID, 1, v, ""); err != nil {
   928  		t.Fatalf("Unable to put labels for %s: %v\n", labelsCtx, err)
   929  	}
   930  	if v.NumVoxels() != int64(len(data))/8 {
   931  		t.Errorf("# voxels (%d) after PutVoxels != # original voxels (%d)\n",
   932  			v.NumVoxels(), int64(len(data))/8)
   933  	}
   934  
   935  	// Read the stored image
   936  	v2, err := lbls.NewVoxels(subvol, nil)
   937  	if err != nil {
   938  		t.Fatalf("Unable to make new labels ExtHandler: %v\n", err)
   939  	}
   940  	if err = lbls.GetVoxels(versionID, v2, ""); err != nil {
   941  		t.Fatalf("Unable to get voxels for %s: %v\n", labelsCtx, err)
   942  	}
   943  
   944  	// Make sure the retrieved image matches the original
   945  	if v.Stride() != v2.Stride() {
   946  		t.Errorf("Stride in retrieved subvol incorrect\n")
   947  	}
   948  	if v.Interpolable() != v2.Interpolable() {
   949  		t.Errorf("Interpolable bool in retrieved subvol incorrect\n")
   950  	}
   951  	if !reflect.DeepEqual(v.Size(), v2.Size()) {
   952  		t.Errorf("Size in retrieved subvol incorrect: %s vs expected %s\n",
   953  			v2.Size(), v.Size())
   954  	}
   955  	if v.NumVoxels() != v2.NumVoxels() {
   956  		t.Errorf("# voxels in retrieved is different: %d vs expected %d\n",
   957  			v2.NumVoxels(), v.NumVoxels())
   958  	}
   959  	byteData := v2.Data()
   960  
   961  	for i := int64(0); i < v2.NumVoxels()*8; i++ {
   962  		if byteData[i] != data[i] {
   963  			t.Logf("Size of data: %d bytes from GET, %d bytes in PUT\n", len(data), len(data))
   964  			t.Fatalf("GET subvol (%d) != PUT subvol (%d) @ uint64 #%d", byteData[i], data[i], i)
   965  		}
   966  	}
   967  }
   968  
   969  func TestLabelarrayRepoPersistence(t *testing.T) {
   970  	if err := server.OpenTest(); err != nil {
   971  		t.Fatalf("can't open test server: %v\n", err)
   972  	}
   973  	defer server.CloseTest()
   974  
   975  	uuid, _ := initTestRepo()
   976  
   977  	// Make labels and set various properties
   978  	config := dvid.NewConfig()
   979  	config.Set("BlockSize", "12,13,14")
   980  	config.Set("VoxelSize", "1.1,2.8,11")
   981  	config.Set("VoxelUnits", "microns,millimeters,nanometers")
   982  	config.Set("MinPoint", "1,2,3")
   983  	config.Set("MaxPoint", "7,8,9")
   984  	config.Set("CountLabels", "false")
   985  	config.Set("MaxDownresLevel", "5")
   986  	dataservice, err := datastore.NewData(uuid, labelsT, "mylabels", config)
   987  	if err == nil {
   988  		t.Fatalf("expected error with bad block size but didn't get it")
   989  	}
   990  	config.Set("BlockSize", "64,32,16")
   991  	dataservice, err = datastore.NewData(uuid, labelsT, "mylabels", config)
   992  	if err != nil || dataservice == nil {
   993  		t.Fatalf("Unable to create labels instance: %v\n", err)
   994  	}
   995  	lbls, ok := dataservice.(*Data)
   996  	if !ok {
   997  		t.Errorf("Can't cast labels data service into Data\n")
   998  	}
   999  	if !lbls.IndexedLabels {
  1000  		t.Errorf("expected IndexedLabels to be true for default but was false\n")
  1001  	}
  1002  	if lbls.MaxDownresLevel != 5 {
  1003  		t.Errorf("expected MaxDownresLevel to be 5, not %d\n", lbls.MaxDownresLevel)
  1004  	}
  1005  	oldData := *lbls
  1006  
  1007  	// Check properties setting.
  1008  	apiStr := fmt.Sprintf("%snode/%s/mylabels/info", server.WebAPIPath, uuid)
  1009  	result := server.TestHTTP(t, "GET", apiStr, nil)
  1010  	var parsed = struct {
  1011  		Base struct {
  1012  			TypeName, Name string
  1013  		}
  1014  		Extended struct {
  1015  			BlockSize       dvid.Point3d
  1016  			VoxelSize       dvid.NdFloat32
  1017  			VoxelUnits      dvid.NdString
  1018  			MinPoint        dvid.Point3d
  1019  			MaxPoint        dvid.Point3d
  1020  			MaxDownresLevel int
  1021  		}
  1022  	}{}
  1023  	if err := json.Unmarshal(result, &parsed); err != nil {
  1024  		t.Fatalf("Error parsing JSON response of metadata: %v\n", err)
  1025  	}
  1026  	if !parsed.Extended.BlockSize.Equals(dvid.Point3d{64, 32, 16}) {
  1027  		t.Errorf("Bad BlockSize in new labelmap instance: %s\n", parsed.Extended.BlockSize)
  1028  	}
  1029  	if parsed.Extended.MaxDownresLevel != 5 {
  1030  		t.Errorf("Bad MaxDownresLevel in new labelmap instance: %d\n", parsed.Extended.MaxDownresLevel)
  1031  	}
  1032  	if !parsed.Extended.VoxelSize.Equals(dvid.NdFloat32{1.1, 2.8, 11.0}) {
  1033  		t.Errorf("Bad VoxelSize in new labelmap instance: %s\n", parsed.Extended.VoxelSize)
  1034  	}
  1035  	if !parsed.Extended.MinPoint.Equals(dvid.Point3d{1, 2, 3}) {
  1036  		t.Errorf("Bad MinPoint in new labelmap instance: %s\n", parsed.Extended.MinPoint)
  1037  	}
  1038  	if !parsed.Extended.MaxPoint.Equals(dvid.Point3d{7, 8, 9}) {
  1039  		t.Errorf("Bad MaxPoint in new labelmap instance: %s\n", parsed.Extended.MaxPoint)
  1040  	}
  1041  
  1042  	payload := bytes.NewBufferString(`{"MaxDownresLevel":"8"}`)
  1043  	result = server.TestHTTP(t, "POST", apiStr, payload)
  1044  	if lbls.MaxDownresLevel != 8 {
  1045  		t.Errorf("Bad MaxDownresLevel after POST /info: %d\n", lbls.MaxDownresLevel)
  1046  	}
  1047  
  1048  	// Restart test datastore and see if datasets are still there.
  1049  	if err = datastore.SaveDataByUUID(uuid, lbls); err != nil {
  1050  		t.Fatalf("Unable to save repo during labels persistence test: %v\n", err)
  1051  	}
  1052  	datastore.CloseReopenTest()
  1053  
  1054  	dataservice2, err := datastore.GetDataByUUIDName(uuid, "mylabels")
  1055  	if err != nil {
  1056  		t.Fatalf("Can't get labels instance from reloaded test db: %v\n", err)
  1057  	}
  1058  	lbls2, ok := dataservice2.(*Data)
  1059  	if !ok {
  1060  		t.Errorf("Returned new data instance 2 is not imageblk.Data\n")
  1061  	}
  1062  	if !oldData.Equals(lbls2) {
  1063  		t.Errorf("Expected %v, got %v\n", oldData, *lbls2)
  1064  	}
  1065  	if lbls2.MaxDownresLevel != 8 {
  1066  		t.Errorf("Bad MaxDownresLevel: %d\n", lbls2.MaxDownresLevel)
  1067  	}
  1068  }
  1069  
  1070  func TestBadCalls(t *testing.T) {
  1071  	if err := server.OpenTest(); err != nil {
  1072  		t.Fatalf("can't open test server: %v\n", err)
  1073  	}
  1074  	defer server.CloseTest()
  1075  
  1076  	// Create testbed volume and data instances
  1077  	uuid, _ := initTestRepo()
  1078  	var config dvid.Config
  1079  	config.Set("MaxDownresLevel", "2")
  1080  	server.CreateTestInstance(t, uuid, "labelmap", "labels", config)
  1081  
  1082  	reqStr := fmt.Sprintf("%snode/%s/labels/supervoxels/100", server.WebAPIPath, uuid)
  1083  	server.TestBadHTTP(t, "GET", reqStr, nil)
  1084  
  1085  	reqStr = fmt.Sprintf("%snode/%s/labels/size/100", server.WebAPIPath, uuid)
  1086  	server.TestBadHTTP(t, "GET", reqStr, nil)
  1087  
  1088  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol-size/100", server.WebAPIPath, uuid)
  1089  	server.TestBadHTTP(t, "GET", reqStr, nil)
  1090  
  1091  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/100", server.WebAPIPath, uuid)
  1092  	server.TestBadHTTP(t, "GET", reqStr, nil)
  1093  
  1094  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol-coarse/100", server.WebAPIPath, uuid)
  1095  	server.TestBadHTTP(t, "GET", reqStr, nil)
  1096  
  1097  	reqStr = fmt.Sprintf("%snode/%s/labels/cleave/100", server.WebAPIPath, uuid)
  1098  	server.TestBadHTTP(t, "POST", reqStr, bytes.NewBufferString("[4]"))
  1099  
  1100  	reqStr = fmt.Sprintf("%snode/%s/labels/split-supervoxel/100", server.WebAPIPath, uuid)
  1101  	server.TestBadHTTP(t, "POST", reqStr, nil)
  1102  
  1103  	reqStr = fmt.Sprintf("%snode/%s/labels/split/100", server.WebAPIPath, uuid)
  1104  	server.TestBadHTTP(t, "POST", reqStr, nil)
  1105  
  1106  	reqStr = fmt.Sprintf("%snode/%s/labels/index/100", server.WebAPIPath, uuid)
  1107  	server.TestBadHTTP(t, "POST", reqStr, nil)
  1108  
  1109  	reqStr = fmt.Sprintf("%snode/%s/labels/indices", server.WebAPIPath, uuid)
  1110  	server.TestBadHTTP(t, "POST", reqStr, nil)
  1111  
  1112  	reqStr = fmt.Sprintf("%snode/%s/labels/mappings", server.WebAPIPath, uuid)
  1113  	server.TestBadHTTP(t, "POST", reqStr, nil)
  1114  }
  1115  
  1116  func TestExtents(t *testing.T) {
  1117  	if err := server.OpenTest(); err != nil {
  1118  		t.Fatalf("can't open test server: %v\n", err)
  1119  	}
  1120  	defer server.CloseTest()
  1121  
  1122  	uuid, _ := datastore.NewTestRepo()
  1123  	if len(uuid) < 5 {
  1124  		t.Fatalf("Bad root UUID for new repo: %s\n", uuid)
  1125  	}
  1126  	server.CreateTestInstance(t, uuid, "labelmap", "labels", dvid.Config{})
  1127  
  1128  	extents := `{
  1129  		"MinPoint": [68, 127, 210],
  1130  		"MaxPoint": [1023, 4811, 12187]
  1131  	}`
  1132  	apiStr := fmt.Sprintf("%snode/%s/labels/extents", server.WebAPIPath, uuid)
  1133  	server.TestHTTP(t, "POST", apiStr, bytes.NewBufferString(extents))
  1134  
  1135  	apiStr = fmt.Sprintf("%snode/%s/commit", server.WebAPIPath, uuid)
  1136  	payload := bytes.NewBufferString(`{"note": "first version"}`)
  1137  	server.TestHTTP(t, "POST", apiStr, payload)
  1138  
  1139  	versionReq := fmt.Sprintf("%snode/%s/newversion", server.WebAPIPath, uuid)
  1140  	respData := server.TestHTTP(t, "POST", versionReq, nil)
  1141  	resp := struct {
  1142  		Child dvid.UUID `json:"child"`
  1143  	}{}
  1144  	if err := json.Unmarshal(respData, &resp); err != nil {
  1145  		t.Errorf("Expected 'child' JSON response.  Got %s\n", string(respData))
  1146  	}
  1147  
  1148  	extents2 := `{
  1149  		"MinPoint": [3, 4, 210],
  1150  		"MaxPoint": [2048, 4811, 12187]
  1151  	}`
  1152  	apiStr = fmt.Sprintf("%snode/%s/labels/extents", server.WebAPIPath, resp.Child)
  1153  	server.TestHTTP(t, "POST", apiStr, bytes.NewBufferString(extents2))
  1154  
  1155  	apiStr = fmt.Sprintf("%snode/%s/labels/info", server.WebAPIPath, uuid)
  1156  	result := server.TestHTTP(t, "GET", apiStr, nil)
  1157  	var parsed = struct {
  1158  		Base struct {
  1159  			TypeName, Name string
  1160  		}
  1161  		Extended struct {
  1162  			BlockSize  dvid.Point3d
  1163  			VoxelSize  dvid.NdFloat32
  1164  			VoxelUnits dvid.NdString
  1165  			MinPoint   dvid.Point3d
  1166  			MaxPoint   dvid.Point3d
  1167  			MinIndex   dvid.Point3d
  1168  			MaxIndex   dvid.Point3d
  1169  		}
  1170  	}{}
  1171  	if err := json.Unmarshal(result, &parsed); err != nil {
  1172  		t.Fatalf("Error parsing JSON response of new instance metadata: %v\n", err)
  1173  	}
  1174  	fmt.Printf("got: %s\n", string(result))
  1175  	if !parsed.Extended.MinPoint.Equals(dvid.Point3d{68, 127, 210}) {
  1176  		t.Errorf("Bad MinPoint in new labelmap instance: %s\n", parsed.Extended.MinPoint)
  1177  	}
  1178  	if !parsed.Extended.MaxPoint.Equals(dvid.Point3d{1023, 4811, 12187}) {
  1179  		t.Errorf("Bad MaxPoint in new labelmap instance: %s\n", parsed.Extended.MaxPoint)
  1180  	}
  1181  	if !parsed.Extended.MinIndex.Equals(dvid.Point3d{1, 1, 3}) {
  1182  		t.Errorf("Bad MinIndex in new labelmap instance: %s\n", parsed.Extended.MinIndex)
  1183  	}
  1184  	if !parsed.Extended.MaxIndex.Equals(dvid.Point3d{15, 75, 190}) {
  1185  		t.Errorf("Bad MaxIndex in new labelmap instance: %s\n", parsed.Extended.MaxIndex)
  1186  	}
  1187  
  1188  	apiStr = fmt.Sprintf("%snode/%s/labels/info", server.WebAPIPath, resp.Child)
  1189  	result = server.TestHTTP(t, "GET", apiStr, nil)
  1190  	if err := json.Unmarshal(result, &parsed); err != nil {
  1191  		t.Fatalf("Error parsing JSON response of new instance metadata: %v\n", err)
  1192  	}
  1193  	fmt.Printf("got: %s\n", string(result))
  1194  	if !parsed.Extended.MinPoint.Equals(dvid.Point3d{3, 4, 210}) {
  1195  		t.Errorf("Bad MinPoint in new labelmap instance: %s\n", parsed.Extended.MinPoint)
  1196  	}
  1197  	if !parsed.Extended.MaxPoint.Equals(dvid.Point3d{2048, 4811, 12187}) {
  1198  		t.Errorf("Bad MaxPoint in new labelmap instance: %s\n", parsed.Extended.MaxPoint)
  1199  	}
  1200  	if !parsed.Extended.MinIndex.Equals(dvid.Point3d{0, 0, 3}) {
  1201  		t.Errorf("Bad MinIndex in new labelmap instance: %s\n", parsed.Extended.MinIndex)
  1202  	}
  1203  	if !parsed.Extended.MaxIndex.Equals(dvid.Point3d{32, 75, 190}) {
  1204  		t.Errorf("Bad MaxIndex in new labelmap instance: %s\n", parsed.Extended.MaxIndex)
  1205  	}
  1206  }
  1207  
  1208  func TestMultiscaleIngest(t *testing.T) {
  1209  	if err := server.OpenTest(); err != nil {
  1210  		t.Fatalf("can't open test server: %v\n", err)
  1211  	}
  1212  	defer server.CloseTest()
  1213  
  1214  	// Create testbed volume and data instances
  1215  	uuid, _ := initTestRepo()
  1216  	var config dvid.Config
  1217  	config.Set("MaxDownresLevel", "2")
  1218  	server.CreateTestInstance(t, uuid, "labelmap", "labels", config)
  1219  
  1220  	// Create an easily interpreted label volume with a couple of labels.
  1221  	volume := newTestVolume(128, 128, 128)
  1222  	volume.addSubvol(dvid.Point3d{40, 40, 40}, dvid.Point3d{40, 40, 40}, 1)
  1223  	volume.addSubvol(dvid.Point3d{40, 40, 80}, dvid.Point3d{40, 40, 40}, 2)
  1224  	volume.addSubvol(dvid.Point3d{80, 40, 40}, dvid.Point3d{40, 40, 40}, 13)
  1225  	volume.addSubvol(dvid.Point3d{40, 80, 40}, dvid.Point3d{40, 40, 40}, 209)
  1226  	volume.addSubvol(dvid.Point3d{80, 80, 40}, dvid.Point3d{40, 40, 40}, 311)
  1227  	volume.put(t, uuid, "labels")
  1228  
  1229  	// Verify initial ingest for hi-res
  1230  	if err := downres.BlockOnUpdating(uuid, "labels"); err != nil {
  1231  		t.Fatalf("Error blocking on update for labels: %v\n", err)
  1232  	}
  1233  
  1234  	hires := newTestVolume(128, 128, 128)
  1235  	hires.get(t, uuid, "labels", false)
  1236  	hires.verifyLabel(t, 1, 45, 45, 45)
  1237  	hires.verifyLabel(t, 2, 50, 50, 100)
  1238  	hires.verifyLabel(t, 13, 100, 60, 60)
  1239  	hires.verifyLabel(t, 209, 55, 100, 55)
  1240  	hires.verifyLabel(t, 311, 81, 81, 41)
  1241  
  1242  	expectedLabels := []uint64{1, 2, 13, 209, 311}
  1243  	expectedSize := uint64(40 * 40 * 40)
  1244  
  1245  	// Verify our label index voxel counts are correct.
  1246  	for _, label := range expectedLabels {
  1247  		reqStr := fmt.Sprintf("%snode/%s/labels/size/%d", server.WebAPIPath, uuid, label)
  1248  		r := server.TestHTTP(t, "GET", reqStr, nil)
  1249  		var jsonVal struct {
  1250  			Voxels uint64 `json:"voxels"`
  1251  		}
  1252  		if err := json.Unmarshal(r, &jsonVal); err != nil {
  1253  			t.Fatalf("unable to get size for label %d: %v", label, err)
  1254  		}
  1255  		if jsonVal.Voxels != expectedSize {
  1256  			t.Errorf("thought label %d would have %d voxels, got %d\n", label, expectedSize, jsonVal.Voxels)
  1257  		}
  1258  	}
  1259  	reqStr := fmt.Sprintf("%snode/%s/labels/size/3", server.WebAPIPath, uuid)
  1260  	server.TestBadHTTP(t, "GET", reqStr, nil)
  1261  
  1262  	reqStr = fmt.Sprintf("%snode/%s/labels/sizes", server.WebAPIPath, uuid)
  1263  	bodystr := "[1, 2, 3, 13, 209, 311]"
  1264  	r := server.TestHTTP(t, "GET", reqStr, bytes.NewBufferString(bodystr))
  1265  	if string(r) != "[64000,64000,0,64000,64000,64000]" {
  1266  		t.Errorf("bad batch sizes result.  got: %s\n", string(r))
  1267  	}
  1268  
  1269  	// Verify the label streaming endpoint.
  1270  	reqStr = fmt.Sprintf("%snode/%s/labels/listlabels", server.WebAPIPath, uuid)
  1271  	r = server.TestHTTP(t, "GET", reqStr, nil)
  1272  	if len(r) != len(expectedLabels)*8 {
  1273  		t.Errorf("expected %d labels from /listlabels but got %d bytes\n", len(expectedLabels), len(r))
  1274  	}
  1275  	for i, label := range expectedLabels {
  1276  		gotLabel := binary.LittleEndian.Uint64(r[i*8 : i*8+8])
  1277  		if label != gotLabel {
  1278  			t.Errorf("expected label %d but got %d in /listlabels pos %d\n", label, gotLabel, i)
  1279  		}
  1280  	}
  1281  	reqStr = fmt.Sprintf("%snode/%s/labels/listlabels?start=4&number=2", server.WebAPIPath, uuid)
  1282  	r = server.TestHTTP(t, "GET", reqStr, nil)
  1283  	if len(r) != 2*8 {
  1284  		t.Fatalf("expected %d labels from /listlabels but got %d bytes\n", 2, len(r))
  1285  	}
  1286  	for i, label := range expectedLabels[2:4] {
  1287  		gotLabel := binary.LittleEndian.Uint64(r[i*8 : i*8+8])
  1288  		if label != gotLabel {
  1289  			t.Errorf("expected label %d but got %d in /listlabels pos %d\n", label, gotLabel, i)
  1290  		}
  1291  	}
  1292  
  1293  	// Verify the label + voxel count streaming endpoint.
  1294  	reqStr = fmt.Sprintf("%snode/%s/labels/listlabels?sizes=true", server.WebAPIPath, uuid)
  1295  	r = server.TestHTTP(t, "GET", reqStr, nil)
  1296  	if len(r) != len(expectedLabels)*16 {
  1297  		t.Errorf("expected %d labels and sizes from /listlabels but got %d bytes\n", len(expectedLabels), len(r))
  1298  	}
  1299  	for i, label := range expectedLabels {
  1300  		gotLabel := binary.LittleEndian.Uint64(r[i*16 : i*16+8])
  1301  		if label != gotLabel {
  1302  			t.Errorf("expected label %d but got %d in /listlabels pos %d\n", label, gotLabel, i)
  1303  		}
  1304  		gotSize := binary.LittleEndian.Uint64(r[i*16+8 : i*16+16])
  1305  		if expectedSize != gotSize {
  1306  			t.Errorf("expected size %d for label %d but got %d in /listlabels pos %d\n", expectedSize, label, gotSize, i)
  1307  		}
  1308  	}
  1309  
  1310  	// Check the first downres: 64^3
  1311  	downres1 := newTestVolume(64, 64, 64)
  1312  	downres1.getScale(t, uuid, "labels", 1, false)
  1313  	downres1.verifyLabel(t, 1, 30, 30, 30)
  1314  	downres1.verifyLabel(t, 2, 21, 21, 45)
  1315  	downres1.verifyLabel(t, 13, 45, 21, 36)
  1316  	downres1.verifyLabel(t, 209, 21, 50, 35)
  1317  	downres1.verifyLabel(t, 311, 45, 55, 35)
  1318  	expected1 := newTestVolume(64, 64, 64)
  1319  	expected1.addSubvol(dvid.Point3d{20, 20, 20}, dvid.Point3d{20, 20, 20}, 1)
  1320  	expected1.addSubvol(dvid.Point3d{20, 20, 40}, dvid.Point3d{20, 20, 20}, 2)
  1321  	expected1.addSubvol(dvid.Point3d{40, 20, 20}, dvid.Point3d{20, 20, 20}, 13)
  1322  	expected1.addSubvol(dvid.Point3d{20, 40, 20}, dvid.Point3d{20, 20, 20}, 209)
  1323  	expected1.addSubvol(dvid.Point3d{40, 40, 20}, dvid.Point3d{20, 20, 20}, 311)
  1324  	if err := downres1.equals(expected1); err != nil {
  1325  		t.Errorf("1st downres 'labels' isn't what is expected: %v\n", err)
  1326  	}
  1327  
  1328  	// Check the second downres to voxel: 32^3
  1329  	expected2 := newTestVolume(32, 32, 32)
  1330  	expected2.addSubvol(dvid.Point3d{10, 10, 10}, dvid.Point3d{10, 10, 10}, 1)
  1331  	expected2.addSubvol(dvid.Point3d{10, 10, 20}, dvid.Point3d{10, 10, 10}, 2)
  1332  	expected2.addSubvol(dvid.Point3d{20, 10, 10}, dvid.Point3d{10, 10, 10}, 13)
  1333  	expected2.addSubvol(dvid.Point3d{10, 20, 10}, dvid.Point3d{10, 10, 10}, 209)
  1334  	expected2.addSubvol(dvid.Point3d{20, 20, 10}, dvid.Point3d{10, 10, 10}, 311)
  1335  	downres2 := newTestVolume(32, 32, 32)
  1336  	downres2.getScale(t, uuid, "labels", 2, false)
  1337  	if err := downres2.equals(expected2); err != nil {
  1338  		t.Errorf("2nd downres 'labels' isn't what is expected: %v\n", err)
  1339  	}
  1340  
  1341  	// // Check blocks endpoint for different scales.
  1342  	volume.testGetBlocks(t, "hi-res block check", uuid, "labels", "", 0)
  1343  	volume.testGetBlocks(t, "hi-res block check", uuid, "labels", "uncompressed", 0)
  1344  	volume.testGetBlocks(t, "hi-res block check", uuid, "labels", "blocks", 0)
  1345  	volume.testGetBlocks(t, "hi-res block check", uuid, "labels", "gzip", 0)
  1346  
  1347  	expected1.testGetBlocks(t, "downres #1 block check", uuid, "labels", "", 1)
  1348  	expected1.testGetBlocks(t, "downres #1 block check", uuid, "labels", "uncompressed", 1)
  1349  	expected1.testGetBlocks(t, "downres #1 block check", uuid, "labels", "blocks", 1)
  1350  	expected1.testGetBlocks(t, "downres #1 block check", uuid, "labels", "gzip", 1)
  1351  
  1352  	expected2a := newTestVolume(64, 64, 64) // can only get block-aligned subvolumes
  1353  	expected2a.addSubvol(dvid.Point3d{10, 10, 10}, dvid.Point3d{10, 10, 10}, 1)
  1354  	expected2a.addSubvol(dvid.Point3d{10, 10, 20}, dvid.Point3d{10, 10, 10}, 2)
  1355  	expected2a.addSubvol(dvid.Point3d{20, 10, 10}, dvid.Point3d{10, 10, 10}, 13)
  1356  	expected2a.addSubvol(dvid.Point3d{10, 20, 10}, dvid.Point3d{10, 10, 10}, 209)
  1357  	expected2a.addSubvol(dvid.Point3d{20, 20, 10}, dvid.Point3d{10, 10, 10}, 311)
  1358  	expected2a.testGetBlocks(t, "downres #2 block check", uuid, "labels", "", 2)
  1359  	expected2a.testGetBlocks(t, "downres #2 block check", uuid, "labels", "uncompressed", 2)
  1360  	expected2a.testGetBlocks(t, "downres #2 block check", uuid, "labels", "blocks", 2)
  1361  	expected2a.testGetBlocks(t, "downres #2 block check", uuid, "labels", "gzip", 2)
  1362  }
  1363  
  1364  // TestMultiscaleIngest2 tests ingesting using the /ingest-supervoxels endpoint.
  1365  func TestMultiscaleIngest2(t *testing.T) {
  1366  	if err := server.OpenTest(); err != nil {
  1367  		t.Fatalf("can't open test server: %v\n", err)
  1368  	}
  1369  	defer server.CloseTest()
  1370  
  1371  	// Create testbed volume and data instances
  1372  	uuid, _ := initTestRepo()
  1373  	var config dvid.Config
  1374  	config.Set("MaxDownresLevel", "2")
  1375  	server.CreateTestInstance(t, uuid, "labelmap", "labels", config)
  1376  
  1377  	// Create an easily interpreted label volume with a couple of labels.
  1378  	volume := newTestVolume(128, 128, 128)
  1379  	volume.addSubvol(dvid.Point3d{40, 40, 40}, dvid.Point3d{40, 40, 40}, 1)
  1380  	volume.addSubvol(dvid.Point3d{40, 40, 80}, dvid.Point3d{40, 40, 40}, 2)
  1381  	volume.addSubvol(dvid.Point3d{80, 40, 40}, dvid.Point3d{40, 40, 40}, 13)
  1382  	volume.addSubvol(dvid.Point3d{40, 80, 40}, dvid.Point3d{40, 40, 40}, 209)
  1383  	volume.addSubvol(dvid.Point3d{80, 80, 40}, dvid.Point3d{40, 40, 40}, 311)
  1384  	volume.put(t, uuid, "labels")
  1385  
  1386  	// Verify initial ingest for hi-res
  1387  	if err := downres.BlockOnUpdating(uuid, "labels"); err != nil {
  1388  		t.Fatalf("Error blocking on update for labels: %v\n", err)
  1389  	}
  1390  
  1391  	hires := newTestVolume(128, 128, 128)
  1392  	hires.get(t, uuid, "labels", false)
  1393  	hires.verifyLabel(t, 1, 45, 45, 45)
  1394  	hires.verifyLabel(t, 2, 50, 50, 100)
  1395  	hires.verifyLabel(t, 13, 100, 60, 60)
  1396  	hires.verifyLabel(t, 209, 55, 100, 55)
  1397  	hires.verifyLabel(t, 311, 81, 81, 41)
  1398  
  1399  	expectedLabels := []uint64{1, 2, 13, 209, 311}
  1400  	expectedSize := uint64(40 * 40 * 40)
  1401  
  1402  	// Verify our label index voxel counts are correct.
  1403  	for _, label := range expectedLabels {
  1404  		reqStr := fmt.Sprintf("%snode/%s/labels/size/%d", server.WebAPIPath, uuid, label)
  1405  		r := server.TestHTTP(t, "GET", reqStr, nil)
  1406  		var jsonVal struct {
  1407  			Voxels uint64 `json:"voxels"`
  1408  		}
  1409  		if err := json.Unmarshal(r, &jsonVal); err != nil {
  1410  			t.Fatalf("unable to get size for label %d: %v", label, err)
  1411  		}
  1412  		if jsonVal.Voxels != expectedSize {
  1413  			t.Errorf("thought label %d would have %d voxels, got %d\n", label, expectedSize, jsonVal.Voxels)
  1414  		}
  1415  	}
  1416  	reqStr := fmt.Sprintf("%snode/%s/labels/size/3", server.WebAPIPath, uuid)
  1417  	server.TestBadHTTP(t, "GET", reqStr, nil)
  1418  
  1419  	reqStr = fmt.Sprintf("%snode/%s/labels/sizes", server.WebAPIPath, uuid)
  1420  	bodystr := "[1, 2, 3, 13, 209, 311]"
  1421  	r := server.TestHTTP(t, "GET", reqStr, bytes.NewBufferString(bodystr))
  1422  	if string(r) != "[64000,64000,0,64000,64000,64000]" {
  1423  		t.Errorf("bad batch sizes result.  got: %s\n", string(r))
  1424  	}
  1425  
  1426  	// Verify the label streaming endpoint.
  1427  	reqStr = fmt.Sprintf("%snode/%s/labels/listlabels", server.WebAPIPath, uuid)
  1428  	r = server.TestHTTP(t, "GET", reqStr, nil)
  1429  	if len(r) != len(expectedLabels)*8 {
  1430  		t.Errorf("expected %d labels from /listlabels but got %d bytes\n", len(expectedLabels), len(r))
  1431  	}
  1432  	for i, label := range expectedLabels {
  1433  		gotLabel := binary.LittleEndian.Uint64(r[i*8 : i*8+8])
  1434  		if label != gotLabel {
  1435  			t.Errorf("expected label %d but got %d in /listlabels pos %d\n", label, gotLabel, i)
  1436  		}
  1437  	}
  1438  	reqStr = fmt.Sprintf("%snode/%s/labels/listlabels?start=4&number=2", server.WebAPIPath, uuid)
  1439  	r = server.TestHTTP(t, "GET", reqStr, nil)
  1440  	if len(r) != 2*8 {
  1441  		t.Fatalf("expected %d labels from /listlabels but got %d bytes\n", 2, len(r))
  1442  	}
  1443  	for i, label := range expectedLabels[2:4] {
  1444  		gotLabel := binary.LittleEndian.Uint64(r[i*8 : i*8+8])
  1445  		if label != gotLabel {
  1446  			t.Errorf("expected label %d but got %d in /listlabels pos %d\n", label, gotLabel, i)
  1447  		}
  1448  	}
  1449  
  1450  	// Verify the label + voxel count streaming endpoint.
  1451  	reqStr = fmt.Sprintf("%snode/%s/labels/listlabels?sizes=true", server.WebAPIPath, uuid)
  1452  	r = server.TestHTTP(t, "GET", reqStr, nil)
  1453  	if len(r) != len(expectedLabels)*16 {
  1454  		t.Errorf("expected %d labels and sizes from /listlabels but got %d bytes\n", len(expectedLabels), len(r))
  1455  	}
  1456  	for i, label := range expectedLabels {
  1457  		gotLabel := binary.LittleEndian.Uint64(r[i*16 : i*16+8])
  1458  		if label != gotLabel {
  1459  			t.Errorf("expected label %d but got %d in /listlabels pos %d\n", label, gotLabel, i)
  1460  		}
  1461  		gotSize := binary.LittleEndian.Uint64(r[i*16+8 : i*16+16])
  1462  		if expectedSize != gotSize {
  1463  			t.Errorf("expected size %d for label %d but got %d in /listlabels pos %d\n", expectedSize, label, gotSize, i)
  1464  		}
  1465  	}
  1466  
  1467  	// Check the first downres: 64^3
  1468  	downres1 := newTestVolume(64, 64, 64)
  1469  	downres1.getScale(t, uuid, "labels", 1, false)
  1470  	downres1.verifyLabel(t, 1, 30, 30, 30)
  1471  	downres1.verifyLabel(t, 2, 21, 21, 45)
  1472  	downres1.verifyLabel(t, 13, 45, 21, 36)
  1473  	downres1.verifyLabel(t, 209, 21, 50, 35)
  1474  	downres1.verifyLabel(t, 311, 45, 55, 35)
  1475  	expected1 := newTestVolume(64, 64, 64)
  1476  	expected1.addSubvol(dvid.Point3d{20, 20, 20}, dvid.Point3d{20, 20, 20}, 1)
  1477  	expected1.addSubvol(dvid.Point3d{20, 20, 40}, dvid.Point3d{20, 20, 20}, 2)
  1478  	expected1.addSubvol(dvid.Point3d{40, 20, 20}, dvid.Point3d{20, 20, 20}, 13)
  1479  	expected1.addSubvol(dvid.Point3d{20, 40, 20}, dvid.Point3d{20, 20, 20}, 209)
  1480  	expected1.addSubvol(dvid.Point3d{40, 40, 20}, dvid.Point3d{20, 20, 20}, 311)
  1481  	if err := downres1.equals(expected1); err != nil {
  1482  		t.Errorf("1st downres 'labels' isn't what is expected: %v\n", err)
  1483  	}
  1484  
  1485  	// Check the second downres to voxel: 32^3
  1486  	expected2 := newTestVolume(32, 32, 32)
  1487  	expected2.addSubvol(dvid.Point3d{10, 10, 10}, dvid.Point3d{10, 10, 10}, 1)
  1488  	expected2.addSubvol(dvid.Point3d{10, 10, 20}, dvid.Point3d{10, 10, 10}, 2)
  1489  	expected2.addSubvol(dvid.Point3d{20, 10, 10}, dvid.Point3d{10, 10, 10}, 13)
  1490  	expected2.addSubvol(dvid.Point3d{10, 20, 10}, dvid.Point3d{10, 10, 10}, 209)
  1491  	expected2.addSubvol(dvid.Point3d{20, 20, 10}, dvid.Point3d{10, 10, 10}, 311)
  1492  	downres2 := newTestVolume(32, 32, 32)
  1493  	downres2.getScale(t, uuid, "labels", 2, false)
  1494  	if err := downres2.equals(expected2); err != nil {
  1495  		t.Errorf("2nd downres 'labels' isn't what is expected: %v\n", err)
  1496  	}
  1497  
  1498  	// // Check blocks endpoint for different scales.
  1499  	volume.testGetBlocks(t, "hi-res block check", uuid, "labels", "", 0)
  1500  	volume.testGetBlocks(t, "hi-res block check", uuid, "labels", "uncompressed", 0)
  1501  	volume.testGetBlocks(t, "hi-res block check", uuid, "labels", "blocks", 0)
  1502  	volume.testGetBlocks(t, "hi-res block check", uuid, "labels", "gzip", 0)
  1503  
  1504  	expected1.testGetBlocks(t, "downres #1 block check", uuid, "labels", "", 1)
  1505  	expected1.testGetBlocks(t, "downres #1 block check", uuid, "labels", "uncompressed", 1)
  1506  	expected1.testGetBlocks(t, "downres #1 block check", uuid, "labels", "blocks", 1)
  1507  	expected1.testGetBlocks(t, "downres #1 block check", uuid, "labels", "gzip", 1)
  1508  
  1509  	expected2a := newTestVolume(64, 64, 64) // can only get block-aligned subvolumes
  1510  	expected2a.addSubvol(dvid.Point3d{10, 10, 10}, dvid.Point3d{10, 10, 10}, 1)
  1511  	expected2a.addSubvol(dvid.Point3d{10, 10, 20}, dvid.Point3d{10, 10, 10}, 2)
  1512  	expected2a.addSubvol(dvid.Point3d{20, 10, 10}, dvid.Point3d{10, 10, 10}, 13)
  1513  	expected2a.addSubvol(dvid.Point3d{10, 20, 10}, dvid.Point3d{10, 10, 10}, 209)
  1514  	expected2a.addSubvol(dvid.Point3d{20, 20, 10}, dvid.Point3d{10, 10, 10}, 311)
  1515  	expected2a.testGetBlocks(t, "downres #2 block check", uuid, "labels", "", 2)
  1516  	expected2a.testGetBlocks(t, "downres #2 block check", uuid, "labels", "uncompressed", 2)
  1517  	expected2a.testGetBlocks(t, "downres #2 block check", uuid, "labels", "blocks", 2)
  1518  	expected2a.testGetBlocks(t, "downres #2 block check", uuid, "labels", "gzip", 2)
  1519  }
  1520  
  1521  // tests vanishing labels when they are downres out of existence
  1522  func TestMultiscaleVanish(t *testing.T) {
  1523  	if err := server.OpenTest(); err != nil {
  1524  		t.Fatalf("can't open test server: %v\n", err)
  1525  	}
  1526  	defer server.CloseTest()
  1527  
  1528  	// Create testbed volume and data instances
  1529  	uuid, _ := initTestRepo()
  1530  	var config dvid.Config
  1531  	config.Set("MaxDownresLevel", "8")
  1532  	server.CreateTestInstance(t, uuid, "labelmap", "labels", config)
  1533  
  1534  	hires := newTestVolume(128, 128, 128)
  1535  	hires.addSubvol(dvid.Point3d{0, 0, 0}, dvid.Point3d{128, 128, 128}, 1)
  1536  	hires.addSubvol(dvid.Point3d{40, 40, 40}, dvid.Point3d{2, 2, 2}, 2)
  1537  	hires.addSubvol(dvid.Point3d{16, 16, 16}, dvid.Point3d{4, 4, 4}, 3)
  1538  	hires.addSubvol(dvid.Point3d{1, 1, 1}, dvid.Point3d{1, 1, 1}, 4)
  1539  	hires.put(t, uuid, "labels")
  1540  	if err := downres.BlockOnUpdating(uuid, "labels"); err != nil {
  1541  		t.Fatalf("Error blocking on update for labels: %v\n", err)
  1542  	}
  1543  
  1544  	// at hires all spares volumes should exist
  1545  	reqStr := fmt.Sprintf("%snode/%s/labels/sparsevol/1", server.WebAPIPath, uuid)
  1546  	encoding := server.TestHTTP(t, "GET", reqStr, nil)
  1547  	if len(encoding) == 0 {
  1548  		t.Fatalf("expected non-zero sparsevol return for label 1")
  1549  	}
  1550  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/2", server.WebAPIPath, uuid)
  1551  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1552  	if len(encoding) == 0 {
  1553  		t.Fatalf("expected non-zero sparsevol return for label 2")
  1554  	}
  1555  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/3", server.WebAPIPath, uuid)
  1556  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1557  	if len(encoding) == 0 {
  1558  		t.Fatalf("expected non-zero sparsevol return for label 3")
  1559  	}
  1560  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/4", server.WebAPIPath, uuid)
  1561  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1562  	if len(encoding) == 0 {
  1563  		t.Fatalf("expected non-zero sparsevol return for label 4")
  1564  	}
  1565  
  1566  	// -- test bounds
  1567  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/3?minx=14&maxx=18", server.WebAPIPath, uuid)
  1568  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1569  	if len(encoding) == 0 {
  1570  		t.Fatalf("expected non-zero sparsevol return for label 3 with bounds")
  1571  	}
  1572  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/3?minx=10&maxx=15", server.WebAPIPath, uuid)
  1573  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1574  	if len(encoding) != 0 {
  1575  		t.Fatalf("expected zero sparsevol return for label 3 with out-of-scope bounds, got %d bytes", len(encoding))
  1576  	}
  1577  
  1578  	// downres 1: 4 should drop out
  1579  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/1?scale=1", server.WebAPIPath, uuid)
  1580  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1581  	if len(encoding) == 0 {
  1582  		t.Fatalf("expected non-zero sparsevol return for label 1")
  1583  	}
  1584  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/2?scale=1", server.WebAPIPath, uuid)
  1585  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1586  	if len(encoding) == 0 {
  1587  		t.Fatalf("expected non-zero sparsevol return for label 3")
  1588  	}
  1589  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/3?scale=1", server.WebAPIPath, uuid)
  1590  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1591  	if len(encoding) == 0 {
  1592  		t.Fatalf("expected non-zero sparsevol return for label 3")
  1593  	}
  1594  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/4?scale=1", server.WebAPIPath, uuid)
  1595  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1596  	if len(encoding) != 0 {
  1597  		t.Fatalf("expected zero sparsevol return for label 4")
  1598  	}
  1599  
  1600  	// -- test bounds
  1601  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/3?scale=1&minx=7&maxx=9", server.WebAPIPath, uuid)
  1602  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1603  	if len(encoding) == 0 {
  1604  		t.Fatalf("expected non-zero level-1 sparsevol return for label 3 with bounds")
  1605  	}
  1606  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/3?scale=1&minx=5&maxx=7", server.WebAPIPath, uuid)
  1607  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1608  	if len(encoding) != 0 {
  1609  		t.Fatalf("expected zero level-1 sparsevol return for label 3 with out-of-scope bounds, got %d bytes", len(encoding))
  1610  	}
  1611  
  1612  	// downres 2: 2 should drop out
  1613  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/1?scale=2", server.WebAPIPath, uuid)
  1614  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1615  	if len(encoding) == 0 {
  1616  		t.Fatalf("expected non-zero sparsevol return for label 1")
  1617  	}
  1618  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/2?scale=2", server.WebAPIPath, uuid)
  1619  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1620  	if len(encoding) != 0 {
  1621  		t.Fatalf("expected zero sparsevol return for label 2")
  1622  	}
  1623  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/3?scale=2", server.WebAPIPath, uuid)
  1624  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1625  	if len(encoding) == 0 {
  1626  		t.Fatalf("expected non-zero sparsevol return for label 3")
  1627  	}
  1628  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/4?scale=2", server.WebAPIPath, uuid)
  1629  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1630  	if len(encoding) != 0 {
  1631  		t.Fatalf("expected zero sparsevol return for label 4")
  1632  	}
  1633  
  1634  	// downres 3: 3 should drop out
  1635  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/1?scale=3", server.WebAPIPath, uuid)
  1636  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1637  	if len(encoding) == 0 {
  1638  		t.Fatalf("expected non-zero sparsevol return for label 1")
  1639  	}
  1640  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/2?scale=3", server.WebAPIPath, uuid)
  1641  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1642  	if len(encoding) != 0 {
  1643  		t.Fatalf("expected zero sparsevol return for label 2")
  1644  	}
  1645  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/3?scale=3", server.WebAPIPath, uuid)
  1646  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1647  	if len(encoding) != 0 {
  1648  		t.Fatalf("expected zero sparsevol return for label 3")
  1649  	}
  1650  	reqStr = fmt.Sprintf("%snode/%s/labels/sparsevol/4?scale=3", server.WebAPIPath, uuid)
  1651  	encoding = server.TestHTTP(t, "GET", reqStr, nil)
  1652  	if len(encoding) != 0 {
  1653  		t.Fatalf("expected zero sparsevol return for label 4")
  1654  	}
  1655  }
  1656  
  1657  func readGzipFile(filename string) ([]byte, error) {
  1658  	f, err := os.Open(filename)
  1659  	if err != nil {
  1660  		return nil, err
  1661  	}
  1662  	defer f.Close()
  1663  
  1664  	fz, err := gzip.NewReader(f)
  1665  	if err != nil {
  1666  		return nil, err
  1667  	}
  1668  	defer fz.Close()
  1669  
  1670  	data, err := ioutil.ReadAll(fz)
  1671  	if err != nil {
  1672  		return nil, err
  1673  	}
  1674  	return data, nil
  1675  }
  1676  
  1677  type testData struct {
  1678  	u        []uint64
  1679  	b        *labels.Block
  1680  	filename string
  1681  }
  1682  
  1683  func (d testData) String() string {
  1684  	return filepath.Base(d.filename)
  1685  }
  1686  
  1687  func solidTestData(label uint64) (td testData) {
  1688  	td.b = labels.MakeSolidBlock(label, dvid.Point3d{64, 64, 64})
  1689  	numVoxels := 64 * 64 * 64
  1690  	td.u = make([]uint64, numVoxels)
  1691  	td.filename = fmt.Sprintf("solid volume of label %d", label)
  1692  	for i := 0; i < numVoxels; i++ {
  1693  		td.u[i] = label
  1694  	}
  1695  	return
  1696  }
  1697  
  1698  var testFiles = []string{
  1699  	"../../test_data/fib19-64x64x64-sample1.dat.gz",
  1700  	"../../test_data/fib19-64x64x64-sample2.dat.gz",
  1701  	"../../test_data/cx-64x64x64-sample1.dat.gz",
  1702  	"../../test_data/cx-64x64x64-sample2.dat.gz",
  1703  }
  1704  
  1705  func loadTestData(t *testing.T, filename string) (td testData) {
  1706  	uint64array, err := readGzipFile(filename)
  1707  	if err != nil {
  1708  		t.Fatalf("unable to open test data file %q: %v\n", filename, err)
  1709  	}
  1710  	td.u, err = dvid.ByteToUint64(uint64array)
  1711  	if err != nil {
  1712  		t.Fatalf("unable to create alias []uint64 for data file %q: %v\n", filename, err)
  1713  	}
  1714  	td.b, err = labels.MakeBlock(uint64array, dvid.Point3d{64, 64, 64})
  1715  	if err != nil {
  1716  		t.Fatalf("unable to convert data from file %q into block: %v\n", filename, err)
  1717  	}
  1718  	td.filename = filename
  1719  	return
  1720  }
  1721  
  1722  func writeTestInt32(t *testing.T, buf *bytes.Buffer, i int32) {
  1723  	b := make([]byte, 4)
  1724  	binary.LittleEndian.PutUint32(b, uint32(i))
  1725  	n, err := buf.Write(b)
  1726  	if n != 4 || err != nil {
  1727  		t.Fatalf("couldn't write value %d (%d bytes) to buffer: %v\n", i, n, err)
  1728  	}
  1729  }
  1730  
  1731  func testGetBlock(t *testing.T, uuid dvid.UUID, name string, bcoord dvid.Point3d, td testData) {
  1732  	apiStr := fmt.Sprintf("%snode/%s/%s/blocks/%d_%d_%d/%d_%d_%d?compression=blocks", server.WebAPIPath,
  1733  		uuid, name, 64, 64, 64, bcoord[0]*64, bcoord[1]*64, bcoord[2]*64)
  1734  	data := server.TestHTTP(t, "GET", apiStr, nil)
  1735  
  1736  	b := 0
  1737  	if b+16 > len(data) {
  1738  		t.Fatalf("Only got %d bytes back from block API call\n", len(data))
  1739  	}
  1740  	x := int32(binary.LittleEndian.Uint32(data[b : b+4]))
  1741  	b += 4
  1742  	y := int32(binary.LittleEndian.Uint32(data[b : b+4]))
  1743  	b += 4
  1744  	z := int32(binary.LittleEndian.Uint32(data[b : b+4]))
  1745  	b += 4
  1746  	n := int(binary.LittleEndian.Uint32(data[b : b+4]))
  1747  	b += 4
  1748  	if x != bcoord[0] || y != bcoord[1] || z != bcoord[2] {
  1749  		t.Fatalf("Bad block coordinate: expected %s, got (%d,%d,%d)\n", bcoord, x, y, z)
  1750  	}
  1751  
  1752  	gzipIn := bytes.NewBuffer(data[b : b+n])
  1753  	zr, err := gzip.NewReader(gzipIn)
  1754  	if err != nil {
  1755  		t.Fatalf("can't uncompress gzip block: %v\n", err)
  1756  	}
  1757  	uncompressed, err := ioutil.ReadAll(zr)
  1758  	if err != nil {
  1759  		t.Fatalf("can't uncompress gzip block: %v\n", err)
  1760  	}
  1761  	zr.Close()
  1762  
  1763  	var block labels.Block
  1764  	if err = block.UnmarshalBinary(uncompressed); err != nil {
  1765  		t.Fatalf("unable to deserialize label block (%d, %d, %d): %v\n", x, y, z, err)
  1766  	}
  1767  	izyx := dvid.IndexZYX{bcoord[0], bcoord[1], bcoord[2]}
  1768  	checkBlock(t, labels.PositionedBlock{block, izyx.ToIZYXString()}, td)
  1769  }
  1770  
  1771  func checkBlock(t *testing.T, pb labels.PositionedBlock, td testData) {
  1772  	bytearray, _ := pb.Block.MakeLabelVolume()
  1773  	uint64array, err := dvid.AliasByteToUint64(bytearray)
  1774  	if err != nil {
  1775  		t.Fatalf("error converting returned block %s to uint64 array: %v\n", pb.BCoord, err)
  1776  	}
  1777  	if len(uint64array) != len(td.u) {
  1778  		t.Fatalf("got block %s with %d labels != expected %d labels\n", pb.BCoord, len(uint64array), len(td.u))
  1779  	}
  1780  	for i, val := range uint64array {
  1781  		if val != td.u[i] {
  1782  			t.Fatalf("error in block %s, pos %d: got label %d, expected label %d\n", pb.BCoord, i, val, td.u[i])
  1783  		}
  1784  	}
  1785  	runtime.KeepAlive(&bytearray)
  1786  }
  1787  
  1788  func decodeReturnedBlocks(t *testing.T, data []byte) []labels.PositionedBlock {
  1789  	var blocks []labels.PositionedBlock
  1790  	b := 0
  1791  	for {
  1792  		if b+16 > len(data) {
  1793  			t.Fatalf("Only got %d bytes back from block API call\n", len(data))
  1794  		}
  1795  		x := int32(binary.LittleEndian.Uint32(data[b : b+4]))
  1796  		b += 4
  1797  		y := int32(binary.LittleEndian.Uint32(data[b : b+4]))
  1798  		b += 4
  1799  		z := int32(binary.LittleEndian.Uint32(data[b : b+4]))
  1800  		b += 4
  1801  		n := int(binary.LittleEndian.Uint32(data[b : b+4]))
  1802  		b += 4
  1803  		bcoord := dvid.ChunkPoint3d{x, y, z}.ToIZYXString()
  1804  
  1805  		dvid.Infof("uncompressing block (%d,%d,%d) of %d bytes...\n", x, y, z, n)
  1806  		gzipIn := bytes.NewBuffer(data[b : b+n])
  1807  		zr, err := gzip.NewReader(gzipIn)
  1808  		if err != nil {
  1809  			t.Fatalf("can't uncompress gzip block: %v\n", err)
  1810  		}
  1811  		uncompressed, err := ioutil.ReadAll(zr)
  1812  		if err != nil {
  1813  			t.Fatalf("can't uncompress gzip block: %v\n", err)
  1814  		}
  1815  		zr.Close()
  1816  
  1817  		var block labels.Block
  1818  		if err = block.UnmarshalBinary(uncompressed); err != nil {
  1819  			t.Fatalf("unable to deserialize label block (%d, %d, %d): %v\n", x, y, z, err)
  1820  		}
  1821  		blocks = append(blocks, labels.PositionedBlock{BCoord: bcoord, Block: block})
  1822  		b += n
  1823  		if len(data) == b {
  1824  			break
  1825  		}
  1826  	}
  1827  	return blocks
  1828  }
  1829  
  1830  func testGetSpecificBlocks(t *testing.T, uuid dvid.UUID, name string, supervoxels bool, bcoordStr string) []labels.PositionedBlock {
  1831  	apiStr := fmt.Sprintf("%snode/%s/%s/specificblocks?compression=blocks&supervoxels=%t&blocks=%s", server.WebAPIPath,
  1832  		uuid, name, supervoxels, bcoordStr)
  1833  	data := server.TestHTTP(t, "GET", apiStr, nil)
  1834  	return decodeReturnedBlocks(t, data)
  1835  }
  1836  
  1837  func testGetVolumeBlocks(t *testing.T, uuid dvid.UUID, name string, supervoxels bool, size, offset dvid.Point3d) []labels.PositionedBlock {
  1838  	apiStr := fmt.Sprintf("%snode/%s/%s/blocks/%d_%d_%d/%d_%d_%d?compression=blocks&supervoxels=%t", server.WebAPIPath,
  1839  		uuid, name, size[0], size[1], size[2], offset[0], offset[1], offset[2], supervoxels)
  1840  	data := server.TestHTTP(t, "GET", apiStr, nil)
  1841  	return decodeReturnedBlocks(t, data)
  1842  }
  1843  
  1844  func TestPostBlocks(t *testing.T) {
  1845  	if err := server.OpenTest(); err != nil {
  1846  		t.Fatalf("can't open test server: %v\n", err)
  1847  	}
  1848  	defer server.CloseTest()
  1849  
  1850  	uuid, _ := datastore.NewTestRepo()
  1851  	if len(uuid) < 5 {
  1852  		t.Fatalf("Bad root UUID for new repo: %s\n", uuid)
  1853  	}
  1854  	server.CreateTestInstance(t, uuid, "labelmap", "labels", dvid.Config{})
  1855  
  1856  	blockCoords := []dvid.Point3d{
  1857  		{1, 2, 3},
  1858  		{2, 2, 3},
  1859  		{1, 3, 4},
  1860  		{2, 3, 4},
  1861  	}
  1862  	var data [4]testData
  1863  	var buf bytes.Buffer
  1864  	for i, fname := range testFiles {
  1865  		writeTestInt32(t, &buf, blockCoords[i][0])
  1866  		writeTestInt32(t, &buf, blockCoords[i][1])
  1867  		writeTestInt32(t, &buf, blockCoords[i][2])
  1868  		data[i] = loadTestData(t, fname)
  1869  		gzipped, err := data[i].b.CompressGZIP()
  1870  		if err != nil {
  1871  			t.Fatalf("unable to gzip compress block: %v\n", err)
  1872  		}
  1873  		writeTestInt32(t, &buf, int32(len(gzipped)))
  1874  		n, err := buf.Write(gzipped)
  1875  		if err != nil {
  1876  			t.Fatalf("unable to write gzip block: %v\n", err)
  1877  		}
  1878  		if n != len(gzipped) {
  1879  			t.Fatalf("unable to write %d bytes to buffer, only wrote %d bytes\n", len(gzipped), n)
  1880  		}
  1881  	}
  1882  
  1883  	apiStr := fmt.Sprintf("%snode/%s/labels/blocks", server.WebAPIPath, uuid)
  1884  	server.TestHTTP(t, "POST", apiStr, &buf)
  1885  
  1886  	if err := datastore.BlockOnUpdating(uuid, "labels"); err != nil {
  1887  		t.Fatalf("Error blocking on sync of labels: %v\n", err)
  1888  	}
  1889  
  1890  	// test volume GET
  1891  	start := dvid.Point3d{1 * 64, 2 * 64, 3 * 64}
  1892  	end := dvid.Point3d{3*64 - 1, 4*64 - 1, 5*64 - 1}
  1893  	testExtents(t, "labels", uuid, start, end)
  1894  
  1895  	vol := labelVol{
  1896  		size:      dvid.Point3d{2, 2, 2}, // in blocks
  1897  		nx:        128,
  1898  		ny:        128,
  1899  		nz:        128,
  1900  		blockSize: dvid.Point3d{64, 64, 64},
  1901  		offset:    dvid.Point3d{64, 128, 192},
  1902  		name:      "labels",
  1903  	}
  1904  	got := vol.getLabelVolume(t, uuid, "", "")
  1905  	gotLabels, err := dvid.AliasByteToUint64(got)
  1906  	if err != nil {
  1907  		t.Fatal(err)
  1908  	}
  1909  	var bcoordStr string
  1910  	for i := 0; i < 4; i++ {
  1911  		x0 := (blockCoords[i][0] - 1) * 64
  1912  		y0 := (blockCoords[i][1] - 2) * 64
  1913  		z0 := (blockCoords[i][2] - 3) * 64
  1914  		bcoordStr += fmt.Sprintf("%d,%d,%d", blockCoords[i][0], blockCoords[i][1], blockCoords[i][2])
  1915  		if i != 3 {
  1916  			bcoordStr += ","
  1917  		}
  1918  		var x, y, z int32
  1919  		for z = 0; z < 64; z++ {
  1920  			for y = 0; y < 64; y++ {
  1921  				for x = 0; x < 64; x++ {
  1922  					di := z*64*64 + y*64 + x
  1923  					gi := (z+z0)*128*128 + (y+y0)*128 + x + x0
  1924  					if data[i].u[di] != gotLabels[gi] {
  1925  						t.Fatalf("Error in block %s dvid coord (%d,%d,%d): expected %d, got %d\n", blockCoords[i], x+x0, y+y0, z+z0, data[i].u[di], gotLabels[gi])
  1926  					}
  1927  				}
  1928  			}
  1929  		}
  1930  	}
  1931  	runtime.KeepAlive(&got)
  1932  
  1933  	// test GET /blocks
  1934  	for i, td := range data {
  1935  		testGetBlock(t, uuid, "labels", blockCoords[i], td)
  1936  	}
  1937  
  1938  	// test GET /specificblocks
  1939  	pblocks := testGetSpecificBlocks(t, uuid, "labels", true, bcoordStr)
  1940  	for i, td := range data {
  1941  		izyx := dvid.IndexZYX{blockCoords[i][0], blockCoords[i][1], blockCoords[i][2]}
  1942  		izyxStr := izyx.ToIZYXString()
  1943  		var j int
  1944  		for _, pb := range pblocks {
  1945  			if izyxStr == pb.BCoord {
  1946  				break
  1947  			}
  1948  			j++
  1949  		}
  1950  		if j == 4 {
  1951  			t.Fatalf("Didn't find block %s in retrieved blocks\n", izyxStr)
  1952  		}
  1953  		checkBlock(t, pblocks[j], td)
  1954  	}
  1955  	bcoordStr2 := "100,23,89,"
  1956  	for i := 0; i < 2; i++ {
  1957  		bcoordStr2 += fmt.Sprintf("%d,%d,%d,", blockCoords[i][0], blockCoords[i][1], blockCoords[i][2])
  1958  	}
  1959  	bcoordStr2 += "0,50,40"
  1960  	pblocks = testGetSpecificBlocks(t, uuid, "labels", true, bcoordStr2)
  1961  	if len(pblocks) != 2 {
  1962  		t.Fatalf("expected 2 blocks, got %d blocks instead\n", len(pblocks))
  1963  	}
  1964  	var gotBlocks int
  1965  	for _, pb := range pblocks {
  1966  		for i, td := range data {
  1967  			izyx := dvid.IndexZYX{blockCoords[i][0], blockCoords[i][1], blockCoords[i][2]}
  1968  			izyxStr := izyx.ToIZYXString()
  1969  			if izyxStr == pb.BCoord {
  1970  				gotBlocks++
  1971  				checkBlock(t, pb, td)
  1972  			}
  1973  		}
  1974  	}
  1975  	if gotBlocks != 2 {
  1976  		t.Fatalf("expected to receive 2 blocks, got %d instead\n", gotBlocks)
  1977  	}
  1978  
  1979  	// test GET /indices
  1980  	apiStr = fmt.Sprintf("%snode/%s/labels/indices", server.WebAPIPath, uuid)
  1981  	returnData := server.TestHTTP(t, "GET", apiStr, strings.NewReader(`[0, 1, 52011980226]`))
  1982  	var indices proto.LabelIndices
  1983  	if err := pb.Unmarshal(returnData, &indices); err != nil {
  1984  		t.Fatalf("error unmarshaling label indices: %v\n", err)
  1985  	}
  1986  	if len(indices.Indices) != 3 {
  1987  		t.Fatalf("expected 3 indices returned, got %d\n", len(indices.Indices))
  1988  	}
  1989  	if indices.Indices[0].Label != 0 || len(indices.Indices[0].Blocks) != 0 {
  1990  		t.Fatalf("got bad label 0 index return: %v\n", indices.Indices[0])
  1991  	}
  1992  	if indices.Indices[1].Label != 1 || len(indices.Indices[1].Blocks) != 0 {
  1993  		t.Fatalf("got bad label 1 index return: %v\n", indices.Indices[1])
  1994  	}
  1995  	if indices.Indices[2].Label != 52011980226 || len(indices.Indices[2].Blocks) != 1 && indices.Indices[2].Blocks[13194143727618].Counts[52011980226] != 7963 {
  1996  		t.Fatalf("got bad label 52011980226 index return: %v\n", indices.Indices[2])
  1997  	}
  1998  	server.TestBadHTTP(t, "GET", apiStr, nil)
  1999  	server.TestBadHTTP(t, "GET", apiStr, strings.NewReader(``))
  2000  	server.TestBadHTTP(t, "GET", apiStr, strings.NewReader(`{}`))
  2001  	returnData = server.TestHTTP(t, "GET", apiStr, strings.NewReader(`[]`))
  2002  	if returnData != nil {
  2003  		t.Fatalf("got non-nil response from bad request: %v\n", returnData)
  2004  	}
  2005  
  2006  	// test GET /indices-compressed
  2007  	apiStr = fmt.Sprintf("%snode/%s/labels/indices-compressed", server.WebAPIPath, uuid)
  2008  	returnData = server.TestHTTP(t, "GET", apiStr, strings.NewReader(`[0, 1, 52011980226]`))
  2009  
  2010  	i := 0
  2011  	datasize := binary.LittleEndian.Uint64(returnData[i : i+8])
  2012  	i += 8
  2013  	label := binary.LittleEndian.Uint64(returnData[i : i+8])
  2014  	if label != 0 || datasize != 0 {
  2015  		t.Fatalf("got bad label 0 index return: label %d, datasize %d\n", label, datasize)
  2016  	}
  2017  
  2018  	i += 8
  2019  	datasize = binary.LittleEndian.Uint64(returnData[i : i+8])
  2020  	i += 8
  2021  	label = binary.LittleEndian.Uint64(returnData[i : i+8])
  2022  	if label != 1 || datasize != 0 {
  2023  		t.Fatalf("got bad label 1 index return: label %d, datasize %d\n", label, datasize)
  2024  	}
  2025  
  2026  	i += 8
  2027  	datasize = binary.LittleEndian.Uint64(returnData[i : i+8])
  2028  	i += 8
  2029  	label = binary.LittleEndian.Uint64(returnData[i : i+8])
  2030  	i += 8
  2031  	if label != 52011980226 || datasize != 38 {
  2032  		t.Fatalf("got bad label 52011980226 index return: label %d, datasize %d\n", label, datasize)
  2033  	}
  2034  	idx := uncompressIndex(t, returnData[i:i+38])
  2035  	if idx.Label != 52011980226 || len(idx.Blocks) != 1 && idx.Blocks[13194143727618].Counts[52011980226] != 7963 {
  2036  		t.Fatalf("got bad label 52011980226 index return: %v\n", *idx)
  2037  	}
  2038  	server.TestBadHTTP(t, "GET", apiStr, nil)
  2039  	server.TestBadHTTP(t, "GET", apiStr, strings.NewReader(``))
  2040  	server.TestBadHTTP(t, "GET", apiStr, strings.NewReader(`{}`))
  2041  	returnData = server.TestHTTP(t, "GET", apiStr, strings.NewReader(`[]`))
  2042  	if returnData != nil {
  2043  		t.Fatalf("got non-nil response from bad request: %v\n", returnData)
  2044  	}
  2045  }
  2046  
  2047  func uncompressIndex(t *testing.T, data []byte) *labels.Index {
  2048  	val, _, err := dvid.DeserializeData(data, true)
  2049  	if err != nil {
  2050  		t.Fatalf("unable to uncompress label index data, %d bytes", len(data))
  2051  	}
  2052  
  2053  	idx := new(labels.Index)
  2054  	if err := pb.Unmarshal(val, idx); err != nil {
  2055  		t.Fatalf("unable to uncompress label index data, %d bytes", len(data))
  2056  	}
  2057  	return idx
  2058  }
  2059  
  2060  func testExtents(t *testing.T, name string, uuid dvid.UUID, min, max dvid.Point3d) {
  2061  	apiStr := fmt.Sprintf("%snode/%s/%s/metadata", server.WebAPIPath, uuid, name)
  2062  	r := server.TestHTTP(t, "GET", apiStr, nil)
  2063  	fmt.Printf("metadata: %s\n", string(r))
  2064  	jsonVal := make(map[string]interface{})
  2065  	if err := json.Unmarshal(r, &jsonVal); err != nil {
  2066  		t.Errorf("Unable to get metadata in JSON format.  Instead got: %v\n", jsonVal)
  2067  	}
  2068  	propData, ok := jsonVal["Properties"]
  2069  	if !ok {
  2070  		t.Fatalf("Could not parse Properties out of returned JSON: %v\n", jsonVal)
  2071  	}
  2072  	props, ok := propData.(map[string]interface{})
  2073  	if !ok {
  2074  		t.Fatalf("Could not create properties map: %v\n", propData)
  2075  	}
  2076  	pt, ok := props["MaxPoint"]
  2077  	if !ok {
  2078  		t.Fatalf("Couldn't get MaxPoint from Properties object: %v\n", props)
  2079  	}
  2080  	if pt == nil {
  2081  		t.Fatalf("Couldn't find MaxPoint in Properties object: %v\n", props)
  2082  	}
  2083  	maxPoint, ok := pt.([]interface{})
  2084  	if !ok {
  2085  		t.Fatalf("Couldn't parse MaxPoint %s: %v\n", reflect.TypeOf(pt), pt)
  2086  	}
  2087  	x, y, z := maxPoint[0].(float64), maxPoint[1].(float64), maxPoint[2].(float64)
  2088  	if x != float64(max[0]) {
  2089  		t.Errorf("Bad MaxPoint X: expected %.0f, got %d\n", x, max[0])
  2090  	}
  2091  	if y != float64(max[1]) {
  2092  		t.Errorf("Bad MaxPoint Y: expected %.0f, got %d\n", y, max[1])
  2093  	}
  2094  	if z != float64(max[2]) {
  2095  		t.Errorf("Bad MaxPoint Z: expected %.0f, got %d\n", z, max[2])
  2096  	}
  2097  }
  2098  
  2099  func TestIngestBlocks(t *testing.T) {
  2100  	if err := server.OpenTest(); err != nil {
  2101  		t.Fatalf("can't open test server: %v\n", err)
  2102  	}
  2103  	defer server.CloseTest()
  2104  
  2105  	uuid, _ := datastore.NewTestRepo()
  2106  	if len(uuid) < 5 {
  2107  		t.Fatalf("Bad root UUID for new repo: %s\n", uuid)
  2108  	}
  2109  	server.CreateTestInstance(t, uuid, "labelmap", "labels", dvid.Config{})
  2110  
  2111  	blockCoords := []dvid.Point3d{
  2112  		{1, 2, 3},
  2113  		{2, 2, 3},
  2114  		{1, 3, 4},
  2115  		{2, 3, 4},
  2116  	}
  2117  	var data [4]testData
  2118  	var buf bytes.Buffer
  2119  	for i, fname := range testFiles {
  2120  		writeTestInt32(t, &buf, blockCoords[i][0])
  2121  		writeTestInt32(t, &buf, blockCoords[i][1])
  2122  		writeTestInt32(t, &buf, blockCoords[i][2])
  2123  		data[i] = loadTestData(t, fname)
  2124  		gzipped, err := data[i].b.CompressGZIP()
  2125  		if err != nil {
  2126  			t.Fatalf("unable to gzip compress block: %v\n", err)
  2127  		}
  2128  		writeTestInt32(t, &buf, int32(len(gzipped)))
  2129  		n, err := buf.Write(gzipped)
  2130  		if err != nil {
  2131  			t.Fatalf("unable to write gzip block: %v\n", err)
  2132  		}
  2133  		if n != len(gzipped) {
  2134  			t.Fatalf("unable to write %d bytes to buffer, only wrote %d bytes\n", len(gzipped), n)
  2135  		}
  2136  	}
  2137  
  2138  	apiStr := fmt.Sprintf("%snode/%s/labels/ingest-supervoxels", server.WebAPIPath, uuid)
  2139  	server.TestHTTP(t, "POST", apiStr, &buf)
  2140  
  2141  	if err := datastore.BlockOnUpdating(uuid, "labels"); err != nil {
  2142  		t.Fatalf("Error blocking on update of labels: %v\n", err)
  2143  	}
  2144  
  2145  	// test volume GET
  2146  	vol := labelVol{
  2147  		size:      dvid.Point3d{2, 2, 2}, // in blocks
  2148  		nx:        128,
  2149  		ny:        128,
  2150  		nz:        128,
  2151  		blockSize: dvid.Point3d{64, 64, 64},
  2152  		offset:    dvid.Point3d{64, 128, 192},
  2153  		name:      "labels",
  2154  	}
  2155  	got := vol.getLabelVolume(t, uuid, "", "")
  2156  	gotLabels, err := dvid.AliasByteToUint64(got)
  2157  	if err != nil {
  2158  		t.Fatal(err)
  2159  	}
  2160  	var bcoordStr string
  2161  	for i := 0; i < 4; i++ {
  2162  		x0 := (blockCoords[i][0] - 1) * 64
  2163  		y0 := (blockCoords[i][1] - 2) * 64
  2164  		z0 := (blockCoords[i][2] - 3) * 64
  2165  		bcoordStr += fmt.Sprintf("%d,%d,%d", blockCoords[i][0], blockCoords[i][1], blockCoords[i][2])
  2166  		if i != 3 {
  2167  			bcoordStr += ","
  2168  		}
  2169  		var x, y, z int32
  2170  		for z = 0; z < 64; z++ {
  2171  			for y = 0; y < 64; y++ {
  2172  				for x = 0; x < 64; x++ {
  2173  					di := z*64*64 + y*64 + x
  2174  					gi := (z+z0)*128*128 + (y+y0)*128 + x + x0
  2175  					if data[i].u[di] != gotLabels[gi] {
  2176  						t.Fatalf("Error in block %s dvid coord (%d,%d,%d): expected %d, got %d\n", blockCoords[i], x+x0, y+y0, z+z0, data[i].u[di], gotLabels[gi])
  2177  					}
  2178  				}
  2179  			}
  2180  		}
  2181  	}
  2182  	runtime.KeepAlive(&got)
  2183  
  2184  	// test GET /blocks
  2185  	for i, td := range data {
  2186  		testGetBlock(t, uuid, "labels", blockCoords[i], td)
  2187  	}
  2188  
  2189  	// test GET /specificblocks
  2190  	pblocks := testGetSpecificBlocks(t, uuid, "labels", true, bcoordStr)
  2191  	for i, td := range data {
  2192  		izyx := dvid.IndexZYX{blockCoords[i][0], blockCoords[i][1], blockCoords[i][2]}
  2193  		izyxStr := izyx.ToIZYXString()
  2194  		var j int
  2195  		for _, pb := range pblocks {
  2196  			if izyxStr == pb.BCoord {
  2197  				break
  2198  			}
  2199  			j++
  2200  		}
  2201  		if j == 4 {
  2202  			t.Fatalf("Didn't find block %s in retrieved blocks\n", izyxStr)
  2203  		}
  2204  		checkBlock(t, pblocks[j], td)
  2205  	}
  2206  	bcoordStr2 := "100,23,89,"
  2207  	for i := 0; i < 2; i++ {
  2208  		bcoordStr2 += fmt.Sprintf("%d,%d,%d,", blockCoords[i][0], blockCoords[i][1], blockCoords[i][2])
  2209  	}
  2210  	bcoordStr2 += "0,50,40"
  2211  	pblocks = testGetSpecificBlocks(t, uuid, "labels", true, bcoordStr2)
  2212  	if len(pblocks) != 2 {
  2213  		t.Fatalf("expected 2 blocks, got %d blocks instead\n", len(pblocks))
  2214  	}
  2215  	var gotBlocks int
  2216  	for _, pb := range pblocks {
  2217  		for i, td := range data {
  2218  			izyx := dvid.IndexZYX{blockCoords[i][0], blockCoords[i][1], blockCoords[i][2]}
  2219  			izyxStr := izyx.ToIZYXString()
  2220  			if izyxStr == pb.BCoord {
  2221  				gotBlocks++
  2222  				checkBlock(t, pb, td)
  2223  			}
  2224  		}
  2225  	}
  2226  	if gotBlocks != 2 {
  2227  		t.Fatalf("expected to receive 2 blocks, got %d instead\n", gotBlocks)
  2228  	}
  2229  }
  2230  
  2231  func TestPostBlock(t *testing.T) {
  2232  	if err := server.OpenTest(); err != nil {
  2233  		t.Fatalf("can't open test server: %v\n", err)
  2234  	}
  2235  	defer server.CloseTest()
  2236  
  2237  	uuid, _ := datastore.NewTestRepo()
  2238  	if len(uuid) < 5 {
  2239  		t.Fatalf("Bad root UUID for new repo: %s\n", uuid)
  2240  	}
  2241  	server.CreateTestInstance(t, uuid, "labelmap", "labels", dvid.Config{})
  2242  
  2243  	f, err := os.Open("../../test_data/fib19-64x64x64-sample1-block.dat.gz")
  2244  	if err != nil {
  2245  		t.Fatalf("Couldn't open compressed block test data: %v\n", err)
  2246  	}
  2247  	data, err := ioutil.ReadAll(f)
  2248  	if err != nil {
  2249  		t.Fatalf("Couldn't read compressed block test data: %v\n", err)
  2250  	}
  2251  	var buf bytes.Buffer
  2252  	writeTestInt32(t, &buf, 0)
  2253  	writeTestInt32(t, &buf, 0)
  2254  	writeTestInt32(t, &buf, 0)
  2255  	writeTestInt32(t, &buf, int32(len(data)))
  2256  	fmt.Printf("Writing %d bytes of compressed block\n", len(data))
  2257  	n, err := buf.Write(data)
  2258  	if err != nil {
  2259  		t.Fatalf("unable to write gzip block: %v\n", err)
  2260  	}
  2261  	if n != len(data) {
  2262  		t.Fatalf("unable to write %d bytes to buffer, only wrote %d bytes\n", len(data), n)
  2263  	}
  2264  
  2265  	apiStr := fmt.Sprintf("%snode/%s/labels/blocks", server.WebAPIPath, uuid)
  2266  	server.TestHTTP(t, "POST", apiStr, &buf)
  2267  
  2268  	if err := datastore.BlockOnUpdating(uuid, "labels"); err != nil {
  2269  		t.Fatalf("Error blocking on sync of labels: %v\n", err)
  2270  	}
  2271  }
  2272  
  2273  func TestBigPostBlock(t *testing.T) {
  2274  	if err := server.OpenTest(); err != nil {
  2275  		t.Fatalf("can't open test server: %v\n", err)
  2276  	}
  2277  	defer server.CloseTest()
  2278  
  2279  	uuid, _ := datastore.NewTestRepo()
  2280  	if len(uuid) < 5 {
  2281  		t.Fatalf("Bad root UUID for new repo: %s\n", uuid)
  2282  	}
  2283  	server.CreateTestInstance(t, uuid, "labelmap", "labels", dvid.Config{})
  2284  
  2285  	f, err := os.Open("../../test_data/stream_1block.dat")
  2286  	if err != nil {
  2287  		t.Fatalf("Couldn't open compressed block test data: %v\n", err)
  2288  	}
  2289  	data, err := ioutil.ReadAll(f)
  2290  	if err != nil {
  2291  		t.Fatalf("Couldn't read compressed block test data: %v\n", err)
  2292  	}
  2293  
  2294  	apiStr := fmt.Sprintf("%snode/%s/labels/blocks", server.WebAPIPath, uuid)
  2295  	server.TestHTTP(t, "POST", apiStr, bytes.NewBuffer(data))
  2296  
  2297  	if err := datastore.BlockOnUpdating(uuid, "labels"); err != nil {
  2298  		t.Fatalf("Error blocking on sync of labels: %v\n", err)
  2299  	}
  2300  }
  2301  
  2302  type testBlock struct {
  2303  	bcoord dvid.ChunkPoint3d
  2304  	labels []uint64
  2305  }
  2306  
  2307  // Create two test blocks composed of labels 1 and 2.
  2308  // For 1st block, coord (2,3,4), label 2 if x <= 31, label 1 if x >= 32.
  2309  // For 2nd block, coord (3,3,4), label 1 if x <= 31, label 2 if x >= 32.
  2310  func setupTestBlocks(t *testing.T, uuid dvid.UUID) (testBlockData [2]testBlock) {
  2311  	server.CreateTestInstance(t, uuid, "labelmap", "labels", dvid.Config{})
  2312  
  2313  	numVoxels := 64 * 64 * 64
  2314  	blockVol0 := make([]uint64, numVoxels)
  2315  	i := 0
  2316  	for z := 0; z < 64; z++ {
  2317  		for y := 0; y < 64; y++ {
  2318  			for x := 0; x < 32; x++ {
  2319  				blockVol0[i] = 2
  2320  				i++
  2321  			}
  2322  			for x := 32; x < 64; x++ {
  2323  				blockVol0[i] = 1
  2324  				i++
  2325  			}
  2326  		}
  2327  	}
  2328  	block0, err := labels.MakeBlock(dvid.AliasUint64ToByte(blockVol0), dvid.Point3d{64, 64, 64})
  2329  	if err != nil {
  2330  		t.Fatalf("error making block 0: %v\n", err)
  2331  	}
  2332  	runtime.KeepAlive(&blockVol0)
  2333  	block0data, err := block0.CompressGZIP()
  2334  	if err != nil {
  2335  		t.Fatalf("error making block 0: %v\n", err)
  2336  	}
  2337  	blockVol1 := make([]uint64, numVoxels)
  2338  	i = 0
  2339  	for z := 0; z < 64; z++ {
  2340  		for y := 0; y < 64; y++ {
  2341  			for x := 0; x < 32; x++ {
  2342  				blockVol1[i] = 1
  2343  				i++
  2344  			}
  2345  			for x := 32; x < 64; x++ {
  2346  				blockVol1[i] = 2
  2347  				i++
  2348  			}
  2349  		}
  2350  	}
  2351  	block1, err := labels.MakeBlock(dvid.AliasUint64ToByte(blockVol1), dvid.Point3d{64, 64, 64})
  2352  	if err != nil {
  2353  		t.Fatalf("error making block 0: %v\n", err)
  2354  	}
  2355  	runtime.KeepAlive(&blockVol1)
  2356  	block1data, err := block1.CompressGZIP()
  2357  	if err != nil {
  2358  		t.Fatalf("error making block 0: %v\n", err)
  2359  	}
  2360  
  2361  	testBlockData = [2]testBlock{
  2362  		{
  2363  			bcoord: dvid.ChunkPoint3d{2, 3, 4},
  2364  			labels: blockVol0,
  2365  		},
  2366  		{
  2367  			bcoord: dvid.ChunkPoint3d{3, 3, 4},
  2368  			labels: blockVol1,
  2369  		},
  2370  	}
  2371  
  2372  	var buf bytes.Buffer
  2373  	writeTestInt32(t, &buf, 2)
  2374  	writeTestInt32(t, &buf, 3)
  2375  	writeTestInt32(t, &buf, 4)
  2376  	writeTestInt32(t, &buf, int32(len(block0data)))
  2377  	n, err := buf.Write(block0data)
  2378  	if err != nil {
  2379  		t.Fatalf("unable to write gzip block: %v\n", err)
  2380  	}
  2381  	if n != len(block0data) {
  2382  		t.Fatalf("unable to write %d bytes to buffer, only wrote %d bytes\n", len(block0data), n)
  2383  	}
  2384  	writeTestInt32(t, &buf, 3)
  2385  	writeTestInt32(t, &buf, 3)
  2386  	writeTestInt32(t, &buf, 4)
  2387  	writeTestInt32(t, &buf, int32(len(block1data)))
  2388  	n, err = buf.Write(block1data)
  2389  	if err != nil {
  2390  		t.Fatalf("unable to write gzip block: %v\n", err)
  2391  	}
  2392  	if n != len(block1data) {
  2393  		t.Fatalf("unable to write %d bytes to buffer, only wrote %d bytes\n", len(block1data), n)
  2394  	}
  2395  
  2396  	apiStr := fmt.Sprintf("%snode/%s/labels/blocks", server.WebAPIPath, uuid)
  2397  	server.TestHTTP(t, "POST", apiStr, &buf)
  2398  
  2399  	apiStr = fmt.Sprintf("%snode/%s/labels/blocks/128_64_64/128_192_256?compression=blocks", server.WebAPIPath, uuid)
  2400  	respRec := server.TestHTTPResponse(t, "GET", apiStr, nil)
  2401  	for bnum := 0; bnum < 2; bnum++ {
  2402  		gotBlock, _, bx, by, bz, err := readStreamedBlock(respRec.Body, 0)
  2403  		if err != nil {
  2404  			t.Fatalf("problem reading block %d from stream: %v\n", bnum, err)
  2405  		}
  2406  		for _, label := range gotBlock.Labels {
  2407  			if label != 1 && label != 2 {
  2408  				t.Errorf("got bad block with label %d when only 1 or 2 should have been present\n", label)
  2409  			}
  2410  		}
  2411  		bcoord := dvid.ChunkPoint3d{bx, by, bz}
  2412  		var found bool
  2413  		for i := 0; i < 2; i++ {
  2414  			if bcoord == testBlockData[i].bcoord {
  2415  				found = true
  2416  				labelBytes, _ := gotBlock.MakeLabelVolume()
  2417  				labelVol, err := dvid.AliasByteToUint64(labelBytes)
  2418  				if err != nil {
  2419  					t.Fatalf("problem inflating block %s labels to []uint64: %v\n", bcoord, err)
  2420  				}
  2421  				for v, val := range labelVol {
  2422  					if testBlockData[i].labels[v] != val {
  2423  						t.Fatalf("label mismatch found at index %d, expected %d, got %d\n", v, testBlockData[i].labels[v], val)
  2424  					}
  2425  				}
  2426  				runtime.KeepAlive(&labelBytes)
  2427  			}
  2428  		}
  2429  		if !found {
  2430  			t.Fatalf("got block %s but wasn't an expected block!\n", bcoord)
  2431  		}
  2432  	}
  2433  	return
  2434  }
  2435  
  2436  func TestBlocksWithMerge(t *testing.T) {
  2437  	if err := server.OpenTest(); err != nil {
  2438  		t.Fatalf("can't open test server: %v\n", err)
  2439  	}
  2440  	defer server.CloseTest()
  2441  
  2442  	uuid, _ := datastore.NewTestRepo()
  2443  	if len(uuid) < 5 {
  2444  		t.Fatalf("Bad root UUID for new repo: %s\n", uuid)
  2445  	}
  2446  	testBlockData := setupTestBlocks(t, uuid)
  2447  
  2448  	testMerge := mergeJSON(`[1, 2]`)
  2449  	testMerge.send(t, uuid, "labels")
  2450  
  2451  	apiStr := fmt.Sprintf("%snode/%s/labels/blocks/128_64_64/128_192_256?compression=blocks", server.WebAPIPath, uuid)
  2452  	respRec := server.TestHTTPResponse(t, "GET", apiStr, nil)
  2453  	for bnum := 0; bnum < 2; bnum++ {
  2454  		gotBlock, _, bx, by, bz, err := readStreamedBlock(respRec.Body, 0)
  2455  		if err != nil {
  2456  			t.Fatalf("problem reading block %d from stream: %v\n", bnum, err)
  2457  		}
  2458  		for _, label := range gotBlock.Labels {
  2459  			if label != 1 {
  2460  				t.Errorf("got bad block with label %d when only 1 should have been present\n", label)
  2461  			}
  2462  		}
  2463  		bcoord := dvid.ChunkPoint3d{bx, by, bz}
  2464  		var found bool
  2465  		for i := 0; i < 2; i++ {
  2466  			if bcoord == testBlockData[i].bcoord {
  2467  				found = true
  2468  				labelBytes, _ := gotBlock.MakeLabelVolume()
  2469  				labelVol, err := dvid.AliasByteToUint64(labelBytes)
  2470  				if err != nil {
  2471  					t.Fatalf("problem inflating block %s labels to []uint64: %v\n", bcoord, err)
  2472  				}
  2473  				for v, val := range labelVol {
  2474  					if testBlockData[i].labels[v] != 0 && val != 1 {
  2475  						t.Fatalf("label mismatch found at index %d, expected 1, got %d\n", v, val)
  2476  					}
  2477  				}
  2478  				runtime.KeepAlive(&labelBytes)
  2479  			}
  2480  		}
  2481  		if !found {
  2482  			t.Fatalf("got block %s but wasn't an expected block!\n", bcoord)
  2483  		}
  2484  	}
  2485  
  2486  	apiStr = fmt.Sprintf("%snode/%s/labels/blocks/128_64_64/128_192_256?compression=blocks&supervoxels=true", server.WebAPIPath, uuid)
  2487  	respRec = server.TestHTTPResponse(t, "GET", apiStr, nil)
  2488  	gotBlock0, _, _, _, _, err := readStreamedBlock(respRec.Body, 0)
  2489  	if err != nil {
  2490  		t.Errorf("error trying to readStreamedBlock: %v\n", err)
  2491  	}
  2492  	gotLabels := make(labels.Set)
  2493  	for _, label := range gotBlock0.Labels {
  2494  		gotLabels[label] = struct{}{}
  2495  		if label != 1 && label != 2 {
  2496  			t.Errorf("got unexpected label in block: %d\n", label)
  2497  		}
  2498  	}
  2499  	if _, found := gotLabels[1]; !found {
  2500  		t.Errorf("expected label 1 but found none\n")
  2501  	}
  2502  	if _, found := gotLabels[2]; !found {
  2503  		t.Errorf("expected label 2 but found none\n")
  2504  	}
  2505  	gotBlock1, _, _, _, _, err := readStreamedBlock(respRec.Body, 0)
  2506  	if err != nil {
  2507  		t.Errorf("error trying to readStreamedBlock: %v\n", err)
  2508  	}
  2509  	gotLabels = make(labels.Set)
  2510  	for _, label := range gotBlock1.Labels {
  2511  		gotLabels[label] = struct{}{}
  2512  		if label != 1 && label != 2 {
  2513  			t.Errorf("got unexpected label in block: %d\n", label)
  2514  		}
  2515  	}
  2516  	if _, found := gotLabels[1]; !found {
  2517  		t.Errorf("expected label 1 but found none\n")
  2518  	}
  2519  	if _, found := gotLabels[2]; !found {
  2520  		t.Errorf("expected label 2 but found none\n")
  2521  	}
  2522  }
  2523  
  2524  func TestBlocksWithRenumber(t *testing.T) {
  2525  	if err := server.OpenTest(); err != nil {
  2526  		t.Fatalf("can't open test server: %v\n", err)
  2527  	}
  2528  	defer server.CloseTest()
  2529  
  2530  	uuid, _ := datastore.NewTestRepo()
  2531  	if len(uuid) < 5 {
  2532  		t.Fatalf("Bad root UUID for new repo: %s\n", uuid)
  2533  	}
  2534  	testBlockData := setupTestBlocks(t, uuid)
  2535  
  2536  	testRenumber := renumberJSON(`[3, 1, 4, 2]`)
  2537  	testRenumber.send(t, uuid, "labels")
  2538  
  2539  	apiStr := fmt.Sprintf("%snode/%s/labels/blocks/128_64_64/128_192_256?compression=blocks", server.WebAPIPath, uuid)
  2540  	respRec := server.TestHTTPResponse(t, "GET", apiStr, nil)
  2541  	for bnum := 0; bnum < 2; bnum++ {
  2542  		gotBlock, _, bx, by, bz, err := readStreamedBlock(respRec.Body, 0)
  2543  		if err != nil {
  2544  			t.Fatalf("problem reading block %d from stream: %v\n", bnum, err)
  2545  		}
  2546  		for _, label := range gotBlock.Labels {
  2547  			if label != 3 && label != 4 {
  2548  				t.Errorf("got bad block with label %d when only 3 or 4 should have been present\n", label)
  2549  			}
  2550  		}
  2551  		bcoord := dvid.ChunkPoint3d{bx, by, bz}
  2552  		var found bool
  2553  		for i := 0; i < 2; i++ {
  2554  			if bcoord == testBlockData[i].bcoord {
  2555  				var first, second uint64
  2556  				if i == 0 {
  2557  					first = 4
  2558  					second = 3
  2559  				} else {
  2560  					first = 3
  2561  					second = 4
  2562  				}
  2563  				found = true
  2564  				labelBytes, _ := gotBlock.MakeLabelVolume()
  2565  				labelVol, err := dvid.AliasByteToUint64(labelBytes)
  2566  				if err != nil {
  2567  					t.Fatalf("problem inflating block %s labels to []uint64: %v\n", bcoord, err)
  2568  				}
  2569  				i = 0
  2570  				for z := 0; z < 64; z++ {
  2571  					for y := 0; y < 64; y++ {
  2572  						for x := 0; x < 32; x++ {
  2573  							if labelVol[i] != first {
  2574  								t.Fatalf("label mismatch found at index %d, expected %d got %d\n", i, first, labelVol[i])
  2575  							}
  2576  							i++
  2577  						}
  2578  						for x := 32; x < 64; x++ {
  2579  							if labelVol[i] != second {
  2580  								t.Fatalf("label mismatch found at index %d, expected %d got %d\n", i, second, labelVol[i])
  2581  							}
  2582  							i++
  2583  						}
  2584  					}
  2585  				}
  2586  				runtime.KeepAlive(&labelBytes)
  2587  			}
  2588  		}
  2589  		if !found {
  2590  			t.Fatalf("got block %s but wasn't an expected block!\n", bcoord)
  2591  		}
  2592  	}
  2593  
  2594  	apiStr = fmt.Sprintf("%snode/%s/labels/blocks/128_64_64/128_192_256?compression=blocks", server.WebAPIPath, uuid)
  2595  	respRec = server.TestHTTPResponse(t, "GET", apiStr, nil)
  2596  	gotBlock0, _, _, _, _, err := readStreamedBlock(respRec.Body, 0)
  2597  	if err != nil {
  2598  		t.Errorf("error trying to readStreamedBlock: %v\n", err)
  2599  	}
  2600  	gotLabels := make(labels.Set)
  2601  	for _, label := range gotBlock0.Labels {
  2602  		gotLabels[label] = struct{}{}
  2603  		if label != 3 && label != 4 {
  2604  			t.Errorf("got unexpected label in block: %d\n", label)
  2605  		}
  2606  	}
  2607  	if _, found := gotLabels[3]; !found {
  2608  		t.Errorf("expected label 3 but found none\n")
  2609  	}
  2610  	if _, found := gotLabels[4]; !found {
  2611  		t.Errorf("expected label 4 but found none\n")
  2612  	}
  2613  	gotBlock1, _, _, _, _, err := readStreamedBlock(respRec.Body, 0)
  2614  	if err != nil {
  2615  		t.Errorf("error trying to readStreamedBlock: %v\n", err)
  2616  	}
  2617  	gotLabels = make(labels.Set)
  2618  	for _, label := range gotBlock1.Labels {
  2619  		gotLabels[label] = struct{}{}
  2620  		if label != 3 && label != 4 {
  2621  			t.Errorf("got unexpected label in block: %d\n", label)
  2622  		}
  2623  	}
  2624  	if _, found := gotLabels[3]; !found {
  2625  		t.Errorf("expected label 3 but found none\n")
  2626  	}
  2627  	if _, found := gotLabels[3]; !found {
  2628  		t.Errorf("expected label 4 but found none\n")
  2629  	}
  2630  }
  2631  
  2632  func testLabels(t *testing.T, labelsIndexed bool) {
  2633  	if err := server.OpenTest(); err != nil {
  2634  		t.Fatalf("can't open test server: %v\n", err)
  2635  	}
  2636  	defer server.CloseTest()
  2637  
  2638  	uuid, _ := datastore.NewTestRepo()
  2639  	if len(uuid) < 5 {
  2640  		t.Fatalf("Bad root UUID for new repo: %s\n", uuid)
  2641  	}
  2642  
  2643  	// Create a labelmap instance
  2644  	var config dvid.Config
  2645  	config.Set("BlockSize", "32,32,32")
  2646  	if !labelsIndexed {
  2647  		config.Set("IndexedLabels", "false")
  2648  	}
  2649  	server.CreateTestInstance(t, uuid, "labelmap", "labels", config)
  2650  
  2651  	vol := labelVol{
  2652  		startLabel: 2,
  2653  		size:       dvid.Point3d{5, 5, 5}, // in blocks
  2654  		blockSize:  dvid.Point3d{32, 32, 32},
  2655  		offset:     dvid.Point3d{32, 64, 96},
  2656  		name:       "labels",
  2657  	}
  2658  	vol.postLabelVolume(t, uuid, "", "", 0)
  2659  	vol.testGetLabelVolume(t, uuid, "", "")
  2660  
  2661  	end := dvid.Point3d{32 + 160 - 1, 64 + 160 - 1, 96 + 160 - 1}
  2662  	testExtents(t, "labels", uuid, vol.offset, end)
  2663  
  2664  	// Test the blocks API
  2665  	vol.testBlocks(t, "GET default blocks (lz4)", uuid, "")
  2666  	vol.testBlocks(t, "GET uncompressed blocks", uuid, "uncompressed")
  2667  	vol.testBlocks(t, "GET DVID compressed label blocks", uuid, "blocks")
  2668  	vol.testBlocks(t, "GET gzip blocks", uuid, "gzip")
  2669  
  2670  	apiStr := fmt.Sprintf("%snode/%s/%s/blocks/64_32_32/0_0_0?compression=blocks", server.WebAPIPath,
  2671  		uuid, vol.name)
  2672  	data := server.TestHTTP(t, "GET", apiStr, nil)
  2673  	if len(data) != 0 {
  2674  		t.Fatalf("expected no data return for unset block, got %d bytes instead\n", len(data))
  2675  	}
  2676  	apiStr = fmt.Sprintf("%snode/%s/%s/blocks/64_32_32/0_64_96?compression=blocks", server.WebAPIPath,
  2677  		uuid, vol.name)
  2678  	data = server.TestHTTP(t, "GET", apiStr, nil)
  2679  	blocks := decodeReturnedBlocks(t, data)
  2680  	if len(data) == 0 {
  2681  		t.Fatalf("expected on block of data, got no data in response\n")
  2682  	}
  2683  	if len(blocks) != 1 {
  2684  		t.Fatalf("expected one block of two blocks requested, got %d blocks instead\n", len(blocks))
  2685  	}
  2686  
  2687  	// Test the "label" endpoint.
  2688  	apiStr = fmt.Sprintf("%snode/%s/%s/label/100_64_96", server.WebAPIPath, uuid, "labels")
  2689  	jsonResp := server.TestHTTP(t, "GET", apiStr, nil)
  2690  	var r labelResp
  2691  	if err := json.Unmarshal(jsonResp, &r); err != nil {
  2692  		t.Fatalf("Unable to parse 'label' endpoint response: %s\n", jsonResp)
  2693  	}
  2694  	if r.Label != vol.label(100, 64, 96) {
  2695  		t.Fatalf("Expected label %d @ (100, 64, 96) got label %d\n", vol.label(100, 64, 96), r.Label)
  2696  	}
  2697  
  2698  	apiStr = fmt.Sprintf("%snode/%s/%s/label/10000_64000_9600121", server.WebAPIPath, uuid, "labels")
  2699  	jsonResp = server.TestHTTP(t, "GET", apiStr, nil)
  2700  	if err := json.Unmarshal(jsonResp, &r); err != nil {
  2701  		t.Fatalf("Unable to parse 'label' endpoint response: %s\n", jsonResp)
  2702  	}
  2703  	if r.Label != 0 {
  2704  		t.Fatalf("Expected label 0 at random huge point, got label %d\n", r.Label)
  2705  	}
  2706  
  2707  	// Test the "labels" endpoint.
  2708  	apiStr = fmt.Sprintf("%snode/%s/%s/labels", server.WebAPIPath, uuid, "labels")
  2709  	payload := `[[100,64,96],[78,93,156],[104,65,97]]`
  2710  	jsonResp = server.TestHTTP(t, "GET", apiStr, bytes.NewBufferString(payload))
  2711  	var labels [3]uint64
  2712  	if err := json.Unmarshal(jsonResp, &labels); err != nil {
  2713  		t.Fatalf("Unable to parse 'labels' endpoint response: %s\n", jsonResp)
  2714  	}
  2715  	if labels[0] != vol.label(100, 64, 96) {
  2716  		t.Fatalf("Expected label %d @ (100, 64, 96) got label %d\n", vol.label(100, 64, 96), labels[0])
  2717  	}
  2718  	if labels[1] != vol.label(78, 93, 156) {
  2719  		t.Fatalf("Expected label %d @ (78, 93, 156) got label %d\n", vol.label(78, 93, 156), labels[1])
  2720  	}
  2721  	if labels[2] != vol.label(104, 65, 97) {
  2722  		t.Fatalf("Expected label %d @ (104, 65, 97) got label %d\n", vol.label(104, 65, 97), labels[2])
  2723  	}
  2724  
  2725  	// Repost the label volume 3 more times with increasing starting values.
  2726  	vol.postLabelVolume(t, uuid, "", "", 2100)
  2727  	vol.postLabelVolume(t, uuid, "", "", 8176)
  2728  	vol.postLabelVolume(t, uuid, "", "", 16623)
  2729  
  2730  	vol.testSlices(t, uuid)
  2731  
  2732  	// Try to post last volume concurrently 3x and then check result.
  2733  	wg := new(sync.WaitGroup)
  2734  	wg.Add(3)
  2735  	go func() {
  2736  		vol.postLabelVolume(t, uuid, "", "", 16623)
  2737  		wg.Done()
  2738  	}()
  2739  	go func() {
  2740  		vol.postLabelVolume(t, uuid, "", "", 16623)
  2741  		wg.Done()
  2742  	}()
  2743  	go func() {
  2744  		vol.postLabelVolume(t, uuid, "", "", 16623)
  2745  		wg.Done()
  2746  	}()
  2747  	wg.Wait()
  2748  	vol.testGetLabelVolume(t, uuid, "", "")
  2749  
  2750  	// Try concurrent write of disjoint subvolumes.
  2751  	vol2 := labelVol{
  2752  		size:      dvid.Point3d{5, 5, 5}, // in blocks
  2753  		blockSize: dvid.Point3d{32, 32, 32},
  2754  		offset:    dvid.Point3d{192, 64, 96},
  2755  		name:      "labels",
  2756  	}
  2757  	vol3 := labelVol{
  2758  		size:      dvid.Point3d{5, 5, 5}, // in blocks
  2759  		blockSize: dvid.Point3d{32, 32, 32},
  2760  		offset:    dvid.Point3d{192, 224, 96},
  2761  		name:      "labels",
  2762  	}
  2763  	vol4 := labelVol{
  2764  		size:      dvid.Point3d{5, 5, 5}, // in blocks
  2765  		blockSize: dvid.Point3d{32, 32, 32},
  2766  		offset:    dvid.Point3d{32, 224, 96},
  2767  		name:      "labels",
  2768  	}
  2769  
  2770  	wg.Add(3)
  2771  	go func() {
  2772  		vol2.postLabelVolume(t, uuid, "lz4", "", 4000)
  2773  		wg.Done()
  2774  	}()
  2775  	go func() {
  2776  		vol3.postLabelVolume(t, uuid, "lz4", "", 8000)
  2777  		wg.Done()
  2778  	}()
  2779  	go func() {
  2780  		vol4.postLabelVolume(t, uuid, "lz4", "", 1200)
  2781  		wg.Done()
  2782  	}()
  2783  	wg.Wait()
  2784  	vol.testGetLabelVolume(t, uuid, "", "")
  2785  	vol2.testGetLabelVolume(t, uuid, "", "")
  2786  	vol3.testGetLabelVolume(t, uuid, "", "")
  2787  	vol4.testGetLabelVolume(t, uuid, "", "")
  2788  
  2789  	// Verify various GET 3d volume with compressions and no ROI.
  2790  	vol.testGetLabelVolume(t, uuid, "", "")
  2791  	vol.testGetLabelVolume(t, uuid, "lz4", "")
  2792  	vol.testGetLabelVolume(t, uuid, "gzip", "")
  2793  
  2794  	// Create a new ROI instance.
  2795  	roiName := "myroi"
  2796  	server.CreateTestInstance(t, uuid, "roi", roiName, dvid.Config{})
  2797  
  2798  	// Add ROI data
  2799  	apiStr = fmt.Sprintf("%snode/%s/%s/roi", server.WebAPIPath, uuid, roiName)
  2800  	server.TestHTTP(t, "POST", apiStr, bytes.NewBufferString(labelsJSON()))
  2801  
  2802  	// Post updated labels without ROI and make sure it returns those values.
  2803  	var labelNoROI uint64 = 20000
  2804  	vol.postLabelVolume(t, uuid, "", "", labelNoROI)
  2805  	returned := vol.testGetLabelVolume(t, uuid, "", "")
  2806  	startLabel := binary.LittleEndian.Uint64(returned[0:8])
  2807  	if startLabel != labelNoROI {
  2808  		t.Fatalf("Expected first voxel to be label %d and got %d instead\n", labelNoROI, startLabel)
  2809  	}
  2810  
  2811  	// Post again but now with ROI
  2812  	var labelWithROI uint64 = 40000
  2813  	vol.postLabelVolume(t, uuid, "", roiName, labelWithROI)
  2814  
  2815  	// Verify ROI masking of POST where anything outside ROI is old labels.
  2816  	returned = vol.getLabelVolume(t, uuid, "", "")
  2817  
  2818  	nx := vol.size[0] * vol.blockSize[0]
  2819  	ny := vol.size[1] * vol.blockSize[1]
  2820  	nz := vol.size[2] * vol.blockSize[2]
  2821  	var x, y, z, v int32
  2822  	for z = 0; z < nz; z++ {
  2823  		voxz := z + vol.offset[2]
  2824  		blockz := voxz / vol.blockSize[2]
  2825  		for y = 0; y < ny; y++ {
  2826  			voxy := y + vol.offset[1]
  2827  			blocky := voxy / vol.blockSize[1]
  2828  			for x = 0; x < nx; x++ {
  2829  				voxx := x + vol.offset[0]
  2830  				blockx := voxx / vol.blockSize[0]
  2831  				incr := uint64(x>>2 + y/3 + z/3)
  2832  				oldlabel := labelNoROI + incr
  2833  				newlabel := labelWithROI + incr
  2834  				got := binary.LittleEndian.Uint64(returned[v : v+8])
  2835  				if inroi(blockx, blocky, blockz) {
  2836  					if got != newlabel {
  2837  						t.Fatalf("Expected %d in ROI (%d,%d,%d), got %d\n", newlabel, blockx, blocky, blockz, got)
  2838  					}
  2839  				} else {
  2840  					if got != oldlabel {
  2841  						t.Fatalf("Expected %d outside ROI (%d,%d,%d), got %d\n", oldlabel, blockx, blocky, blockz, got)
  2842  					}
  2843  				}
  2844  				v += 8
  2845  			}
  2846  		}
  2847  	}
  2848  
  2849  	// Verify that a ROI-enabled GET has zeros everywhere outside ROI.
  2850  	returned = vol.getLabelVolume(t, uuid, "", roiName)
  2851  
  2852  	x, y, z, v = 0, 0, 0, 0
  2853  	for z = 0; z < nz; z++ {
  2854  		voxz := z + vol.offset[2]
  2855  		blockz := voxz / vol.blockSize[2]
  2856  		for y = 0; y < ny; y++ {
  2857  			voxy := y + vol.offset[1]
  2858  			blocky := voxy / vol.blockSize[1]
  2859  			for x = 0; x < nx; x++ {
  2860  				voxx := x + vol.offset[0]
  2861  				blockx := voxx / vol.blockSize[0]
  2862  				incr := uint64(x>>2 + y/3 + z/3)
  2863  				newlabel := labelWithROI + incr
  2864  				got := binary.LittleEndian.Uint64(returned[v : v+8])
  2865  				if inroi(blockx, blocky, blockz) {
  2866  					if got != newlabel {
  2867  						t.Fatalf("Expected %d in ROI, got %d\n", newlabel, got)
  2868  					}
  2869  				} else {
  2870  					if got != 0 {
  2871  						t.Fatalf("Expected zero outside ROI, got %d\n", got)
  2872  					}
  2873  				}
  2874  				v += 8
  2875  			}
  2876  		}
  2877  	}
  2878  
  2879  	// Verify non-indexed instances can't access indexed endpoints.
  2880  	if !labelsIndexed {
  2881  		methods := []string{
  2882  			"GET",
  2883  			"HEAD",
  2884  			"GET",
  2885  			"GET",
  2886  			"GET",
  2887  			"GET",
  2888  			"POST",
  2889  			"POST",
  2890  			"POST",
  2891  		}
  2892  		reqs := []string{
  2893  			"sparsevol/20",
  2894  			"sparsevol/20",
  2895  			"sparsevol-by-point/30_89_100",
  2896  			"sparsevol-coarse/20",
  2897  			"maxlabel",
  2898  			"nextlabel",
  2899  			"nextlabel",
  2900  			"merge",
  2901  			"cleave/20",
  2902  		}
  2903  		var r io.Reader
  2904  		for i, req := range reqs {
  2905  			apiStr = fmt.Sprintf("%snode/%s/labels/%s", server.WebAPIPath, uuid, req)
  2906  			if methods[i] == "POST" {
  2907  				r = bytes.NewBufferString("junkdata that should never be used anyway")
  2908  			} else {
  2909  				r = nil
  2910  			}
  2911  			server.TestBadHTTP(t, methods[i], apiStr, r)
  2912  		}
  2913  	}
  2914  }
  2915  
  2916  func TestLabels(t *testing.T) {
  2917  	testLabels(t, true)
  2918  }
  2919  
  2920  func TestLabelsUnindexed(t *testing.T) {
  2921  	testLabels(t, false)
  2922  }
  2923  
  2924  func TestNextLabels(t *testing.T) {
  2925  	if err := server.OpenTest(); err != nil {
  2926  		t.Fatalf("can't open test server: %v\n", err)
  2927  	}
  2928  	defer server.CloseTest()
  2929  
  2930  	uuid, versionID := initTestRepo()
  2931  	lbls := newDataInstance(uuid, t, "mylabels")
  2932  
  2933  	if err := lbls.SetNextLabelStart(10); err != nil {
  2934  		t.Errorf("Error on setting next label start: %v\n", err)
  2935  	}
  2936  	expectedLabel := uint64(11)
  2937  	n, err := lbls.newLabel(versionID)
  2938  	if err != nil {
  2939  		t.Errorf("error on newLabel: %v\n", err)
  2940  	}
  2941  	if n != expectedLabel {
  2942  		t.Errorf("Expected next label to be %d, got %d\n", expectedLabel, n)
  2943  	}
  2944  }