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

     1  package labelmap
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/csv"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"strconv"
    10  	"testing"
    11  
    12  	"github.com/janelia-flyem/dvid/datastore"
    13  	"github.com/janelia-flyem/dvid/datatype/common/labels"
    14  	"github.com/janelia-flyem/dvid/dvid"
    15  	"github.com/janelia-flyem/dvid/server"
    16  )
    17  
    18  func (vc *VCache) checkMapping(t *testing.T, mappedVersions distFromRoot, from, to uint64) {
    19  	mappedLabel, found := vc.mapLabel(from, mappedVersions)
    20  	if !found {
    21  		t.Fatalf("expected mapping of %d to be found\n", from)
    22  	}
    23  	if mappedLabel != to {
    24  		t.Fatalf("expected mapping of %d -> %d, got %d\n", from, to, mappedLabel)
    25  	}
    26  }
    27  
    28  func checkMappings(t *testing.T, v dvid.VersionID, in io.Reader, expected map[uint64]uint64) {
    29  	r := csv.NewReader(in)
    30  	r.Comma = ' '
    31  	records, err := r.ReadAll()
    32  	if err != nil {
    33  		t.Fatal(err)
    34  	}
    35  	got := map[uint64]uint64{}
    36  	var from, to uint64
    37  	for _, line := range records {
    38  		if len(line) == 2 {
    39  			if from, err = strconv.ParseUint(line[0], 10, 64); err != nil {
    40  				t.Fatal(err)
    41  			}
    42  			if to, err = strconv.ParseUint(line[1], 10, 64); err != nil {
    43  				t.Fatal(err)
    44  			}
    45  			got[from] = to
    46  		} else {
    47  			t.Fatalf("version %d: bad response received for mapping: %v\n", v, records)
    48  		}
    49  	}
    50  	if len(expected) != len(got) {
    51  		t.Fatalf("version %d: got mapping of size %d != expected %d: %v\n", v, len(got), len(expected), got)
    52  	}
    53  	for from, to := range got {
    54  		expectedTo, found := expected[from]
    55  		if !found || expectedTo != to {
    56  			t.Fatalf("version %d: expected %v not same as received mapping %v\n", v, expected, got)
    57  		}
    58  	}
    59  }
    60  
    61  func mapUpdate(m0, m1 map[uint64]uint64) map[uint64]uint64 {
    62  	out := map[uint64]uint64{}
    63  	for k, v := range m0 {
    64  		out[k] = v
    65  	}
    66  	for k, v := range m1 {
    67  		out[k] = v
    68  	}
    69  	return out
    70  }
    71  
    72  func TestSVMap(t *testing.T) {
    73  	if err := server.OpenTest(); err != nil {
    74  		t.Fatalf("can't open test server: %v\n", err)
    75  	}
    76  	defer server.CloseTest()
    77  	uuid, v := initTestRepo()
    78  	var config dvid.Config
    79  	server.CreateTestInstance(t, uuid, "labelmap", "labels", config)
    80  
    81  	d, err := GetByVersionName(v, "labels")
    82  	if err != nil {
    83  		t.Fatalf("can't get labelmap data service: %v\n", err)
    84  	}
    85  	vc := initMapping(d, v)
    86  
    87  	mapping := map[uint64]uint64{
    88  		1: 3,
    89  		2: 3,
    90  		4: 6,
    91  		5: 6,
    92  	}
    93  	for from, to := range mapping {
    94  		vc.setMapping(v, from, to)
    95  	}
    96  
    97  	mappedVersions := vc.getMappedVersionsDist(v)
    98  
    99  	for from, to := range mapping {
   100  		vc.checkMapping(t, mappedVersions, from, to)
   101  	}
   102  
   103  	// Create a new version
   104  	apiStr := fmt.Sprintf("%snode/%s/commit", server.WebAPIPath, uuid)
   105  	payload := bytes.NewBufferString(`{"note": "first version"}`)
   106  	server.TestHTTP(t, "POST", apiStr, payload)
   107  
   108  	versionReq := fmt.Sprintf("%snode/%s/newversion", server.WebAPIPath, uuid)
   109  	respData := server.TestHTTP(t, "POST", versionReq, nil)
   110  	resp := struct {
   111  		Child dvid.UUID `json:"child"`
   112  	}{}
   113  	if err := json.Unmarshal(respData, &resp); err != nil {
   114  		t.Errorf("Expected 'child' JSON response.  Got %s\n", string(respData))
   115  	}
   116  	v2, err := datastore.VersionFromUUID(resp.Child)
   117  	if err != nil {
   118  		t.Fatalf("error getting version from UUID: %v\n", err)
   119  	}
   120  
   121  	// Add a different mapping to the new version
   122  	mapping2 := map[uint64]uint64{
   123  		2: 5,
   124  		4: 7,
   125  		5: 8,
   126  	}
   127  	for from, to := range mapping2 {
   128  		vc.setMapping(v2, from, to)
   129  	}
   130  	expected2 := mapUpdate(mapping, mapping2)
   131  
   132  	// Make sure that the mapping is the new one
   133  	mappedVersions2 := vc.getMappedVersionsDist(v2)
   134  
   135  	vc.checkMapping(t, mappedVersions2, 1, 3) // unset should fall back to version 1
   136  	for from, to := range mapping2 {
   137  		vc.checkMapping(t, mappedVersions2, from, to)
   138  	}
   139  
   140  	// Verify that the old mapping is still there
   141  	mappedVersions = vc.getMappedVersionsDist(v)
   142  
   143  	for from, to := range mapping {
   144  		vc.checkMapping(t, mappedVersions, from, to)
   145  	}
   146  
   147  	// Create a new branch off of the first version
   148  	apiStr = fmt.Sprintf("%snode/%s/branch", server.WebAPIPath, uuid)
   149  	payload = bytes.NewBufferString(`{"branch": "branch 1", "note": "version 3"}`)
   150  	respData = server.TestHTTP(t, "POST", apiStr, payload)
   151  	if err := json.Unmarshal(respData, &resp); err != nil {
   152  		t.Errorf("Expected 'child' JSON response.  Got %s\n", string(respData))
   153  	}
   154  	v3, err := datastore.VersionFromUUID(resp.Child)
   155  	if err != nil {
   156  		t.Fatalf("error getting version from UUID: %v\n", err)
   157  	}
   158  
   159  	// Get a new mapping
   160  	mapping3 := map[uint64]uint64{
   161  		3: 15,
   162  		4: 17,
   163  		6: 18,
   164  	}
   165  	for from, to := range mapping3 {
   166  		vc.setMapping(v3, from, to)
   167  	}
   168  	expected3 := mapUpdate(mapping, mapping3)
   169  
   170  	// Make sure that the mapping is the new one
   171  	mappedVersions3 := vc.getMappedVersionsDist(v3)
   172  
   173  	vc.checkMapping(t, mappedVersions3, 1, 3) // unset should fall back to version 1
   174  	vc.checkMapping(t, mappedVersions3, 2, 3) // unset should fall back to version 1
   175  	vc.checkMapping(t, mappedVersions3, 5, 6) // unset should fall back to version 1
   176  	for from, to := range mapping3 {
   177  		vc.checkMapping(t, mappedVersions3, from, to)
   178  	}
   179  
   180  	// Verify that the old mapping is still there
   181  	mappedVersions = vc.getMappedVersionsDist(v)
   182  
   183  	for from, to := range mapping {
   184  		vc.checkMapping(t, mappedVersions, from, to)
   185  	}
   186  
   187  	// check mappings
   188  	buf := new(bytes.Buffer)
   189  	if err := d.writeMappings(buf, v, false); err != nil {
   190  		t.Fatal(err)
   191  	}
   192  	checkMappings(t, v, buf, mapping)
   193  	buf.Reset()
   194  	if err := d.writeMappings(buf, v2, false); err != nil {
   195  		t.Fatal(err)
   196  	}
   197  	checkMappings(t, v2, buf, expected2)
   198  	if err := d.writeMappings(buf, v3, false); err != nil {
   199  		t.Fatal(err)
   200  	}
   201  	checkMappings(t, v3, buf, expected3)
   202  }
   203  
   204  // Tests the logging of various mutations and whether they are properly
   205  // reloaded from the log.
   206  func TestMappingIngest(t *testing.T) {
   207  	if err := server.OpenTest(); err != nil {
   208  		t.Fatalf("can't open test server: %v\n", err)
   209  	}
   210  	defer server.CloseTest()
   211  
   212  	uuid, v := initTestRepo()
   213  	var config dvid.Config
   214  	server.CreateTestInstance(t, uuid, "labelmap", "labels", config)
   215  
   216  	d, err := GetByVersionName(v, "labels")
   217  	if err != nil {
   218  		t.Fatalf("can't get labelmap data service: %v\n", err)
   219  	}
   220  	vc := initMapping(d, v)
   221  
   222  	mapping := map[uint64]uint64{
   223  		1: 1,
   224  		5: 1,
   225  
   226  		2: 2,
   227  		3: 3,
   228  		4: 4,
   229  	}
   230  	for from, to := range mapping {
   231  		vc.setMapping(v, from, to)
   232  	}
   233  
   234  	// Renumber of label 4 to 50.
   235  	mutID := d.NewMutationID()
   236  	supervoxels := labels.Set{4: struct{}{}}
   237  	addRenumberToMapping(d, v, mutID, 4, 50, supervoxels)
   238  
   239  	// Merge label 2 into 3.
   240  	mutID = d.NewMutationID()
   241  	supervoxels = labels.Set{2: struct{}{}}
   242  	addMergeToMapping(d, v, mutID, 3, supervoxels)
   243  
   244  	// Cleave label 1 so that sv 1 remains and sv 5 -> 6.
   245  	mutID = d.NewMutationID()
   246  	op := labels.CleaveOp{
   247  		MutID:              mutID,
   248  		Target:             1,
   249  		CleavedLabel:       6,
   250  		CleavedSupervoxels: []uint64{5},
   251  	}
   252  	addCleaveToMapping(d, v, op)
   253  
   254  	// Check current in-memory map.
   255  	expected := map[uint64]uint64{
   256  		1: 1,
   257  		5: 6,
   258  		2: 3,
   259  		3: 3,
   260  		4: 50,
   261  	}
   262  	mappedVersions := vc.getMappedVersionsDist(v)
   263  	for from, to := range expected {
   264  		vc.checkMapping(t, mappedVersions, from, to)
   265  	}
   266  
   267  	// Reload the mapping from the log.
   268  	vc2 := initMapping(d, v)
   269  	vc2.initToVersion(d, v, true)
   270  
   271  	// Test that the mapping is correct.
   272  	mappedVersions = vc2.getMappedVersionsDist(v)
   273  	for from, to := range expected {
   274  		vc2.checkMapping(t, mappedVersions, from, to)
   275  	}
   276  }