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

     1  package imagetile
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"log"
    10  	"reflect"
    11  	"sync"
    12  	"testing"
    13  
    14  	"github.com/janelia-flyem/dvid/datastore"
    15  	"github.com/janelia-flyem/dvid/datatype/imageblk"
    16  	"github.com/janelia-flyem/dvid/datatype/roi"
    17  	"github.com/janelia-flyem/dvid/dvid"
    18  	"github.com/janelia-flyem/dvid/server"
    19  	"github.com/janelia-flyem/dvid/storage"
    20  )
    21  
    22  var (
    23  	mstype, grayscaleT, roitype datastore.TypeService
    24  	testMu                      sync.Mutex
    25  )
    26  
    27  // Sets package-level testRepo and TestVersionID
    28  func initTestRepo() (dvid.UUID, dvid.VersionID) {
    29  	testMu.Lock()
    30  	defer testMu.Unlock()
    31  	if mstype == nil {
    32  		var err error
    33  		mstype, err = datastore.TypeServiceByName(TypeName)
    34  		if err != nil {
    35  			log.Fatalf("Can't get imagetile type: %s\n", err)
    36  		}
    37  		grayscaleT, err = datastore.TypeServiceByName("uint8blk")
    38  		if err != nil {
    39  			log.Fatalf("Can't get grayscale type: %s\n", err)
    40  		}
    41  		roitype, err = datastore.TypeServiceByName(roi.TypeName)
    42  		if err != nil {
    43  			log.Fatalf("Can't get ROI type: %v\n", err)
    44  		}
    45  	}
    46  	return datastore.NewTestRepo()
    47  }
    48  
    49  func makeGrayscale(uuid dvid.UUID, t *testing.T, name dvid.InstanceName) *imageblk.Data {
    50  	config := dvid.NewConfig()
    51  	dataservice, err := datastore.NewData(uuid, grayscaleT, name, config)
    52  	if err != nil {
    53  		t.Errorf("Unable to create grayscale instance %q: %v\n", name, err)
    54  	}
    55  	grayscale, ok := dataservice.(*imageblk.Data)
    56  	if !ok {
    57  		t.Errorf("Can't cast data service into imageblk Data\n")
    58  	}
    59  	return grayscale
    60  }
    61  
    62  const testTileSpec = `
    63  {
    64      "0": {  "Resolution": [10.0, 10.0, 10.0], "TileSize": [512, 512, 512] },
    65      "1": {  "Resolution": [20.0, 20.0, 20.0], "TileSize": [512, 512, 512] },
    66      "2": {  "Resolution": [40.0, 40.0, 40.0], "TileSize": [512, 512, 512] },
    67      "3": {  "Resolution": [80.0, 80.0, 80.0], "TileSize": [512, 512, 512] }
    68  }
    69  `
    70  
    71  func TestLoadTileSpec(t *testing.T) {
    72  	tileSpec, err := LoadTileSpec([]byte(testTileSpec))
    73  	if err != nil {
    74  		t.Errorf("Unable to load tile spec: %v\n", err)
    75  	}
    76  	if len(tileSpec) != 4 {
    77  		t.Errorf("Bad tile spec load: only %d elements != 4\n", len(tileSpec))
    78  	}
    79  	if tileSpec[2].Resolution.GetMax() != 40.0 {
    80  		t.Errorf("Bad tile spec at level 2: %v\n", tileSpec[2])
    81  	}
    82  	if tileSpec[3].TileSize.Value(2) != 512 {
    83  		t.Errorf("Bad tile spec at level 3: %v\n", tileSpec[3])
    84  	}
    85  }
    86  
    87  const testMetadata = `
    88  {
    89  	"MinTileCoord": [0,0,0],
    90  	"MaxTileCoord": [5,5,4],
    91  	"Levels": {
    92  	    "0": {  "Resolution": [10.0, 10.0, 10.0], "TileSize": [512, 512, 512] },
    93  	    "1": {  "Resolution": [20.0, 20.0, 20.0], "TileSize": [512, 512, 512] },
    94  	    "2": {  "Resolution": [40.0, 40.0, 40.0], "TileSize": [512, 512, 512] },
    95  	    "3": {  "Resolution": [80.0, 80.0, 80.0], "TileSize": [512, 512, 512] }
    96  	}
    97  }
    98  `
    99  
   100  func TestSetMetadata(t *testing.T) {
   101  	if err := server.OpenTest(); err != nil {
   102  		t.Fatalf("can't open test server: %v\n", err)
   103  	}
   104  	defer server.CloseTest()
   105  
   106  	uuid, _ := initTestRepo()
   107  	server.CreateTestInstance(t, uuid, "imagetile", "tiles", dvid.Config{})
   108  
   109  	// Store Metadata
   110  	url := fmt.Sprintf("%snode/%s/tiles/metadata", server.WebAPIPath, uuid)
   111  	server.TestHTTP(t, "POST", url, bytes.NewBufferString(testMetadata))
   112  
   113  	// Check instance really has it set.
   114  	var metadata metadataJSON
   115  	respStr := server.TestHTTP(t, "GET", url, nil)
   116  	if err := json.Unmarshal(respStr, &metadata); err != nil {
   117  		t.Fatalf("Couldn't parse JSON response to metadata request (%v):\n%s\n", err, respStr)
   118  	}
   119  	expectMin := dvid.Point3d{0, 0, 0}
   120  	expectMax := dvid.Point3d{5, 5, 4}
   121  	if !expectMin.Equals(metadata.MinTileCoord) {
   122  		t.Errorf("Expected min tile coord %s, got %s\n", expectMin, metadata.MinTileCoord)
   123  	}
   124  	if !expectMax.Equals(metadata.MaxTileCoord) {
   125  		t.Errorf("Expected max tile coord %s, got %s\n", expectMax, metadata.MaxTileCoord)
   126  	}
   127  	tileSpec, err := parseTileSpec(metadata.Levels)
   128  	if err != nil {
   129  		t.Errorf("Error parsing returned tile level spec:\n%v\n", metadata.Levels)
   130  	}
   131  	if len(tileSpec) != 4 {
   132  		t.Errorf("Bad tile spec load: only %d elements != 4\n", len(tileSpec))
   133  	}
   134  	if tileSpec[2].Resolution.GetMax() != 40.0 {
   135  		t.Errorf("Bad tile spec at level 2: %v\n", tileSpec[2])
   136  	}
   137  	if tileSpec[3].TileSize.Value(2) != 512 {
   138  		t.Errorf("Bad tile spec at level 3: %v\n", tileSpec[3])
   139  	}
   140  }
   141  
   142  func TestMultiscale2dRepoPersistence(t *testing.T) {
   143  	if err := server.OpenTest(); err != nil {
   144  		t.Fatalf("can't open test server: %v\n", err)
   145  	}
   146  	defer server.CloseTest()
   147  
   148  	// Make source
   149  	uuid, _ := initTestRepo()
   150  	makeGrayscale(uuid, t, "grayscale")
   151  
   152  	// Make labels and set various properties
   153  	config := dvid.NewConfig()
   154  	config.Set("Placeholder", "true")
   155  	config.Set("Format", "jpg")
   156  	config.Set("Source", "grayscale")
   157  	dataservice, err := datastore.NewData(uuid, mstype, "myimagetile", config)
   158  	if err != nil {
   159  		t.Errorf("Unable to create imagetile instance: %v\n", err)
   160  	}
   161  	msdata, ok := dataservice.(*Data)
   162  	if !ok {
   163  		t.Fatalf("Can't cast imagetile data service into imagetile.Data\n")
   164  	}
   165  	oldData := *msdata
   166  
   167  	// Restart test datastore and see if datasets are still there.
   168  	if err = datastore.SaveDataByUUID(uuid, msdata); err != nil {
   169  		t.Fatalf("Unable to save repo during imagetile persistence test: %v\n", err)
   170  	}
   171  	datastore.CloseReopenTest()
   172  
   173  	dataservice2, err := datastore.GetDataByUUIDName(uuid, "myimagetile")
   174  	if err != nil {
   175  		t.Fatalf("Can't get keyvalue instance from reloaded test db: %v\n", err)
   176  	}
   177  	msdata2, ok := dataservice2.(*Data)
   178  	if !ok {
   179  		t.Errorf("Returned new data instance 2 is not imagetile.Data\n")
   180  	}
   181  
   182  	if !reflect.DeepEqual(oldData.Properties, msdata2.Properties) {
   183  		t.Errorf("Expected properties %v, got %v\n", oldData.Properties, msdata2.Properties)
   184  	}
   185  }
   186  
   187  func TestTileKey(t *testing.T) {
   188  	if err := server.OpenTest(); err != nil {
   189  		t.Fatalf("can't open test server: %v\n", err)
   190  	}
   191  	defer server.CloseTest()
   192  
   193  	uuid, _ := initTestRepo()
   194  	server.CreateTestInstance(t, uuid, "imagetile", "tiles", dvid.Config{})
   195  
   196  	keyURL := fmt.Sprintf("%snode/%s/tiles/tilekey/xy/0/1_2_3", server.WebAPIPath, uuid)
   197  	respStr := server.TestHTTP(t, "GET", keyURL, nil)
   198  	keyResp := struct {
   199  		Key string `json:"key"`
   200  	}{}
   201  	if err := json.Unmarshal(respStr, &keyResp); err != nil {
   202  		t.Fatalf("Couldn't parse JSON response to tilekey request (%v):\n%s\n", err, keyResp)
   203  	}
   204  	kb := make([]byte, hex.DecodedLen(len(keyResp.Key)))
   205  	_, err := hex.Decode(kb, []byte(keyResp.Key))
   206  	if err != nil {
   207  		t.Fatalf("Couldn't parse return hex key: %s", keyResp.Key)
   208  	}
   209  
   210  	// Decipher TKey portion to make sure it's correct.
   211  	key := storage.Key(kb)
   212  	tk, err := storage.TKeyFromKey(key)
   213  	if err != nil {
   214  		t.Fatalf("Couldn't get TKey from returned key (%v): %x", err, kb)
   215  	}
   216  	tile, plane, scale, err := DecodeTKey(tk)
   217  	if err != nil {
   218  		t.Fatalf("Bad decode of TKey (%v): %x", err, tk)
   219  	}
   220  	expectTile := dvid.ChunkPoint3d{1, 2, 3}
   221  	if tile != expectTile {
   222  		t.Errorf("Expected tile %v, got %v\n", expectTile, tile)
   223  	}
   224  	if !plane.Equals(dvid.XY) {
   225  		t.Errorf("Expected plane to be XY, got %v\n", plane)
   226  	}
   227  	if scale != 0 {
   228  		t.Errorf("Expected scale to be 0, got %d\n", scale)
   229  	}
   230  }
   231  
   232  const testMetadata2 = `
   233  {
   234  	"MinTileCoord": [0,0,0],
   235  	"MaxTileCoord": [30,30,30],
   236  	"Levels": {
   237  	    "0": {  "Resolution": [10.0, 10.0, 10.0], "TileSize": [512, 512, 512] },
   238  	    "1": {  "Resolution": [20.0, 20.0, 20.0], "TileSize": [512, 512, 512] },
   239  	    "2": {  "Resolution": [40.0, 40.0, 40.0], "TileSize": [512, 512, 512] },
   240  	    "3": {  "Resolution": [80.0, 80.0, 80.0], "TileSize": [512, 512, 512] }
   241  	}
   242  }
   243  `
   244  
   245  var testSpans = []dvid.Span{
   246  	dvid.Span{100, 101, 200, 210}, dvid.Span{100, 102, 200, 210}, dvid.Span{100, 103, 201, 212},
   247  	dvid.Span{101, 101, 201, 213}, dvid.Span{101, 102, 202, 215}, dvid.Span{101, 103, 202, 216},
   248  	dvid.Span{102, 101, 200, 210}, dvid.Span{102, 103, 201, 216}, dvid.Span{102, 104, 203, 217},
   249  	dvid.Span{103, 101, 200, 210}, dvid.Span{103, 103, 200, 210}, dvid.Span{103, 105, 201, 212},
   250  }
   251  
   252  func getSpansJSON(spans []dvid.Span) io.Reader {
   253  	jsonBytes, err := json.Marshal(spans)
   254  	if err != nil {
   255  		log.Fatalf("Can't encode spans into JSON: %v\n", err)
   256  	}
   257  	return bytes.NewReader(jsonBytes)
   258  }
   259  
   260  func TestTileCheck(t *testing.T) {
   261  	if err := server.OpenTest(); err != nil {
   262  		t.Fatalf("can't open test server: %v\n", err)
   263  	}
   264  	defer server.CloseTest()
   265  
   266  	// Make source
   267  	uuid, _ := initTestRepo()
   268  	makeGrayscale(uuid, t, "grayscale")
   269  
   270  	// Make imagetile and set various properties
   271  	config := dvid.NewConfig()
   272  	config.Set("Placeholder", "true")
   273  	config.Set("Format", "jpg")
   274  	config.Set("Source", "grayscale")
   275  	tileservice, err := datastore.NewData(uuid, mstype, "myimagetile", config)
   276  	if err != nil {
   277  		t.Errorf("Unable to create imagetile instance: %v\n", err)
   278  	}
   279  	msdata, ok := tileservice.(*Data)
   280  	if !ok {
   281  		t.Fatalf("Can't cast imagetile data service into imagetile.Data\n")
   282  	}
   283  
   284  	// Store Metadata
   285  	url := fmt.Sprintf("%snode/%s/myimagetile/metadata", server.WebAPIPath, uuid)
   286  	server.TestHTTP(t, "POST", url, bytes.NewBufferString(testMetadata2))
   287  
   288  	// Create the ROI
   289  	_, err = datastore.NewData(uuid, roitype, "myroi", dvid.NewConfig())
   290  	if err != nil {
   291  		t.Errorf("Error creating new roi instance: %v\n", err)
   292  	}
   293  
   294  	// PUT an ROI
   295  	roiRequest := fmt.Sprintf("%snode/%s/myroi/roi", server.WebAPIPath, uuid)
   296  	server.TestHTTP(t, "POST", roiRequest, getSpansJSON(testSpans))
   297  
   298  	// Create fake filter
   299  	spec := fmt.Sprintf("roi:myroi,%s", uuid)
   300  	f, err := msdata.NewFilter(storage.FilterSpec(spec))
   301  	if err != nil {
   302  		t.Errorf("Couldn't make filter: %v\n", err)
   303  	}
   304  	if f == nil {
   305  		t.Fatalf("Couldn't detect myroi data instance\n")
   306  	}
   307  
   308  	// Check various key values for proper spatial checks.
   309  	var tx, ty int32
   310  	tx = (205 * 32) / 512
   311  	ty = (101 * 32) / 512
   312  	tile := dvid.ChunkPoint3d{tx, ty, 101 * 32}
   313  	scale := Scaling(0)
   314  	tk, err := NewTKey(tile, dvid.XY, scale)
   315  	if err != nil {
   316  		t.Errorf("bad tkey: %v\n", err)
   317  	}
   318  	tkv := &storage.TKeyValue{K: tk}
   319  	skip, err := f.Check(tkv)
   320  	if err != nil {
   321  		t.Errorf("Error on Check of key %q: %v\n", tkv.K, err)
   322  	}
   323  	if skip {
   324  		t.Errorf("Expected false skip, got %v for tile %s\n", skip, tile)
   325  	}
   326  
   327  	tile = dvid.ChunkPoint3d{tx, ty, 106 * 32}
   328  	tk, err = NewTKey(tile, dvid.XY, scale)
   329  	if err != nil {
   330  		t.Errorf("bad tkey: %v\n", err)
   331  	}
   332  	tkv = &storage.TKeyValue{K: tk}
   333  	skip, err = f.Check(tkv)
   334  	if err != nil {
   335  		t.Errorf("Error on Check of key %q: %v\n", tkv.K, err)
   336  	}
   337  	if !skip {
   338  		t.Errorf("Expected true skip, got %v for tile %s\n", skip, tile)
   339  	}
   340  
   341  	tx = (205 * 32) / 512
   342  	ty = (121 * 32) / 512
   343  	tile = dvid.ChunkPoint3d{tx, ty, 101 * 32}
   344  	tk, err = NewTKey(tile, dvid.XY, scale)
   345  	if err != nil {
   346  		t.Errorf("bad tkey: %v\n", err)
   347  	}
   348  	tkv = &storage.TKeyValue{K: tk}
   349  	skip, err = f.Check(tkv)
   350  	if err != nil {
   351  		t.Errorf("Error on Check of key %q: %v\n", tkv.K, err)
   352  	}
   353  	if !skip {
   354  		t.Errorf("Expected true skip, got %v for tile %s\n", skip, tile)
   355  	}
   356  
   357  	tx = (225 * 32) / 512
   358  	ty = (101 * 32) / 512
   359  	tile = dvid.ChunkPoint3d{tx, ty, 101 * 32}
   360  	tk, err = NewTKey(tile, dvid.XY, scale)
   361  	if err != nil {
   362  		t.Errorf("bad tkey: %v\n", err)
   363  	}
   364  	tkv = &storage.TKeyValue{K: tk}
   365  	skip, err = f.Check(tkv)
   366  	if err != nil {
   367  		t.Errorf("Error on Check of key %q: %v\n", tkv.K, err)
   368  	}
   369  	if !skip {
   370  		t.Errorf("Expected true skip, got %v for tile %s\n", skip, tile)
   371  	}
   372  
   373  }