github.com/holochain/holochain-proto@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/jsribosome_test.go (about) 1 package holochain 2 3 import ( 4 "encoding/json" 5 "fmt" 6 . "github.com/holochain/holochain-proto/hash" 7 b58 "github.com/jbenet/go-base58" 8 ic "github.com/libp2p/go-libp2p-crypto" 9 peer "github.com/libp2p/go-libp2p-peer" 10 "github.com/robertkrimen/otto" 11 . "github.com/smartystreets/goconvey/convey" 12 "strings" 13 "testing" 14 ) 15 16 func TestNewJSRibosome(t *testing.T) { 17 18 Convey("new should create a ribosome", t, func() { 19 d, _, h := PrepareTestChain("test") 20 defer CleanupTestChain(h, d) 21 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: `1 + 1`}) 22 So(err, ShouldBeNil) 23 z := v.(*JSRibosome) 24 i, _ := z.lastResult.ToInteger() 25 So(i, ShouldEqual, 2) 26 }) 27 Convey("new fail to create ribosome when code is bad", t, func() { 28 d, _, h := PrepareTestChain("test") 29 defer CleanupTestChain(h, d) 30 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: "\n1+ )"}) 31 So(v, ShouldBeNil) 32 So(err.Error(), ShouldEqual, "Error executing JavaScript: (anonymous): Line 38:4 Unexpected token )") 33 }) 34 35 Convey("you can set the error handling configuration", t, func() { 36 d, _, h := PrepareTestChain("test") 37 defer CleanupTestChain(h, d) 38 _, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Config: map[string]interface{}{"ErrorHandling": ErrHandlingReturnErrorsStr}}) 39 So(err, ShouldBeNil) 40 _, err = NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Config: map[string]interface{}{"ErrorHandling": ErrHandlingThrowErrorsStr}}) 41 So(err, ShouldBeNil) 42 _, err = NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Config: map[string]interface{}{"ErrorHandling": 2}}) 43 So(err.Error(), ShouldEqual, "Expected ErrorHandling config value to be string") 44 _, err = NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Config: map[string]interface{}{"ErrorHandling": "fish"}}) 45 So(err.Error(), ShouldEqual, "Expected ErrorHandling config value to be 'throwErrors' or 'returnErrorValue', was: 'fish'") 46 }) 47 48 Convey("it should have an App structure:", t, func() { 49 d, _, h := PrepareTestChain("test") 50 defer CleanupTestChain(h, d) 51 52 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType}) 53 So(err, ShouldBeNil) 54 z := v.(*JSRibosome) 55 56 _, err = z.Run("App.Name") 57 So(err, ShouldBeNil) 58 s, _ := z.lastResult.ToString() 59 So(s, ShouldEqual, h.Name()) 60 61 _, err = z.Run("App.DNA.Hash") 62 So(err, ShouldBeNil) 63 s, _ = z.lastResult.ToString() 64 So(s, ShouldEqual, h.dnaHash.String()) 65 66 _, err = z.Run("App.Agent.Hash") 67 So(err, ShouldBeNil) 68 s, _ = z.lastResult.ToString() 69 So(s, ShouldEqual, h.agentHash.String()) 70 71 _, err = z.Run("App.Agent.TopHash") 72 So(err, ShouldBeNil) 73 s, _ = z.lastResult.ToString() 74 So(s, ShouldEqual, h.agentTopHash.String()) // top an agent are the same at startup 75 So(s, ShouldEqual, h.agentHash.String()) 76 77 _, err = z.Run("App.Agent.String") 78 So(err, ShouldBeNil) 79 s, _ = z.lastResult.ToString() 80 So(s, ShouldEqual, h.Agent().Identity()) 81 82 _, err = z.Run("App.Key.Hash") 83 So(err, ShouldBeNil) 84 s, _ = z.lastResult.ToString() 85 So(s, ShouldEqual, h.nodeIDStr) 86 87 }) 88 89 Convey("it should have an HC structure:", t, func() { 90 d, _, h := PrepareTestChain("test") 91 defer CleanupTestChain(h, d) 92 93 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType}) 94 So(err, ShouldBeNil) 95 z := v.(*JSRibosome) 96 97 _, err = z.Run("HC.HashNotFound") 98 So(err, ShouldBeNil) 99 s, _ := z.lastResult.ToString() 100 So(s, ShouldEqual, "null") 101 102 _, err = z.Run("HC.SysEntryType.DNA") 103 So(err, ShouldBeNil) 104 s, _ = z.lastResult.ToString() 105 So(s, ShouldEqual, DNAEntryType) 106 107 _, err = z.Run("HC.SysEntryType.Agent") 108 So(err, ShouldBeNil) 109 s, _ = z.lastResult.ToString() 110 So(s, ShouldEqual, AgentEntryType) 111 112 _, err = z.Run("HC.SysEntryType.Key") 113 So(err, ShouldBeNil) 114 s, _ = z.lastResult.ToString() 115 So(s, ShouldEqual, KeyEntryType) 116 117 _, err = z.Run("HC.SysEntryType.Headers") 118 So(err, ShouldBeNil) 119 s, _ = z.lastResult.ToString() 120 So(s, ShouldEqual, HeadersEntryType) 121 122 _, err = z.Run("HC.SysEntryType.Del") 123 So(err, ShouldBeNil) 124 s, _ = z.lastResult.ToString() 125 So(s, ShouldEqual, DelEntryType) 126 127 _, err = z.Run("HC.SysEntryType.Migrate") 128 So(err, ShouldBeNil) 129 s, _ = z.lastResult.ToString() 130 So(s, ShouldEqual, MigrateEntryType) 131 132 _, err = z.Run("HC.Version") 133 So(err, ShouldBeNil) 134 s, _ = z.lastResult.ToString() 135 So(s, ShouldEqual, VersionStr) 136 137 _, err = z.Run("HC.Status.Deleted") 138 So(err, ShouldBeNil) 139 i, _ := z.lastResult.ToInteger() 140 So(i, ShouldEqual, StatusDeleted) 141 142 _, err = z.Run("HC.Status.Live") 143 So(err, ShouldBeNil) 144 i, _ = z.lastResult.ToInteger() 145 So(i, ShouldEqual, StatusLive) 146 147 _, err = z.Run("HC.Status.Rejected") 148 So(err, ShouldBeNil) 149 i, _ = z.lastResult.ToInteger() 150 So(i, ShouldEqual, StatusRejected) 151 152 _, err = z.Run("HC.Status.Modified") 153 So(err, ShouldBeNil) 154 i, _ = z.lastResult.ToInteger() 155 So(i, ShouldEqual, StatusModified) 156 157 _, err = z.Run("HC.Status.Any") 158 So(err, ShouldBeNil) 159 i, _ = z.lastResult.ToInteger() 160 So(i, ShouldEqual, StatusAny) 161 162 _, err = z.Run("HC.Bridge.Caller") 163 So(err, ShouldBeNil) 164 i, _ = z.lastResult.ToInteger() 165 So(i, ShouldEqual, BridgeCaller) 166 167 _, err = z.Run("HC.Bridge.Callee") 168 So(err, ShouldBeNil) 169 i, _ = z.lastResult.ToInteger() 170 So(i, ShouldEqual, BridgeCallee) 171 172 _, err = z.Run("HC.BundleCancel.Reason.UserCancel") 173 So(err, ShouldBeNil) 174 s, _ = z.lastResult.ToString() 175 So(s, ShouldEqual, BundleCancelReasonUserCancel) 176 177 _, err = z.Run("HC.BundleCancel.Reason.Timeout") 178 So(err, ShouldBeNil) 179 s, _ = z.lastResult.ToString() 180 So(s, ShouldEqual, BundleCancelReasonTimeout) 181 182 _, err = z.Run("HC.BundleCancel.Response.OK") 183 So(err, ShouldBeNil) 184 s, _ = z.lastResult.ToString() 185 So(s, ShouldEqual, BundleCancelResponseOK) 186 187 _, err = z.Run("HC.BundleCancel.Response.Commit") 188 So(err, ShouldBeNil) 189 s, _ = z.lastResult.ToString() 190 So(s, ShouldEqual, BundleCancelResponseCommit) 191 192 _, err = z.Run("HC.Migrate.Close") 193 So(err, ShouldBeNil) 194 s, _ = z.lastResult.ToString() 195 So(s, ShouldEqual, MigrateEntryTypeClose) 196 197 _, err = z.Run("HC.Migrate.Open") 198 So(err, ShouldBeNil) 199 s, _ = z.lastResult.ToString() 200 So(s, ShouldEqual, MigrateEntryTypeOpen) 201 202 }) 203 204 Convey("should have the built in functions:", t, func() { 205 d, _, h := PrepareTestChain("test") 206 defer CleanupTestChain(h, d) 207 208 zome, _ := h.GetZome("jsSampleZome") 209 v, err := NewJSRibosome(h, zome) 210 So(err, ShouldBeNil) 211 z := v.(*JSRibosome) 212 213 Convey("property", func() { 214 _, err = z.Run(`property("description")`) 215 So(err, ShouldBeNil) 216 s, _ := z.lastResult.ToString() 217 So(s, ShouldEqual, "a bogus test holochain") 218 219 ShouldLog(&infoLog, func() { 220 _, err = z.Run(`property("` + ID_PROPERTY + `")`) 221 So(err, ShouldBeNil) 222 }, "Warning: Getting special properties via property() is deprecated as of 3. Returning nil values. Use App* instead\n") 223 224 }) 225 226 // add entries onto the chain to get hash values for testing 227 hash := commit(h, "oddNumbers", "3") 228 profileHash := commit(h, "profile", `{"firstName":"Zippy","lastName":"Pinhead"}`) 229 230 Convey("makeHash", func() { 231 _, err = z.Run(`makeHash("oddNumbers","3")`) 232 So(err, ShouldBeNil) 233 z := v.(*JSRibosome) 234 hash1, err := NewHash(z.lastResult.String()) 235 So(err, ShouldBeNil) 236 So(hash1.String(), ShouldEqual, hash.String()) 237 238 _, err = z.Run(`makeHash("profile",{"firstName":"Zippy","lastName":"Pinhead"})`) 239 So(err, ShouldBeNil) 240 hash1, err = NewHash(z.lastResult.String()) 241 So(err, ShouldBeNil) 242 So(hash1.String(), ShouldEqual, profileHash.String()) 243 }) 244 245 Convey("getBridges", func() { 246 _, err = z.Run(`getBridges()`) 247 So(err, ShouldBeNil) 248 z := v.(*JSRibosome) 249 s, _ := z.lastResult.Export() 250 So(fmt.Sprintf("%v", s), ShouldEqual, "[]") 251 252 hFromHash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzfrom") 253 254 var token string 255 ShouldLog(h.nucleus.alog, func() { 256 token, err = h.AddBridgeAsCallee(hFromHash, "") 257 if err != nil { 258 panic(err) 259 } 260 }, `testGetBridges:[{"Side":1,"Token":"`) 261 262 ShouldLog(h.nucleus.alog, func() { 263 hToHash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqto") 264 err = h.AddBridgeAsCaller("jsSampleZome", hToHash, "fakeAppName", token, "fakeurl", "") 265 if err != nil { 266 panic(err) 267 } 268 }, fmt.Sprintf(`[{"CalleeApp":"QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqto","CalleeName":"fakeAppName","Side":0},{"Side":1,"Token":"%s"}]`, token)) 269 270 }) 271 272 // Sign - this function signs the data that is passed with the user's privKey and returns the signed data 273 Convey("sign", func() { 274 d, _, h := PrepareTestChain("test") 275 defer CleanupTestChain(h, d) 276 277 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType}) 278 So(err, ShouldBeNil) 279 z := v.(*JSRibosome) 280 // sig should match the value that is returned 281 privKey := h.agent.PrivKey() 282 sig, err := privKey.Sign([]byte("3")) 283 //test1 284 _, err = z.Run(`sign("3")`) 285 So(err, ShouldBeNil) 286 //z := v.(*JSRibosome) 287 So(z.lastResult.String(), ShouldEqual, b58.Encode(sig)) 288 //test2 289 sig, err = privKey.Sign([]byte("{\"firstName\":\"jackT\",\"lastName\":\"hammer\"}")) 290 _, err = z.Run(`sign('{"firstName":"jackT","lastName":"hammer"}')`) 291 So(err, ShouldBeNil) 292 So(z.lastResult.String(), ShouldEqual, b58.Encode(sig)) 293 }) 294 295 //Verifying signature of a particular user 296 // sig will be signed by the user and We will verifySignature i.e verify if the user we know signed it 297 Convey("verifySignature", func() { 298 d, _, h := PrepareTestChain("test") 299 defer CleanupTestChain(h, d) 300 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType}) 301 So(err, ShouldBeNil) 302 z := v.(*JSRibosome) 303 privKey := h.agent.PrivKey() 304 pubKey := privKey.GetPublic() 305 var pubKeyBytes []byte 306 pubKeyBytes, err = ic.MarshalPublicKey(pubKey) 307 if err != nil { 308 panic(err) 309 } 310 //verifySignature function SUCESS Condition 311 sig, err := privKey.Sign([]byte("3")) 312 _, err = z.Run(fmt.Sprintf(`verifySignature("%s","%s","%s")`, b58.Encode((sig)), "3", b58.Encode(pubKeyBytes))) 313 So(err, ShouldBeNil) 314 So(z.lastResult.String(), ShouldEqual, "true") 315 316 _, err = z.Run(fmt.Sprintf(`verifySignature(sign("3"),"%s","%s")`, "3", b58.Encode(pubKeyBytes))) 317 So(err, ShouldBeNil) 318 So(z.lastResult.String(), ShouldEqual, "true") 319 320 //verifySignature function FAILURE Condition 321 _, err = z.Run(fmt.Sprintf(`verifySignature("%s","%s","%s")`, b58.Encode(sig), "34", b58.Encode(pubKeyBytes))) 322 So(err, ShouldBeNil) 323 So(z.lastResult.String(), ShouldEqual, "false") 324 }) 325 326 Convey("call", func() { 327 // a string calling function 328 _, err := z.Run(`call("zySampleZome","addEven","432")`) 329 So(err, ShouldBeNil) 330 So(h.chain.Entries[len(h.chain.Hashes)-1].Content(), ShouldEqual, "432") 331 z := v.(*JSRibosome) 332 hash, _ := NewHash(z.lastResult.String()) 333 entry, _, _ := h.chain.GetEntry(hash) 334 So(entry.Content(), ShouldEqual, "432") 335 336 // a json calling function 337 _, err = z.Run(`call("zySampleZome","addPrime",{prime:7})`) 338 So(err, ShouldBeNil) 339 So(h.chain.Entries[len(h.chain.Hashes)-1].Content(), ShouldEqual, `{"prime":7}`) 340 hashJSONStr := z.lastResult.String() 341 var hashStr string 342 json.Unmarshal([]byte(hashJSONStr), &hashStr) 343 hash, _ = NewHash(hashStr) 344 entry, _, _ = h.chain.GetEntry(hash) 345 So(entry.Content(), ShouldEqual, `{"prime":7}`) 346 347 }) 348 Convey("bridge", func() { 349 _, err := z.Run(`bridge("QmVGtdTZdTFaLsaj2RwdVG8jcjNNcp1DE914DKZ2kHmXHw","zySampleZome","testStrFn1","foo")`) 350 So(err.Error(), ShouldEqual, `{"errorMessage":"no active bridge","function":"bridge","name":"HolochainError","source":{}}`) 351 352 // TODO 353 // This test can't work because of the import cycle that we can't import 354 // apptest into holochain. 355 // The solution is to have a different method other than web access, i.e. direct call 356 // for the bridge. 357 358 /* 359 // set up a bridge app 360 361 d, s, h := PrepareTestChain("test") 362 defer CleanupTestChain(h, d) 363 364 h2, err := s.MakeTestingApp(filepath.Join(s.Path, "test2"), "json",nil) 365 if err != nil { 366 panic(err) 367 } 368 bridgeApps := []BridgeApp{BridgeApp{ 369 H: h2, 370 Side: BridgeCallee, 371 Port: "31111", 372 }} 373 bridgeAppServers, err := BuildBridges(h, bridgeApps) 374 if err != nil { 375 panic(err) 376 } 377 _, err := z.Run(fmt.Sprintf(`bridge("%s","zySampleZome","testStrFn1","foo")`, h2.DNAHash().String())) 378 So(err, ShouldBeNil) 379 result := z.lastResult.String() 380 So(result, ShouldEqual, "result: foo") 381 bridgeAppServers[0].Stop() 382 bridgeAppServers[0].Wait() 383 */ 384 }) 385 Convey("send", func() { 386 ShouldLog(h.nucleus.alog, func() { 387 _, err := z.Run(`debug("result was: "+JSON.stringify(send(App.Key.Hash,{ping:"foobar"})))`) 388 So(err, ShouldBeNil) 389 }, `result was: "{\"pong\":\"foobar\"}"`) 390 }) 391 Convey("send async", func() { 392 ShouldLog(h.nucleus.alog, func() { 393 _, err := z.Run(`send(App.Key.Hash,{ping:"foobar"},{Callback:{Function:"asyncPing",ID:"123"}})`) 394 So(err, ShouldBeNil) 395 err = <-h.asyncSends 396 So(err, ShouldBeNil) 397 }, `async result of message with 123 was: {"pong":"foobar"}`) 398 }) 399 Convey("send async with 100ms timeout", func() { 400 _, err := z.Run(`send(App.Key.Hash,{block:true},{Callback:{Function:"asyncPing",ID:"123"},Timeout:100})`) 401 So(err, ShouldBeNil) 402 err = <-h.asyncSends 403 So(err, ShouldBeError, SendTimeoutErr) 404 }) 405 Convey("bundleStart and bundleClose", func() { 406 _, err := z.Run(`bundleStart(123,"myBundle")`) 407 So(err, ShouldBeNil) 408 bundle := h.chain.BundleStarted() 409 So(bundle, ShouldNotBeNil) 410 _, err = z.Run(`commit("oddNumbers","7")`) 411 So(err, ShouldBeNil) 412 bundleCommitHash, _ := NewHash(z.lastResult.String()) 413 entry, _, _ := bundle.chain.GetEntry(bundleCommitHash) 414 So(entry.Content(), ShouldEqual, "7") 415 416 So(h.chain.BundleStarted(), ShouldNotBeNil) 417 _, err = z.Run(`bundleClose(true)`) 418 So(err, ShouldBeNil) 419 So(h.chain.BundleStarted(), ShouldBeNil) 420 entry, _, _ = h.chain.GetEntry(bundleCommitHash) 421 So(entry.Content(), ShouldEqual, "7") 422 }) 423 Convey("migrate", func() { 424 dnaHash, err := genTestStringHash() 425 So(err, ShouldBeNil) 426 key, err := genTestStringHash() 427 So(err, ShouldBeNil) 428 data, err := genTestString() 429 430 _, err = z.Run(`migrate(HC.Migrate.Close,"` + dnaHash.String() + `","` + key.String() + `","` + data + `")`) 431 So(err, ShouldBeNil) 432 migrationEntryHash, _ := NewHash(z.lastResult.String()) 433 entry, _, _ := h.chain.GetEntry(migrationEntryHash) 434 So(entry.Content(), ShouldEqual, "{\"Type\":\"close\",\"DNAHash\":\""+dnaHash.String()+"\",\"Key\":\""+key.String()+"\",\"Data\":\""+data+"\"}") 435 }) 436 }) 437 } 438 439 func TestJSQuery(t *testing.T) { 440 d, _, h := PrepareTestChain("test") 441 defer CleanupTestChain(h, d) 442 zome, _ := h.GetZome("jsSampleZome") 443 v, err := NewJSRibosome(h, zome) 444 if err != nil { 445 panic(err) 446 } 447 z := v.(*JSRibosome) 448 449 Convey("query", t, func() { 450 // add entries onto the chain to get hash values for testing 451 hash := commit(h, "oddNumbers", "3") 452 commit(h, "secret", "foo") 453 commit(h, "oddNumbers", "7") 454 commit(h, "secret", "bar") 455 profileHash := commit(h, "profile", `{"firstName":"Zippy","lastName":"Pinhead"}`) 456 commit(h, "rating", fmt.Sprintf(`{"Links":[{"Base":"%s","Link":"%s","Tag":"4stars"}]}`, hash.String(), profileHash.String())) 457 458 ShouldLog(h.nucleus.alog, func() { 459 _, err := z.Run(`debug(query({Constrain:{EntryTypes:["oddNumbers"]}}))`) 460 So(err, ShouldBeNil) 461 }, `[3,7]`) 462 ShouldLog(h.nucleus.alog, func() { 463 _, err := z.Run(`debug(query({Return:{Hashes:true},Constrain:{EntryTypes:["oddNumbers"]}}))`) 464 So(err, ShouldBeNil) 465 }, `["QmSwMfay3iCynzBFeq9rPzTMTnnuQSMUSe84whjcC9JPAo","QmfMPAEdN1BB9imcz97NsaYYaWEN3baC5aSDXqJSiWt4e6"]`) 466 ShouldLog(h.nucleus.alog, func() { 467 _, err := z.Run(`debug(query({Return:{Hashes:true,Entries:true},Constrain:{EntryTypes:["oddNumbers"]}}))`) 468 So(err, ShouldBeNil) 469 }, `[{"Entry":3,"Hash":"QmSwMfay3iCynzBFeq9rPzTMTnnuQSMUSe84whjcC9JPAo"},{"Entry":7,"Hash":"QmfMPAEdN1BB9imcz97NsaYYaWEN3baC5aSDXqJSiWt4e6"}]`) 470 ShouldLog(h.nucleus.alog, func() { 471 _, err := z.Run(`debug(query({Return:{Headers:true,Entries:true},Constrain:{EntryTypes:["oddNumbers"]}}))`) 472 So(err, ShouldBeNil) 473 }, `[{"Entry":3,"Header":{"EntryLink":"QmSwMfay3iCynzBFeq9rPzTMTnnuQSMUSe84whjcC9JPAo","HeaderLink":"Qm`) 474 ShouldLog(h.nucleus.alog, func() { 475 _, err := z.Run(`debug(query({Constrain:{EntryTypes:["secret"]}}))`) 476 So(err, ShouldBeNil) 477 }, `["foo","bar"]`) 478 ShouldLog(h.nucleus.alog, func() { 479 _, err := z.Run(`debug(query({Constrain:{EntryTypes:["profile"]}}))`) 480 So(err, ShouldBeNil) 481 }, `[{"firstName":"Zippy","lastName":"Pinhead"}]`) 482 ShouldLog(h.nucleus.alog, func() { 483 _, err := z.Run(`debug(query({Constrain:{EntryTypes:["%agent"]}}))`) 484 So(err, ShouldBeNil) 485 }, `[{"Identity":"Herbert \u003ch@bert.com\u003e","PublicKey":"4XTTM8sJEQD5zMLT1gtu2ogshwg5AdUPNhJRbLvs77gsVtQQi","Revocation":""}]`) 486 487 _, err := z.Run(`debug(query({Constrain:{EntryTypes:["%dna"]}}))`) 488 So(err.Error(), ShouldEqual, `{"errorMessage":"data format not implemented: _DNA","function":"query","name":"HolochainError","source":{}}`) 489 490 ShouldLog(h.nucleus.alog, func() { 491 _, err := z.Run(`debug(query({Constrain:{EntryTypes:["rating"]}}))`) 492 So(err, ShouldBeNil) 493 }, `[{"Links":[{"Base":"QmSwMfay3iCynzBFeq9rPzTMTnnuQSMUSe84whjcC9JPAo","Link":"QmYeinX5vhuA91D3v24YbgyLofw9QAxY6PoATrBHnRwbtt","Tag":"4stars"}]}]`) 494 }) 495 } 496 497 func TestJSGenesis(t *testing.T) { 498 d, _, h := PrepareTestChain("test") 499 defer CleanupTestChain(h, d) 500 Convey("it should fail if the genesis function returns false", t, func() { 501 z, _ := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: `function genesis() {return false}`}) 502 err := z.ChainGenesis() 503 So(err.Error(), ShouldEqual, "genesis failed") 504 }) 505 Convey("it should work if the genesis function returns true", t, func() { 506 z, _ := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: `function genesis() {return true}`}) 507 err := z.ChainGenesis() 508 So(err, ShouldBeNil) 509 }) 510 } 511 512 func TestJSBridgeGenesis(t *testing.T) { 513 d, _, h := PrepareTestChain("test") 514 defer CleanupTestChain(h, d) 515 516 fakeToApp, _ := NewHash("QmVGtdTZdTFaLsaj2134RwdVG8jcjNNcp1DE914DKZ2kHmXHx") 517 Convey("it should fail if the bridge genesis function returns false", t, func() { 518 519 ShouldLog(&h.Config.Loggers.App, func() { 520 z, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: `function bridgeGenesis(side,app,data) {debug(app+" "+data);if (side==HC.Bridge.Caller) {return false;} return true;}`}) 521 So(err, ShouldBeNil) 522 err = z.BridgeGenesis(BridgeCaller, h.dnaHash, "test data") 523 So(err.Error(), ShouldEqual, "bridgeGenesis failed") 524 }, h.dnaHash.String()+" test data") 525 }) 526 Convey("it should work if the genesis function returns true", t, func() { 527 ShouldLog(&h.Config.Loggers.App, func() { 528 z, _ := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: `function bridgeGenesis(side,app,data) {debug(app+" "+data);if (side==HC.Bridge.Caller) {return false;} return true;}`}) 529 err := z.BridgeGenesis(BridgeCallee, fakeToApp, "test data") 530 So(err, ShouldBeNil) 531 }, fakeToApp.String()+" test data") 532 }) 533 } 534 535 func TestJSReceive(t *testing.T) { 536 d, _, h := PrepareTestChain("test") 537 defer CleanupTestChain(h, d) 538 Convey("it should call a receive function", t, func() { 539 z, _ := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: `function receive(from,msg) {return {foo:msg.bar}}`}) 540 response, err := z.Receive("fakehash", `{"bar":"baz"}`) 541 So(err, ShouldBeNil) 542 So(response, ShouldEqual, `{"foo":"baz"}`) 543 }) 544 } 545 func TestJSBundleCanceled(t *testing.T) { 546 d, _, h := PrepareTestChain("test") 547 defer CleanupTestChain(h, d) 548 Convey("it should call a bundleCanceled function", t, func() { 549 z, _ := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: `function bundleCanceled(reason,userParam) {debug("fish:"+userParam+reason); return HC.BundleCancel.Response.OK}`}) 550 _, err := z.BundleCanceled(BundleCancelReasonUserCancel) 551 So(err, ShouldEqual, ErrBundleNotStarted) 552 h.chain.StartBundle("myBundle") 553 ShouldLog(h.nucleus.alog, func() { 554 response, err := z.BundleCanceled(BundleCancelReasonUserCancel) 555 So(err, ShouldBeNil) 556 So(response, ShouldEqual, BundleCancelResponseOK) 557 }, `fish:myBundle`+BundleCancelReasonUserCancel) 558 }) 559 } 560 561 func TestJSbuildValidate(t *testing.T) { 562 d, _, h := PrepareTestChain("test") 563 defer CleanupTestChain(h, d) 564 565 e := GobEntry{C: "2"} 566 a := NewCommitAction("evenNumbers", &e) 567 var header Header 568 a.header = &header 569 570 def := EntryDef{Name: "evenNumbers", DataFormat: DataFormatString} 571 572 Convey("it should build commit", t, func() { 573 code, err := buildJSValidateAction(a, &def, nil, []string{"fake_src_hash"}) 574 So(err, ShouldBeNil) 575 So(code, ShouldEqual, `validateCommit("evenNumbers","2",{"EntryLink":"","Type":"","Time":"0001-01-01T00:00:00Z"},{},["fake_src_hash"])`) 576 }) 577 578 Convey("it should build put", t, func() { 579 a := NewPutAction("evenNumbers", &e, &header) 580 pkg, _ := MakePackage(h, PackagingReq{PkgReqChain: int64(PkgReqChainOptFull)}) 581 vpkg, _ := MakeValidationPackage(h, &pkg) 582 _, err := buildJSValidateAction(a, &def, vpkg, []string{"fake_src_hash"}) 583 So(err, ShouldBeNil) 584 // So(code, ShouldEqual, `validatePut("evenNumbers","2",{"EntryLink":"","Type":"","Time":"0001-01-01T00:00:00Z"},pgk,["fake_src_hash"])`) 585 }) 586 587 } 588 589 func TestJSValidateCommit(t *testing.T) { 590 d, _, h := PrepareTestChain("test") 591 defer CleanupTestChain(h, d) 592 // a, _ := NewAgent(LibP2P, "Joe", MakeTestSeed("")) 593 // h := NewHolochain(a, "some/path", "yaml", Zome{RibosomeType:JSRibosomeType,}) 594 // a := h.agent 595 h.Config.Loggers.App.Format = "" 596 h.Config.Loggers.App.New(nil) 597 hdr := mkTestHeader("evenNumbers") 598 pkg, _ := MakePackage(h, PackagingReq{PkgReqChain: int64(PkgReqChainOptFull)}) 599 vpkg, _ := MakeValidationPackage(h, &pkg) 600 601 Convey("it should be passing in the correct values", t, func() { 602 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: `function validateCommit(name,entry,header,pkg,sources) {debug(name);debug(entry);debug(JSON.stringify(header));debug(JSON.stringify(sources));debug(JSON.stringify(pkg));return true};`}) 603 So(err, ShouldBeNil) 604 d := EntryDef{Name: "evenNumbers", DataFormat: DataFormatString} 605 ShouldLog(&h.Config.Loggers.App, func() { 606 a := NewCommitAction("oddNumbers", &GobEntry{C: "foo"}) 607 a.header = &hdr 608 err = v.ValidateAction(a, &d, nil, []string{"fakehashvalue"}) 609 So(err, ShouldBeNil) 610 }, `evenNumbers 611 foo 612 {"EntryLink":"QmNiCwBNA8MWDADTFVq1BonUEJbS2SvjAoNkZZrhEwcuU2","Time":"1970-01-01T00:00:01Z","Type":"evenNumbers"} 613 ["fakehashvalue"] 614 {} 615 `) 616 }) 617 Convey("should run an entry value against the defined validator for string data", t, func() { 618 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: `function validateCommit(name,entry,header,pkg,sources) { return (entry=="fish")};`}) 619 So(err, ShouldBeNil) 620 d := EntryDef{Name: "oddNumbers", DataFormat: DataFormatString} 621 622 a := NewCommitAction("oddNumbers", &GobEntry{C: "cow"}) 623 a.header = &hdr 624 err = v.ValidateAction(a, &d, nil, nil) 625 So(IsValidationFailedErr(err), ShouldBeTrue) 626 627 a = NewCommitAction("oddNumbers", &GobEntry{C: "fish"}) 628 a.header = &hdr 629 err = v.ValidateAction(a, &d, vpkg, nil) 630 So(err, ShouldBeNil) 631 }) 632 Convey("should run an entry value against the defined validator for js data", t, func() { 633 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: `function validateCommit(name,entry,header,pkg,sources) { return (entry=="fish")};`}) 634 d := EntryDef{Name: "evenNumbers", DataFormat: DataFormatRawJS} 635 636 a := NewCommitAction("oddNumbers", &GobEntry{C: "\"cow\""}) 637 a.header = &hdr 638 err = v.ValidateAction(a, &d, nil, nil) 639 So(IsValidationFailedErr(err), ShouldBeTrue) 640 641 a = NewCommitAction("oddNumbers", &GobEntry{C: "\"fish\""}) 642 a.header = &hdr 643 err = v.ValidateAction(a, &d, nil, nil) 644 So(err, ShouldBeNil) 645 }) 646 Convey("should run an entry value against the defined validator for json data", t, func() { 647 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: `function validateCommit(name,entry,header,pkg,sources) { return (entry.data=="fish")};`}) 648 d := EntryDef{Name: "evenNumbers", DataFormat: DataFormatJSON} 649 650 a := NewCommitAction("evenNumbers", &GobEntry{C: `{"data":"cow"}`}) 651 a.header = &hdr 652 err = v.ValidateAction(a, &d, nil, nil) 653 So(IsValidationFailedErr(err), ShouldBeTrue) 654 655 a = NewCommitAction("evenNumbers", &GobEntry{C: `{"data":"fish"}`}) 656 a.header = &hdr 657 err = v.ValidateAction(a, &d, nil, nil) 658 So(err, ShouldBeNil) 659 }) 660 } 661 662 func TestPrepareJSValidateArgs(t *testing.T) { 663 d := EntryDef{Name: "evenNumbers", DataFormat: DataFormatString} 664 665 Convey("it should prepare args for commit", t, func() { 666 e := GobEntry{C: "2"} 667 a := NewCommitAction("evenNumbers", &e) 668 var header Header 669 a.header = &header 670 args, err := prepareJSValidateArgs(a, &d) 671 So(err, ShouldBeNil) 672 So(args, ShouldEqual, `"2",{"EntryLink":"","Type":"","Time":"0001-01-01T00:00:00Z"}`) 673 }) 674 Convey("it should prepare args for put", t, func() { 675 e := GobEntry{C: "2"} 676 var header Header 677 a := NewPutAction("evenNumbers", &e, &header) 678 679 args, err := prepareJSValidateArgs(a, &d) 680 So(err, ShouldBeNil) 681 So(args, ShouldEqual, `"2",{"EntryLink":"","Type":"","Time":"0001-01-01T00:00:00Z"}`) 682 }) 683 Convey("it should prepare args for mod", t, func() { 684 e := GobEntry{C: "4"} 685 var header = Header{Type: "foo"} 686 hash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2") // fake hash for previous entry 687 a := NewModAction("evenNumbers", &e, hash) 688 a.header = &header 689 690 args, err := prepareJSValidateArgs(a, &d) 691 So(err, ShouldBeNil) 692 So(args, ShouldEqual, `"4",{"EntryLink":"","Type":"foo","Time":"0001-01-01T00:00:00Z"},"QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2"`) 693 }) 694 Convey("it should prepare args for del", t, func() { 695 hash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2") 696 entry := DelEntry{Hash: hash, Message: "expired"} 697 a := NewDelAction(entry) 698 args, err := prepareJSValidateArgs(a, &d) 699 So(err, ShouldBeNil) 700 So(args, ShouldEqual, `"QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2"`) 701 }) 702 Convey("it should prepare args for link", t, func() { 703 hash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2") 704 a := NewLinkAction("evenNumbers", []Link{{Base: "QmdRXz53TVT9qBYfbXctHyy2GpTNa6YrpAy6ZcDGG8Xhc5", Link: "QmdRXz53TVT9qBYfbXctHyy2GpTNa6YrpAy6ZcDGG8Xhc5", Tag: "fish"}}) 705 a.validationBase = hash 706 args, err := prepareJSValidateArgs(a, &d) 707 So(err, ShouldBeNil) 708 So(args, ShouldEqual, `"QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2",JSON.parse("[{\"LinkAction\":\"\",\"Base\":\"QmdRXz53TVT9qBYfbXctHyy2GpTNa6YrpAy6ZcDGG8Xhc5\",\"Link\":\"QmdRXz53TVT9qBYfbXctHyy2GpTNa6YrpAy6ZcDGG8Xhc5\",\"Tag\":\"fish\"}]")`) 709 }) 710 } 711 712 func TestJSSanitize(t *testing.T) { 713 Convey("should strip quotes and returns", t, func() { 714 So(jsSanitizeString(`"`), ShouldEqual, `\"`) 715 So(jsSanitizeString(`\"`), ShouldEqual, `\\\"`) 716 So(jsSanitizeString("\"x\ny"), ShouldEqual, "\\\"x\\ny") 717 }) 718 } 719 720 func TestJSExposeCall(t *testing.T) { 721 d, _, h := PrepareTestChain("test") 722 defer CleanupTestChain(h, d) 723 724 v, zome, err := h.MakeRibosome("jsSampleZome") 725 if err != nil { 726 panic(err) 727 } 728 z := v.(*JSRibosome) 729 Convey("should allow calling exposed STRING based functions", t, func() { 730 cater, _ := zome.GetFunctionDef("testStrFn1") 731 result, err := z.Call(cater, "fish \"zippy\"") 732 So(err, ShouldBeNil) 733 So(result.(string), ShouldEqual, "result: fish \"zippy\"") 734 735 adder, _ := zome.GetFunctionDef("testStrFn2") 736 result, err = z.Call(adder, "10") 737 So(err, ShouldBeNil) 738 So(result.(string), ShouldEqual, "12") 739 }) 740 Convey("should allow calling exposed JSON based functions", t, func() { 741 times2, _ := zome.GetFunctionDef("testJsonFn1") 742 result, err := z.Call(times2, `{"input": 2}`) 743 So(err, ShouldBeNil) 744 So(result.(string), ShouldEqual, `{"input":2,"output":4}`) 745 }) 746 Convey("should sanitize against bad strings", t, func() { 747 cater, _ := zome.GetFunctionDef("testStrFn1") 748 result, err := z.Call(cater, "fish \"\nzippy\"") 749 So(err, ShouldBeNil) 750 So(result.(string), ShouldEqual, "result: fish \"\nzippy\"") 751 }) 752 Convey("should fail on bad JSON", t, func() { 753 times2, _ := zome.GetFunctionDef("testJsonFn1") 754 _, err := z.Call(times2, "{\"input\n\": 2}") 755 So(err, ShouldBeError) 756 }) 757 Convey("should allow a function declared with JSON parameter to be called with no parameter", t, func() { 758 emptyParametersJson, _ := zome.GetFunctionDef("testJsonFn2") 759 result, err := z.Call(emptyParametersJson, "") 760 So(err, ShouldBeNil) 761 So(result, ShouldEqual, "[{\"a\":\"b\"}]") 762 }) 763 } 764 765 func TestJSDHT(t *testing.T) { 766 d, _, h := PrepareTestChain("test") 767 defer CleanupTestChain(h, d) 768 769 hash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2") 770 Convey("get should return HC.HashNotFound if it doesn't exist", t, func() { 771 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`get("%s")===HC.HashNotFound;`, hash.String())}) 772 773 So(err, ShouldBeNil) 774 z := v.(*JSRibosome) 775 x, err := z.lastResult.Export() 776 So(err, ShouldBeNil) 777 So(fmt.Sprintf("%v", x), ShouldEqual, `true`) 778 }) 779 780 // add an entry onto the chain 781 hash = commit(h, "oddNumbers", "7") 782 783 Convey("get should return entry", t, func() { 784 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`get("%s");`, hash.String())}) 785 So(err, ShouldBeNil) 786 z := v.(*JSRibosome) 787 x, err := z.lastResult.Export() 788 So(err, ShouldBeNil) 789 So(fmt.Sprintf("%v", x), ShouldEqual, `7`) 790 }) 791 792 Convey("get should return entry of sys types", t, func() { 793 ShouldLog(h.nucleus.alog, func() { 794 _, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`debug(get("%s"));`, h.agentHash.String())}) 795 So(err, ShouldBeNil) 796 }, `{"Identity":"Herbert \u003ch@bert.com\u003e","PublicKey":"4XTTM8sJEQD5zMLT1gtu2ogshwg5AdUPNhJRbLvs77gsVtQQi","Revocation":""}`) 797 ShouldLog(h.nucleus.alog, func() { 798 _, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`debug(get("%s"));`, h.nodeID.Pretty())}) 799 So(err, ShouldBeNil) 800 }, "4XTTM8sJEQD5zMLT1gtu2ogshwg5AdUPNhJRbLvs77gsVtQQi") 801 }) 802 803 Convey("get should return entry type", t, func() { 804 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`get("%s",{GetMask:HC.GetMask.EntryType});`, hash.String())}) 805 So(err, ShouldBeNil) 806 z := v.(*JSRibosome) 807 x, err := z.lastResult.Export() 808 So(err, ShouldBeNil) 809 So(fmt.Sprintf("%v", x.(string)), ShouldEqual, `oddNumbers`) 810 }) 811 812 Convey("get should return sources", t, func() { 813 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`get("%s",{GetMask:HC.GetMask.Sources});`, hash.String())}) 814 So(err, ShouldBeNil) 815 z := v.(*JSRibosome) 816 x, err := z.lastResult.Export() 817 So(err, ShouldBeNil) 818 So(fmt.Sprintf("%v", x), ShouldEqual, fmt.Sprintf("[%v]", h.nodeIDStr)) 819 }) 820 821 Convey("get should return collection", t, func() { 822 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`get("%s",{GetMask:HC.GetMask.All});`, hash.String())}) 823 So(err, ShouldBeNil) 824 z := v.(*JSRibosome) 825 x, err := z.lastResult.Export() 826 So(err, ShouldBeNil) 827 obj := x.(map[string]interface{}) 828 So(obj["Entry"], ShouldEqual, `7`) 829 So(obj["EntryType"].(string), ShouldEqual, `oddNumbers`) 830 So(fmt.Sprintf("%v", obj["Sources"]), ShouldEqual, fmt.Sprintf("[%v]", h.nodeIDStr)) 831 }) 832 833 profileHash := commit(h, "profile", `{"firstName":"Zippy","lastName":"Pinhead"}`) 834 835 Convey("get should parsed JSON object of JSON type entries", t, func() { 836 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`get("%s");`, profileHash.String())}) 837 So(err, ShouldBeNil) 838 z := v.(*JSRibosome) 839 So(z.lastResult.Class(), ShouldEqual, "Object") 840 x, err := z.lastResult.Export() 841 So(err, ShouldBeNil) 842 y := x.(map[string]interface{}) 843 So(y["firstName"], ShouldEqual, "Zippy") 844 So(y["lastName"], ShouldEqual, "Pinhead") 845 }) 846 847 reviewHash := commit(h, "review", "this is my bogus review of some thing") 848 849 commit(h, "rating", fmt.Sprintf(`{"Links":[{"Base":"%s","Link":"%s","Tag":"4stars"},{"Base":"%s","Link":"%s","Tag":"4stars"}]}`, hash.String(), profileHash.String(), hash.String(), reviewHash.String())) 850 851 Convey("getLinks should return the Links", t, func() { 852 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`getLinks("%s","4stars");`, hash.String())}) 853 So(err, ShouldBeNil) 854 z := v.(*JSRibosome) 855 So(z.lastResult.Class(), ShouldEqual, "Array") 856 links, _ := z.lastResult.Export() 857 l0 := links.([]map[string]interface{})[0] 858 l1 := links.([]map[string]interface{})[1] 859 860 So(fmt.Sprintf("%v", l0["Hash"]), ShouldEqual, reviewHash.String()) 861 So(fmt.Sprintf("%v", l1["Hash"]), ShouldEqual, profileHash.String()) 862 }) 863 864 Convey("getLinks with empty tag should return the Links and tags", t, func() { 865 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`getLinks("%s","");`, hash.String())}) 866 So(err, ShouldBeNil) 867 z := v.(*JSRibosome) 868 So(z.lastResult.Class(), ShouldEqual, "Array") 869 links, _ := z.lastResult.Export() 870 l0 := links.([]map[string]interface{})[0] 871 l1 := links.([]map[string]interface{})[1] 872 873 So(fmt.Sprintf("%v", l0["Hash"]), ShouldEqual, reviewHash.String()) 874 So(fmt.Sprintf("%v", l0["Tag"]), ShouldEqual, "4stars") 875 So(fmt.Sprintf("%v", l1["Hash"]), ShouldEqual, profileHash.String()) 876 So(fmt.Sprintf("%v", l1["Tag"]), ShouldEqual, "4stars") 877 878 }) 879 880 Convey("getLinks with load option should return the Links and entries", t, func() { 881 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`getLinks("%s","4stars",{Load:true});`, hash.String())}) 882 So(err, ShouldBeNil) 883 z := v.(*JSRibosome) 884 So(z.lastResult.Class(), ShouldEqual, "Array") 885 links, _ := z.lastResult.Export() 886 l0 := links.([]map[string]interface{})[0] 887 l1 := links.([]map[string]interface{})[1] 888 So(l1["Hash"], ShouldEqual, profileHash.String()) 889 lp := l1["Entry"].(map[string]interface{}) 890 So(fmt.Sprintf("%v", lp["firstName"]), ShouldEqual, "Zippy") 891 So(fmt.Sprintf("%v", lp["lastName"]), ShouldEqual, "Pinhead") 892 So(l1["EntryType"], ShouldEqual, "profile") 893 So(l1["Source"], ShouldEqual, h.nodeIDStr) 894 895 So(l0["Hash"], ShouldEqual, reviewHash.String()) 896 So(fmt.Sprintf("%v", l0["Entry"]), ShouldEqual, `this is my bogus review of some thing`) 897 So(l0["EntryType"], ShouldEqual, "review") 898 }) 899 900 Convey("getLinks with load option should return the Links and entries for linked sys types", t, func() { 901 commit(h, "rating", fmt.Sprintf(`{"Links":[{"Base":"%s","Link":"%s","Tag":"4stars"},{"Base":"%s","Link":"%s","Tag":"4stars"}]}`, profileHash.String(), h.nodeIDStr, profileHash.String(), h.agentHash.String())) 902 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`getLinks("%s","4stars",{Load:true});`, profileHash.String())}) 903 So(err, ShouldBeNil) 904 z := v.(*JSRibosome) 905 So(z.lastResult.Class(), ShouldEqual, "Array") 906 links, _ := z.lastResult.Export() 907 l0 := links.([]map[string]interface{})[0] 908 l1 := links.([]map[string]interface{})[1] 909 So(l1["Hash"], ShouldEqual, h.agentHash.String()) 910 lp := l1["Entry"].(map[string]interface{}) 911 So(fmt.Sprintf("%v", lp["Identity"]), ShouldEqual, "Herbert <h@bert.com>") 912 So(fmt.Sprintf("%v", lp["PublicKey"]), ShouldEqual, "4XTTM8sJEQD5zMLT1gtu2ogshwg5AdUPNhJRbLvs77gsVtQQi") 913 So(l1["EntryType"], ShouldEqual, AgentEntryType) 914 So(l1["Source"], ShouldEqual, h.nodeIDStr) 915 916 So(l0["Hash"], ShouldEqual, h.nodeIDStr) 917 So(fmt.Sprintf("%v", l0["Entry"]), ShouldEqual, "4XTTM8sJEQD5zMLT1gtu2ogshwg5AdUPNhJRbLvs77gsVtQQi") 918 So(l0["EntryType"], ShouldEqual, KeyEntryType) 919 }) 920 921 Convey("commit with del link should delete link", t, func() { 922 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`commit("rating",{Links:[{"LinkAction":HC.LinkAction.Del,Base:"%s",Link:"%s",Tag:"4stars"}]});`, hash.String(), profileHash.String())}) 923 So(err, ShouldBeNil) 924 z := v.(*JSRibosome) 925 _, err = NewHash(z.lastResult.String()) 926 So(err, ShouldBeNil) 927 928 links, _ := h.dht.GetLinks(hash, "4stars", StatusLive) 929 So(fmt.Sprintf("%v", links), ShouldEqual, fmt.Sprintf("[{QmWbbUf6G38hT27kmrQ5UYFbXUPTGokKvDiaQbczFYNjuN %s}]", h.nodeIDStr)) 930 links, _ = h.dht.GetLinks(hash, "4stars", StatusDeleted) 931 So(fmt.Sprintf("%v", links), ShouldEqual, fmt.Sprintf("[{QmYeinX5vhuA91D3v24YbgyLofw9QAxY6PoATrBHnRwbtt %s}]", h.nodeIDStr)) 932 }) 933 934 Convey("getLinks with StatusMask option should return deleted Links", t, func() { 935 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`getLinks("%s","4stars",{StatusMask:HC.Status.Deleted});`, hash.String())}) 936 So(err, ShouldBeNil) 937 z := v.(*JSRibosome) 938 939 So(z.lastResult.Class(), ShouldEqual, "Array") 940 links, _ := z.lastResult.Export() 941 l0 := links.([]map[string]interface{})[0] 942 So(l0["Hash"], ShouldEqual, profileHash.String()) 943 }) 944 945 Convey("getLinks with quotes in tags should work", t, func() { 946 947 commit(h, "rating", fmt.Sprintf(`{"Links":[{"Base":"%s","Link":"%s","Tag":"\"quotes!\""}]}`, hash.String(), profileHash.String())) 948 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`getLinks("%s","\"quotes!\"");`, hash.String())}) 949 So(err, ShouldBeNil) 950 z := v.(*JSRibosome) 951 So(z.lastResult.Class(), ShouldEqual, "Array") 952 links, _ := z.lastResult.Export() 953 l0 := links.([]map[string]interface{})[0] 954 955 So(fmt.Sprintf("%v", l0["Hash"]), ShouldEqual, profileHash.String()) 956 }) 957 958 Convey("update should commit a new entry and on DHT mark item modified", t, func() { 959 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`update("profile",{firstName:"Zippy",lastName:"ThePinhead"},"%s")`, profileHash.String())}) 960 So(err, ShouldBeNil) 961 z := v.(*JSRibosome) 962 profileHashStr2 := z.lastResult.String() 963 964 header := h.chain.Top() 965 So(profileHashStr2, ShouldEqual, header.EntryLink.String()) 966 So(header.Change.String(), ShouldEqual, profileHash.String()) 967 968 // the entry should be marked as Modifed 969 data, _, _, _, err := h.dht.Get(profileHash, StatusDefault, GetMaskDefault) 970 So(err, ShouldEqual, ErrHashModified) 971 So(string(data), ShouldEqual, profileHashStr2) 972 973 // but a regular get, should resolve through 974 v, err = NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`get("%s");`, profileHash.String())}) 975 z = v.(*JSRibosome) 976 x, err := z.lastResult.Export() 977 So(err, ShouldBeNil) 978 979 y := x.(map[string]interface{}) 980 So(y["firstName"], ShouldEqual, "Zippy") 981 So(y["lastName"], ShouldEqual, "ThePinhead") 982 }) 983 984 Convey("remove function should mark item deleted", t, func() { 985 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`remove("%s","expired");`, hash.String())}) 986 So(err, ShouldBeNil) 987 z := v.(*JSRibosome) 988 delhashstr := z.lastResult.String() 989 _, err = NewHash(delhashstr) 990 So(err, ShouldBeNil) 991 992 v, err = NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`get("%s");`, hash.String())}) 993 So(err.Error(), ShouldEqual, `{"errorMessage":"hash deleted","function":"get","name":"HolochainError","source":{}}`) 994 995 v, err = NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: fmt.Sprintf(`get("%s",{StatusMask:HC.Status.Deleted});`, hash.String())}) 996 So(err, ShouldBeNil) 997 z = v.(*JSRibosome) 998 999 x, err := z.lastResult.Export() 1000 So(err, ShouldBeNil) 1001 So(fmt.Sprintf("%v", x), ShouldEqual, `7`) 1002 }) 1003 1004 Convey("updateAgent function without options should fail", t, func() { 1005 _, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, 1006 Code: fmt.Sprintf(`updateAgent({})`)}) 1007 So(err.Error(), ShouldEqual, `{"errorMessage":"expecting identity and/or revocation option","function":"updateAgent","name":"HolochainError","source":{}}`) 1008 }) 1009 1010 Convey("updateAgent function should commit a new agent entry", t, func() { 1011 oldPubKey, _ := h.agent.EncodePubKey() 1012 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, 1013 Code: fmt.Sprintf(`updateAgent({Identity:"new identity"})`)}) 1014 So(err, ShouldBeNil) 1015 z := v.(*JSRibosome) 1016 newAgentHash := z.lastResult.String() 1017 So(h.agentTopHash.String(), ShouldEqual, newAgentHash) 1018 header := h.chain.Top() 1019 So(header.Type, ShouldEqual, AgentEntryType) 1020 So(newAgentHash, ShouldEqual, header.EntryLink.String()) 1021 So(h.agent.Identity(), ShouldEqual, "new identity") 1022 newPubKey, _ := h.agent.EncodePubKey() 1023 So(fmt.Sprintf("%v", newPubKey), ShouldEqual, fmt.Sprintf("%v", oldPubKey)) 1024 entry, _, _ := h.chain.GetEntry(header.EntryLink) 1025 a, _ := AgentEntryFromJSON(entry.Content().(string)) 1026 So(a.Identity, ShouldEqual, "new identity") 1027 So(fmt.Sprintf("%v", a.PublicKey), ShouldEqual, fmt.Sprintf("%v", oldPubKey)) 1028 }) 1029 1030 Convey("updateAgent function with revoke option should commit a new agent entry and mark key as modified on DHT", t, func() { 1031 oldPubKey, _ := h.agent.PubKey().Bytes() 1032 oldPeer := h.nodeID 1033 oldKey, _ := NewHash(h.nodeIDStr) 1034 oldAgentHash := h.agentHash 1035 1036 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, 1037 Code: fmt.Sprintf(`updateAgent({Revocation:"some revocation data"})`)}) 1038 So(err, ShouldBeNil) 1039 z := v.(*JSRibosome) 1040 newAgentHash := z.lastResult.String() 1041 So(newAgentHash, ShouldEqual, h.agentTopHash.String()) 1042 So(oldAgentHash.String(), ShouldNotEqual, h.agentTopHash.String()) 1043 1044 header := h.chain.Top() 1045 So(header.Type, ShouldEqual, AgentEntryType) 1046 So(newAgentHash, ShouldEqual, header.EntryLink.String()) 1047 newPubKey, _ := h.agent.EncodePubKey() 1048 So(fmt.Sprintf("%v", newPubKey), ShouldNotEqual, fmt.Sprintf("%v", oldPubKey)) 1049 entry, _, _ := h.chain.GetEntry(header.EntryLink) 1050 revocation := &SelfRevocation{} 1051 a, _ := AgentEntryFromJSON(entry.Content().(string)) 1052 revocation.Unmarshal(a.Revocation) 1053 1054 w, _ := NewSelfRevocationWarrant(revocation) 1055 payload, _ := w.Property("payload") 1056 1057 So(string(payload.([]byte)), ShouldEqual, "some revocation data") 1058 So(fmt.Sprintf("%v", a.PublicKey), ShouldEqual, fmt.Sprintf("%v", newPubKey)) 1059 1060 // the new Key should be available on the DHT 1061 newKey, _ := NewHash(h.nodeIDStr) 1062 data, _, _, _, err := h.dht.Get(newKey, StatusDefault, GetMaskDefault) 1063 So(err, ShouldBeNil) 1064 So(string(data), ShouldEqual, newPubKey) 1065 1066 // the old key should be marked as Modifed and we should get the new hash as the data 1067 data, _, _, _, err = h.dht.Get(oldKey, StatusDefault, GetMaskDefault) 1068 So(err, ShouldEqual, ErrHashModified) 1069 So(string(data), ShouldEqual, h.nodeIDStr) 1070 1071 // the new key should be a peerID in the node 1072 peers := h.node.host.Peerstore().Peers() 1073 var found bool 1074 1075 for _, p := range peers { 1076 pStr := peer.IDB58Encode(p) 1077 if pStr == h.nodeIDStr { 1078 1079 found = true 1080 break 1081 } 1082 } 1083 So(found, ShouldBeTrue) 1084 1085 // the old peerID should now be in the blockedlist 1086 peerList, err := h.dht.getList(BlockedList) 1087 So(err, ShouldBeNil) 1088 So(len(peerList.Records), ShouldEqual, 1) 1089 So(peerList.Records[0].ID, ShouldEqual, oldPeer) 1090 So(h.node.IsBlocked(oldPeer), ShouldBeTrue) 1091 1092 }) 1093 1094 Convey("updateAgent function should update library values", t, func() { 1095 v, err := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, 1096 Code: fmt.Sprintf(`updateAgent({Identity:"new id",Revocation:"some revocation data"});App.Key.Hash+"."+App.Agent.TopHash+"."+App.Agent.String`)}) 1097 So(err, ShouldBeNil) 1098 z := v.(*JSRibosome) 1099 libVals := z.lastResult.String() 1100 s := strings.Split(libVals, ".") 1101 1102 So(s[0], ShouldEqual, h.nodeIDStr) 1103 So(s[1], ShouldEqual, h.agentTopHash.String()) 1104 So(s[2], ShouldEqual, "new id") 1105 1106 }) 1107 } 1108 1109 func TestJSProcessArgs(t *testing.T) { 1110 d, _, h := PrepareTestChain("test") 1111 defer CleanupTestChain(h, d) 1112 1113 v, _ := NewJSRibosome(h, &Zome{RibosomeType: JSRibosomeType, Code: ""}) 1114 z := v.(*JSRibosome) 1115 1116 nilValue := otto.UndefinedValue() 1117 Convey("it should check for wrong number of args", t, func() { 1118 oArgs := []otto.Value{nilValue, nilValue} 1119 args := []Arg{{}} 1120 err := jsProcessArgs(z, args, oArgs) 1121 So(err, ShouldEqual, ErrWrongNargs) 1122 1123 // test with args that are optional: two that are required and one not 1124 args = []Arg{{}, {}, {Optional: true}} 1125 oArgs = []otto.Value{nilValue} 1126 err = jsProcessArgs(z, args, oArgs) 1127 So(err, ShouldEqual, ErrWrongNargs) 1128 1129 oArgs = []otto.Value{nilValue, nilValue, nilValue, nilValue} 1130 err = jsProcessArgs(z, args, oArgs) 1131 So(err, ShouldEqual, ErrWrongNargs) 1132 1133 }) 1134 Convey("it should treat StringArg as string", t, func() { 1135 args := []Arg{{Name: "foo", Type: StringArg}} 1136 err := jsProcessArgs(z, args, []otto.Value{nilValue}) 1137 So(err.Error(), ShouldEqual, "argument 1 (foo) should be string") 1138 val, _ := z.vm.ToValue("bar") 1139 err = jsProcessArgs(z, args, []otto.Value{val}) 1140 So(err, ShouldBeNil) 1141 So(args[0].value.(string), ShouldEqual, "bar") 1142 }) 1143 Convey("it should convert IntArg to int64", t, func() { 1144 args := []Arg{{Name: "foo", Type: IntArg}} 1145 err := jsProcessArgs(z, args, []otto.Value{nilValue}) 1146 So(err.Error(), ShouldEqual, "argument 1 (foo) should be int") 1147 val, _ := z.vm.ToValue(314) 1148 err = jsProcessArgs(z, args, []otto.Value{val}) 1149 So(err, ShouldBeNil) 1150 So(args[0].value.(int64), ShouldEqual, 314) 1151 }) 1152 Convey("it should convert BoolArg to bool", t, func() { 1153 args := []Arg{{Name: "foo", Type: BoolArg}} 1154 err := jsProcessArgs(z, args, []otto.Value{nilValue}) 1155 So(err.Error(), ShouldEqual, "argument 1 (foo) should be boolean") 1156 val, _ := z.vm.ToValue(true) 1157 err = jsProcessArgs(z, args, []otto.Value{val}) 1158 So(err, ShouldBeNil) 1159 So(args[0].value.(bool), ShouldEqual, true) 1160 }) 1161 1162 Convey("EntryArg should only accept strings for string type entries", t, func() { 1163 args := []Arg{{Name: "entryType", Type: StringArg}, {Name: "foo", Type: EntryArg}} 1164 entryType, _ := z.vm.ToValue("review") 1165 1166 err := jsProcessArgs(z, args, []otto.Value{entryType, nilValue}) 1167 So(err, ShouldBeError) 1168 So(err.Error(), ShouldEqual, "argument 2 (foo) should be string") 1169 1170 val, _ := z.vm.ToValue("bar") 1171 err = jsProcessArgs(z, args, []otto.Value{entryType, val}) 1172 So(err, ShouldBeNil) 1173 So(args[1].value.(string), ShouldEqual, "bar") 1174 1175 // create an otto.object for a test arg 1176 val, _ = z.vm.ToValue(map[string]string{"H": "foo", "E": "bar"}) 1177 err = jsProcessArgs(z, args, []otto.Value{entryType, val}) 1178 So(err, ShouldBeError) 1179 So(err.Error(), ShouldEqual, "argument 2 (foo) should be string") 1180 1181 val, _ = z.vm.ToValue(3.1415) 1182 err = jsProcessArgs(z, args, []otto.Value{entryType, val}) 1183 So(err, ShouldBeError) 1184 So(err.Error(), ShouldEqual, "argument 2 (foo) should be string") 1185 }) 1186 1187 Convey("EntryArg should only accept objects for links type entries", t, func() { 1188 args := []Arg{{Name: "entryType", Type: StringArg}, {Name: "foo", Type: EntryArg}} 1189 entryType, _ := z.vm.ToValue("rating") 1190 1191 err := jsProcessArgs(z, args, []otto.Value{entryType, nilValue}) 1192 So(err, ShouldBeError) 1193 So(err.Error(), ShouldEqual, "argument 2 (foo) should be object") 1194 1195 val, _ := z.vm.ToValue("bar") 1196 err = jsProcessArgs(z, args, []otto.Value{entryType, val}) 1197 So(err, ShouldBeError) 1198 So(err.Error(), ShouldEqual, "argument 2 (foo) should be object") 1199 1200 // create an otto.object for a test arg 1201 val, _ = z.vm.ToValue(map[string]string{"H": "foo", "E": "bar"}) 1202 err = jsProcessArgs(z, args, []otto.Value{entryType, val}) 1203 So(err, ShouldBeNil) 1204 So(args[1].value.(string), ShouldEqual, `{"E":"bar","H":"foo"}`) 1205 1206 val, _ = z.vm.ToValue(3.1415) 1207 err = jsProcessArgs(z, args, []otto.Value{entryType, val}) 1208 So(err, ShouldBeError) 1209 So(err.Error(), ShouldEqual, "argument 2 (foo) should be object") 1210 }) 1211 1212 Convey("EntryArg should convert all values to JSON for JSON type entries", t, func() { 1213 args := []Arg{{Name: "entryType", Type: StringArg}, {Name: "foo", Type: EntryArg}} 1214 entryType, _ := z.vm.ToValue("profile") 1215 1216 err := jsProcessArgs(z, args, []otto.Value{entryType, nilValue}) 1217 So(err, ShouldBeNil) 1218 So(args[1].value.(string), ShouldEqual, "undefined") 1219 1220 val, _ := z.vm.ToValue("bar") 1221 err = jsProcessArgs(z, args, []otto.Value{entryType, val}) 1222 So(err, ShouldBeNil) 1223 So(args[1].value.(string), ShouldEqual, `"bar"`) 1224 1225 val, _ = z.vm.ToValue(3.1415) 1226 err = jsProcessArgs(z, args, []otto.Value{entryType, val}) 1227 So(err, ShouldBeNil) 1228 So(args[1].value.(string), ShouldEqual, `3.1415`) 1229 1230 // create an otto.object for a test arg 1231 val, _ = z.vm.ToValue(map[string]string{"H": "foo", "E": "bar"}) 1232 err = jsProcessArgs(z, args, []otto.Value{entryType, val}) 1233 So(err, ShouldBeNil) 1234 So(args[1].value.(string), ShouldEqual, `{"E":"bar","H":"foo"}`) 1235 }) 1236 1237 // currently ArgsArg and EntryArg are identical, but we expect this to change 1238 Convey("it should convert ArgsArg from string or object", t, func() { 1239 args := []Arg{{Name: "foo", Type: ArgsArg}} 1240 err := jsProcessArgs(z, args, []otto.Value{nilValue}) 1241 So(err.Error(), ShouldEqual, "argument 1 (foo) should be string or object") 1242 val, _ := z.vm.ToValue("bar") 1243 err = jsProcessArgs(z, args, []otto.Value{val}) 1244 So(err, ShouldBeNil) 1245 So(args[0].value.(string), ShouldEqual, "bar") 1246 1247 // create an otto.object for a test arg 1248 val, _ = z.vm.ToValue(map[string]string{"H": "foo", "E": "bar"}) 1249 err = jsProcessArgs(z, args, []otto.Value{val}) 1250 So(err, ShouldBeNil) 1251 So(args[0].value.(string), ShouldEqual, `{"E":"bar","H":"foo"}`) 1252 }) 1253 1254 Convey("it should convert MapArg a map", t, func() { 1255 args := []Arg{{Name: "foo", Type: MapArg}} 1256 err := jsProcessArgs(z, args, []otto.Value{nilValue}) 1257 So(err.Error(), ShouldEqual, "argument 1 (foo) should be object") 1258 1259 // create a js object 1260 m := make(map[string]interface{}) 1261 m["H"] = "fakehashvalue" 1262 m["I"] = 314 1263 val, _ := z.vm.ToValue(m) 1264 err = jsProcessArgs(z, args, []otto.Value{val}) 1265 So(err, ShouldBeNil) 1266 x := args[0].value.(map[string]interface{}) 1267 So(x["H"].(string), ShouldEqual, "fakehashvalue") 1268 So(x["I"].(int), ShouldEqual, 314) 1269 }) 1270 1271 Convey("it should convert ToStrArg any type to a string", t, func() { 1272 args := []Arg{{Name: "any", Type: ToStrArg}} 1273 val, _ := z.vm.ToValue("bar") 1274 err := jsProcessArgs(z, args, []otto.Value{val}) 1275 So(err, ShouldBeNil) 1276 So(args[0].value.(string), ShouldEqual, "bar") 1277 val, _ = z.vm.ToValue(123) 1278 err = jsProcessArgs(z, args, []otto.Value{val}) 1279 So(err, ShouldBeNil) 1280 So(args[0].value.(string), ShouldEqual, "123") 1281 val, _ = z.vm.ToValue(true) 1282 err = jsProcessArgs(z, args, []otto.Value{val}) 1283 So(err, ShouldBeNil) 1284 So(args[0].value.(string), ShouldEqual, "true") 1285 m := make(map[string]interface{}) 1286 m["H"] = "fakehashvalue" 1287 m["I"] = 314 1288 val, _ = z.vm.ToValue(m) 1289 err = jsProcessArgs(z, args, []otto.Value{val}) 1290 So(err, ShouldBeNil) 1291 So(args[0].value.(string), ShouldEqual, `{"H":"fakehashvalue","I":314}`) 1292 1293 }) 1294 }