github.com/metacurrency/holochain@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/service_test.go (about) 1 package holochain 2 3 import ( 4 "bytes" 5 "fmt" 6 ic "github.com/libp2p/go-libp2p-crypto" 7 . "github.com/smartystreets/goconvey/convey" 8 "os" 9 "path/filepath" 10 "testing" 11 ) 12 13 func TestInit(t *testing.T) { 14 d := SetupTestDir() 15 defer CleanupTestDir(d) 16 17 Convey("we can detect an uninitialized directory", t, func() { 18 So(IsInitialized(filepath.Join(d, DefaultDirectoryName)), ShouldBeFalse) 19 }) 20 21 agent := "Fred Flintstone <fred@flintstone.com>" 22 23 s, err := Init(filepath.Join(d, DefaultDirectoryName), AgentIdentity(agent), MakeTestSeed(agent)) 24 25 Convey("when initializing service in a directory", t, func() { 26 So(err, ShouldBeNil) 27 28 Convey("it should return a service with default values", func() { 29 So(s.DefaultAgent.Identity(), ShouldEqual, AgentIdentity(agent)) 30 So(fmt.Sprintf("%v", s.Settings), ShouldEqual, "{true true bootstrap.holochain.net:10000 true true}") 31 }) 32 33 p := filepath.Join(d, DefaultDirectoryName) 34 Convey("it should create agent files", func() { 35 a, err := LoadAgent(p) 36 So(err, ShouldBeNil) 37 So(a.Identity(), ShouldEqual, AgentIdentity(agent)) 38 }) 39 40 Convey("we can detect that it was initialized", func() { 41 So(IsInitialized(filepath.Join(d, DefaultDirectoryName)), ShouldBeTrue) 42 }) 43 44 Convey("it should create an agent file", func() { 45 a, err := ReadFile(p, AgentFileName) 46 So(err, ShouldBeNil) 47 So(string(a), ShouldEqual, agent) 48 }) 49 }) 50 } 51 52 func TestLoadService(t *testing.T) { 53 d, service := setupTestService() 54 root := service.Path 55 defer CleanupTestDir(d) 56 Convey("loading service from disk should set up the struct", t, func() { 57 s, err := LoadService(root) 58 So(err, ShouldBeNil) 59 So(s.Path, ShouldEqual, root) 60 So(s.Settings.DefaultPeerModeDHTNode, ShouldEqual, true) 61 So(s.Settings.DefaultPeerModeAuthor, ShouldEqual, true) 62 So(s.DefaultAgent.Identity(), ShouldEqual, AgentIdentity("Herbert <h@bert.com>")) 63 }) 64 65 } 66 67 func TestValidateServiceConfig(t *testing.T) { 68 svc := ServiceConfig{} 69 70 Convey("it should fail without one peer mode set to true", t, func() { 71 err := svc.Validate() 72 So(err.Error(), ShouldEqual, SysFileName+": At least one peer mode must be set to true.") 73 }) 74 75 svc.DefaultPeerModeAuthor = true 76 77 Convey("it should validate", t, func() { 78 err := svc.Validate() 79 So(err, ShouldBeNil) 80 }) 81 82 } 83 84 func TestConfiguredChains(t *testing.T) { 85 d, s, h := SetupTestChain("test") 86 defer CleanupTestChain(h, d) 87 88 Convey("Configured chains should return a hash of all the chains in the Service", t, func() { 89 chains, err := s.ConfiguredChains() 90 So(err, ShouldBeNil) 91 So(chains["test"].nucleus.dna.UUID, ShouldEqual, h.nucleus.dna.UUID) 92 }) 93 } 94 95 func TestServiceGenChain(t *testing.T) { 96 d, s, h := SetupTestChain("test") 97 defer CleanupTestChain(h, d) 98 99 Convey("it should return a list of the chains", t, func() { 100 list := s.ListChains() 101 So(list, ShouldEqual, "installed holochains:\n test <not-started>\n") 102 }) 103 Convey("it should start a chain and return a holochain object", t, func() { 104 DNAHash, err := DNAHashofUngenedChain(h) 105 So(err, ShouldBeNil) 106 h2, err := s.GenChain("test") 107 So(err, ShouldBeNil) 108 So(h2.nucleus.dna.UUID, ShouldEqual, h.nucleus.dna.UUID) 109 list := s.ListChains() 110 So(list, ShouldEqual, fmt.Sprintf("installed holochains:\n test %v\n", h2.dnaHash)) 111 112 So(DNAHash.String(), ShouldEqual, h2.DNAHash().String()) 113 114 }) 115 } 116 117 func TestCloneNew(t *testing.T) { 118 d, s, h0 := SetupTestChain("test") 119 defer CleanupTestChain(h0, d) 120 121 name := "test2" 122 root := filepath.Join(s.Path, name) 123 124 orig := filepath.Join(s.Path, "test") 125 126 agent, err := LoadAgent(s.Path) 127 if err != nil { 128 panic(err) 129 } 130 131 Convey("it should clone a chain by copying and creating an new UUID", t, func() { 132 // change the agent identity from the default to confirm that 133 // a separate copy is saved 134 var a *LibP2PAgent 135 a = agent.(*LibP2PAgent) 136 a.identity += "extra" 137 138 hc, err := s.Clone(orig, root, a, CloneWithNewUUID, InitializeDB) 139 So(err, ShouldBeNil) 140 So(hc.Name(), ShouldEqual, name) 141 // clone returns the ungened HC so hash won't have be calculated 142 So(hc.DNAHash().String(), ShouldEqual, "") 143 144 So(DirExists(root, ChainDataDir), ShouldBeTrue) 145 So(FileExists(root, ChainDataDir, StoreFileName), ShouldBeTrue) 146 147 h, err := s.Load(name) // reload to confirm that it got saved correctly 148 So(err, ShouldBeNil) 149 150 So(h.Name(), ShouldEqual, "test2") 151 So(h.nucleus.dna.UUID, ShouldNotEqual, h0.nucleus.dna.UUID) 152 153 agent, err := LoadAgent(h.rootPath) 154 So(err, ShouldBeNil) 155 So(h.agent.Identity(), ShouldEqual, agent.Identity()) 156 So(h.agent.Identity(), ShouldEqual, a.Identity()) 157 So(ic.KeyEqual(h.agent.PrivKey(), a.PrivKey()), ShouldBeTrue) 158 So(ic.KeyEqual(h.agent.PubKey(), a.PubKey()), ShouldBeTrue) 159 160 So(compareFile(filepath.Join(orig, "dna", "zySampleZome"), filepath.Join(h.DNAPath(), "zySampleZome"), "zySampleZome.zy"), ShouldBeTrue) 161 162 So(h.rootPath, ShouldEqual, root) 163 So(h.UIPath(), ShouldEqual, root+"/ui") 164 So(h.DNAPath(), ShouldEqual, root+"/dna") 165 So(h.DBPath(), ShouldEqual, root+"/db") 166 167 So(compareFile(filepath.Join(orig, "ui"), h.UIPath(), "index.html"), ShouldBeTrue) 168 So(compareFile(filepath.Join(orig, "dna", "zySampleZome"), filepath.Join(h.DNAPath(), "zySampleZome"), "profile.json"), ShouldBeTrue) 169 So(compareFile(filepath.Join(orig, "dna"), h.DNAPath(), "properties_schema.json"), ShouldBeTrue) 170 So(compareFile(orig, h.rootPath, ConfigFileName+".toml"), ShouldBeTrue) 171 172 So(compareFile(filepath.Join(orig, ChainTestDir), filepath.Join(h.rootPath, ChainTestDir), "testSet1.json"), ShouldBeTrue) 173 174 So(h.nucleus.dna.Progenitor.Identity, ShouldEqual, a.identity) 175 pk, _ := agent.PubKey().Bytes() 176 So(string(h.nucleus.dna.Progenitor.PubKey), ShouldEqual, string(pk)) 177 }) 178 } 179 180 func TestCloneJoin(t *testing.T) { 181 d, s, h0 := SetupTestChain("test") 182 defer CleanupTestChain(h0, d) 183 184 name := "test2" 185 root := filepath.Join(s.Path, name) 186 187 orig := filepath.Join(s.Path, "test") 188 189 agent, err := LoadAgent(s.Path) 190 if err != nil { 191 panic(err) 192 } 193 194 Convey("it should clone a chain by copying and without creating a new UUID", t, func() { 195 hc, err := s.Clone(orig, root, agent, CloneWithSameUUID, InitializeDB) 196 So(err, ShouldBeNil) 197 So(hc.Name(), ShouldEqual, "test") 198 // clone returns the ungened HC so hash won't have be calculated 199 So(hc.DNAHash().String(), ShouldEqual, "") 200 201 So(DirExists(root, ChainDataDir), ShouldBeTrue) 202 So(FileExists(root, ChainDataDir, StoreFileName), ShouldBeTrue) 203 204 h, err := s.Load(name) // reload to confirm that it got saved correctly 205 So(err, ShouldBeNil) 206 207 So(h.Name(), ShouldEqual, "test") 208 So(h.nucleus.dna.UUID, ShouldEqual, h0.nucleus.dna.UUID) 209 agent, err := LoadAgent(s.Path) 210 So(err, ShouldBeNil) 211 So(h.agent.Identity(), ShouldEqual, agent.Identity()) 212 So(ic.KeyEqual(h.agent.PrivKey(), agent.PrivKey()), ShouldBeTrue) 213 214 So(ic.KeyEqual(h.agent.PubKey(), agent.PubKey()), ShouldBeTrue) 215 src, _ := ReadFile(orig, "dna", "zySampleZome.zy") 216 dst, _ := ReadFile(root, "zySampleZome.zy") 217 So(string(src), ShouldEqual, string(dst)) 218 So(FileExists(h.UIPath(), "index.html"), ShouldBeTrue) 219 So(FileExists(h.DNAPath(), "zySampleZome", "profile.json"), ShouldBeTrue) 220 So(FileExists(h.DNAPath(), "properties_schema.json"), ShouldBeTrue) 221 So(FileExists(h.rootPath, ConfigFileName+".toml"), ShouldBeTrue) 222 223 So(h.nucleus.dna.Progenitor.Identity, ShouldEqual, "Progenitor Agent <progenitore@example.com>") 224 pk := []byte{8, 1, 18, 32, 193, 43, 31, 148, 23, 249, 163, 154, 128, 25, 237, 167, 253, 63, 214, 220, 206, 131, 217, 74, 168, 30, 215, 237, 231, 160, 69, 89, 48, 17, 104, 210} 225 So(string(h.nucleus.dna.Progenitor.PubKey), ShouldEqual, string(pk)) 226 227 }) 228 } 229 230 func TestCloneNoDB(t *testing.T) { 231 d, s, h := SetupTestChain("test") 232 defer CleanupTestChain(h, d) 233 234 name := "test2" 235 root := filepath.Join(s.Path, name) 236 237 orig := filepath.Join(s.Path, "test") 238 239 agent, err := LoadAgent(s.Path) 240 if err != nil { 241 panic(err) 242 } 243 244 Convey("it should create a chain without initializing the DB files", t, func() { 245 _, err = s.Clone(orig, root, agent, CloneWithNewUUID, SkipInitializeDB) 246 So(err, ShouldBeNil) 247 248 So(DirExists(root, ChainDataDir), ShouldBeFalse) 249 So(FileExists(root, ChainDNADir, "zySampleZome", "profile.json"), ShouldBeTrue) 250 }) 251 } 252 253 func TestMakeTestingApp(t *testing.T) { 254 d, s := setupTestService() 255 defer CleanupTestDir(d) 256 name := "test" 257 root := filepath.Join(s.Path, name) 258 259 Convey("we detected unconfigured holochains", t, func() { 260 f, err := s.IsConfigured(name) 261 So(f, ShouldEqual, "") 262 So(err.Error(), ShouldEqual, fmt.Sprintf("No DNA file in %s%s", filepath.Join(root, ChainDNADir), string(os.PathSeparator))) 263 _, err = s.load("test", "json") 264 So(err.Error(), ShouldEqual, "open "+filepath.Join(root, ConfigFileName+".json")+": no such file or directory") 265 266 }) 267 268 Convey("when generating a dev holochain", t, func() { 269 h, err := s.MakeTestingApp(root, "json", InitializeDB, CloneWithNewUUID, nil) 270 So(err, ShouldBeNil) 271 272 f, err := s.IsConfigured(name) 273 So(err, ShouldBeNil) 274 So(f, ShouldEqual, "json") 275 276 h, err = s.Load(name) 277 So(err, ShouldBeNil) 278 279 lh, err := s.load(name, "json") 280 So(err, ShouldBeNil) 281 So(lh.nodeID, ShouldEqual, h.nodeID) 282 So(lh.nodeIDStr, ShouldEqual, h.nodeIDStr) 283 284 So(lh.Config.DHTPort, ShouldEqual, DefaultDHTPort) 285 So(h.Config.PeerModeDHTNode, ShouldEqual, s.Settings.DefaultPeerModeDHTNode) 286 So(h.Config.PeerModeAuthor, ShouldEqual, s.Settings.DefaultPeerModeAuthor) 287 So(h.Config.BootstrapServer, ShouldEqual, s.Settings.DefaultBootstrapServer) 288 So(h.Config.EnableMDNS, ShouldEqual, s.Settings.DefaultEnableMDNS) 289 290 So(DirExists(root), ShouldBeTrue) 291 So(DirExists(h.DNAPath()), ShouldBeTrue) 292 So(DirExists(h.TestPath()), ShouldBeTrue) 293 So(DirExists(h.UIPath()), ShouldBeTrue) 294 So(FileExists(h.TestPath(), "sampleScenario", "listener.json"), ShouldBeTrue) 295 So(FileExists(h.DNAPath(), "zySampleZome", "profile.json"), ShouldBeTrue) 296 So(FileExists(h.UIPath(), "index.html"), ShouldBeTrue) 297 So(FileExists(h.UIPath(), "hc.js"), ShouldBeTrue) 298 So(FileExists(h.rootPath, ConfigFileName+".json"), ShouldBeTrue) 299 300 Convey("we should not be able re generate it", func() { 301 _, err = s.MakeTestingApp(root, "json", SkipInitializeDB, CloneWithNewUUID, nil) 302 So(err.Error(), ShouldEqual, "holochain: "+root+" already exists") 303 }) 304 }) 305 306 Convey("generating a dev holochain in an absolute directory initdb should work", t, func() { 307 root := filepath.Join("/tmp", MakeTestDirName()) 308 _, err := s.MakeTestingApp(root, "json", InitializeDB, CloneWithNewUUID, nil) 309 os.RemoveAll(root) 310 So(err, ShouldBeNil) 311 }) 312 313 } 314 315 func TestSaveFromAppPackage(t *testing.T) { 316 d, s := setupTestService() 317 defer CleanupTestDir(d) 318 name := "test" 319 root := filepath.Join(s.Path, name) 320 321 Convey("it should write out a appPackage file to a directory tree with JSON encoding", t, func() { 322 appPackageReader := bytes.NewBuffer([]byte(BasicTemplateAppPackage)) 323 324 appPackage, err := s.SaveFromAppPackage(appPackageReader, root, "appName", nil, BasicTemplateAppPackageFormat, "json", false) 325 So(err, ShouldBeNil) 326 So(appPackage, ShouldNotBeNil) 327 So(appPackage.Version, ShouldEqual, AppPackageVersion) 328 So(appPackage.DNA.Name, ShouldEqual, "appName") 329 So(DirExists(root), ShouldBeTrue) 330 So(DirExists(root, ChainDNADir), ShouldBeTrue) 331 So(DirExists(root, ChainUIDir), ShouldBeTrue) 332 So(DirExists(root, ChainTestDir), ShouldBeTrue) 333 So(DirExists(root, ChainTestDir, appPackage.Scenarios[0].Name), ShouldBeTrue) 334 So(FileExists(root, ChainTestDir, appPackage.Scenarios[0].Name, appPackage.Scenarios[0].Roles[0].Name+".json"), ShouldBeTrue) 335 So(FileExists(root, ChainTestDir, appPackage.Scenarios[0].Name, appPackage.Scenarios[0].Roles[1].Name+".json"), ShouldBeTrue) 336 So(FileExists(root, ChainTestDir, appPackage.Scenarios[0].Name, "_config.json"), ShouldBeTrue) 337 338 So(DirExists(root, ChainDNADir, "sampleZome"), ShouldBeTrue) 339 So(FileExists(root, ChainDNADir, "sampleZome", "sampleEntry.json"), ShouldBeTrue) 340 So(FileExists(root, ChainDNADir, "sampleZome", "sampleZome.js"), ShouldBeTrue) 341 So(FileExists(root, ChainDNADir, DNAFileName+".json"), ShouldBeTrue) 342 So(FileExists(root, ChainDNADir, "properties_schema.json"), ShouldBeTrue) 343 So(FileExists(root, ChainTestDir, "sample.json"), ShouldBeTrue) 344 So(FileExists(root, ChainUIDir, "index.html"), ShouldBeTrue) 345 So(FileExists(root, ChainUIDir, "hc.js"), ShouldBeTrue) 346 So(FileExists(root, AgentFileName), ShouldBeTrue) 347 So(FileExists(root, PrivKeyFileName), ShouldBeTrue) 348 }) 349 350 Convey("it should write out a appPackage file to a directory tree with toml encoding", t, func() { 351 appPackageReader := bytes.NewBuffer([]byte(BasicTemplateAppPackage)) 352 353 root2 := filepath.Join(s.Path, name+"2") 354 355 appPackage, err := s.SaveFromAppPackage(appPackageReader, root2, "appName", nil, BasicTemplateAppPackageFormat, "toml", false) 356 So(err, ShouldBeNil) 357 So(appPackage, ShouldNotBeNil) 358 So(appPackage.Version, ShouldEqual, AppPackageVersion) 359 So(DirExists(root2), ShouldBeTrue) 360 So(FileExists(root2, ChainDNADir, DNAFileName+".toml"), ShouldBeTrue) 361 // the reset of the files are still saved as json... 362 }) 363 364 Convey("it should write out a appPackage file to a directory tree with binary UI files", t, func() { 365 appPackageReader := bytes.NewBuffer([]byte(TestingAppAppPackage())) 366 367 _, err := s.SaveFromAppPackage(appPackageReader, root+"3", "appName2", nil, TestingAppDecodingFormat, "json", false) 368 root3 := filepath.Join(s.Path, name+"3") 369 370 So(err, ShouldBeNil) 371 So(DirExists(root3, ChainUIDir), ShouldBeTrue) 372 So(FileExists(root3, ChainUIDir, "index.html"), ShouldBeTrue) 373 So(FileExists(root3, ChainUIDir, "logo.png"), ShouldBeTrue) 374 }) 375 376 } 377 378 func TestMakeConfig(t *testing.T) { 379 d, s := setupTestService() 380 defer CleanupTestDir(d) 381 h := &Holochain{encodingFormat: "json", rootPath: d} 382 Convey("make config should produce default values", t, func() { 383 err := makeConfig(h, s) 384 So(err, ShouldBeNil) 385 So(h.Config.DHTPort, ShouldEqual, DefaultDHTPort) 386 So(h.Config.EnableMDNS, ShouldBeTrue) 387 So(h.Config.BootstrapServer, ShouldNotEqual, "") 388 So(h.Config.Loggers.App.Format, ShouldEqual, "%{color:cyan}%{message}") 389 390 }) 391 392 Convey("make config should produce default config from OS env overridden values", t, func() { 393 os.Setenv("HOLOCHAINCONFIG_DHTPORT", "12345") 394 os.Setenv("HOLOCHAINCONFIG_ENABLEMDNS", "false") 395 os.Setenv("HCLOG_PREFIX", "prefix:%{color:cyan}") 396 os.Setenv("HOLOCHAINCONFIG_BOOTSTRAP", "_") 397 err := makeConfig(h, s) 398 So(err, ShouldBeNil) 399 400 So(h.Config.DHTPort, ShouldEqual, 12345) 401 So(h.Config.EnableMDNS, ShouldBeFalse) 402 So(h.Config.Loggers.App.Format, ShouldEqual, "%{color:cyan}%{message}") 403 So(h.Config.Loggers.App.Prefix, ShouldEqual, "prefix:") 404 So(h.Config.Loggers.App.PrefixColor, ShouldEqual, h.Config.Loggers.App.GetColor("cyan")) 405 So(h.Config.BootstrapServer, ShouldEqual, "") 406 }) 407 } 408 409 func TestMakeAppPackage(t *testing.T) { 410 d, s := setupTestService() 411 defer CleanupTestDir(d) 412 name := "test" 413 root := filepath.Join(s.Path, name) 414 h, err := s.MakeTestingApp(root, "json", InitializeDB, CloneWithNewUUID, nil) 415 if err != nil { 416 panic(err) 417 } 418 Convey("make appPackage should produce a appPackage file for holochain", t, func() { 419 packageBlob, err := s.MakeAppPackage(h) 420 So(err, ShouldBeNil) 421 appPackageReader := bytes.NewBuffer(packageBlob) 422 if err != nil { 423 panic(err) 424 } 425 root = filepath.Join(s.Path, "appFromAppPackage") 426 appPackage, err := s.SaveFromAppPackage(appPackageReader, root, "appFromAppPackage", nil, "json", "json", false) 427 So(err, ShouldBeNil) 428 So(appPackage, ShouldNotBeNil) 429 So(appPackage.Version, ShouldEqual, AppPackageVersion) 430 So(appPackage.DNA.Name, ShouldEqual, "appFromAppPackage") 431 432 So(DirExists(root), ShouldBeTrue) 433 So(DirExists(root, ChainDNADir), ShouldBeTrue) 434 So(DirExists(root, ChainUIDir), ShouldBeTrue) 435 So(DirExists(root, ChainTestDir), ShouldBeTrue) 436 So(DirExists(root, ChainTestDir, appPackage.Scenarios[0].Name), ShouldBeTrue) 437 So(FileExists(root, ChainTestDir, appPackage.Scenarios[0].Name, appPackage.Scenarios[0].Roles[0].Name+".json"), ShouldBeTrue) 438 So(FileExists(root, ChainTestDir, appPackage.Scenarios[0].Name, appPackage.Scenarios[0].Roles[1].Name+".json"), ShouldBeTrue) 439 So(FileExists(root, ChainTestDir, appPackage.Scenarios[0].Name, TestConfigFileName), ShouldBeTrue) 440 441 So(DirExists(root, ChainDNADir, "jsSampleZome"), ShouldBeTrue) 442 So(FileExists(root, ChainDNADir, "jsSampleZome", "profile.json"), ShouldBeTrue) 443 So(FileExists(root, ChainDNADir, "jsSampleZome", "jsSampleZome.js"), ShouldBeTrue) 444 So(FileExists(root, ChainDNADir, DNAFileName+".json"), ShouldBeTrue) 445 So(FileExists(root, ChainDNADir, "properties_schema.json"), ShouldBeTrue) 446 So(FileExists(root, ChainTestDir, "testSet1.json"), ShouldBeTrue) 447 So(FileExists(root, ChainTestDir, "testSet1.json"), ShouldBeTrue) 448 So(FileExists(root, ChainUIDir, "index.html"), ShouldBeTrue) 449 So(FileExists(root, ChainUIDir, "hc.js"), ShouldBeTrue) 450 So(FileExists(root, ChainUIDir, "logo.png"), ShouldBeTrue) 451 }) 452 } 453 454 func TestLoadTestFiles(t *testing.T) { 455 d, _, h := SetupTestChain("test") 456 defer CleanupTestChain(h, d) 457 458 Convey("it should fail if there's no test data", t, func() { 459 tests, err := LoadTestFiles(d) 460 So(tests, ShouldBeNil) 461 So(err.Error(), ShouldEqual, "no test files found in: "+d) 462 }) 463 464 Convey("it should load test files", t, func() { 465 path := h.TestPath() 466 tests, err := LoadTestFiles(path) 467 So(err, ShouldBeNil) 468 So(len(tests), ShouldEqual, 2) 469 So(tests["testSet1"].Identity, ShouldEqual, "123-456-7890") 470 }) 471 } 472 473 func TestGetScenarioData(t *testing.T) { 474 d, _, h := SetupTestChain("test") 475 defer CleanupTestChain(h, d) 476 Convey("it should return list of scenarios", t, func() { 477 scenarios, err := GetTestScenarios(h) 478 So(err, ShouldBeNil) 479 _, ok := scenarios["sampleScenario"] 480 So(ok, ShouldBeTrue) 481 _, ok = scenarios["foo"] 482 So(ok, ShouldBeFalse) 483 }) 484 Convey("it should return list of scenarios in a role", t, func() { 485 scenarios, err := GetTestScenarioRoles(h, "sampleScenario") 486 So(err, ShouldBeNil) 487 So(fmt.Sprintf("%v", scenarios), ShouldEqual, `[listener speaker]`) 488 }) 489 }