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

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