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

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