github.com/holochain/holochain-proto@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 }