github.com/metacurrency/holochain@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/holochain_test.go (about) 1 package holochain 2 3 import ( 4 "bytes" 5 "encoding/gob" 6 "fmt" 7 "github.com/google/uuid" 8 . "github.com/holochain/holochain-proto/hash" 9 peer "github.com/libp2p/go-libp2p-peer" 10 . "github.com/smartystreets/goconvey/convey" 11 "os" 12 "path/filepath" 13 "testing" 14 "time" 15 ) 16 17 func TestMain(m *testing.M) { 18 os.Setenv("_HCTEST", "1") 19 // disable UPNP for tests 20 os.Setenv("HOLOCHAINCONFIG_ENABLENATUPNP", "false") 21 22 InitializeHolochain() 23 os.Exit(m.Run()) 24 } 25 26 func TestNewHolochain(t *testing.T) { 27 a, _ := NewAgent(LibP2P, "Joe", MakeTestSeed("")) 28 29 Convey("New should fill Holochain struct with provided values and new UUID", t, func() { 30 31 h := NewHolochain(a, "some/path", "json") 32 nUUID := string(uuid.NodeID()) 33 So(nUUID, ShouldEqual, string(h.nucleus.dna.UUID.NodeID())) // this nodeID is from UUID code, i.e the machine's host (not the LibP2P nodeID below) 34 So(h.agent.Identity(), ShouldEqual, "Joe") 35 So(h.agent.PrivKey(), ShouldEqual, a.PrivKey()) 36 So(h.encodingFormat, ShouldEqual, "json") 37 So(h.rootPath, ShouldEqual, "some/path") 38 So(h.UIPath(), ShouldEqual, "some/path/ui") 39 So(h.DNAPath(), ShouldEqual, "some/path/dna") 40 So(h.DBPath(), ShouldEqual, "some/path/db") 41 nodeID, nodeIDStr, _ := h.agent.NodeID() 42 So(h.nodeID, ShouldEqual, nodeID) 43 So(h.nodeIDStr, ShouldEqual, nodeIDStr) 44 So(h.nodeIDStr, ShouldEqual, peer.IDB58Encode(h.nodeID)) 45 46 So(h.nucleus.dna.Progenitor.Identity, ShouldEqual, "Joe") 47 pk, _ := a.PubKey().Bytes() 48 So(string(h.nucleus.dna.Progenitor.PubKey), ShouldEqual, string(pk)) 49 }) 50 Convey("New with Zome should fill them", t, func() { 51 z := Zome{Name: "zySampleZome", 52 Description: "zome desc", 53 Code: "zome_zySampleZome.zy", 54 Entries: []EntryDef{ 55 {Name: "entryTypeFoo", DataFormat: DataFormatString}, 56 {Name: "entryTypeBar", DataFormat: DataFormatRawZygo}, 57 }, 58 } 59 60 h := NewHolochain(a, "some/path", "yaml", z) 61 nz, _ := h.GetZome("zySampleZome") 62 So(nz.Description, ShouldEqual, "zome desc") 63 So(nz.Code, ShouldEqual, "zome_zySampleZome.zy") 64 So(fmt.Sprintf("%v", nz.Entries[0]), ShouldEqual, "{entryTypeFoo string <nil>}") 65 So(fmt.Sprintf("%v", nz.Entries[1]), ShouldEqual, "{entryTypeBar zygo <nil>}") 66 }) 67 68 } 69 70 func TestSetupConfig(t *testing.T) { 71 Convey("it should set the intervals", t, func() { 72 config := Config{} 73 config.EnableWorldModel = false 74 config.Setup() 75 So(config.holdingCheckInterval, ShouldEqual, 0) 76 77 So(config.gossipInterval, ShouldEqual, DefaultGossipInterval) 78 So(config.bootstrapRefreshInterval, ShouldEqual, BootstrapTTL) 79 So(config.routingRefreshInterval, ShouldEqual, DefaultRoutingRefreshInterval) 80 So(config.retryInterval, ShouldEqual, DefaultRetryInterval) 81 82 config.EnableWorldModel = true 83 config.Setup() 84 So(config.holdingCheckInterval, ShouldEqual, DefaultHoldingCheckInterval) 85 }) 86 87 Convey("it should honor env variables", t, func() { 88 config := Config{} 89 So(config.EnableWorldModel, ShouldBeFalse) 90 os.Setenv("HC_GOSSIP_INTERVAL", "3") 91 os.Setenv("HC_HOLDING_INTERVAL", "2") 92 config.Setup() 93 So(config.gossipInterval, ShouldEqual, time.Second*3) 94 So(config.holdingCheckInterval, ShouldEqual, time.Second*2) 95 So(config.EnableWorldModel, ShouldBeTrue) 96 }) 97 os.Unsetenv("HC_GOSSIP_INTERVAL") 98 os.Unsetenv("HC_HOLDING_INTERVAL") 99 100 } 101 102 func TestSetupLogging(t *testing.T) { 103 d, _, h := SetupTestChain("test") 104 defer CleanupTestChain(h, d) 105 Convey("it should initialize the loggers", t, func() { 106 err := h.Config.SetupLogging() 107 So(err, ShouldBeNil) 108 // test some default configurations 109 So(h.Config.Loggers.App.Enabled, ShouldBeFalse) 110 So(h.Config.Loggers.DHT.Enabled, ShouldBeFalse) 111 So(h.Config.Loggers.World.Enabled, ShouldBeFalse) 112 So(h.Config.Loggers.Gossip.Enabled, ShouldBeFalse) 113 So(h.Config.Loggers.TestFailed.w, ShouldEqual, os.Stderr) 114 // test that a sample color got initialized 115 So(fmt.Sprintf("%v", h.Config.Loggers.App.color), ShouldEqual, "&{[36] <nil>}") 116 }) 117 Convey("it should initialize the loggers with env vars", t, func() { 118 os.Setenv("HCLOG_APP_ENABLE", "0") 119 os.Setenv("HCLOG_DHT_ENABLE", "1") 120 os.Setenv("HCLOG_WORLD_ENABLE", "1") 121 os.Setenv("HCLOG_GOSSIP_ENABLE", "true") 122 os.Setenv("HCLOG_PREFIX", "a prefix:") 123 h.Config.Loggers.DHT.Format = "%{message}" 124 err := h.Config.SetupLogging() 125 So(err, ShouldBeNil) 126 So(h.Config.Loggers.App.Enabled, ShouldBeFalse) 127 So(h.Config.Loggers.DHT.Enabled, ShouldBeTrue) 128 So(h.Config.Loggers.World.Enabled, ShouldBeTrue) 129 So(h.Config.Loggers.Gossip.Enabled, ShouldBeTrue) 130 var buf bytes.Buffer 131 h.Config.Loggers.DHT.w = &buf 132 h.Config.Loggers.DHT.Log("test") 133 So(string(buf.Bytes()), ShouldEqual, "a prefix:test\n") 134 135 // restore env 136 os.Unsetenv("HCLOG_APP_ENABLE") 137 os.Unsetenv("HCLOG_DHT_ENABLE") 138 os.Unsetenv("HCLOG_WORLD_ENABLE") 139 os.Unsetenv("HCLOG_GOSSIP_ENABLE") 140 os.Unsetenv("HCLOG_PREFIX") 141 debugLog.SetPrefix("") 142 infoLog.SetPrefix("") 143 }) 144 } 145 146 func TestDebuggingSetup(t *testing.T) { 147 d, _, h := SetupTestChain("test") 148 defer CleanupTestChain(h, d) 149 150 Convey("it should look in the environment to know if we should turn on debugging", t, func() { 151 val, yes := DebuggingRequestedViaEnv() 152 So(yes, ShouldBeFalse) 153 os.Setenv("HCDEBUG", "0") 154 val, yes = DebuggingRequestedViaEnv() 155 So(yes, ShouldBeTrue) 156 So(val, ShouldBeFalse) 157 os.Setenv("HCDEBUG", "false") 158 val, yes = DebuggingRequestedViaEnv() 159 So(yes, ShouldBeTrue) 160 So(val, ShouldBeFalse) 161 os.Setenv("HCDEBUG", "FALSE") 162 val, yes = DebuggingRequestedViaEnv() 163 So(yes, ShouldBeTrue) 164 So(val, ShouldBeFalse) 165 os.Setenv("HCDEBUG", "1") 166 val, yes = DebuggingRequestedViaEnv() 167 So(yes, ShouldBeTrue) 168 So(val, ShouldBeTrue) 169 os.Setenv("HCDEBUG", "True") 170 val, yes = DebuggingRequestedViaEnv() 171 So(yes, ShouldBeTrue) 172 So(val, ShouldBeTrue) 173 os.Setenv("HCDEBUG", "true") 174 val, yes = DebuggingRequestedViaEnv() 175 So(yes, ShouldBeTrue) 176 So(val, ShouldBeTrue) 177 }) 178 Convey("it should setup debugging output", t, func() { 179 // test the output of the debug log 180 var buf bytes.Buffer 181 log := &h.Config.Loggers.Debug 182 log.w = &buf 183 var enabled = log.Enabled 184 log.Enabled = true 185 186 h.Debug("test") 187 So(string(buf.Bytes()), ShouldContainSubstring, "HC: holochain_test.go.") 188 So(string(buf.Bytes()), ShouldContainSubstring, ": test\n") 189 190 // restore state of debug log 191 log.w = os.Stdout 192 log.Enabled = enabled 193 }) 194 } 195 196 func TestPrepare(t *testing.T) { 197 Convey("it should fail if the requires version is incorrect", t, func() { 198 dna := DNA{DHTConfig: DHTConfig{HashType: "sha1"}, RequiresVersion: Version + 1} 199 h := Holochain{} 200 h.nucleus = NewNucleus(&h, &dna) 201 nextVersion := fmt.Sprintf("%d", Version+1) 202 err := h.Prepare() 203 So(err.Error(), ShouldEqual, "Chain requires Holochain version "+nextVersion) 204 205 }) 206 Convey("it should return no err if the requires version is correct", t, func() { 207 d, _, h := SetupTestChain("test") 208 defer CleanupTestChain(h, d) 209 210 dna := DNA{DHTConfig: DHTConfig{HashType: "sha1"}, RequiresVersion: Version} 211 h.nucleus = NewNucleus(h, &dna) 212 err := h.Prepare() 213 So(err, ShouldBeNil) 214 }) 215 //@todo build out test for other tests for prepare 216 } 217 218 func TestPrepareHashType(t *testing.T) { 219 220 Convey("A bad hash type should return an error", t, func() { 221 dna := DNA{DHTConfig: DHTConfig{HashType: "bogus"}} 222 h := Holochain{} 223 h.nucleus = NewNucleus(&h, &dna) 224 err := h.PrepareHashType() 225 So(err.Error(), ShouldEqual, "Unknown hash type: bogus") 226 }) 227 Convey("It should initialized fixed and variable sized hashes", t, func() { 228 dna := DNA{DHTConfig: DHTConfig{HashType: "sha1"}} 229 h := Holochain{} 230 h.nucleus = NewNucleus(&h, &dna) 231 err := h.PrepareHashType() 232 So(err, ShouldBeNil) 233 var hash Hash 234 hash, err = Sum(h.hashSpec, []byte("test data")) 235 So(err, ShouldBeNil) 236 So(hash.String(), ShouldEqual, "5duC28CW416wX42vses7TeTeRYwku9") 237 238 h.nucleus.dna.DHTConfig.HashType = "blake2b-256" 239 err = h.PrepareHashType() 240 So(err, ShouldBeNil) 241 hash, err = Sum(h.hashSpec, []byte("test data")) 242 So(err, ShouldBeNil) 243 So(hash.String(), ShouldEqual, "2DrjgbL49zKmX4P7UgdopSCC7MhfVUySNbRHBQzdDuXgaJSNEg") 244 }) 245 } 246 247 func TestNewEntry(t *testing.T) { 248 d, s := setupTestService() 249 defer CleanupTestDir(d) 250 n := "test" 251 path := filepath.Join(s.Path, n) 252 h, err := s.MakeTestingApp(path, "toml", InitializeDB, CloneWithNewUUID, nil) 253 if err != nil { 254 panic(err) 255 } 256 257 entryTypeFoo := `(message (from "art") (to "eric") (contents "test"))` 258 259 now := time.Unix(1, 1) // pick a constant time so the test will always work 260 261 e := GobEntry{C: entryTypeFoo} 262 headerHash, header, err := h.NewEntry(now, "entryTypeFoo", &e) 263 Convey("parameters passed in should be in the header", t, func() { 264 So(err, ShouldBeNil) 265 So(header.Time == now, ShouldBeTrue) 266 So(header.Type, ShouldEqual, "entryTypeFoo") 267 So(header.HeaderLink.IsNullHash(), ShouldBeTrue) 268 }) 269 Convey("the entry hash is correct", t, func() { 270 So(err, ShouldBeNil) 271 So(header.EntryLink.String(), ShouldEqual, "QmdRXz53TVT9qBYfbXctHyy2GpTNa6YrpAy6ZcDGG8Xhc5") 272 }) 273 274 // can't check against a fixed hash because signature created each time test runs is 275 // different (though valid) so the header will hash to a different value 276 Convey("the returned header hash is the SHA256 of the byte encoded header", t, func() { 277 b, _ := header.Marshal() 278 var hh Hash 279 hh, err = Sum(h.hashSpec, b) 280 So(err, ShouldBeNil) 281 So(headerHash.String(), ShouldEqual, hh.String()) 282 }) 283 284 Convey("it should have signed the entry with my key", t, func() { 285 sig := header.Sig 286 hash := header.EntryLink 287 valid, err := h.agent.PrivKey().GetPublic().Verify([]byte(hash), sig.S) 288 So(err, ShouldBeNil) 289 So(valid, ShouldBeTrue) 290 }) 291 292 Convey("it should store the header and entry to the data store", t, func() { 293 s1 := fmt.Sprintf("%v", *header) 294 d1 := fmt.Sprintf("%v", entryTypeFoo) 295 296 h2, err := h.chain.Get(headerHash) 297 So(err, ShouldBeNil) 298 s2 := fmt.Sprintf("%v", *h2) 299 So(s2, ShouldEqual, s1) 300 301 Convey("and the returned header should hash to the same value", func() { 302 b, _ := (h2).Marshal() 303 var hh Hash 304 hh, err = Sum(h.hashSpec, b) 305 So(err, ShouldBeNil) 306 So(headerHash.String(), ShouldEqual, hh.String()) 307 }) 308 309 var d2 interface{} 310 var d2t string 311 d2, d2t, err = h.chain.GetEntry(h2.EntryLink) 312 So(err, ShouldBeNil) 313 So(d2t, ShouldEqual, "entryTypeFoo") 314 315 So(d2, ShouldNotBeNil) 316 So(d2.(Entry).Content(), ShouldEqual, d1) 317 }) 318 319 Convey("Top should still work", t, func() { 320 hash, err := h.Top() 321 So(err, ShouldBeNil) 322 So(hash.Equal(headerHash), ShouldBeTrue) 323 }) 324 325 e = GobEntry{C: "more data"} 326 _, header2, err := h.NewEntry(now, "entryTypeFoo", &e) 327 328 Convey("a second entry should have prev link correctly set", t, func() { 329 So(err, ShouldBeNil) 330 So(header2.HeaderLink.String(), ShouldEqual, headerHash.String()) 331 }) 332 } 333 334 func TestHeader(t *testing.T) { 335 var h1, h2 Header 336 h1 = mkTestHeader("entryTypeFoo") 337 338 var buf bytes.Buffer 339 enc := gob.NewEncoder(&buf) 340 err := enc.Encode(&h1) 341 Convey("it should encode", t, func() { 342 So(err, ShouldBeNil) 343 }) 344 345 dec := gob.NewDecoder(&buf) 346 err = dec.Decode(&h2) 347 348 Convey("it should decode", t, func() { 349 s1 := fmt.Sprintf("%v", h1) 350 s2 := fmt.Sprintf("%v", h2) 351 So(err, ShouldBeNil) 352 So(s1, ShouldEqual, s2) 353 }) 354 } 355 356 func TestAddAgentEntry(t *testing.T) { 357 d, _, h := SetupTestChain("test") 358 defer CleanupTestChain(h, d) 359 360 Convey("it should add an agent entry to the chain", t, func() { 361 headerHash, agentHash, err := h.AddAgentEntry(&FakeRevocation{data: "some revocation data"}) 362 So(err, ShouldBeNil) 363 364 hdr, err := h.chain.Get(headerHash) 365 So(err, ShouldBeNil) 366 367 So(hdr.EntryLink.String(), ShouldEqual, agentHash.String()) 368 369 entry, _, err := h.chain.GetEntry(agentHash) 370 So(err, ShouldBeNil) 371 372 a, err := AgentEntryFromJSON(entry.Content().(string)) 373 So(err, ShouldBeNil) 374 375 So(a.Identity, ShouldEqual, h.agent.Identity()) 376 pk, _ := h.agent.EncodePubKey() 377 So(string(a.PublicKey), ShouldEqual, string(pk)) 378 So(string(a.Revocation), ShouldEqual, "some revocation data") 379 }) 380 } 381 382 func TestGenChain(t *testing.T) { 383 d, _, h := SetupTestChain("test") 384 defer CleanupTestChain(h, d) 385 var err error 386 387 Convey("before GenChain call DNAHash call should fail", t, func() { 388 h := h.DNAHash() 389 So(h.String(), ShouldEqual, "") 390 }) 391 392 var headerHash Hash 393 Convey("GenChain call works", t, func() { 394 headerHash, err = h.GenChain() 395 So(err, ShouldBeNil) 396 }) 397 398 var header Header 399 Convey("top link should be Key entry", t, func() { 400 hdr, err := h.chain.Get(headerHash) 401 So(err, ShouldBeNil) 402 entry, _, err := h.chain.GetEntry(hdr.EntryLink) 403 So(err, ShouldBeNil) 404 header = *hdr 405 a, _ := AgentEntryFromJSON(entry.Content().(string)) 406 So(a.Identity, ShouldEqual, h.agent.Identity()) 407 pk, _ := h.agent.EncodePubKey() 408 So(string(a.PublicKey), ShouldEqual, string(pk)) 409 So(string(a.Revocation), ShouldEqual, "") 410 }) 411 412 var dnaHash Hash 413 Convey("next link should be the dna entry", t, func() { 414 hdr, err := h.chain.Get(header.HeaderLink) 415 So(err, ShouldBeNil) 416 entry, et, err := h.chain.GetEntry(hdr.EntryLink) 417 So(err, ShouldBeNil) 418 So(et, ShouldEqual, DNAEntryType) 419 420 var buf bytes.Buffer 421 err = h.EncodeDNA(&buf) 422 So(err, ShouldBeNil) 423 So(string(entry.Content().([]byte)), ShouldEqual, buf.String()) 424 dnaHash = hdr.EntryLink 425 }) 426 427 Convey("holochain id and top should have now been set", t, func() { 428 id := h.DNAHash() 429 So(err, ShouldBeNil) 430 So(id.String(), ShouldEqual, dnaHash.String()) 431 top, err := h.Top() 432 So(err, ShouldBeNil) 433 So(top.String(), ShouldEqual, headerHash.String()) 434 }) 435 } 436 437 func TestWalk(t *testing.T) { 438 d, _, h := PrepareTestChain("test") 439 defer CleanupTestChain(h, d) 440 441 // add an extra link onto the chain 442 entryTypeFoo := `(message (from "art") (to "eric") (contents "test"))` 443 now := time.Unix(1, 1) // pick a constant time so the test will always work 444 e := GobEntry{C: entryTypeFoo} 445 _, _, err := h.NewEntry(now, "entryTypeFoo", &e) 446 if err != nil { 447 panic(err) 448 } 449 450 Convey("walk should call a function on all the elements of a chain", t, func() { 451 452 c := make(map[int]string, 0) 453 // c := make([]string,0) 454 idx := 0 455 err := h.Walk(func(key *Hash, header *Header, entry Entry) (err error) { 456 c[idx] = header.EntryLink.String() 457 idx++ 458 // c = append(c, header.HeaderLink.String()) 459 return nil 460 }, false) 461 So(err, ShouldBeNil) 462 id := h.DNAHash() 463 So(c[2], ShouldEqual, id.String()) 464 // So(c,ShouldEqual,"fish") 465 }) 466 } 467 468 func TestGetZome(t *testing.T) { 469 d, _, h := SetupTestChain("test") 470 defer CleanupTestChain(h, d) 471 472 Convey("it should fail if the zome isn't defined in the DNA", t, func() { 473 _, err := h.GetZome("bogusZome") 474 So(err.Error(), ShouldEqual, "unknown zome: bogusZome") 475 }) 476 Convey("it should return the Zome structure of a defined zome", t, func() { 477 z, err := h.GetZome("zySampleZome") 478 So(err, ShouldBeNil) 479 So(z.Name, ShouldEqual, "zySampleZome") 480 }) 481 } 482 483 func TestMakeRibosome(t *testing.T) { 484 d, _, h := SetupTestChain("test") 485 defer CleanupTestChain(h, d) 486 487 Convey("it should fail if the zome isn't defined in the DNA", t, func() { 488 _, _, err := h.MakeRibosome("bogusZome") 489 So(err.Error(), ShouldEqual, "unknown zome: bogusZome") 490 }) 491 Convey("it should make a ribosome based on the type and return the zome def", t, func() { 492 v, zome, err := h.MakeRibosome("zySampleZome") 493 So(err, ShouldBeNil) 494 So(zome.Name, ShouldEqual, "zySampleZome") 495 z := v.(*ZygoRibosome) 496 _, err = z.env.Run() 497 So(err, ShouldBeNil) 498 }) 499 } 500 501 func TestCall(t *testing.T) { 502 d, _, h := PrepareTestChain("test") 503 defer CleanupTestChain(h, d) 504 505 Convey("it should call the exposed function", t, func() { 506 result, err := h.Call("zySampleZome", "testStrFn1", "arg1 arg2", ZOME_EXPOSURE) 507 So(err, ShouldBeNil) 508 So(result.(string), ShouldEqual, "result: arg1 arg2") 509 510 result, err = h.Call("zySampleZome", "addEven", "42", ZOME_EXPOSURE) 511 So(err, ShouldBeNil) 512 513 ph := h.chain.Top().EntryLink 514 So(result.(string), ShouldEqual, ph.String()) 515 516 _, err = h.Call("zySampleZome", "addEven", "41", ZOME_EXPOSURE) 517 So(err.Error(), ShouldEqual, "Error calling 'commit': Validation Failed: 41 is not even") 518 }) 519 Convey("it should fail calls to functions not exposed to the given context", t, func() { 520 _, err := h.Call("zySampleZome", "testStrFn1", "arg1 arg2", PUBLIC_EXPOSURE) 521 So(err.Error(), ShouldEqual, "function not available") 522 }) 523 } 524 525 func TestCommit(t *testing.T) { 526 d, _, h := PrepareTestChain("test") 527 defer CleanupTestChain(h, d) 528 529 // add an entry onto the chain 530 hash := commit(h, "oddNumbers", "7") 531 532 Convey("publicly shared entries should generate a put", t, func() { 533 err := h.dht.Exists(hash, StatusLive) 534 So(err, ShouldBeNil) 535 }) 536 537 profileHash := commit(h, "profile", `{"firstName":"Zippy","lastName":"Pinhead"}`) 538 539 Convey("it should attach links after commit of Links entry", t, func() { 540 commit(h, "rating", fmt.Sprintf(`{"Links":[{"Base":"%s","Link":"%s","Tag":"4stars"}]}`, hash.String(), profileHash.String())) 541 542 results, err := h.dht.GetLinks(hash, "4stars", StatusLive) 543 So(err, ShouldBeNil) 544 So(fmt.Sprintf("%v", results), ShouldEqual, fmt.Sprintf("[{QmYeinX5vhuA91D3v24YbgyLofw9QAxY6PoATrBHnRwbtt %s}]", h.nodeIDStr)) 545 }) 546 } 547 548 func TestQuery(t *testing.T) { 549 d, _, h := PrepareTestChain("test") 550 defer CleanupTestChain(h, d) 551 552 commit(h, "profile", `{"firstName":"Pebbles","lastName":"Flintstone"}`) 553 hash1 := commit(h, "oddNumbers", "7") 554 commit(h, "secret", "foo") 555 hash2 := commit(h, "oddNumbers", "9") 556 commit(h, "secret", "bar") 557 commit(h, "secret", "baz") 558 commit(h, "profile", `{"firstName":"Zippy","lastName":"Pinhead"}`) 559 commit(h, "profile", `{"firstName":"Zerbina","lastName":"Pinhead"}`) 560 561 Convey("query with no options should return entire chain entries only", t, func() { 562 results, err := h.Query(nil) 563 So(err, ShouldBeNil) 564 So(len(results), ShouldEqual, 10) 565 So(results[0].Header.Type, ShouldEqual, DNAEntryType) 566 So(results[1].Header.Type, ShouldEqual, AgentEntryType) 567 So(results[2].Entry.Content(), ShouldEqual, `{"firstName":"Pebbles","lastName":"Flintstone"}`) 568 So(results[3].Entry.Content(), ShouldEqual, "7") 569 So(results[4].Entry.Content(), ShouldEqual, "foo") 570 So(results[5].Entry.Content(), ShouldEqual, "9") 571 So(results[6].Entry.Content(), ShouldEqual, "bar") 572 So(results[7].Entry.Content(), ShouldEqual, "baz") 573 So(results[8].Entry.Content(), ShouldEqual, `{"firstName":"Zippy","lastName":"Pinhead"}`) 574 So(results[9].Entry.Content(), ShouldEqual, `{"firstName":"Zerbina","lastName":"Pinhead"}`) 575 }) 576 Convey("query with order should reverse the order", t, func() { 577 results, err := h.Query(&QueryOptions{Order: QueryOrder{Ascending: true}}) 578 So(err, ShouldBeNil) 579 So(len(results), ShouldEqual, 10) 580 So(results[9].Header.Type, ShouldEqual, DNAEntryType) 581 So(results[8].Header.Type, ShouldEqual, AgentEntryType) 582 So(results[7].Entry.Content(), ShouldEqual, `{"firstName":"Pebbles","lastName":"Flintstone"}`) 583 So(results[6].Entry.Content(), ShouldEqual, "7") 584 So(results[5].Entry.Content(), ShouldEqual, "foo") 585 So(results[4].Entry.Content(), ShouldEqual, "9") 586 So(results[3].Entry.Content(), ShouldEqual, "bar") 587 So(results[2].Entry.Content(), ShouldEqual, "baz") 588 So(results[1].Entry.Content(), ShouldEqual, `{"firstName":"Zippy","lastName":"Pinhead"}`) 589 So(results[0].Entry.Content(), ShouldEqual, `{"firstName":"Zerbina","lastName":"Pinhead"}`) 590 }) 591 592 Convey("query with with count and page should select items", t, func() { 593 q := &QueryOptions{} 594 q.Constrain.Count = 2 595 q.Constrain.Page = 2 // zero based 596 results, err := h.Query(q) 597 So(err, ShouldBeNil) 598 So(len(results), ShouldEqual, 2) 599 So(results[0].Entry.Content(), ShouldEqual, "foo") 600 So(results[1].Entry.Content(), ShouldEqual, "9") 601 }) 602 603 Convey("query with with count and page partially past end should select items", t, func() { 604 q := &QueryOptions{} 605 q.Constrain.Count = 4 606 q.Constrain.Page = 2 // zero based 607 results, err := h.Query(q) 608 So(err, ShouldBeNil) 609 So(len(results), ShouldEqual, 2) 610 So(results[0].Entry.Content(), ShouldEqual, `{"firstName":"Zippy","lastName":"Pinhead"}`) 611 So(results[1].Entry.Content(), ShouldEqual, `{"firstName":"Zerbina","lastName":"Pinhead"}`) 612 }) 613 614 Convey("query with with count and page past end should be empty", t, func() { 615 q := &QueryOptions{} 616 q.Constrain.Count = 10 617 q.Constrain.Page = 1 // zero based 618 results, err := h.Query(q) 619 So(err, ShouldBeNil) 620 So(len(results), ShouldEqual, 0) 621 }) 622 623 Convey("query with entry type options should return that type only", t, func() { 624 q := &QueryOptions{} 625 q.Constrain.EntryTypes = []string{"oddNumbers"} 626 results, err := h.Query(q) 627 So(err, ShouldBeNil) 628 So(len(results), ShouldEqual, 2) 629 So(results[0].Entry.Content(), ShouldEqual, "7") 630 So(results[1].Entry.Content(), ShouldEqual, "9") 631 }) 632 Convey("query with multiple entry type options should return those types only", t, func() { 633 q := &QueryOptions{} 634 q.Constrain.EntryTypes = []string{"oddNumbers", "secret"} 635 results, err := h.Query(q) 636 So(err, ShouldBeNil) 637 So(len(results), ShouldEqual, 5) 638 So(results[0].Entry.Content(), ShouldEqual, "7") 639 So(results[1].Entry.Content(), ShouldEqual, "foo") 640 So(results[2].Entry.Content(), ShouldEqual, "9") 641 So(results[3].Entry.Content(), ShouldEqual, "bar") 642 So(results[4].Entry.Content(), ShouldEqual, "baz") 643 }) 644 Convey("query with hash options should return only hashes", t, func() { 645 q := &QueryOptions{} 646 q.Constrain.EntryTypes = []string{"oddNumbers"} 647 q.Return.Hashes = true 648 results, err := h.Query(q) 649 So(err, ShouldBeNil) 650 So(results[0].Header.EntryLink.String(), ShouldEqual, hash1.String()) 651 So(results[1].Header.EntryLink.String(), ShouldEqual, hash2.String()) 652 So(results[0].Entry, ShouldBeNil) 653 So(results[1].Entry, ShouldBeNil) 654 }) 655 Convey("query with equals constraint", t, func() { 656 q := &QueryOptions{} 657 q.Constrain.EntryTypes = []string{"secret"} 658 q.Constrain.Equals = "foo" 659 results, err := h.Query(q) 660 So(err, ShouldBeNil) 661 So(len(results), ShouldEqual, 1) 662 So(results[0].Entry.Content(), ShouldEqual, "foo") 663 }) 664 Convey("query with contains constraint", t, func() { 665 q := &QueryOptions{} 666 q.Constrain.EntryTypes = []string{"secret"} 667 q.Constrain.Contains = "o" 668 results, err := h.Query(q) 669 So(err, ShouldBeNil) 670 So(len(results), ShouldEqual, 1) 671 So(results[0].Entry.Content(), ShouldEqual, "foo") 672 }) 673 Convey("query with matches constraint", t, func() { 674 q := &QueryOptions{} 675 q.Constrain.EntryTypes = []string{"secret"} 676 q.Constrain.Matches = ".a." 677 results, err := h.Query(q) 678 So(err, ShouldBeNil) 679 So(len(results), ShouldEqual, 2) 680 So(results[0].Entry.Content(), ShouldEqual, "bar") 681 So(results[1].Entry.Content(), ShouldEqual, "baz") 682 }) 683 Convey("query with equals field constraint", t, func() { 684 q := &QueryOptions{} 685 q.Constrain.EntryTypes = []string{"profile"} 686 q.Constrain.Equals = `{"firstName":"Zippy"}` 687 results, err := h.Query(q) 688 So(err, ShouldBeNil) 689 So(len(results), ShouldEqual, 1) 690 So(results[0].Entry.Content(), ShouldEqual, `{"firstName":"Zippy","lastName":"Pinhead"}`) 691 }) 692 Convey("query with equals multiple field constraint", t, func() { 693 q := &QueryOptions{} 694 q.Constrain.EntryTypes = []string{"profile"} 695 q.Constrain.Equals = `{"firstName":"Zippy","lastName":"Flintstone"}` 696 results, err := h.Query(q) 697 So(err, ShouldBeNil) 698 So(len(results), ShouldEqual, 2) 699 So(results[0].Entry.Content(), ShouldEqual, `{"firstName":"Pebbles","lastName":"Flintstone"}`) 700 So(results[1].Entry.Content(), ShouldEqual, `{"firstName":"Zippy","lastName":"Pinhead"}`) 701 702 }) 703 Convey("query with contains field constraint", t, func() { 704 q := &QueryOptions{} 705 q.Constrain.EntryTypes = []string{"profile"} 706 q.Constrain.Contains = `{"firstName":"Z"}` 707 results, err := h.Query(q) 708 So(err, ShouldBeNil) 709 So(len(results), ShouldEqual, 2) 710 So(results[0].Entry.Content(), ShouldEqual, `{"firstName":"Zippy","lastName":"Pinhead"}`) 711 So(results[1].Entry.Content(), ShouldEqual, `{"firstName":"Zerbina","lastName":"Pinhead"}`) 712 }) 713 Convey("query with matches field constraint", t, func() { 714 q := &QueryOptions{} 715 q.Constrain.EntryTypes = []string{"profile"} 716 q.Constrain.Matches = `{"firstName":".*b"}` 717 results, err := h.Query(q) 718 So(err, ShouldBeNil) 719 So(len(results), ShouldEqual, 2) 720 So(results[0].Entry.Content(), ShouldEqual, `{"firstName":"Pebbles","lastName":"Flintstone"}`) 721 So(results[1].Entry.Content(), ShouldEqual, `{"firstName":"Zerbina","lastName":"Pinhead"}`) 722 }) 723 Convey("query from bundle", t, func() { 724 q := &QueryOptions{Bundle: true} 725 _, err := h.Query(q) 726 So(err, ShouldEqual, ErrBundleNotStarted) 727 h.Chain().StartBundle(0) 728 results, err := h.Query(q) 729 So(err, ShouldBeNil) 730 So(len(results), ShouldEqual, 0) 731 commit(h, "secret", "flam") 732 results, err = h.Query(q) 733 So(err, ShouldBeNil) 734 So(len(results), ShouldEqual, 1) 735 }) 736 } 737 738 func TestGetEntryDef(t *testing.T) { 739 d, _, h := SetupTestChain("test") 740 defer CleanupTestDir(d) 741 Convey("it should fail on bad entry types", t, func() { 742 _, _, err := h.GetEntryDef("foobar") 743 So(err, ShouldBeError) 744 So(err.Error(), ShouldEqual, "no definition for entry type: foobar") 745 }) 746 Convey("it should get entry definitions", t, func() { 747 zome, def, err := h.GetEntryDef("evenNumbers") 748 So(err, ShouldBeNil) 749 So(zome.Name, ShouldEqual, "zySampleZome") 750 So(fmt.Sprintf("%v", def), ShouldEqual, "&{evenNumbers zygo public <nil>}") 751 }) 752 Convey("it should get sys entry definitions", t, func() { 753 zome, def, err := h.GetEntryDef(DNAEntryType) 754 So(err, ShouldBeNil) 755 So(zome, ShouldBeNil) 756 So(def, ShouldEqual, DNAEntryDef) 757 zome, def, err = h.GetEntryDef(AgentEntryType) 758 So(err, ShouldBeNil) 759 So(zome, ShouldBeNil) 760 So(def, ShouldEqual, AgentEntryDef) 761 zome, def, err = h.GetEntryDef(KeyEntryType) 762 So(err, ShouldBeNil) 763 So(zome, ShouldBeNil) 764 So(def, ShouldEqual, KeyEntryDef) 765 zome, def, err = h.GetEntryDef(HeadersEntryType) 766 So(err, ShouldBeNil) 767 So(zome, ShouldBeNil) 768 So(def, ShouldEqual, HeadersEntryDef) 769 zome, def, err = h.GetEntryDef(DelEntryType) 770 So(err, ShouldBeNil) 771 So(zome, ShouldBeNil) 772 So(def, ShouldEqual, DelEntryDef) 773 zome, def, err = h.GetEntryDef(MigrateEntryType) 774 So(err, ShouldBeNil) 775 So(zome, ShouldBeNil) 776 So(def, ShouldEqual, MigrateEntryDef) 777 }) 778 Convey("it should get private entry definition", t, func() { 779 zome, def, err := h.GetEntryDef("privateData") 780 So(err, ShouldBeNil) 781 So(zome, ShouldNotBeNil) 782 So(def, ShouldNotBeNil) 783 }) 784 } 785 786 func TestGetPrivateEntryDefs(t *testing.T) { 787 d, _, h := SetupTestChain("test") 788 defer CleanupTestDir(d) 789 Convey("it should contain only private entry definition", t, func() { 790 _, privateData, _ := h.GetEntryDef("privateData") 791 privateDefs := h.GetPrivateEntryDefs() 792 So(len(privateDefs), ShouldEqual, 1) 793 So(privateDefs[0].Name, ShouldEqual, privateData.Name) 794 }) 795 } 796 797 func TestSigning(t *testing.T) { 798 d, _, h := SetupTestChain("test") 799 defer CleanupTestDir(d) 800 Convey("a user should be able to sign and verify data", t, func() { 801 privKey := h.agent.PrivKey() 802 sig, err := privKey.Sign([]byte("3")) 803 if err != nil { 804 panic(err) 805 } 806 signature, err := h.Sign([]byte("3")) 807 So(err, ShouldBeNil) 808 So(string(signature.S), ShouldEqual, string(sig)) 809 810 matched, err := h.VerifySignature(signature, string([]byte("3")), h.agent.PubKey()) 811 So(err, ShouldBeNil) 812 So(matched, ShouldBeTrue) 813 814 matched, err = h.VerifySignature(signature, string([]byte("32")), h.agent.PubKey()) 815 So(err, ShouldBeNil) 816 So(matched, ShouldBeFalse) 817 }) 818 } 819 820 //func TestDNADefaults(t *testing.T) { 821 // h, err := DecodeDNA(strings.NewReader( [[Zomes]]` 822 //Name = "test" 823 //Description = "test-zome" 824 //RibosomeType = "zygo"`), "toml") 825 // if err != nil { 826 // return 827 // } 828 // Convey("it should substitute default values", t, func() { 829 // So(h.Zomes[0].Code, ShouldEqual, "test.zy") 830 // }) 831 //} 832 833 func commit(h *Holochain, entryType, entryStr string) (entryHash Hash) { 834 entry := GobEntry{C: entryStr} 835 a := NewCommitAction(entryType, &entry) 836 fn := &APIFnCommit{} 837 fn.SetAction(a) 838 r, err := fn.Call(h) 839 if err != nil { 840 panic(err) 841 } 842 if r != nil { 843 entryHash = r.(Hash) 844 } 845 if err != nil { 846 panic(err) 847 } 848 return 849 }