github.com/holochain/holochain-proto@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/zygosome_test.go (about) 1 package holochain 2 3 import ( 4 "encoding/json" 5 "fmt" 6 zygo "github.com/glycerine/zygomys/zygo" 7 . "github.com/holochain/holochain-proto/hash" 8 peer "github.com/libp2p/go-libp2p-peer" 9 . "github.com/smartystreets/goconvey/convey" 10 "strings" 11 "testing" 12 ) 13 14 func TestNewZygoRibosome(t *testing.T) { 15 Convey("new should create a ribosome", t, func() { 16 d, _, h := PrepareTestChain("test") 17 defer CleanupTestChain(h, d) 18 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: `(+ 1 1)`}) 19 z := v.(*ZygoRibosome) 20 So(err, ShouldBeNil) 21 So(z.lastResult.(*zygo.SexpInt).Val, ShouldEqual, 2) 22 }) 23 Convey("new fail to create ribosome when code is bad", t, func() { 24 d, _, h := PrepareTestChain("test") 25 defer CleanupTestChain(h, d) 26 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: "(should make a zygo syntax error"}) 27 So(v, ShouldBeNil) 28 So(err.Error(), ShouldEqual, "Zygomys load error: Error on line 1: parser needs more input\n") 29 }) 30 31 Convey("it should have an App structure:", t, func() { 32 d, _, h := PrepareTestChain("test") 33 defer CleanupTestChain(h, d) 34 35 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: ""}) 36 So(err, ShouldBeNil) 37 z := v.(*ZygoRibosome) 38 39 _, err = z.Run("App_Name") 40 So(err, ShouldBeNil) 41 s := z.lastResult.(*zygo.SexpStr).S 42 So(s, ShouldEqual, h.Name()) 43 _, err = z.Run("App_DNA_Hash") 44 So(err, ShouldBeNil) 45 s = z.lastResult.(*zygo.SexpStr).S 46 So(s, ShouldEqual, h.dnaHash.String()) 47 _, err = z.Run("App_Agent_Hash") 48 So(err, ShouldBeNil) 49 s = z.lastResult.(*zygo.SexpStr).S 50 So(s, ShouldEqual, h.agentHash.String()) 51 _, err = z.Run("App_Agent_TopHash") 52 So(err, ShouldBeNil) 53 s = z.lastResult.(*zygo.SexpStr).S 54 So(s, ShouldEqual, h.agentHash.String()) 55 56 _, err = z.Run("App_Agent_String") 57 So(err, ShouldBeNil) 58 s = z.lastResult.(*zygo.SexpStr).S 59 So(s, ShouldEqual, h.Agent().Identity()) 60 61 _, err = z.Run("App_Key_Hash") 62 So(err, ShouldBeNil) 63 s = z.lastResult.(*zygo.SexpStr).S 64 So(s, ShouldEqual, h.nodeIDStr) 65 }) 66 67 Convey("it should have an HC structure:", t, func() { 68 d, _, h := PrepareTestChain("test") 69 defer CleanupTestChain(h, d) 70 71 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType}) 72 So(err, ShouldBeNil) 73 z := v.(*ZygoRibosome) 74 75 _, err = z.Run("HC_HashNotFound") 76 So(err, ShouldBeNil) 77 x := z.lastResult 78 So(x, ShouldEqual, zygo.SexpNull) 79 80 _, err = z.Run("HC_Version") 81 So(err, ShouldBeNil) 82 s := z.lastResult.(*zygo.SexpStr).S 83 So(s, ShouldEqual, VersionStr) 84 85 _, err = z.Run("HC_Status_Deleted") 86 So(err, ShouldBeNil) 87 i := z.lastResult.(*zygo.SexpInt).Val 88 So(i, ShouldEqual, StatusDeleted) 89 90 _, err = z.Run("HC_Status_Live") 91 So(err, ShouldBeNil) 92 i = z.lastResult.(*zygo.SexpInt).Val 93 So(i, ShouldEqual, StatusLive) 94 95 _, err = z.Run("HC_Status_Rejected") 96 So(err, ShouldBeNil) 97 i = z.lastResult.(*zygo.SexpInt).Val 98 So(i, ShouldEqual, StatusRejected) 99 100 _, err = z.Run("HC_Status_Modified") 101 So(err, ShouldBeNil) 102 i = z.lastResult.(*zygo.SexpInt).Val 103 So(i, ShouldEqual, StatusModified) 104 105 _, err = z.Run("HC_Status_Any") 106 So(err, ShouldBeNil) 107 i = z.lastResult.(*zygo.SexpInt).Val 108 So(i, ShouldEqual, StatusAny) 109 110 _, err = z.Run("HC_Migrate_Close") 111 So(err, ShouldBeNil) 112 s = z.lastResult.(*zygo.SexpStr).S 113 So(s, ShouldEqual, MigrateEntryTypeClose) 114 115 _, err = z.Run("HC_Migrate_Open") 116 So(err, ShouldBeNil) 117 s = z.lastResult.(*zygo.SexpStr).S 118 So(s, ShouldEqual, MigrateEntryTypeOpen) 119 120 }) 121 122 Convey("should have the built in functions:", t, func() { 123 d, _, h := PrepareTestChain("test") 124 defer CleanupTestChain(h, d) 125 126 zome, _ := h.GetZome("zySampleZome") 127 v, err := NewZygoRibosome(h, zome) 128 So(err, ShouldBeNil) 129 z := v.(*ZygoRibosome) 130 131 Convey("atoi", func() { 132 _, err = z.Run(`(atoi "3141")`) 133 So(err, ShouldBeNil) 134 So(z.lastResult.(*zygo.SexpInt).Val, ShouldEqual, 3141) 135 _, err = z.Run(`(atoi 1)`) 136 So(err.Error(), ShouldEqual, "Zygomys exec error: Error calling 'atoi': argument to atoi should be string") 137 }) 138 Convey("isprime", func() { 139 _, err = z.Run(`(isprime 100)`) 140 So(err, ShouldBeNil) 141 So(z.lastResult.(*zygo.SexpBool).Val, ShouldEqual, false) 142 _, err = z.Run(`(isprime 7)`) 143 So(err, ShouldBeNil) 144 So(z.lastResult.(*zygo.SexpBool).Val, ShouldEqual, true) 145 _, err = z.Run(`(isprime "fish")`) 146 So(err.Error(), ShouldEqual, "Zygomys exec error: Error calling 'isprime': argument to isprime should be int") 147 }) 148 Convey("property", func() { 149 _, err = z.Run(`(property "description")`) 150 So(err, ShouldBeNil) 151 So(z.lastResult.(*zygo.SexpStr).S, ShouldEqual, "a bogus test holochain") 152 153 ShouldLog(&infoLog, func() { 154 _, err = z.Run(`(property "` + ID_PROPERTY + `")`) 155 So(err, ShouldBeNil) 156 }, "Warning: Getting special properties via property() is deprecated as of 3. Returning nil values. Use App* instead\n") 157 158 }) 159 160 // add entries onto the chain to get hash values for testing 161 hash := commit(h, "evenNumbers", "4") 162 profileHash := commit(h, "profile", `{"firstName":"Zippy","lastName":"Pinhead"}`) 163 164 Convey("makeHash", func() { 165 _, err = z.Run(`(makeHash "evenNumbers" "4")`) 166 So(err, ShouldBeNil) 167 z := v.(*ZygoRibosome) 168 hash1, err := NewHash(z.lastResult.(*zygo.SexpStr).S) 169 So(err, ShouldBeNil) 170 So(hash1.String(), ShouldEqual, hash.String()) 171 172 _, err = z.Run(`(makeHash "profile" (hash firstName:"Zippy" lastName:"Pinhead"))`) 173 So(err, ShouldBeNil) 174 hash1, err = NewHash(z.lastResult.(*zygo.SexpStr).S) 175 So(err, ShouldBeNil) 176 So(hash1.String(), ShouldEqual, profileHash.String()) 177 }) 178 179 Convey("getBridges", func() { 180 _, err = z.Run(`(getBridges)`) 181 So(err, ShouldBeNil) 182 z := v.(*ZygoRibosome) 183 184 So(len(z.lastResult.(*zygo.SexpArray).Val), ShouldEqual, 0) 185 186 hFromHash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzfrom") 187 var token string 188 token, err = h.AddBridgeAsCallee(hFromHash, "") 189 if err != nil { 190 panic(err) 191 } 192 193 hToHash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqto") 194 err = h.AddBridgeAsCaller("jsSampleZome", hToHash, "fakeAppName", token, "fakeurl", "") 195 if err != nil { 196 panic(err) 197 } 198 199 ShouldLog(h.nucleus.alog, func() { 200 _, err := z.Run(`(testGetBridges)`) 201 So(err, ShouldBeNil) 202 }, fmt.Sprintf(`[ (hash Side:0 CalleeApp:"QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzkqto" CalleeName:"fakeAppName") (hash Side:1 Token:"%s")]`, token)) 203 204 }) 205 206 Convey("call", func() { 207 // a string calling function 208 _, err := z.Run(`(call "jsSampleZome" "addOdd" "321")`) 209 So(err, ShouldBeNil) 210 So(h.chain.Entries[len(h.chain.Hashes)-1].Content(), ShouldEqual, "321") 211 z := v.(*ZygoRibosome) 212 hashStr := z.lastResult.(*zygo.SexpStr).S 213 hash, _ := NewHash(hashStr) 214 entry, _, _ := h.chain.GetEntry(hash) 215 So(entry.Content(), ShouldEqual, "321") 216 217 // a json calling function 218 _, err = z.Run(`(call "jsSampleZome" "addProfile" (hash firstName: "Jane" lastName: "Jetson"))`) 219 So(err, ShouldBeNil) 220 So(h.chain.Entries[len(h.chain.Hashes)-1].Content(), ShouldEqual, `{"firstName":"Jane","lastName":"Jetson"}`) 221 hashJSONStr := z.lastResult.(*zygo.SexpStr).S 222 json.Unmarshal([]byte(hashJSONStr), &hashStr) 223 hash, _ = NewHash(hashStr) 224 entry, _, _ = h.chain.GetEntry(hash) 225 So(entry.Content(), ShouldEqual, `{"firstName":"Jane","lastName":"Jetson"}`) 226 227 }) 228 Convey("bridge", func() { 229 // hard to test because we need to fire up a separate app someplace else 230 _, err := z.Run(`(bridge "QmVGtdTZdTFaLsaj2RwdVG8jcjNNcp1DE914DKZ2kHmXHw" "jsSampleZome" "getProperty" "language")`) 231 So(err.Error(), ShouldEqual, "Zygomys exec error: Error calling 'bridge': no active bridge") 232 }) 233 234 Convey("send", func() { 235 ShouldLog(h.nucleus.alog, func() { 236 _, err := z.Run(`(debug (concat "result was: " (str (hget (send App_Key_Hash (hash ping: "foobar")) %result))))`) 237 So(err, ShouldBeNil) 238 }, `result was: "{\"pong\":\"foobar\"}"`) 239 }) 240 Convey("send async", func() { 241 ShouldLog(h.nucleus.alog, func() { 242 _, err := z.Run(`(send App_Key_Hash (hash ping: "foobar") (hash Callback: (hash Function: "asyncPing" ID:"123")))`) 243 So(err, ShouldBeNil) 244 err = <-h.asyncSends 245 So(err, ShouldBeNil) 246 }, `async result of message with 123 was: (hash pong:"foobar")`) 247 }) 248 Convey("migrate", func() { 249 dnaHash, err := genTestStringHash() 250 So(err, ShouldBeNil) 251 key, err := genTestStringHash() 252 So(err, ShouldBeNil) 253 data, err := genTestString() 254 So(err, ShouldBeNil) 255 256 _, err = z.Run(`(migrate HC_Migrate_Close "` + dnaHash.String() + `" "` + key.String() + `" "` + data + `")`) 257 So(err, ShouldBeNil) 258 migrationEntryHash, _ := NewHash(z.lastResult.(*zygo.SexpStr).S) 259 entry, _, _ := h.chain.GetEntry(migrationEntryHash) 260 So(entry.Content(), ShouldEqual, "{\"Type\":\"close\",\"DNAHash\":\""+dnaHash.String()+"\",\"Key\":\""+key.String()+"\",\"Data\":\""+data+"\"}") 261 }) 262 }) 263 } 264 265 func TestZygoQuery(t *testing.T) { 266 d, _, h := PrepareTestChain("test") 267 defer CleanupTestChain(h, d) 268 269 zome, _ := h.GetZome("zySampleZome") 270 v, err := NewZygoRibosome(h, zome) 271 if err != nil { 272 panic(err) 273 } 274 z := v.(*ZygoRibosome) 275 276 Convey("query", t, func() { 277 // add entries onto the chain to get hash values for testing 278 commit(h, "evenNumbers", "2") 279 commit(h, "secret", "foo") 280 commit(h, "evenNumbers", "4") 281 commit(h, "secret", "bar") 282 commit(h, "profile", `{"firstName":"Zippy","lastName":"Pinhead"}`) 283 284 ShouldLog(h.nucleus.alog, func() { 285 _, err := z.Run(`(debug (str (query (hash Constrain: (hash EntryTypes: ["evenNumbers"])))))`) 286 So(err, ShouldBeNil) 287 }, `["2" "4"]`) 288 ShouldLog(h.nucleus.alog, func() { 289 _, err := z.Run(`(debug (str (query (hash Return: (hash Hashes: true) Constrain: (hash EntryTypes:["evenNumbers"])))))`) 290 So(err, ShouldBeNil) 291 }, `["QmQzp4h9pvLVJHUx6rFxxC4ViqgnznYqXvoa9HsJgACMmi" "QmS4bKx7zZt6qoX2om5M5ik3X2k4Fco2nFx82CDJ3iVKj2"]`) 292 ShouldLog(h.nucleus.alog, func() { 293 _, err := z.Run(`(debug (str (query ( hash Return: (hash Hashes:true Entries:true) Constrain: (hash EntryTypes: ["evenNumbers"])))))`) 294 So(err, ShouldBeNil) 295 }, `[ (hash Hash:"QmQzp4h9pvLVJHUx6rFxxC4ViqgnznYqXvoa9HsJgACMmi" Entry:"2") (hash Hash:"QmS4bKx7zZt6qoX2om5M5ik3X2k4Fco2nFx82CDJ3iVKj2" Entry:"4")]`) 296 ShouldLog(h.nucleus.alog, func() { 297 _, err := z.Run(`(debug (query (hash Return: (hash Headers:true Entries:true) Constrain: (hash EntryTypes: ["evenNumbers"]))))`) 298 So(err, ShouldBeNil) 299 }, `"Type":"evenNumbers","EntryLink":"QmQzp4h9pvLVJHUx6rFxxC4ViqgnznYqXvoa9HsJgACMmi","HeaderLink":"Qm`) 300 ShouldLog(h.nucleus.alog, func() { 301 _, err := z.Run(`(debug (query (hash Constrain: (hash EntryTypes: ["secret"]))))`) 302 So(err, ShouldBeNil) 303 }, `["foo","bar"]`) 304 ShouldLog(h.nucleus.alog, func() { 305 _, err := z.Run(`(debug (str (query (hash Constrain: (hash EntryTypes: ["profile"])))))`) 306 So(err, ShouldBeNil) 307 }, `["{\"firstName\":\"Zippy\",\"lastName\":\"Pinhead\"}"]`) 308 ShouldLog(h.nucleus.alog, func() { 309 _, err := z.Run(`(debug (str (query (hash Constrain: (hash EntryTypes: ["%agent"])))))`) 310 So(err, ShouldBeNil) 311 }, `["{\"Identity\":\"Herbert \\u003ch@bert.com\\u003e\",\"Revocation\":\"\",\"PublicKey\":\"4XTTM8sJEQD5zMLT1gtu2ogshwg5AdUPNhJRbLvs77gsVtQQi\"}"]`) 312 }) 313 } 314 func TestZygoGenesis(t *testing.T) { 315 d, _, h := PrepareTestChain("test") 316 defer CleanupTestChain(h, d) 317 Convey("it should fail if the genesis function returns false", t, func() { 318 z, _ := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: `(defn genesis [] false)`}) 319 err := z.ChainGenesis() 320 So(err.Error(), ShouldEqual, "genesis failed") 321 }) 322 Convey("it should work if the genesis function returns true", t, func() { 323 z, _ := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: `(defn genesis [] true)`}) 324 err := z.ChainGenesis() 325 So(err, ShouldBeNil) 326 }) 327 } 328 329 func TestZygoBridgeGenesis(t *testing.T) { 330 d, _, h := PrepareTestChain("test") 331 defer CleanupTestChain(h, d) 332 333 fakeToApp, _ := NewHash("QmVGtdTZdTFaLsaj2RwdVG8jcjNNcp1DE914DKZ2kHmXHx") 334 Convey("it should fail if the bridge genesis function returns false", t, func() { 335 ShouldLog(&h.Config.Loggers.App, func() { 336 z, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: `(defn bridgeGenesis [side app data] (begin (debug (concat app " " data)) false))`}) 337 So(err, ShouldBeNil) 338 err = z.BridgeGenesis(BridgeCaller, h.dnaHash, "test data") 339 So(err.Error(), ShouldEqual, "bridgeGenesis failed") 340 }, h.dnaHash.String()+" test data") 341 }) 342 Convey("it should work if the bridge genesis function returns true", t, func() { 343 ShouldLog(&h.Config.Loggers.App, func() { 344 z, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: `(defn bridgeGenesis [side app data] (begin (debug (concat app " " data)) true))`}) 345 So(err, ShouldBeNil) 346 err = z.BridgeGenesis(BridgeCallee, fakeToApp, "test data") 347 So(err, ShouldBeNil) 348 }, fakeToApp.String()+" test data") 349 }) 350 } 351 352 func TestZyReceive(t *testing.T) { 353 d, _, h := PrepareTestChain("test") 354 defer CleanupTestChain(h, d) 355 Convey("it should call a receive function that returns a hash", t, func() { 356 z, _ := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: `(defn receive [from msg] (hash %foo (hget msg %bar)))`}) 357 response, err := z.Receive("fakehash", `{"bar":"baz"}`) 358 So(err, ShouldBeNil) 359 So(response, ShouldEqual, `{"foo":"baz"}`) 360 }) 361 362 Convey("it should call a receive function that returns a string", t, func() { 363 z, _ := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: `(defn receive [from msg] (concat "fish:" (hget msg %bar)))`}) 364 response, err := z.Receive("fakehash", `{"bar":"baz"}`) 365 So(err, ShouldBeNil) 366 So(response, ShouldEqual, `"fish:baz"`) 367 }) 368 369 Convey("it should call a receive function that returns an int", t, func() { 370 z, _ := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: `(defn receive [from msg] (len (hget msg %bar)))`}) 371 response, err := z.Receive("fakehash", `{"bar":"baz"}`) 372 So(err, ShouldBeNil) 373 So(response, ShouldEqual, `3`) 374 }) 375 } 376 377 func TestZybuildValidate(t *testing.T) { 378 d, _, h := PrepareTestChain("test") 379 defer CleanupTestChain(h, d) 380 381 e := GobEntry{C: "3"} 382 a := NewCommitAction("oddNumbers", &e) 383 var header Header 384 a.header = &header 385 386 def := EntryDef{Name: "oddNumbers", DataFormat: DataFormatString} 387 388 Convey("it should build commit", t, func() { 389 code, err := buildZyValidateAction(a, &def, nil, []string{"fake_src_hash"}) 390 So(err, ShouldBeNil) 391 So(code, ShouldEqual, `(validateCommit "oddNumbers" "3" (hash EntryLink:"" Type:"" Time:"0001-01-01T00:00:00Z") (hash) (unjson (raw "[\"fake_src_hash\"]")))`) 392 }) 393 Convey("it should build put", t, func() { 394 a := NewPutAction("evenNumbers", &e, &header) 395 pkg, _ := MakePackage(h, PackagingReq{PkgReqChain: int64(PkgReqChainOptFull)}) 396 vpkg, _ := MakeValidationPackage(h, &pkg) 397 _, err := buildZyValidateAction(a, &def, vpkg, []string{"fake_src_hash"}) 398 So(err, ShouldBeNil) 399 //So(code, ShouldEqual, `validatePut("evenNumbers","2",{"EntryLink":"","Type":"","Time":"0001-01-01T00:00:00Z"},pgk,["fake_src_hash"])`) 400 }) 401 } 402 403 func TestZyValidateCommit(t *testing.T) { 404 a, _ := NewAgent(LibP2P, "Joe", MakeTestSeed("")) 405 h := NewHolochain(a, "some/path", "yaml", Zome{RibosomeType: ZygoRibosomeType}) 406 h.Config.Loggers.App.New(nil) 407 hdr := mkTestHeader("evenNumbers") 408 409 Convey("it should be passing in the correct values", t, func() { 410 v, err := NewZygoRibosome(&h, &Zome{RibosomeType: ZygoRibosomeType, Code: `(defn validateCommit [name entry header pkg sources] (debug name) (debug entry) (debug header) (debug sources) (debug pkg) true)`}) 411 So(err, ShouldBeNil) 412 d := EntryDef{Name: "evenNumbers", DataFormat: DataFormatString} 413 ShouldLog(&h.Config.Loggers.App, func() { 414 a := NewCommitAction("oddNumbers", &GobEntry{C: "foo"}) 415 a.header = &hdr 416 err = v.ValidateAction(a, &d, nil, []string{"fakehashvalue"}) 417 So(err, ShouldBeNil) 418 }, `evenNumbers 419 foo 420 {"EntryLink":"QmNiCwBNA8MWDADTFVq1BonUEJbS2SvjAoNkZZrhEwcuU2","Type":"evenNumbers","Time":"1970-01-01T00:00:01Z"} 421 ["fakehashvalue"] 422 {"Atype":"hash"} 423 `) 424 }) 425 Convey("should run an entry value against the defined validator for string data", t, func() { 426 v, err := NewZygoRibosome(&h, &Zome{RibosomeType: ZygoRibosomeType, Code: `(defn validateCommit [name entry header pkg sources] (cond (== entry "fish") true false))`}) 427 So(err, ShouldBeNil) 428 d := EntryDef{Name: "oddNumbers", DataFormat: DataFormatString} 429 430 a := NewCommitAction("oddNumbers", &GobEntry{C: "cow"}) 431 a.header = &hdr 432 err = v.ValidateAction(a, &d, nil, nil) 433 So(IsValidationFailedErr(err), ShouldBeTrue) 434 435 a = NewCommitAction("oddNumbers", &GobEntry{C: "fish"}) 436 a.header = &hdr 437 err = v.ValidateAction(a, &d, nil, nil) 438 So(err, ShouldBeNil) 439 }) 440 Convey("should run an entry value against the defined validator for zygo data", t, func() { 441 v, err := NewZygoRibosome(&h, &Zome{RibosomeType: ZygoRibosomeType, Code: `(defn validateCommit [name entry header pkg sources] (cond (== entry "fish") true false))`}) 442 d := EntryDef{Name: "evenNumbers", DataFormat: DataFormatRawZygo} 443 444 a := NewCommitAction("oddNumbers", &GobEntry{C: "\"cow\""}) 445 a.header = &hdr 446 err = v.ValidateAction(a, &d, nil, nil) 447 So(IsValidationFailedErr(err), ShouldBeTrue) 448 449 a = NewCommitAction("oddNumbers", &GobEntry{C: "\"fish\""}) 450 a.header = &hdr 451 err = v.ValidateAction(a, &d, nil, nil) 452 So(err, ShouldBeNil) 453 }) 454 Convey("should run an entry value against the defined validator for json data", t, func() { 455 v, err := NewZygoRibosome(&h, &Zome{RibosomeType: ZygoRibosomeType, Code: `(defn validateCommit [name entry header pkg sources] (cond (== (hget entry data:) "fish") true false))`}) 456 d := EntryDef{Name: "evenNumbers", DataFormat: DataFormatJSON} 457 458 a := NewCommitAction("evenNumbers", &GobEntry{C: `{"data":"cow"}`}) 459 a.header = &hdr 460 err = v.ValidateAction(a, &d, nil, nil) 461 So(IsValidationFailedErr(err), ShouldBeTrue) 462 463 a = NewCommitAction("evenNumbers", &GobEntry{C: `{"data":"fish"}`}) 464 a.header = &hdr 465 err = v.ValidateAction(a, &d, nil, nil) 466 So(err, ShouldBeNil) 467 }) 468 } 469 470 func TestPrepareZyValidateArgs(t *testing.T) { 471 d := EntryDef{Name: "oddNumbers", DataFormat: DataFormatString} 472 473 Convey("it should prepare args for commit", t, func() { 474 e := GobEntry{C: "3"} 475 a := NewCommitAction("oddNumbers", &e) 476 var header Header 477 a.header = &header 478 args, err := prepareZyValidateArgs(a, &d) 479 So(err, ShouldBeNil) 480 So(args, ShouldEqual, `"3" (hash EntryLink:"" Type:"" Time:"0001-01-01T00:00:00Z")`) 481 }) 482 Convey("it should prepare args for put", t, func() { 483 e := GobEntry{C: "3"} 484 var header Header 485 a := NewPutAction("oddNumbers", &e, &header) 486 487 args, err := prepareZyValidateArgs(a, &d) 488 So(err, ShouldBeNil) 489 So(args, ShouldEqual, `"3" (hash EntryLink:"" Type:"" Time:"0001-01-01T00:00:00Z")`) 490 }) 491 Convey("it should prepare args for mod", t, func() { 492 e := GobEntry{C: "7"} 493 var header = Header{Type: "foo"} 494 hash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2") // fake hash for previous 495 a := NewModAction("oddNumbers", &e, hash) 496 a.header = &header 497 args, err := prepareZyValidateArgs(a, &d) 498 So(err, ShouldBeNil) 499 So(args, ShouldEqual, `"7" (hash EntryLink:"" Type:"foo" Time:"0001-01-01T00:00:00Z") "QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2"`) 500 }) 501 Convey("it should prepare args for del", t, func() { 502 hash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2") 503 entry := DelEntry{Hash: hash, Message: "expired"} 504 a := NewDelAction(entry) 505 args, err := prepareZyValidateArgs(a, &d) 506 So(err, ShouldBeNil) 507 So(args, ShouldEqual, `"QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2"`) 508 }) 509 Convey("it should prepare args for link", t, func() { 510 hash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2") 511 a := NewLinkAction("oddNumbers", []Link{{Base: "QmdRXz53TVT9qBYfbXctHyy2GpTNa6YrpAy6ZcDGG8Xhc5", Link: "QmdRXz53TVT9qBYfbXctHyy2GpTNa6YrpAy6ZcDGG8Xhc5", Tag: "fish"}}) 512 a.validationBase = hash 513 args, err := prepareZyValidateArgs(a, &d) 514 So(err, ShouldBeNil) 515 So(args, ShouldEqual, `"QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2" (unjson (raw "[{\"LinkAction\":\"\",\"Base\":\"QmdRXz53TVT9qBYfbXctHyy2GpTNa6YrpAy6ZcDGG8Xhc5\",\"Link\":\"QmdRXz53TVT9qBYfbXctHyy2GpTNa6YrpAy6ZcDGG8Xhc5\",\"Tag\":\"fish\"}]"))`) 516 }) 517 } 518 519 func TestZySanitize(t *testing.T) { 520 Convey("should strip quotes", t, func() { 521 So(sanitizeZyString(`"`), ShouldEqual, `\"`) 522 So(sanitizeZyString("\"x\ny"), ShouldEqual, "\\\"x\ny") 523 }) 524 } 525 526 func TestZygoExposeCall(t *testing.T) { 527 d, _, h := PrepareTestChain("test") 528 defer CleanupTestChain(h, d) 529 530 v, zome, err := h.MakeRibosome("zySampleZome") 531 if err != nil { 532 panic(err) 533 } 534 z := v.(*ZygoRibosome) 535 536 Convey("should allow calling exposed STRING based functions", t, func() { 537 cater, _ := zome.GetFunctionDef("testStrFn1") 538 result, err := z.Call(cater, "fish \"zippy\"") 539 So(err, ShouldBeNil) 540 So(result.(string), ShouldEqual, "result: fish \"zippy\"") 541 542 adder, _ := zome.GetFunctionDef("testStrFn2") 543 result, err = z.Call(adder, "10") 544 So(err, ShouldBeNil) 545 So(result.(string), ShouldEqual, "12") 546 }) 547 Convey("should allow calling exposed JSON based functions", t, func() { 548 times2, _ := zome.GetFunctionDef("testJsonFn1") 549 result, err := z.Call(times2, `{"input": 2}`) 550 So(err, ShouldBeNil) 551 So(string(result.(string)), ShouldEqual, `{"input":2, "output":4}`) 552 }) 553 Convey("should allow a function declared with JSON parameter to be called with no parameter", t, func() { 554 emptyParametersJSON, _ := zome.GetFunctionDef("testJsonFn2") 555 result, err := z.Call(emptyParametersJSON, "") 556 So(err, ShouldBeNil) 557 So(string(result.(string)), ShouldEqual, `[{"a":"b"}]`) 558 }) 559 } 560 561 func TestZygoDHT(t *testing.T) { 562 d, _, h := PrepareTestChain("test") 563 defer CleanupTestChain(h, d) 564 565 hash, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2") 566 Convey("get should return HC_HashNotFound if it doesn't exist", t, func() { 567 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: fmt.Sprintf(`(== (get "%s") HC_HashNotFound)`, hash.String())}) 568 So(err, ShouldBeNil) 569 z := v.(*ZygoRibosome) 570 r := z.lastResult.(*zygo.SexpBool) 571 So(err, ShouldBeNil) 572 So(r.Val, ShouldEqual, true) 573 }) 574 // add an entry onto the chain 575 hash = commit(h, "evenNumbers", "2") 576 577 Convey("get should return entry", t, func() { 578 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: fmt.Sprintf(`(get "%s")`, hash.String())}) 579 So(err, ShouldBeNil) 580 z := v.(*ZygoRibosome) 581 r, err := z.lastResult.(*zygo.SexpHash).HashGet(z.env, z.env.MakeSymbol("result")) 582 So(err, ShouldBeNil) 583 So(r.(*zygo.SexpStr).S, ShouldEqual, `"2"`) 584 }) 585 586 Convey("get should return entry of sys types", t, func() { 587 ShouldLog(h.nucleus.alog, func() { 588 _, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: fmt.Sprintf(`(debug (get "%s"))`, h.agentHash.String())}) 589 So(err, ShouldBeNil) 590 }, `{"result":"\"{\\\"Identity\\\":\\\"Herbert \\\\u003ch@bert.com\\\\u003e\\\",\\\"Revocation\\\":\\\"\\\",\\\"PublicKey\\\":\\\"4XTTM8sJEQD5zMLT1gtu2ogshwg5AdUPNhJRbLvs77gsVtQQi\\\"}\""}`) 591 }) 592 593 Convey("get should return entry type", t, func() { 594 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: fmt.Sprintf(`(get "%s" (hash GetMask:HC_GetMask_EntryType))`, hash.String())}) 595 So(err, ShouldBeNil) 596 z := v.(*ZygoRibosome) 597 r, err := z.lastResult.(*zygo.SexpHash).HashGet(z.env, z.env.MakeSymbol("result")) 598 So(err, ShouldBeNil) 599 So(r.(*zygo.SexpStr).S, ShouldEqual, "evenNumbers") 600 }) 601 602 Convey("get should return sources", t, func() { 603 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: fmt.Sprintf(`(get "%s" (hash GetMask:HC_GetMask_Sources))`, hash.String())}) 604 So(err, ShouldBeNil) 605 z := v.(*ZygoRibosome) 606 r, err := z.lastResult.(*zygo.SexpHash).HashGet(z.env, z.env.MakeSymbol("result")) 607 So(err, ShouldBeNil) 608 So(r.(*zygo.SexpArray).Val[0].(*zygo.SexpStr).S, ShouldEqual, h.nodeIDStr) 609 }) 610 611 Convey("get should return collection", t, func() { 612 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: fmt.Sprintf(`(get "%s" (hash GetMask:HC_GetMask_All))`, hash.String())}) 613 So(err, ShouldBeNil) 614 z := v.(*ZygoRibosome) 615 r, err := z.lastResult.(*zygo.SexpHash).HashGet(z.env, z.env.MakeSymbol("result")) 616 So(err, ShouldBeNil) 617 resp := r.(*zygo.SexpHash) 618 e, _ := resp.HashGet(z.env, z.env.MakeSymbol("EntryType")) 619 So(e.(*zygo.SexpStr).S, ShouldEqual, "evenNumbers") 620 e, _ = resp.HashGet(z.env, z.env.MakeSymbol("Entry")) 621 So(e.(*zygo.SexpStr).S, ShouldEqual, `"2"`) 622 e, _ = resp.HashGet(z.env, z.env.MakeSymbol("Sources")) 623 So(e.(*zygo.SexpArray).Val[0].(*zygo.SexpStr).S, ShouldEqual, h.nodeIDStr) 624 }) 625 profileHash := commit(h, "profile", `{"firstName":"Zippy","lastName":"Pinhead"}`) 626 627 commit(h, "rating", fmt.Sprintf(`{"Links":[{"Base":"%s","Link":"%s","Tag":"4stars"}]}`, hash.String(), profileHash.String())) 628 629 Convey("getLinks function should return the Links", t, func() { 630 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: fmt.Sprintf(`(getLinks "%s" "4stars")`, hash.String())}) 631 So(err, ShouldBeNil) 632 z := v.(*ZygoRibosome) 633 sh := z.lastResult.(*zygo.SexpHash) 634 635 r, err := sh.HashGet(z.env, z.env.MakeSymbol("result")) 636 So(err, ShouldBeNil) 637 So(r.(*zygo.SexpStr).S, ShouldEqual, fmt.Sprintf(`[{"H":"QmYeinX5vhuA91D3v24YbgyLofw9QAxY6PoATrBHnRwbtt","E":"","EntryType":"","T":"","Source":"%s"}]`, h.nodeIDStr)) 638 }) 639 Convey("getLinks function with load option should return the Links and entries", t, func() { 640 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: fmt.Sprintf(`(getLinks "%s" "4stars" (hash Load:true))`, hash.String())}) 641 So(err, ShouldBeNil) 642 z := v.(*ZygoRibosome) 643 sh := z.lastResult.(*zygo.SexpHash) 644 645 r, err := sh.HashGet(z.env, z.env.MakeSymbol("result")) 646 So(err, ShouldBeNil) 647 So(r.(*zygo.SexpStr).S, ShouldEqual, fmt.Sprintf(`[{"H":"QmYeinX5vhuA91D3v24YbgyLofw9QAxY6PoATrBHnRwbtt","E":"{\"firstName\":\"Zippy\",\"lastName\":\"Pinhead\"}","EntryType":"profile","T":"","Source":"%s"}]`, h.nodeIDStr)) 648 }) 649 650 Convey("commit with del link should delete link", t, func() { 651 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: fmt.Sprintf(`(commit "rating" (hash Links:[(hash LinkAction:HC_LinkAction_Del Base:"%s" Link:"%s" Tag:"4stars")]))`, hash.String(), profileHash.String())}) 652 So(err, ShouldBeNil) 653 z := v.(*ZygoRibosome) 654 655 _, err = NewHash(z.lastResult.(*zygo.SexpStr).S) 656 So(err, ShouldBeNil) 657 658 links, _ := h.dht.GetLinks(hash, "4stars", StatusLive) 659 So(fmt.Sprintf("%v", links), ShouldEqual, "[]") 660 links, _ = h.dht.GetLinks(hash, "4stars", StatusDeleted) 661 So(fmt.Sprintf("%v", links), ShouldEqual, fmt.Sprintf("[{QmYeinX5vhuA91D3v24YbgyLofw9QAxY6PoATrBHnRwbtt %s}]", h.nodeIDStr)) 662 }) 663 664 Convey("getLinks function with StatusMask option should return deleted Links", t, func() { 665 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: fmt.Sprintf(`(getLinks "%s" "4stars" (hash StatusMask:HC_Status_Deleted))`, hash.String())}) 666 So(err, ShouldBeNil) 667 z := v.(*ZygoRibosome) 668 669 sh := z.lastResult.(*zygo.SexpHash) 670 r, err := sh.HashGet(z.env, z.env.MakeSymbol("result")) 671 So(err, ShouldBeNil) 672 So(r.(*zygo.SexpStr).S, ShouldEqual, fmt.Sprintf(`[{"H":"QmYeinX5vhuA91D3v24YbgyLofw9QAxY6PoATrBHnRwbtt","E":"","EntryType":"","T":"","Source":"%s"}]`, h.nodeIDStr)) 673 }) 674 675 Convey("update function should commit a new entry and on DHT mark item modified", t, func() { 676 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: fmt.Sprintf(`(update "profile" (hash firstName:"Zippy" lastName:"ThePinhead") "%s")`, profileHash.String())}) 677 So(err, ShouldBeNil) 678 z := v.(*ZygoRibosome) 679 profileHashStr2 := z.lastResult.(*zygo.SexpStr).S 680 681 header := h.chain.Top() 682 So(header.EntryLink.String(), ShouldEqual, profileHashStr2) 683 So(header.Change.String(), ShouldEqual, profileHash.String()) 684 685 // the entry should be marked as Modifed 686 data, _, _, _, err := h.dht.Get(profileHash, StatusDefault, GetMaskDefault) 687 So(err, ShouldEqual, ErrHashModified) 688 So(string(data), ShouldEqual, profileHashStr2) 689 690 // but a regular get, should resolve through 691 v, err = NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: fmt.Sprintf(`(get "%s")`, profileHash.String())}) 692 So(err, ShouldBeNil) 693 z = v.(*ZygoRibosome) 694 r, err := z.lastResult.(*zygo.SexpHash).HashGet(z.env, z.env.MakeSymbol("result")) 695 So(err, ShouldBeNil) 696 So(r.(*zygo.SexpStr).S, ShouldEqual, `"{\"firstName\":\"Zippy\",\"lastName\":\"ThePinhead\"}"`) 697 }) 698 699 Convey("remove function should mark item deleted", t, func() { 700 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: fmt.Sprintf(`(remove "%s" "expired")`, hash.String())}) 701 So(err, ShouldBeNil) 702 703 z := v.(*ZygoRibosome) 704 _, err = NewHash(z.lastResult.(*zygo.SexpStr).S) 705 So(err, ShouldBeNil) 706 707 v, err = NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: fmt.Sprintf(`(get "%s")`, hash.String())}) 708 So(err, ShouldBeNil) 709 z = v.(*ZygoRibosome) 710 711 r, err := z.lastResult.(*zygo.SexpHash).HashGet(z.env, z.env.MakeSymbol("error")) 712 So(err, ShouldBeNil) 713 So(r.(*zygo.SexpStr).S, ShouldEqual, "hash deleted") 714 715 v, err = NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: fmt.Sprintf(`(get "%s" (hash StatusMask:HC_Status_Deleted))`, hash.String())}) 716 So(err, ShouldBeNil) 717 z = v.(*ZygoRibosome) 718 719 r, err = z.lastResult.(*zygo.SexpHash).HashGet(z.env, z.env.MakeSymbol("result")) 720 So(err, ShouldBeNil) 721 So(r.(*zygo.SexpStr).S, ShouldEqual, `"2"`) 722 }) 723 724 Convey("updateAgent function without options should fail", t, func() { 725 _, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, 726 Code: fmt.Sprintf(`(updateAgent (hash))`)}) 727 So(err.Error(), ShouldEqual, "Zygomys exec error: Error calling 'updateAgent': expecting identity and/or revocation option") 728 }) 729 730 Convey("updateAgent function should commit a new agent entry", t, func() { 731 oldPubKey, _ := h.agent.EncodePubKey() 732 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, 733 Code: fmt.Sprintf(`(updateAgent (hash Identity:"new identity"))`)}) 734 So(err, ShouldBeNil) 735 z := v.(*ZygoRibosome) 736 newAgentHash := z.lastResult.(*zygo.SexpStr).S 737 So(h.agentTopHash.String(), ShouldEqual, newAgentHash) 738 header := h.chain.Top() 739 So(header.Type, ShouldEqual, AgentEntryType) 740 So(newAgentHash, ShouldEqual, header.EntryLink.String()) 741 So(h.agent.Identity(), ShouldEqual, "new identity") 742 newPubKey, _ := h.agent.EncodePubKey() 743 So(fmt.Sprintf("%v", newPubKey), ShouldEqual, fmt.Sprintf("%v", oldPubKey)) 744 entry, _, _ := h.chain.GetEntry(header.EntryLink) 745 a, _ := AgentEntryFromJSON(entry.Content().(string)) 746 So(a.Identity, ShouldEqual, "new identity") 747 So(fmt.Sprintf("%v", a.PublicKey), ShouldEqual, fmt.Sprintf("%v", oldPubKey)) 748 }) 749 750 Convey("updateAgent function with revoke option should commit a new agent entry and mark key as modified on DHT", t, func() { 751 oldPubKey, _ := h.agent.EncodePubKey() 752 oldPeer := h.nodeID 753 oldKey, _ := NewHash(h.nodeIDStr) 754 oldAgentHash := h.agentHash 755 756 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, 757 Code: fmt.Sprintf(`(updateAgent (hash Revocation:"some revocation data"))`)}) 758 So(err, ShouldBeNil) 759 z := v.(*ZygoRibosome) 760 newAgentHash := z.lastResult.(*zygo.SexpStr).S 761 762 So(newAgentHash, ShouldEqual, h.agentTopHash.String()) 763 So(oldAgentHash.String(), ShouldNotEqual, h.agentTopHash.String()) 764 765 header := h.chain.Top() 766 So(header.Type, ShouldEqual, AgentEntryType) 767 So(newAgentHash, ShouldEqual, header.EntryLink.String()) 768 newPubKey, _ := h.agent.EncodePubKey() 769 So(fmt.Sprintf("%v", newPubKey), ShouldNotEqual, fmt.Sprintf("%v", oldPubKey)) 770 entry, _, _ := h.chain.GetEntry(header.EntryLink) 771 revocation := &SelfRevocation{} 772 a, _ := AgentEntryFromJSON(entry.Content().(string)) 773 revocation.Unmarshal(a.Revocation) 774 775 w, _ := NewSelfRevocationWarrant(revocation) 776 payload, _ := w.Property("payload") 777 778 So(string(payload.([]byte)), ShouldEqual, "some revocation data") 779 So(fmt.Sprintf("%v", a.PublicKey), ShouldEqual, fmt.Sprintf("%v", newPubKey)) 780 781 // the new Key should be available on the DHT 782 newKey, _ := NewHash(h.nodeIDStr) 783 data, _, _, _, err := h.dht.Get(newKey, StatusDefault, GetMaskDefault) 784 So(err, ShouldBeNil) 785 newpk, _ := h.agent.EncodePubKey() 786 So(string(data), ShouldEqual, newpk) 787 788 // the old key should be marked as Modifed and we should get the new hash as the data 789 data, _, _, _, err = h.dht.Get(oldKey, StatusDefault, GetMaskDefault) 790 So(err, ShouldEqual, ErrHashModified) 791 So(string(data), ShouldEqual, h.nodeIDStr) 792 793 // the new key should be a peerID in the node 794 peers := h.node.host.Peerstore().Peers() 795 var found bool 796 797 for _, p := range peers { 798 pStr := peer.IDB58Encode(p) 799 if pStr == h.nodeIDStr { 800 801 found = true 802 break 803 } 804 } 805 So(found, ShouldBeTrue) 806 807 // the old peerID should now be in the blockedlist 808 peerList, err := h.dht.getList(BlockedList) 809 So(err, ShouldBeNil) 810 So(len(peerList.Records), ShouldEqual, 1) 811 So(peerList.Records[0].ID, ShouldEqual, oldPeer) 812 So(h.node.IsBlocked(oldPeer), ShouldBeTrue) 813 }) 814 815 Convey("updateAgent function should update library values", t, func() { 816 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, 817 Code: fmt.Sprintf(`(let [x (updateAgent (hash Identity:"new id" evocation:"some revocation data"))] (concat App_Key_Hash "." App_Agent_TopHash "." App_Agent_String))`)}) 818 So(err, ShouldBeNil) 819 z := v.(*ZygoRibosome) 820 libVals := z.lastResult.(*zygo.SexpStr).S 821 s := strings.Split(libVals, ".") 822 823 So(s[0], ShouldEqual, h.nodeIDStr) 824 So(s[1], ShouldEqual, h.agentTopHash.String()) 825 So(s[2], ShouldEqual, "new id") 826 827 }) 828 } 829 830 func TestZyProcessArgs(t *testing.T) { 831 d, _, h := PrepareTestChain("test") 832 defer CleanupTestDir(d) 833 834 v, _ := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: ""}) 835 z := v.(*ZygoRibosome) 836 837 Convey("it should check for wrong number of args", t, func() { 838 zyargs := []zygo.Sexp{zygo.SexpNull, zygo.SexpNull} 839 args := []Arg{{}} 840 err := zyProcessArgs(z, args, zyargs) 841 So(err, ShouldEqual, ErrWrongNargs) 842 843 // test with args that are optional: two that are required and one not 844 args = []Arg{{}, {}, {Optional: true}} 845 zyargs = []zygo.Sexp{zygo.SexpNull} 846 err = zyProcessArgs(z, args, zyargs) 847 So(err, ShouldEqual, ErrWrongNargs) 848 849 zyargs = []zygo.Sexp{zygo.SexpNull, zygo.SexpNull, zygo.SexpNull, zygo.SexpNull} 850 err = zyProcessArgs(z, args, zyargs) 851 So(err, ShouldEqual, ErrWrongNargs) 852 }) 853 Convey("it should convert HashArg to Hash", t, func() { 854 hashstr := "QmY8Mzg9F69e5P9AoQPYat6x5HEhc1TVGs11tmfNSzkqh2" 855 args := []Arg{{Name: "foo", Type: HashArg}} 856 err := zyProcessArgs(z, args, []zygo.Sexp{zygo.SexpNull}) 857 So(err.Error(), ShouldEqual, "argument 1 (foo) should be string") 858 var val zygo.Sexp = &zygo.SexpStr{S: hashstr} 859 err = zyProcessArgs(z, args, []zygo.Sexp{val}) 860 So(err, ShouldBeNil) 861 So(args[0].value.(Hash).String(), ShouldEqual, hashstr) 862 }) 863 Convey("it should treat StringArg as string", t, func() { 864 args := []Arg{{Name: "foo", Type: StringArg}} 865 err := zyProcessArgs(z, args, []zygo.Sexp{zygo.SexpNull}) 866 So(err.Error(), ShouldEqual, "argument 1 (foo) should be string") 867 var val zygo.Sexp = &zygo.SexpStr{S: "bar"} 868 err = zyProcessArgs(z, args, []zygo.Sexp{val}) 869 So(err, ShouldBeNil) 870 So(args[0].value.(string), ShouldEqual, "bar") 871 }) 872 Convey("it should convert IntArg to int64", t, func() { 873 args := []Arg{{Name: "foo", Type: IntArg}} 874 err := zyProcessArgs(z, args, []zygo.Sexp{zygo.SexpNull}) 875 So(err.Error(), ShouldEqual, "argument 1 (foo) should be int") 876 var val zygo.Sexp = &zygo.SexpInt{Val: 314} 877 err = zyProcessArgs(z, args, []zygo.Sexp{val}) 878 So(err, ShouldBeNil) 879 So(args[0].value.(int64), ShouldEqual, 314) 880 }) 881 Convey("it should convert BoolArg to bool", t, func() { 882 args := []Arg{{Name: "foo", Type: BoolArg}} 883 err := zyProcessArgs(z, args, []zygo.Sexp{zygo.SexpNull}) 884 So(err.Error(), ShouldEqual, "argument 1 (foo) should be boolean") 885 var val zygo.Sexp = &zygo.SexpBool{Val: true} 886 err = zyProcessArgs(z, args, []zygo.Sexp{val}) 887 So(err, ShouldBeNil) 888 So(args[0].value.(bool), ShouldEqual, true) 889 }) 890 891 // create a zygo hash for a test args 892 hval, _ := zygo.MakeHash(nil, "hash", z.env) 893 hval.HashSet(z.env.MakeSymbol("fname"), &zygo.SexpStr{S: "Jane"}) 894 hval.HashSet(z.env.MakeSymbol("lname"), &zygo.SexpStr{S: "Smith"}) 895 Convey("EntryArg should only accept strings for string type entries", t, func() { 896 args := []Arg{{Name: "entryType", Type: StringArg}, {Name: "foo", Type: EntryArg}} 897 var entryType zygo.Sexp = &zygo.SexpStr{S: "review"} 898 899 err := zyProcessArgs(z, args, []zygo.Sexp{entryType, zygo.SexpNull}) 900 So(err, ShouldBeError) 901 So(err.Error(), ShouldEqual, "argument 2 (foo) should be string") 902 903 err = zyProcessArgs(z, args, []zygo.Sexp{entryType, hval}) 904 So(err, ShouldBeError) 905 So(err.Error(), ShouldEqual, "argument 2 (foo) should be string") 906 907 err = zyProcessArgs(z, args, []zygo.Sexp{entryType, &zygo.SexpInt{Val: 3141}}) 908 So(err, ShouldBeError) 909 So(err.Error(), ShouldEqual, "argument 2 (foo) should be string") 910 911 val := &zygo.SexpStr{S: "bar"} 912 err = zyProcessArgs(z, args, []zygo.Sexp{entryType, val}) 913 So(err, ShouldBeNil) 914 So(args[1].value.(string), ShouldEqual, "bar") 915 }) 916 917 Convey("EntryArg should only accept hashes for links type entries", t, func() { 918 args := []Arg{{Name: "entryType", Type: StringArg}, {Name: "foo", Type: EntryArg}} 919 var entryType zygo.Sexp = &zygo.SexpStr{S: "rating"} 920 921 err := zyProcessArgs(z, args, []zygo.Sexp{entryType, zygo.SexpNull}) 922 So(err, ShouldBeError) 923 So(err.Error(), ShouldEqual, "argument 2 (foo) should be hash") 924 925 err = zyProcessArgs(z, args, []zygo.Sexp{entryType, hval}) 926 So(err, ShouldBeNil) 927 So(args[1].value.(string), ShouldEqual, `{"fname":"Jane","lname":"Smith"}`) 928 929 err = zyProcessArgs(z, args, []zygo.Sexp{entryType, &zygo.SexpStr{S: "bar"}}) 930 So(err, ShouldBeError) 931 So(err.Error(), ShouldEqual, "argument 2 (foo) should be hash") 932 933 err = zyProcessArgs(z, args, []zygo.Sexp{entryType, &zygo.SexpInt{Val: 3141}}) 934 So(err, ShouldBeError) 935 So(err.Error(), ShouldEqual, "argument 2 (foo) should be hash") 936 937 }) 938 939 Convey("EntryArg should convert all values to JSON for JSON type entries", t, func() { 940 args := []Arg{{Name: "entryType", Type: StringArg}, {Name: "foo", Type: EntryArg}} 941 var entryType zygo.Sexp = &zygo.SexpStr{S: "profile"} 942 943 err := zyProcessArgs(z, args, []zygo.Sexp{entryType, zygo.SexpNull}) 944 So(err, ShouldBeNil) 945 So(args[1].value.(string), ShouldEqual, `undefined`) 946 947 err = zyProcessArgs(z, args, []zygo.Sexp{entryType, hval}) 948 So(err, ShouldBeNil) 949 So(args[1].value.(string), ShouldEqual, `{"fname":"Jane","lname":"Smith"}`) 950 951 err = zyProcessArgs(z, args, []zygo.Sexp{entryType, &zygo.SexpStr{S: "bar"}}) 952 So(err, ShouldBeNil) 953 So(args[1].value.(string), ShouldEqual, `"bar"`) 954 955 err = zyProcessArgs(z, args, []zygo.Sexp{entryType, &zygo.SexpInt{Val: 3141}}) 956 So(err, ShouldBeNil) 957 So(args[1].value.(string), ShouldEqual, `3141`) 958 959 }) 960 961 // currently ArgsArg and EntryArg are identical, but we expect this to change 962 Convey("it should convert ArgsArg from string or hash", t, func() { 963 args := []Arg{{Name: "foo", Type: ArgsArg}} 964 err := zyProcessArgs(z, args, []zygo.Sexp{zygo.SexpNull}) 965 So(err.Error(), ShouldEqual, "argument 1 (foo) should be string or hash") 966 var val zygo.Sexp = &zygo.SexpStr{S: "bar"} 967 err = zyProcessArgs(z, args, []zygo.Sexp{val}) 968 So(err, ShouldBeNil) 969 So(args[0].value.(string), ShouldEqual, "bar") 970 971 // create a zygo hash for a test arg 972 973 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: ""}) 974 env := v.(*ZygoRibosome).env 975 hval, _ := zygo.MakeHash(nil, "hash", env) 976 hval.HashSet(env.MakeSymbol("fname"), &zygo.SexpStr{S: "Jane"}) 977 hval.HashSet(env.MakeSymbol("lname"), &zygo.SexpStr{S: "Smith"}) 978 err = zyProcessArgs(z, args, []zygo.Sexp{hval}) 979 So(err, ShouldBeNil) 980 So(args[0].value.(string), ShouldEqual, `{"fname":"Jane","lname":"Smith"}`) 981 982 }) 983 984 Convey("it should convert MapArg to a map", t, func() { 985 args := []Arg{{Name: "foo", Type: MapArg}} 986 err := zyProcessArgs(z, args, []zygo.Sexp{zygo.SexpNull}) 987 So(err.Error(), ShouldEqual, "argument 1 (foo) should be hash") 988 989 // create a zygo hash as a test arg 990 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: ""}) 991 env := v.(*ZygoRibosome).env 992 var hashstr zygo.Sexp = &zygo.SexpStr{S: "fakehashvalue"} 993 hval, _ := zygo.MakeHash(nil, "hash", env) 994 hval.HashSet(env.MakeSymbol("H"), hashstr) 995 hval.HashSet(env.MakeSymbol("I"), &zygo.SexpInt{Val: 314}) 996 997 err = zyProcessArgs(z, args, []zygo.Sexp{hval}) 998 So(err, ShouldBeNil) 999 x := args[0].value.(map[string]interface{}) 1000 So(x["H"].(string), ShouldEqual, "fakehashvalue") 1001 So(x["I"].(float64), ShouldEqual, 314) 1002 }) 1003 1004 Convey("it should convert ToStrArg any type to a string", t, func() { 1005 args := []Arg{{Name: "any", Type: ToStrArg}} 1006 var val zygo.Sexp = &zygo.SexpStr{S: "bar"} 1007 err := zyProcessArgs(z, args, []zygo.Sexp{val}) 1008 So(err, ShouldBeNil) 1009 So(args[0].value.(string), ShouldEqual, "bar") 1010 val = &zygo.SexpInt{Val: 123} 1011 err = zyProcessArgs(z, args, []zygo.Sexp{val}) 1012 So(err, ShouldBeNil) 1013 So(args[0].value.(string), ShouldEqual, "123") 1014 val = &zygo.SexpBool{Val: true} 1015 err = zyProcessArgs(z, args, []zygo.Sexp{val}) 1016 So(err, ShouldBeNil) 1017 So(args[0].value.(string), ShouldEqual, "true") 1018 1019 // create a zygo hash as a test arg 1020 v, err := NewZygoRibosome(h, &Zome{RibosomeType: ZygoRibosomeType, Code: ""}) 1021 env := v.(*ZygoRibosome).env 1022 var hashstr zygo.Sexp = &zygo.SexpStr{S: "fakehashvalue"} 1023 hval, _ := zygo.MakeHash(nil, "hash", env) 1024 hval.HashSet(env.MakeSymbol("H"), hashstr) 1025 hval.HashSet(env.MakeSymbol("I"), &zygo.SexpInt{Val: 314}) 1026 1027 err = zyProcessArgs(z, args, []zygo.Sexp{hval}) 1028 So(args[0].value.(string), ShouldEqual, `{"H":"fakehashvalue","I":314}`) 1029 }) 1030 }