github.com/metacurrency/holochain@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/cmd/hcdev/hcdev_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"reflect"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/davecgh/go-spew/spew"
    14  	holo "github.com/holochain/holochain-proto"
    15  	. "github.com/holochain/holochain-proto/apptest"
    16  	"github.com/holochain/holochain-proto/cmd"
    17  	. "github.com/holochain/holochain-proto/hash"
    18  	. "github.com/smartystreets/goconvey/convey"
    19  	"github.com/urfave/cli"
    20  )
    21  
    22  func TestMain(m *testing.M) {
    23  	// disable UPNP for tests
    24  	os.Setenv("HOLOCHAINCONFIG_ENABLENATUPNP", "false")
    25  	holo.InitializeHolochain()
    26  	os.Exit(m.Run())
    27  }
    28  
    29  func TestSetupApp(t *testing.T) {
    30  	app := setupApp()
    31  	Convey("it should create the cli App", t, func() {
    32  		So(app.Name, ShouldEqual, "hcdev")
    33  	})
    34  }
    35  
    36  func TestDump(t *testing.T) {
    37  	d, s, h := holo.PrepareTestChain("test")
    38  	defer holo.CleanupTestChain(h, d)
    39  	app := setupApp()
    40  
    41  	Convey("'dump --chain' should show chain entries as a human readable string", t, func() {
    42  		out, err := runAppWithStdoutCapture(app, []string{"hcdev", "-DHTport=6001", "-execpath", s.Path, "-path", "test", "dump", "--chain"})
    43  
    44  		So(err, ShouldBeNil)
    45  		So(out, ShouldContainSubstring, "%dna:")
    46  		So(out, ShouldContainSubstring, "%agent:")
    47  	})
    48  
    49  	Convey("'dump --dht' should show chain entries as a human readable string", t, func() {
    50  		out, err := runAppWithStdoutCapture(app, []string{"hcdev", "-DHTport=6001", "-execpath", s.Path, "-path", "test", "dump", "--dht"})
    51  
    52  		So(err, ShouldBeNil)
    53  		So(out, ShouldContainSubstring, "DHT changes: 2")
    54  		So(out, ShouldContainSubstring, "DHT entries:")
    55  	})
    56  
    57  	Convey("'dump --chain --json' should show chain entries as JSON string", t, func() {
    58  		out, err := runAppWithStdoutCapture(app, []string{"hcdev", "-DHTport=6001", "-execpath", s.Path, "-path", "test", "dump", "--chain", "--json"})
    59  
    60  		So(err, ShouldBeNil)
    61  		So(out, ShouldContainSubstring, "{\n    \"%dna\": {")
    62  		So(out, ShouldContainSubstring, ",\n    \"%agent\": {")
    63  	})
    64  
    65  	Convey("'dump --dht --json' should show chain entries as JSON string", t, func() {
    66  		out, err := runAppWithStdoutCapture(app, []string{"hcdev", "-DHTport=6001", "-execpath", s.Path, "-path", "test", "dump", "--dht", "--json"})
    67  
    68  		So(err, ShouldBeNil)
    69  		So(out, ShouldContainSubstring, "\"dht_changes\": [")
    70  		So(out, ShouldContainSubstring, "\"dht_entries\": [")
    71  	})
    72  
    73  	Convey("'dump --chain --format string' should show chain entries as a human readable string", t, func() {
    74  		out, err := runAppWithStdoutCapture(app, []string{"hcdev", "-DHTport=6001", "-execpath", s.Path, "-path", "test", "dump", "--chain", "--format", "string"})
    75  
    76  		So(err, ShouldBeNil)
    77  		So(out, ShouldContainSubstring, "%dna:")
    78  		So(out, ShouldContainSubstring, "%agent:")
    79  	})
    80  
    81  	Convey("'dump --chain --format dot' should show chain entries as GraphViz DOT format", t, func() {
    82  		out, err := runAppWithStdoutCapture(app, []string{"hcdev", "-DHTport=6001", "-execpath", s.Path, "-path", "test", "dump", "--chain", "--format", "dot"})
    83  
    84  		So(err, ShouldBeNil)
    85  		So(out, ShouldContainSubstring, "digraph chain {")
    86  	})
    87  	os.Unsetenv("HOLOCHAINCONFIG_ENABLENATUPNP")
    88  }
    89  
    90  func TestGoScenario_cliCommand(t *testing.T) {
    91  	os.Setenv("HC_TESTING", "true")
    92  	app := setupApp()
    93  
    94  	testCommand := []string{"hcdev", "-debug", "scenario"}
    95  	app.Run(testCommand)
    96  
    97  	// collect information about the execution of the command
    98  	mutableContext, lastRunContext = GetLastRunContext()
    99  
   100  	Convey("run the scenario command", t, func() {
   101  		if debug {
   102  			fmt.Printf("HC: hcdev_test.go: TestGoScenarioCommand: mutableContext\n\n%v", spew.Sdump(mutableContext))
   103  		}
   104  		So(mutableContext.str["command"], ShouldEqual, "scenario")
   105  	})
   106  }
   107  
   108  func Test_testScenarioWriteEnvironment(t *testing.T) {
   109  
   110  }
   111  
   112  func TestRunScenarioTest(t *testing.T) {
   113  	app := setupApp()
   114  
   115  	Convey("try to build holochain without actual source", t, func() {
   116  		// fails because there is no holochain app here
   117  		testCommand := []string{"hcdev", "-debug", "scenario"}
   118  		err := app.Run(testCommand)
   119  		// collect information about the execution of the command
   120  		So(err, ShouldBeError)
   121  	})
   122  
   123  	tmpTestDir, app := setupTestingApp("foo")
   124  	defer os.RemoveAll(tmpTestDir)
   125  
   126  	Convey("run the scenario in the testing app", t, func() {
   127  
   128  		execDir, err := cmd.MakeTmpDir("hcdev_scenariotest")
   129  		So(err, ShouldBeNil)
   130  		//defer os.RemoveAll(execDir)  // can't delete because this stuff runs in the background...
   131  
   132  		// setupTestingApp moved us into the app so we just need to point to  a working directory for the test (execDir)
   133  		testCommand := []string{"hcdev", "-path", tmpTestDir + "/foo", "-execpath", execDir, "scenario", "sampleScenario"}
   134  
   135  		err = app.Run(testCommand)
   136  		So(err, ShouldBeNil)
   137  
   138  		// check that scenario directory is confirmed
   139  		So(mutableContext.str["testScenarioName"], ShouldEqual, "sampleScenario")
   140  
   141  		if debug {
   142  			fmt.Printf("HC: hcdev_test.go: TestRunScenarioTest: mutableContext\n\n%v", spew.Sdump(mutableContext))
   143  		}
   144  
   145  	})
   146  
   147  	//Convey("test incorrect user inputs", t, func() {
   148  	//})
   149  }
   150  
   151  func TestInit(t *testing.T) {
   152  	os.Setenv("HC_TESTING", "true")
   153  	tmpTestDir, err := ioutil.TempDir("", "holochain.testing.hcdev")
   154  	if err != nil {
   155  		panic(err)
   156  	}
   157  	defer os.RemoveAll(tmpTestDir)
   158  
   159  	err = os.Chdir(tmpTestDir)
   160  	if err != nil {
   161  		panic(err)
   162  	}
   163  
   164  	app := setupApp()
   165  	Convey("'init foo' should create default files in 'foo' directory", t, func() {
   166  		os.Args = []string{"hcdev", "init", "foo"}
   167  		err = app.Run(os.Args)
   168  		So(err, ShouldBeNil)
   169  		So(cmd.IsFile(filepath.Join(tmpTestDir, "foo", "dna", "dna.json")), ShouldBeTrue)
   170  		So(cmd.IsDir(tmpTestDir, holo.ChainDataDir), ShouldBeFalse)
   171  	})
   172  
   173  	Convey("'init /tmp/foo' should create default files in the absolute '/tmp/foo' directory", t, func() {
   174  		tmpFoo := filepath.Join("/tmp", "foo")
   175  		os.Args = []string{"hcdev", "init", tmpFoo}
   176  		err = app.Run(os.Args)
   177  		So(err, ShouldBeNil)
   178  		So(cmd.IsFile(filepath.Join(tmpFoo, "dna", "dna.json")), ShouldBeTrue)
   179  		So(cmd.IsDir(tmpTestDir, holo.ChainDataDir), ShouldBeFalse)
   180  		os.RemoveAll(tmpFoo)
   181  	})
   182  
   183  	Convey("'init bar --clone foo' should copy files from foo to bar", t, func() {
   184  		p := filepath.Join(tmpTestDir, "foo", "ui", "foo.js")
   185  		f, err := os.Create(p)
   186  		if err != nil {
   187  			panic(err)
   188  		}
   189  		defer f.Close()
   190  		err = os.Chdir(tmpTestDir)
   191  		if err != nil {
   192  			panic(err)
   193  		}
   194  
   195  		os.Args = []string{"hcdev", "init", "-clone", "foo", "bar"}
   196  
   197  		err = app.Run(os.Args)
   198  		So(err, ShouldBeNil)
   199  		So(cmd.IsFile(filepath.Join(tmpTestDir, "bar", "ui", "foo.js")), ShouldBeTrue)
   200  		So(cmd.IsDir(tmpTestDir, holo.ChainDataDir), ShouldBeFalse)
   201  	})
   202  
   203  	Convey("'init bar --cloneExample=HoloWorld' should copy files from github", t, func() {
   204  		err = os.Chdir(tmpTestDir)
   205  		if err != nil {
   206  			panic(err)
   207  		}
   208  
   209  		// it should clone with the same name as the repo
   210  		os.Args = []string{"hcdev", "init", "-cloneExample=HoloWorld"}
   211  		err = app.Run(os.Args)
   212  		So(err, ShouldBeNil)
   213  		So(cmd.IsFile(filepath.Join(tmpTestDir, "HoloWorld", "dna", "dna.json")), ShouldBeTrue)
   214  		// or from a branch
   215  		err = os.Chdir(tmpTestDir)
   216  		if err != nil {
   217  			panic(err)
   218  		}
   219  		os.Args = []string{"hcdev", "init", "-cloneExample=HoloWorld", "-fromDevelop", "HoloWorld2"}
   220  		err = app.Run(os.Args)
   221  		So(err, ShouldBeNil)
   222  		So(cmd.IsFile(filepath.Join(tmpTestDir, "HoloWorld2", "dna", "dna.json")), ShouldBeTrue)
   223  
   224  		// or with a specified name
   225  		err = os.Chdir(tmpTestDir)
   226  		if err != nil {
   227  			panic(err)
   228  		}
   229  		os.Args = []string{"hcdev", "init", "-cloneExample=HoloWorld", "myHoloWorld"}
   230  		err = app.Run(os.Args)
   231  		So(err, ShouldBeNil)
   232  		So(cmd.IsFile(filepath.Join(tmpTestDir, "myHoloWorld", "dna", "dna.json")), ShouldBeTrue)
   233  		So(cmd.IsDir(tmpTestDir, holo.ChainDataDir), ShouldBeFalse)
   234  
   235  		// but fail if the directory is already there
   236  		err = os.Chdir(tmpTestDir)
   237  		if err != nil {
   238  			panic(err)
   239  		}
   240  		os.Args = []string{"hcdev", "init", "-cloneExample=HoloWorld"}
   241  		err = app.Run(os.Args)
   242  		So(err, ShouldNotBeNil)
   243  		So(os.Getenv("HC_TESTING_EXITERR"), ShouldEqual, "1")
   244  	})
   245  
   246  	Convey("'init -test testingApp' should create the test app", t, func() {
   247  		err = os.Chdir(tmpTestDir)
   248  		if err != nil {
   249  			panic(err)
   250  		}
   251  
   252  		os.Args = []string{"hcdev", "init", "-test", "testingApp"}
   253  
   254  		err = app.Run(os.Args)
   255  		So(err, ShouldBeNil)
   256  		So(cmd.IsFile(filepath.Join(tmpTestDir, "testingApp", "dna", "jsSampleZome", "jsSampleZome.js")), ShouldBeTrue)
   257  		So(cmd.IsDir(tmpTestDir, holo.ChainDataDir), ShouldBeFalse)
   258  	})
   259  
   260  }
   261  
   262  func TestPackage(t *testing.T) {
   263  	app := setupApp()
   264  	tmpTestDir, app := setupTestingApp("foo")
   265  	defer os.RemoveAll(tmpTestDir)
   266  	Convey("'package' should print a appPackage file to stdout", t, func() {
   267  		appPackage, err := cmd.RunAppWithStdoutCapture(app, []string{"hcdev", "package"}, 2*time.Second)
   268  		So(err, ShouldBeNil)
   269  		So(appPackage, ShouldContainSubstring, fmt.Sprintf(`"Version": "%s"`, holo.AppPackageVersion))
   270  	})
   271  	app = setupApp()
   272  	d := holo.SetupTestDir()
   273  	defer os.RemoveAll(d)
   274  	Convey("'package' should output an appPackage file to a file", t, func() {
   275  		cmd.RunAppWithStdoutCapture(app, []string{"hcdev", "package", filepath.Join(d, "scaff.json")}, 2*time.Second)
   276  		appPackage, err := holo.ReadFile(d, "scaff.json")
   277  		So(err, ShouldBeNil)
   278  		So(string(appPackage), ShouldContainSubstring, fmt.Sprintf(`"Version": "%s"`, holo.AppPackageVersion))
   279  
   280  	})
   281  }
   282  
   283  func TestWeb(t *testing.T) {
   284  	os.Setenv("HC_TESTING", "true")
   285  	tmpTestDir, app := setupTestingApp("foo")
   286  	defer os.RemoveAll(tmpTestDir)
   287  
   288  	os.Unsetenv("HCLOG_DHT_ENABLE")
   289  	os.Unsetenv("HCLOG_GOSSIP_ENABLE")
   290  	os.Unsetenv("HCLOG_DEBUG_ENABLE")
   291  
   292  	Convey("'web' should run a webserver", t, func() {
   293  		out, err := cmd.RunAppWithStdoutCapture(app, []string{"hcdev", "-upnp=false", "web"}, 5*time.Second)
   294  		So(err, ShouldBeNil)
   295  		So(out, ShouldContainSubstring, "on port:4141")
   296  		So(out, ShouldContainSubstring, "Serving holochain with DNA hash:")
   297  		// it should include app level debug but not holochain debug
   298  		So(out, ShouldContainSubstring, "running zyZome genesis")
   299  		So(out, ShouldNotContainSubstring, "NewEntry of %dna added as: Qm")
   300  	})
   301  	app = setupApp()
   302  
   303  	Convey("'web -debug' should run a webserver and include holochain debug info", t, func() {
   304  		out, err := cmd.RunAppWithStdoutCapture(app, []string{"hcdev", "-debug", "-upnp=false", "web", "4142"}, 5*time.Second)
   305  		So(err, ShouldBeNil)
   306  		So(out, ShouldContainSubstring, "running zyZome genesis")
   307  		So(out, ShouldContainSubstring, "NewEntry of %dna added as: Qm")
   308  	})
   309  	app = setupApp()
   310  
   311  	Convey("'web' not in an app directory should produce error", t, func() {
   312  		out, err := cmd.RunAppWithStdoutCapture(app, []string{"hcdev", "-path", tmpTestDir, "web"}, 1*time.Second)
   313  		So(err, ShouldBeError)
   314  		So(out, ShouldContainSubstring, "doesn't look like a holochain app")
   315  	})
   316  }
   317  
   318  func TestIdenity(t *testing.T) {
   319  	os.Setenv("HC_TESTING", "true")
   320  	tmpTestDir, app := setupTestingApp("foo")
   321  	defer os.RemoveAll(tmpTestDir)
   322  	Convey("it should create default from users config", t, func() {
   323  		host, _ := os.Hostname()
   324  		So(getIdentity("", ""), ShouldEqual, sysUser.Username+"@"+host)
   325  	})
   326  	Convey("it should use params", t, func() {
   327  		So(getIdentity("foo", "bar"), ShouldEqual, "foo@bar")
   328  	})
   329  	Convey("verbose should show the identity and nodeid", t, func() {
   330  		out, err := cmd.RunAppWithStdoutCapture(app, []string{"hcdev", "-agentID=foo", "-serverID=bar", "-verbose", "web"}, 1*time.Second)
   331  		So(err, ShouldBeNil)
   332  		So(out, ShouldContainSubstring, "Identity: foo")
   333  		So(out, ShouldContainSubstring, "NodeID: QmNQq6JDkxoYFzWVi5C4fVQ47zbFpUDiRg2AF8XE6CDDow")
   334  	})
   335  }
   336  
   337  func TestBridging(t *testing.T) {
   338  	os.Setenv("HC_TESTING", "true")
   339  	tmpTestDir, app := setupTestingApp("foo", "bar")
   340  	defer os.RemoveAll(tmpTestDir)
   341  
   342  	// bridging to ourselves for this test, so write out a bridgeSpecFile to use
   343  	bridgeSourceDir := filepath.Join(tmpTestDir, "bar")
   344  	data := []BridgeSpec{BridgeSpec{Path: bridgeSourceDir, Side: holo.BridgeCallee, BridgeZome: "jsSampleZome", BridgeGenesisCalleeData: "some data 314"}}
   345  	var b bytes.Buffer
   346  	err := holo.Encode(&b, "json", data)
   347  
   348  	if err != nil {
   349  		panic(err)
   350  	}
   351  	if err := holo.WriteFile(b.Bytes(), tmpTestDir, "specs.json"); err != nil {
   352  		panic(err)
   353  	}
   354  
   355  	Convey("bridgeSpecsFile path should setup bridging", t, func() {
   356  		out, err := cmd.RunAppWithStdoutCapture(app, []string{"hcdev", "-bridgeSpecs", filepath.Join(tmpTestDir, "specs.json"), "-upnp=false", "web"}, 5*time.Second)
   357  		So(err, ShouldBeNil)
   358  		//So(out, ShouldContainSubstring, fmt.Sprintf("bridging to %s using zome: jsSampleZome", bridgeSourceDir))
   359  		So(out, ShouldContainSubstring, fmt.Sprintf("Copying bridge chain bar to:"))
   360  		So(out, ShouldContainSubstring, fmt.Sprintf("bridge genesis to-- other side is:")) // getting the DNA is a pain so skip it.
   361  		So(out, ShouldContainSubstring, fmt.Sprintf("bridging data:some data 314"))
   362  	})
   363  }
   364  
   365  func TestSaveBridgeApps(t *testing.T) {
   366  	hashRed, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzfro1")
   367  	hashBlue, _ := NewHash("QmY8Mzg9F69e5P9AoQPYat655HEhc1TVGs11tmfNSzfro2")
   368  
   369  	bridgeAppsForTests := []BridgeAppForTests{
   370  		BridgeAppForTests{
   371  			BridgeApp: holo.BridgeApp{
   372  				Name: "red fish",
   373  				DNA:  hashRed,
   374  				Side: holo.BridgeCaller,
   375  				BridgeGenesisCallerData: "data red from",
   376  				BridgeGenesisCalleeData: "data blue to",
   377  				Port:       "1234",
   378  				BridgeZome: "redzome",
   379  			},
   380  		},
   381  		BridgeAppForTests{
   382  			BridgeApp: holo.BridgeApp{
   383  				Name: "blue fish",
   384  				DNA:  hashBlue,
   385  				Side: holo.BridgeCallee,
   386  				BridgeGenesisCallerData: "data red from",
   387  				BridgeGenesisCalleeData: "data blue to",
   388  				Port:       "4321",
   389  				BridgeZome: "bluezome",
   390  			},
   391  		},
   392  	}
   393  
   394  	Convey("you can save out bridge app data for scenario testing", t, func() {
   395  		fileName, err := saveBridgeAppsToTmpFile(bridgeAppsForTests)
   396  		So(err, ShouldBeNil)
   397  
   398  		bridgeApps, err := getBridgeAppsFromTmpFile(fileName)
   399  		So(err, ShouldBeNil)
   400  		So(reflect.DeepEqual(bridgeApps[0], bridgeAppsForTests[0].BridgeApp), ShouldBeTrue)
   401  		So(reflect.DeepEqual(bridgeApps[1], bridgeAppsForTests[1].BridgeApp), ShouldBeTrue)
   402  		So(len(bridgeApps), ShouldEqual, 2)
   403  	})
   404  }
   405  
   406  func TestConfigFlagsDefault(t *testing.T) {
   407  	os.Setenv("HC_TESTING", "true")
   408  	tmpTestDir, err := ioutil.TempDir("", "holochain.testing.hcdev")
   409  	if err != nil {
   410  		panic(err)
   411  	}
   412  	defer os.RemoveAll(tmpTestDir)
   413  
   414  	runDir := filepath.Join(tmpTestDir, holo.DefaultDirectoryName+"dev")
   415  
   416  	os.Setenv("HOLOPATHDEV", runDir)
   417  
   418  	err = os.Chdir(tmpTestDir)
   419  	if err != nil {
   420  		panic(err)
   421  	}
   422  
   423  	app := setupApp()
   424  	_, err = runAppWithStdoutCapture(app, []string{"hcdev", "init", "foo"})
   425  
   426  	Convey("defaults are mdns on upnp off", t, func() {
   427  		app := setupApp()
   428  		runAppWithStdoutCapture(app, []string{"hcdev", "test"})
   429  		var config holo.Config
   430  		err = holo.DecodeFile(&config, filepath.Join(runDir, "foo", holo.ConfigFileName+".json"))
   431  		So(err, ShouldBeNil)
   432  		So(config.EnableMDNS, ShouldBeTrue)
   433  		So(config.EnableNATUPnP, ShouldBeFalse)
   434  	})
   435  
   436  	os.Unsetenv("HOLOPATHDEV")
   437  	os.Unsetenv("HC_TESTING")
   438  }
   439  
   440  func setupTestingApp(names ...string) (string, *cli.App) {
   441  	tmpTestDir, err := ioutil.TempDir("", "holochain.testing.hcdev")
   442  	if err != nil {
   443  		panic(err)
   444  	}
   445  
   446  	app := setupApp()
   447  
   448  	for _, name := range names {
   449  		_setupTestingApp(name, app, tmpTestDir)
   450  	}
   451  
   452  	err = os.Chdir(filepath.Join(tmpTestDir, names[0]))
   453  	if err != nil {
   454  		panic(err)
   455  	}
   456  	return tmpTestDir, app
   457  }
   458  
   459  func _setupTestingApp(name string, app *cli.App, tmpTestDir string) {
   460  	err := os.Chdir(tmpTestDir)
   461  	if err != nil {
   462  		panic(err)
   463  	}
   464  
   465  	os.Args = []string{"hcdev", "init", "-test", name}
   466  	err = app.Run(os.Args)
   467  	if err != nil {
   468  		panic(err)
   469  	}
   470  
   471  	// cleanup env flags set
   472  	os.Unsetenv("HOLOCHAINCONFIG_ENABLENATUPNP")
   473  	os.Unsetenv("HOLOCHAINCONFIG_BOOTSTRAP")
   474  	os.Unsetenv("HOLOCHAINCONFIG_ENABLEMDNS")
   475  }
   476  
   477  func runAppWithStdoutCapture(app *cli.App, args []string) (out string, err error) {
   478  	return cmd.RunAppWithStdoutCapture(app, args, time.Second*5)
   479  }