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