github.com/metacurrency/holochain@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/buntdbht_test.go (about)

     1  package holochain
     2  
     3  import (
     4  	"fmt"
     5  	. "github.com/holochain/holochain-proto/hash"
     6  	. "github.com/smartystreets/goconvey/convey"
     7  	"github.com/tidwall/buntdb"
     8  	"path/filepath"
     9  	"testing"
    10  )
    11  
    12  func TestBuntHTOpen(t *testing.T) {
    13  	d := SetupTestDir()
    14  	defer CleanupTestDir(d)
    15  
    16  	Convey("It should initialize the data store", t, func() {
    17  		f := filepath.Join(d, DHTStoreFileName)
    18  		So(FileExists(f), ShouldBeFalse)
    19  		ht := &BuntHT{}
    20  		ht.Open(f)
    21  		So(FileExists(f), ShouldBeTrue)
    22  	})
    23  }
    24  
    25  func TestBuntHTPutGetModDel(t *testing.T) {
    26  	d := SetupTestDir()
    27  	defer CleanupTestDir(d)
    28  	node, err := makeNode(1234, "")
    29  	if err != nil {
    30  		panic(err)
    31  	}
    32  	defer node.Close()
    33  
    34  	var id = node.HashAddr
    35  	hash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqh2")
    36  	var idx int
    37  
    38  	ht := &BuntHT{}
    39  	f := filepath.Join(d, DHTStoreFileName)
    40  	ht.Open(f)
    41  
    42  	Convey("It should store and retrieve", t, func() {
    43  		err := ht.Put(node.NewMessage(PUT_REQUEST, HoldReq{EntryHash: hash}), "someType", hash, id, []byte("some value"), StatusLive)
    44  		So(err, ShouldBeNil)
    45  		idx, _ = ht.GetIdx()
    46  
    47  		data, entryType, sources, status, err := ht.Get(hash, StatusLive, GetMaskAll)
    48  		So(err, ShouldBeNil)
    49  		So(string(data), ShouldEqual, "some value")
    50  		So(entryType, ShouldEqual, "someType")
    51  		So(status, ShouldEqual, StatusLive)
    52  		So(sources[0], ShouldEqual, id.Pretty())
    53  
    54  		badhash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqh3")
    55  		data, entryType, _, _, err = ht.Get(badhash, StatusLive, GetMaskDefault)
    56  		So(entryType, ShouldEqual, "")
    57  		So(err, ShouldEqual, ErrHashNotFound)
    58  	})
    59  
    60  	Convey("It should iterate", t, func() {
    61  		hlist := make([]Hash, 0)
    62  		ht.Iterate(func(hsh Hash) bool {
    63  			hlist = append(hlist, hsh)
    64  			return true
    65  		})
    66  		So(len(hlist), ShouldEqual, 1)
    67  		So(hlist[0].String(), ShouldEqual, hash.String())
    68  	})
    69  
    70  	Convey("mod should move the hash to the modified status and record replacedBy link", t, func() {
    71  		newhashStr := "QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqh4"
    72  		newhash, _ := NewHash(newhashStr)
    73  
    74  		m := node.NewMessage(MOD_REQUEST, HoldReq{RelatedHash: hash, EntryHash: newhash})
    75  
    76  		err := ht.Mod(m, hash, newhash)
    77  		So(err, ShouldBeNil)
    78  		data, entryType, _, status, err := ht.Get(hash, StatusAny, GetMaskAll)
    79  		So(err, ShouldBeNil)
    80  		So(string(data), ShouldEqual, "some value")
    81  		So(entryType, ShouldEqual, "someType")
    82  		So(status, ShouldEqual, StatusModified)
    83  
    84  		afterIdx, _ := ht.GetIdx()
    85  
    86  		So(afterIdx-idx, ShouldEqual, 1)
    87  
    88  		data, entryType, _, status, err = ht.Get(hash, StatusLive, GetMaskDefault)
    89  		So(err, ShouldEqual, ErrHashNotFound)
    90  
    91  		data, entryType, _, status, err = ht.Get(hash, StatusDefault, GetMaskDefault)
    92  		So(err, ShouldEqual, ErrHashModified)
    93  		// replaced by link gets returned in the data!!
    94  		So(string(data), ShouldEqual, newhashStr)
    95  
    96  		links, err := ht.GetLinks(hash, SysTagReplacedBy, StatusLive)
    97  		So(err, ShouldBeNil)
    98  		So(len(links), ShouldEqual, 1)
    99  		So(links[0].H, ShouldEqual, newhashStr)
   100  	})
   101  
   102  	Convey("del should move the hash to the deleted status", t, func() {
   103  		m := node.NewMessage(DEL_REQUEST, HoldReq{RelatedHash: hash})
   104  
   105  		err := ht.Del(m, hash)
   106  		So(err, ShouldBeNil)
   107  
   108  		data, entryType, _, status, err := ht.Get(hash, StatusAny, GetMaskAll)
   109  		So(err, ShouldBeNil)
   110  		So(string(data), ShouldEqual, "some value")
   111  		So(entryType, ShouldEqual, "someType")
   112  		So(status, ShouldEqual, StatusDeleted)
   113  
   114  		afterIdx, _ := ht.GetIdx()
   115  
   116  		So(afterIdx-idx, ShouldEqual, 2)
   117  
   118  		data, entryType, _, status, err = ht.Get(hash, StatusLive, GetMaskDefault)
   119  		So(err, ShouldEqual, ErrHashNotFound)
   120  
   121  		data, entryType, _, status, err = ht.Get(hash, StatusDefault, GetMaskDefault)
   122  		So(err, ShouldEqual, ErrHashDeleted)
   123  
   124  	})
   125  }
   126  
   127  func TestBuntHTLinking(t *testing.T) {
   128  	d := SetupTestDir()
   129  	defer CleanupTestDir(d)
   130  	node, err := makeNode(1234, "")
   131  	if err != nil {
   132  		panic(err)
   133  	}
   134  	defer node.Close()
   135  
   136  	var id = node.HashAddr
   137  
   138  	ht := &BuntHT{}
   139  	f := filepath.Join(d, DHTStoreFileName)
   140  	ht.Open(f)
   141  
   142  	baseStr := "QmZcUPvPhD1Xvk6mwijYF8AfR3mG31S1YsEfHG4khrFPRr"
   143  	base, err := NewHash(baseStr)
   144  	if err != nil {
   145  		panic(err)
   146  	}
   147  	linkingEntryHashStr := "QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqh3"
   148  	linkingEntryHash, _ := NewHash(linkingEntryHashStr)
   149  	linkHash1Str := "QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqh1"
   150  	linkHash1, _ := NewHash(linkHash1Str)
   151  	linkHash2Str := "QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqh2"
   152  	//linkHash2, _ := NewHash(linkHash2Str)
   153  	Convey("It should fail if hash doesn't exist", t, func() {
   154  		err := ht.PutLink(nil, baseStr, linkHash1Str, "tag foo")
   155  		So(err, ShouldEqual, ErrHashNotFound)
   156  
   157  		v, err := ht.GetLinks(base, "tag foo", StatusLive)
   158  		So(v, ShouldBeNil)
   159  		So(err, ShouldEqual, ErrHashNotFound)
   160  	})
   161  
   162  	err = ht.Put(node.NewMessage(PUT_REQUEST, HoldReq{EntryHash: base}), "someType", base, id, []byte("some value"), StatusLive)
   163  	if err != nil {
   164  		panic(err)
   165  	}
   166  
   167  	// the message doesn't actually matter for this test because it only gets used later in gossiping
   168  	fakeMsg := node.NewMessage(LINK_REQUEST, HoldReq{RelatedHash: linkHash1, EntryHash: linkingEntryHash})
   169  
   170  	Convey("Low level should add linking events to buntdb", t, func() {
   171  		err := ht.link(fakeMsg, baseStr, linkHash1Str, "link test", StatusLive)
   172  		So(err, ShouldBeNil)
   173  		err = ht.db.View(func(tx *buntdb.Tx) error {
   174  			err = tx.Ascend("link", func(key, value string) bool {
   175  				So(key, ShouldEqual, fmt.Sprintf(`link:%s:%s:link test`, baseStr, linkHash1Str))
   176  				So(value, ShouldEqual, fmt.Sprintf(`[{"Status":%d,"Source":"%s","LinksEntry":"%s"}]`, StatusLive, id.Pretty(), linkingEntryHashStr))
   177  				return true
   178  			})
   179  			return nil
   180  		})
   181  
   182  		err = ht.link(fakeMsg, baseStr, linkHash1Str, "link test", StatusDeleted)
   183  		So(err, ShouldBeNil)
   184  		err = ht.db.View(func(tx *buntdb.Tx) error {
   185  			err = tx.Ascend("link", func(key, value string) bool {
   186  				So(value, ShouldEqual, fmt.Sprintf(`[{"Status":%d,"Source":"%s","LinksEntry":"%s"},{"Status":%d,"Source":"%s","LinksEntry":"%s"}]`, StatusLive, id.Pretty(), linkingEntryHashStr, StatusDeleted, id.Pretty(), linkingEntryHashStr))
   187  				return true
   188  			})
   189  			return nil
   190  		})
   191  	})
   192  
   193  	Convey("It should store and retrieve links values on a base", t, func() {
   194  		data, err := ht.GetLinks(base, "tag foo", StatusLive)
   195  		So(err, ShouldBeNil)
   196  		So(len(data), ShouldEqual, 0)
   197  
   198  		err = ht.PutLink(fakeMsg, baseStr, linkHash1Str, "tag foo")
   199  		So(err, ShouldBeNil)
   200  
   201  		err = ht.PutLink(fakeMsg, baseStr, linkHash2Str, "tag foo")
   202  		So(err, ShouldBeNil)
   203  
   204  		err = ht.PutLink(fakeMsg, baseStr, linkHash1Str, "tag bar")
   205  		So(err, ShouldBeNil)
   206  
   207  		data, err = ht.GetLinks(base, "tag foo", StatusLive)
   208  		So(err, ShouldBeNil)
   209  		So(len(data), ShouldEqual, 2)
   210  		m := data[0]
   211  
   212  		So(m.H, ShouldEqual, linkHash1Str)
   213  		m = data[1]
   214  		So(m.H, ShouldEqual, linkHash2Str)
   215  
   216  		data, err = ht.GetLinks(base, "tag bar", StatusLive)
   217  		So(err, ShouldBeNil)
   218  		So(len(data), ShouldEqual, 1)
   219  		So(data[0].H, ShouldEqual, linkHash1Str)
   220  	})
   221  
   222  	Convey("It should store and retrieve a links source", t, func() {
   223  		err = ht.PutLink(fakeMsg, baseStr, linkHash1Str, "tag source")
   224  		So(err, ShouldBeNil)
   225  
   226  		data, err := ht.GetLinks(base, "tag source", StatusLive)
   227  		So(err, ShouldBeNil)
   228  		So(len(data), ShouldEqual, 1)
   229  
   230  		data, err = ht.GetLinks(base, "tag source", StatusLive)
   231  		So(err, ShouldBeNil)
   232  		So(len(data), ShouldEqual, 1)
   233  		So(data[0].Source, ShouldEqual, id.Pretty())
   234  	})
   235  
   236  	Convey("It should work to put a link a second time", t, func() {
   237  		err = ht.PutLink(fakeMsg, baseStr, linkHash1Str, "tag foo")
   238  		So(err, ShouldBeNil)
   239  	})
   240  
   241  	Convey("It should fail delete links non existent links bases and tags", t, func() {
   242  		badHashStr := "QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqhX"
   243  
   244  		err := ht.DelLink(fakeMsg, badHashStr, linkHash1Str, "tag foo")
   245  		So(err, ShouldEqual, ErrHashNotFound)
   246  		err = ht.DelLink(fakeMsg, baseStr, badHashStr, "tag foo")
   247  		So(err, ShouldEqual, ErrLinkNotFound)
   248  		err = ht.DelLink(fakeMsg, baseStr, linkHash1Str, "tag baz")
   249  		So(err, ShouldEqual, ErrLinkNotFound)
   250  	})
   251  
   252  	Convey("It should delete links", t, func() {
   253  		err := ht.DelLink(fakeMsg, baseStr, linkHash1Str, "tag bar")
   254  		So(err, ShouldBeNil)
   255  		data, err := ht.GetLinks(base, "tag bar", StatusLive)
   256  		So(err, ShouldBeNil)
   257  		So(len(data), ShouldEqual, 0)
   258  
   259  		err = ht.DelLink(fakeMsg, baseStr, linkHash1Str, "tag foo")
   260  		So(err, ShouldBeNil)
   261  		data, err = ht.GetLinks(base, "tag foo", StatusLive)
   262  		So(err, ShouldBeNil)
   263  		So(len(data), ShouldEqual, 1)
   264  
   265  		err = ht.DelLink(fakeMsg, baseStr, linkHash2Str, "tag foo")
   266  		So(err, ShouldBeNil)
   267  		data, err = ht.GetLinks(base, "tag foo", StatusLive)
   268  		So(err, ShouldBeNil)
   269  		So(len(data), ShouldEqual, 0)
   270  	})
   271  }