func TestRenameAction(t *testing.T) { testExist(t, newName, false) testExist(t, oldName, true) do := definitions.NowDo() do.Name = oldName do.NewName = newName log.WithFields(log.Fields{ "from": do.Name, "to": do.NewName, }).Info("Renaming action (from tests)") if err := RenameAction(do); err != nil { log.Error(err) t.Fail() } testExist(t, newName, true) testExist(t, oldName, false) do = definitions.NowDo() do.Name = newName do.NewName = oldName log.WithFields(log.Fields{ "from": do.Name, "to": do.NewName, }).Info("Renaming action (from tests)") if err := RenameAction(do); err != nil { log.Error(err) t.Fail() } testExist(t, newName, false) testExist(t, oldName, true) }
func TestNewService(t *testing.T) { do := def.NowDo() servName := "keys" do.Name = servName do.Operations.Args = []string{"quay.io/eris/keys"} log.WithFields(log.Fields{ "=>": do.Name, "args": do.Operations.Args, }).Debug("Creating a new service (from tests)") e := NewService(do) if e != nil { log.Error(e) tests.IfExit(e) } do = def.NowDo() do.Operations.Args = []string{servName} log.WithFields(log.Fields{ "container number": do.Operations.ContainerNumber, "args": do.Operations.Args, }).Debug("Starting service (from tests)") e = StartService(do) if e != nil { log.Error(e) tests.IfExit(e) } testExistAndRun(t, servName, 1, true, true) testNumbersExistAndRun(t, servName, 1, 1) testKillService(t, servName, true) testExistAndRun(t, servName, 1, false, false) }
func TestKillRmService(t *testing.T) { testStartService(t, servName, false) do := def.NowDo() do.Name = servName do.Rm = false do.RmD = false do.Operations.Args = []string{servName} log.WithField("=>", servName).Debug("Stopping service (from tests)") if e := KillService(do); e != nil { log.Error(e) tests.IfExit(e) } testExistAndRun(t, servName, 1, true, false) testNumbersExistAndRun(t, servName, 1, 0) if os.Getenv("TEST_IN_CIRCLE") == "true" { log.Warn("Testing in Circle where we don't have rm privileges. Skipping test") return } do = def.NowDo() do.Name = servName do.Operations.Args = []string{servName} do.File = false do.RmD = true log.WithField("=>", servName).Debug("Removing service (from tests)") if e := RmService(do); e != nil { log.Error(e) tests.IfExit(e) } testExistAndRun(t, servName, 1, false, false) testNumbersExistAndRun(t, servName, 0, 0) }
func TestLoadServiceDefinition(t *testing.T) { var e error srv, e = loaders.LoadServiceDefinition(servName, true, 1) if e != nil { log.Error(e) tests.IfExit(e) } if srv.Name != servName { log.WithFields(log.Fields{ "expected": servName, "got": srv.Name, }).Error("Improper name on load") } if srv.Service.Name != servName { log.WithFields(log.Fields{ "expected": servName, "got": srv.Service.Name, }).Error("Improper service name on load") tests.IfExit(e) } if !srv.Service.AutoData { log.Error("data_container not properly read on load") tests.IfExit(e) } if srv.Operations.DataContainerName == "" { log.Error("data_container_name not set") tests.IfExit(e) } }
//creates a new data container w/ dir to be used by a test //maybe give create opts? => paths, files, file contents, etc func testCreateDataByImport(t *testing.T, name string) { newDataDir := filepath.Join(common.DataContainersPath, name) if err := os.MkdirAll(newDataDir, 0777); err != nil { log.Error(err) t.FailNow() os.Exit(1) } f, err := os.Create(filepath.Join(newDataDir, "test")) if err != nil { log.Error(err) t.FailNow() os.Exit(1) } defer f.Close() do := definitions.NowDo() do.Name = name do.Source = filepath.Join(common.DataContainersPath, do.Name) do.Destination = common.ErisContainerRoot do.Operations.ContainerNumber = 1 log.WithField("=>", do.Name).Info("Importing data (from tests)") if err := ImportData(do); err != nil { log.Error(err) t.Fail() } testExist(t, name, true) }
func TestInspectData(t *testing.T) { testCreateDataByImport(t, dataName) defer testKillDataCont(t, dataName) do := definitions.NowDo() do.Name = dataName do.Operations.Args = []string{"name"} do.Operations.ContainerNumber = 1 log.WithFields(log.Fields{ "data container": do.Name, "args": do.Operations.Args, }).Info("Inspecting data (from tests)") if err := InspectData(do); err != nil { log.Error(err) t.FailNow() } do = definitions.NowDo() do.Name = dataName do.Operations.Args = []string{"config.network_disabled"} do.Operations.ContainerNumber = 1 log.WithFields(log.Fields{ "data container": do.Name, "args": do.Operations.Args, }).Info("Inspecting data (from tests)") if err := InspectData(do); err != nil { log.Error(err) t.Fail() } }
func IfExit(err error) { if err != nil { log.Error(err) if err := TestsTearDown(); err != nil { log.Error(err) } os.Exit(1) } }
//copied from testutils func ifExit(err error) { if err != nil { log.Error(err) if err := testsTearDown(); err != nil { log.Error(err) } // log.Flush() os.Exit(1) } }
// TODO: skip errors flag func RmData(do *definitions.Do) (err error) { if len(do.Operations.Args) == 0 { do.Operations.Args = []string{do.Name} } for _, name := range do.Operations.Args { do.Name = name if util.IsDataContainer(do.Name, do.Operations.ContainerNumber) { log.WithField("=>", do.Name).Info("Removing data container") srv := definitions.BlankServiceDefinition() srv.Operations.SrvContainerName = util.ContainersName("data", do.Name, do.Operations.ContainerNumber) if err = perform.DockerRemove(srv.Service, srv.Operations, false, do.Volumes); err != nil { log.Errorf("Error removing %s: %v", do.Name, err) return err } } else { err = fmt.Errorf("I cannot find that data container for %s. Please check the data container name you sent me.", do.Name) log.Error(err) return err } if do.RmHF { log.WithField("=>", do.Name).Warn("Removing host directory") if err = os.RemoveAll(filepath.Join(DataContainersPath, do.Name)); err != nil { return err } } } do.Result = "success" return err }
func ifExit(err error) { if err != nil { log.Error(err) testsTearDown() os.Exit(1) } }
func TestRemoveAction(t *testing.T) { do := definitions.NowDo() do.Operations.Args = strings.Fields(oldName) do.File = true if err := RmAction(do); err != nil { log.Error(err) t.Fail() } testExist(t, oldName, false) }
func TestDoAction(t *testing.T) { do := definitions.NowDo() do.Operations.Args = strings.Fields(actionName) do.Quiet = true log.WithField("args", do.Operations.Args).Info("Performing action (from tests)") if err := Do(do); err != nil { log.Error(err) t.Fail() } }
func TestNewAction(t *testing.T) { do := definitions.NowDo() do.Operations.Args = strings.Fields(oldName) log.WithField("args", do.Operations.Args).Info("New action (from tests)") if err := NewAction(do); err != nil { log.Error(err) t.Fail() } testExist(t, oldName, true) }
func testStartChain(t *testing.T, chain string) { do := def.NowDo() do.Name = chain do.Operations.ContainerNumber = 1 do.Operations.PublishAllPorts = true log.WithField("=>", do.Name).Info("Starting chain (from tests)") if e := StartChain(do); e != nil { log.Error(e) tests.IfExit(nil) } testExistAndRun(t, chain, true, true) }
func TestListDataContainers(t *testing.T) { dataName1 := fmt.Sprintf("%s%s", dataName, "one") dataName2 := fmt.Sprintf("%s%s", dataName, "two") datas := make(map[string]bool) datas[dataName] = true datas[dataName1] = true datas[dataName2] = true testCreateDataByImport(t, dataName) testCreateDataByImport(t, dataName1) testCreateDataByImport(t, dataName2) defer testKillDataCont(t, dataName) defer testKillDataCont(t, dataName1) defer testKillDataCont(t, dataName2) do := definitions.NowDo() do.Quiet = true if err := list.ListDatas(do); err != nil { log.Error(err) t.FailNow() } output := strings.Split(do.Result, "\n") i := 0 for _, out := range output { if datas[util.TrimString(out)] == true { i++ } } if i != 3 { log.Error(fmt.Errorf("Expected 3 data containers, got (%v)\n", i)) t.Fail() } }
func TestRenameData(t *testing.T) { testCreateDataByImport(t, dataName) defer testKillDataCont(t, dataName) testExist(t, dataName, true) testExist(t, newName, false) do := definitions.NowDo() do.Name = dataName do.NewName = newName do.Operations.ContainerNumber = 1 log.WithFields(log.Fields{ "from": do.Name, "to": do.NewName, }).Info("Renaming data (from tests)") if err := RenameData(do); err != nil { log.Error(err) t.FailNow() } testExist(t, dataName, false) testExist(t, newName, true) do = definitions.NowDo() do.Name = newName do.NewName = dataName do.Operations.ContainerNumber = 1 log.WithFields(log.Fields{ "from": do.Name, "to": do.NewName, }).Info("Renaming data (from tests)") if err := RenameData(do); err != nil { log.Error(err) t.FailNow() } testExist(t, dataName, true) testExist(t, newName, false) }
func testKillDataCont(t *testing.T, name string) { testCreateDataByImport(t, name) testExist(t, name, true) do := definitions.NowDo() do.Name = name do.Operations.ContainerNumber = 1 if err := RmData(do); err != nil { log.Error(err) t.Fail() } testExist(t, name, false) }
// TODO: this isn't actually testing much! func TestExecChain(t *testing.T) { testStartChain(t, chainName) defer testKillChain(t, chainName) do := def.NowDo() do.Name = chainName do.Operations.Args = strings.Fields("ls -la /home/eris/.eris") do.Operations.Interactive = false log.WithField("=>", do.Name).Info("Executing chain (from tests)") e := ExecChain(do) if e != nil { log.Error(e) t.Fail() } }
func PrintTableReport(typ string, existing, all bool) (string, error) { log.WithField("type", typ).Debug("Table report initialized") var conts []*util.ContainerName if !all { conts = util.ErisContainersByType(typ, existing) } // "MACHINE" is placeholder header := []string{"NAME", "MACHINE", "RUNNING", "CONTAINER NAME", "PORTS"} if err := util.CheckParts(header); err != nil { log.Error(err) // err is silenced by some funcs return "", err } buf := new(bytes.Buffer) table := tablewriter.NewWriter(buf) //name set by logger instead table.SetHeader(header) if all { //get all the things parts, _ := AssembleTable(typ) for _, p := range parts { table.Append(formatLine(p)) } } else { for _, c := range conts { n, _ := PrintLineByContainerName(c.FullName, existing) if typ == "chain" { head, _ := util.GetHead() if n[0] == head { n[0] = fmt.Sprintf("** %s", n[0]) } } table.Append(n) } } // Styling table.SetBorder(false) table.SetCenterSeparator(" ") table.SetColumnSeparator(" ") table.SetRowSeparator("-") table.SetAlignment(tablewriter.ALIGN_LEFT) table.Render() return buf.String(), nil }
func formatLine(p Parts) []string { var running string if p.Running { running = "Yes" } else { running = "No" } //must match header part := []string{p.ShortName, "", running, p.FullName, p.PortsOutput} if err := util.CheckParts(part); err != nil { log.Error(err) return []string{} } return part }
func TestLogsService(t *testing.T) { testStartService(t, servName, false) defer testKillService(t, servName, true) do := def.NowDo() do.Name = servName do.Follow = false do.Tail = "5" log.WithFields(log.Fields{ "=>": servName, "tail": do.Tail, }).Debug("Inspect logs (from tests)") e := LogsService(do) if e != nil { log.Error(e) tests.IfExit(e) } }
func testKillService(t *testing.T, serviceName string, wipe bool) { log.WithField("=>", serviceName).Debug("Stopping service (from tests)") do := def.NowDo() do.Name = serviceName do.Operations.Args = []string{serviceName} if wipe { do.Rm = true do.RmD = true } e := srv.KillService(do) if e != nil { log.Error(e) fatal(t, e) } testExistAndRun(t, serviceName, 1, !wipe, false) testNumbersExistAndRun(t, serviceName, 0, 0) }
func TestExecService(t *testing.T) { testStartService(t, servName, true) defer testKillService(t, servName, true) do := def.NowDo() do.Name = servName do.Operations.Interactive = false do.Operations.Args = strings.Fields("ls -la /root/") log.WithFields(log.Fields{ "=>": servName, "args": do.Operations.Args, }).Debug("Executing service (from tests)") e := ExecService(do) if e != nil { log.Error(e) t.Fail() } }
func testKillDataCont(t *testing.T, name string) { if os.Getenv("TEST_IN_CIRCLE") == "true" { log.Warn("Testing in Circle. Where we don't have rm privileges. Skipping test") return } testCreateDataByImport(t, name) testExist(t, name, true) do := definitions.NowDo() do.Name = name do.Operations.ContainerNumber = 1 if err := RmData(do); err != nil { log.Error(err) t.Fail() } testExist(t, name, false) }
func TestExportData(t *testing.T) { testCreateDataByImport(t, dataName) defer testKillDataCont(t, dataName) do := definitions.NowDo() do.Name = dataName do.Source = common.ErisContainerRoot do.Destination = filepath.Join(common.DataContainersPath, do.Name) do.Operations.ContainerNumber = 1 if err := ExportData(do); err != nil { log.Error(err) t.FailNow() } if _, err := os.Stat(filepath.Join(common.DataContainersPath, dataName, "test")); os.IsNotExist(err) { log.Errorf("Tragic! Exported file does not exist: %s", err) t.Fail() } }
func TestPlopChain(t *testing.T) { cfgFilePath := filepath.Join(common.ChainsPath, "default", "config.toml") do := def.NowDo() do.ConfigFile = cfgFilePath do.Name = chainName do.Operations.ContainerNumber = 1 do.Operations.PublishAllPorts = true log.WithField("=>", chainName).Info("Creating chain (from tests)") tests.IfExit(NewChain(do)) defer testKillChain(t, chainName) do = def.NowDo() do.Type = "config" do.ChainID = chainName newWriter := new(bytes.Buffer) config.GlobalConfig.Writer = newWriter e := PlopChain(do) if e != nil { log.Error(e) t.Fail() } cfgFile, err := ioutil.ReadFile(cfgFilePath) tests.IfExit(err) cfgFilePlop := newWriter.Bytes() // remove [13] that shows up everywhere ... cfgFile = bytes.Replace(cfgFile, []byte{13}, []byte{}, -1) cfgFilePlop = bytes.Replace(cfgFilePlop, []byte{13}, []byte{}, -1) if !bytes.Equal(cfgFile, cfgFilePlop) { log.Errorf("Error: Got: %s. Expected: %s", cfgFilePlop, cfgFile) log.WithFields(log.Fields{ "got": cfgFilePlop, "expected": cfgFile, }).Error("Error comparing config files") t.Fail() } }
func TestExecData(t *testing.T) { testCreateDataByImport(t, dataName) defer testKillDataCont(t, dataName) do := definitions.NowDo() do.Name = dataName do.Operations.Args = []string{"mv", "/home/eris/.eris/test", "/home/eris/.eris/tset"} do.Operations.Interactive = false do.Operations.ContainerNumber = 1 log.WithFields(log.Fields{ "data container": do.Name, "args": do.Operations.Args, }).Info("Executing data (from tests)") if err := ExecData(do); err != nil { log.Error(err) t.Fail() } //TODO check that the file was actually moved! (TestExport _used_ todo that) }
func TestUpdateService(t *testing.T) { testStartService(t, servName, false) defer testKillService(t, servName, true) if os.Getenv("TEST_IN_CIRCLE") == "true" { log.Warn("Testing in Circle where we don't have rm privileges. Skipping test") return } do := def.NowDo() do.Name = servName do.Pull = false do.Timeout = 1 log.WithField("=>", servName).Debug("Update service (from tests)") e := UpdateService(do) if e != nil { log.Error(e) tests.IfExit(e) } testExistAndRun(t, servName, 1, true, true) testNumbersExistAndRun(t, servName, 1, 1) }
// DockerExecService creates and runs a chain or a service container interactively. // // ops.Args - command line parameters // ops.Interactive - if true, set Entrypoint to ops.Args, // if false, set Cmd to ops.Args // // See parameter description for DockerRunService. func DockerExecService(srv *def.Service, ops *def.Operation) error { log.WithField("=>", ops.SrvContainerName).Info("Executing container") optsServ := configureInteractiveContainer(srv, ops) // Fix volume paths. var err error srv.Volumes, err = util.FixDirs(srv.Volumes) if err != nil { return err } // Setup data container. log.WithField("autodata", srv.AutoData).Info("Manage data containers?") if srv.AutoData { optsData, err := configureDataContainer(srv, ops, &optsServ) if err != nil { return err } if _, exists := util.ParseContainers(ops.DataContainerName, true); exists { log.Info("Data container already exists, am not creating") } else { log.Info("Data container does not exist. Creating") _, err := createContainer(optsData) if err != nil { return err } } } log.WithField("image", srv.Image).Debug("Container does not exist. Creating") _, err = createContainer(optsServ) if err != nil { return err } defer func() { log.WithField("=>", optsServ.Name).Info("Removing container") if err := removeContainer(optsServ.Name, false, false); err != nil { log.WithField("=>", optsServ.Name).Error("Tragic! Error removing data container after executing") log.Error(err) } log.WithField("=>", optsServ.Name).Info("Container removed") }() // Start the container. log.WithFields(log.Fields{ "=>": optsServ.Name, "data container": ops.DataContainerName, "entrypoint": optsServ.Config.Entrypoint, "cmd": optsServ.Config.Cmd, "ports published": optsServ.HostConfig.PublishAllPorts, "environment": optsServ.Config.Env, "image": optsServ.Config.Image, "user": optsServ.Config.User, "vols": optsServ.HostConfig.Binds, }).Info("Executing interactive container") if err := startInteractiveContainer(optsServ); err != nil { return err } return nil }
//------------------------------------------------------------------------ func startChain(do *definitions.Do, exec bool) error { chain, err := loaders.LoadChainDefinition(do.Name, false, do.Operations.ContainerNumber) if err != nil { log.Error("Cannot start a chain I cannot find") do.Result = "no file" return nil } if chain.Name == "" { log.Error("Cannot start a chain without a name") do.Result = "no name" return nil } // boot the dependencies (eg. keys, logsrotate) if err := bootDependencies(chain, do); err != nil { return err } chain.Service.Command = loaders.ErisChainStart util.Merge(chain.Operations, do.Operations) chain.Service.Environment = append(chain.Service.Environment, "CHAIN_ID="+chain.ChainID) chain.Service.Environment = append(chain.Service.Environment, do.Env...) if do.Run { chain.Service.Environment = append(chain.Service.Environment, "ERISDB_API=true") } chain.Service.Links = append(chain.Service.Links, do.Links...) log.WithField("=>", chain.Service.Name).Info("Starting a chain") log.WithFields(log.Fields{ "chain container": chain.Operations.SrvContainerName, "environment": chain.Service.Environment, "ports published": chain.Operations.PublishAllPorts, }).Debug() if exec { if do.Image != "" { chain.Service.Image = do.Image } chain.Operations.Args = do.Operations.Args log.WithFields(log.Fields{ "args": chain.Operations.Args, "interactive": chain.Operations.Interactive, }).Debug() // This override is necessary because erisdb uses an entryPoint and // the perform package will respect the images entryPoint if it // exists. chain.Service.EntryPoint = "" chain.Service.Command = "" // there is literally never a reason not to randomize the ports. chain.Operations.PublishAllPorts = true // always link the chain to the exec container when doing chains exec // so that there is never any problems with sending info to the service (chain) container chain.Service.Links = append(chain.Service.Links, fmt.Sprintf("%s:%s", util.ContainersName("chain", chain.Name, 1), "chain")) err = perform.DockerExecService(chain.Service, chain.Operations) } else { err = perform.DockerRunService(chain.Service, chain.Operations) } if err != nil { do.Result = "error" return err } return nil }