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 }