github.com/holochain/holochain-proto@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/jsribosome_test.go (about)

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