func TestLocalScript(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("shell command test doesn't make sense on windows") } Convey("When running local commands in script mode", t, func() { Convey("A multi-line script should run all lines", func() { stdout := &CacheLastWritten{} workingDir, err := filepath.Abs(evergreen.FindEvergreenHome()) So(err, ShouldBeNil) command := &LocalCommand{ CmdString: "set -v\necho 'hi'\necho 'foo'\necho `pwd`", ScriptMode: true, Stdout: stdout, Stderr: ioutil.Discard, WorkingDirectory: workingDir, } // run the command - the working directory should be as specified So(command.Run(), ShouldBeNil) reportedPwd := string(stdout.LastWritten) reportedPwd = reportedPwd[:len(reportedPwd)-1] reportedPwd, err = filepath.EvalSymlinks(reportedPwd) So(err, ShouldBeNil) So(reportedPwd, ShouldEqual, workingDir) }) }) }
func TestLocalScript(t *testing.T) { Convey("When running local commands in script mode", t, func() { Convey("A multi-line script should run all lines", func() { stdout := &CacheLastWritten{} evgHome := evergreen.FindEvergreenHome() workingDir := filepath.Join(evgHome, "command/testdata") command := &LocalCommand{ CmdString: "set -v\necho 'hi'\necho 'foo'\necho `pwd`", ScriptMode: true, Stdout: stdout, Stderr: ioutil.Discard, WorkingDirectory: workingDir, } // run the command - the working directory should be as specified So(command.Run(), ShouldBeNil) So(string(stdout.LastWritten), ShouldEqual, workingDir+"\n") }) }) }
func main() { settings := evergreen.GetSettingsOrExit() if settings.Ui.LogFile != "" { evergreen.SetLogger(settings.Ui.LogFile) } db.SetGlobalSessionProvider(db.SessionFactoryFromConfig(settings)) home := evergreen.FindEvergreenHome() userManager, err := auth.LoadUserManager(settings.AuthConfig) if err != nil { fmt.Println("Failed to create user manager:", err) os.Exit(1) } cookieStore := sessions.NewCookieStore([]byte(settings.Ui.Secret)) uis := ui.UIServer{ nil, // render settings.Ui.Url, // RootURL userManager, // User Manager *settings, // mci settings cookieStore, // cookiestore nil, // plugin panel manager } router, err := uis.NewRouter() if err != nil { fmt.Println("Failed to create router:", err) os.Exit(1) } webHome := filepath.Join(home, "public") functionOptions := ui.FuncOptions{webHome, settings.Ui.HelpUrl, true, router} functions, err := ui.MakeTemplateFuncs(functionOptions, settings.SuperUsers) if err != nil { fmt.Println("Failed to create template function map:", err) os.Exit(1) } uis.Render = render.New(render.Options{ Directory: filepath.Join(home, ui.WebRootPath, ui.Templates), DisableCache: !settings.Ui.CacheTemplates, Funcs: functions, }) err = uis.InitPlugins() if err != nil { fmt.Println("WARNING: Error initializing plugins:", err) } n := negroni.New() n.Use(negroni.NewStatic(http.Dir(webHome))) n.Use(ui.NewLogger()) n.Use(negroni.HandlerFunc(ui.UserMiddleware(userManager))) n.UseHandler(router) graceful.Run(settings.Ui.HttpListenAddr, requestTimeout, n) evergreen.Logger.Logf(slogger.INFO, "UI server cleanly terminated") }
// Run loops while there are any unprocessed alerts and attempts to deliver them. func (qp *QueueProcessor) Run(config *evergreen.Settings) error { evergreen.Logger.Logf(slogger.INFO, "Starting alert queue processor run") home := evergreen.FindEvergreenHome() qp.config = config qp.render = render.New(render.Options{ Directory: filepath.Join(home, "alerts", "templates"), DisableCache: !config.Ui.CacheTemplates, TextFuncs: nil, HtmlFuncs: nil, }) if len(qp.config.SuperUsers) == 0 { evergreen.Logger.Logf(slogger.WARN, "WARNING: No superusers configured, some alerts may have no recipient") } superUsers, err := user.Find(user.ByIds(qp.config.SuperUsers...)) if err != nil { evergreen.Logger.Logf(slogger.ERROR, "Error getting superuser list: %v", err) return err } qp.superUsersConfigs = []model.AlertConfig{} for _, u := range superUsers { qp.superUsersConfigs = append(qp.superUsersConfigs, model.AlertConfig{"email", bson.M{"rcpt": u.Email()}}) } evergreen.Logger.Logf(slogger.INFO, "Super-users config for outgoing alerts is: %#v", qp.superUsersConfigs) evergreen.Logger.Logf(slogger.INFO, "Running alert queue processing") for { nextAlert, err := alert.DequeueAlertRequest() if err != nil { evergreen.Logger.Logf(slogger.ERROR, "Failed to dequeue alert request: %v", err) return err } if nextAlert == nil { evergreen.Logger.Logf(slogger.INFO, "Reached end of queue items - stopping.") break } evergreen.Logger.Logf(slogger.DEBUG, "Processing queue item %v", nextAlert.Id.Hex()) alertContext, err := qp.loadAlertContext(nextAlert) if err != nil { evergreen.Logger.Logf(slogger.ERROR, "Failed to load alert context: %v", err) return err } evergreen.Logger.Logf(slogger.DEBUG, "Delivering queue item %v", nextAlert.Id.Hex()) err = qp.Deliver(nextAlert, alertContext) if err != nil { evergreen.Logger.Logf(slogger.ERROR, "Got error delivering message: %v", err) } } evergreen.Logger.Logf(slogger.INFO, "Finished alert queue processor run.") return nil }
func NewTaskRunner(settings *evergreen.Settings) *TaskRunner { // get mci home, and set the source and destination for the agent // executables evgHome := evergreen.FindEvergreenHome() return &TaskRunner{ settings, &DBHostFinder{}, &DBTaskQueueFinder{}, &AgentBasedHostGateway{ ExecutablesDir: filepath.Join(evgHome, settings.AgentExecutablesDir), }, } }
func main() { settings := evergreen.GetSettingsOrExit() home := evergreen.FindEvergreenHome() uis, err := ui.New(settings, home) if err != nil { fmt.Println("Failed to create ui server: %v", err) os.Exit(1) } router, err := uis.NewRouter() if err != nil { fmt.Println("Failed to create router:", err) os.Exit(1) } webHome := filepath.Join(uis.Home, "public") functionOptions := ui.FuncOptions{webHome, uis.Settings.Ui.HelpUrl, true, router} functions, err := ui.MakeTemplateFuncs(functionOptions, uis.Settings.SuperUsers) htmlFunctions := htmlTemplate.FuncMap(functions) textFunctions := textTemplate.FuncMap(functions) if err != nil { fmt.Println("Failed to create template function map:", err) os.Exit(1) } uis.Render = render.New(render.Options{ Directory: filepath.Join(uis.Home, ui.WebRootPath, ui.Templates), DisableCache: !uis.Settings.Ui.CacheTemplates, HtmlFuncs: htmlFunctions, TextFuncs: textFunctions, }) err = uis.InitPlugins() if err != nil { fmt.Println("WARNING: Error initializing plugins:", err) } n := negroni.New() n.Use(negroni.NewStatic(http.Dir(webHome))) n.Use(ui.NewLogger()) n.Use(negroni.HandlerFunc(ui.UserMiddleware(uis.UserManager))) n.UseHandler(router) graceful.Run(uis.Settings.Ui.HttpListenAddr, requestTimeout, n) evergreen.Logger.Logf(slogger.INFO, "UI server cleanly terminated") }
// LocateCLIBinary returns the (absolute) path to the CLI binary for the given architecture, based // on the system settings. Returns an error if the file does not exist. func LocateCLIBinary(settings *evergreen.Settings, architecture string) (string, error) { clientsSubDir := "clients" if settings.ClientBinariesDir != "" { clientsSubDir = settings.ClientBinariesDir } var path string if filepath.IsAbs(clientsSubDir) { path = filepath.Join(clientsSubDir, architecture, "main") } else { path = filepath.Join(evergreen.FindEvergreenHome(), clientsSubDir, architecture, "main") } _, err := os.Stat(path) if err != nil { return path, err } return filepath.Abs(path) }
func createEnvironment(settings *evergreen.Settings, globals map[string]interface{}) (*web.App, error) { home := evergreen.FindEvergreenHome() templateHome := filepath.Join(home, TemplatePath) funcs, err := web.MakeCommonFunctionMap(settings) if err != nil { return nil, fmt.Errorf("error creating templating functions: %v", err) } // Overwrite globals funcs["Global"] = func(input string) interface{} { return globals[input] } app := web.NewApp() app.TemplateFuncs = funcs app.TemplateFolder = templateHome app.CacheTemplates = true return app, nil }
// Start the task specified, on the host specified. First runs any necessary // preparation on the remote machine, then kicks off the agent process on the // machine. // Returns an error if any step along the way fails. func (self *AgentBasedHostGateway) RunTaskOnHost(settings *evergreen.Settings, taskToRun model.Task, hostObj host.Host) (string, error) { // cache mci home evgHome := evergreen.FindEvergreenHome() // get the host's SSH options cloudHost, err := providers.GetCloudHost(&hostObj, settings) if err != nil { return "", fmt.Errorf("Failed to get cloud host for %v: %v", hostObj.Id, err) } sshOptions, err := cloudHost.GetSSHOptions() if err != nil { return "", fmt.Errorf("Error getting ssh options for host %v: %v", hostObj.Id, err) } // prep the remote host evergreen.Logger.Logf(slogger.INFO, "Prepping remote host %v...", hostObj.Id) agentRevision, err := self.prepRemoteHost(settings, hostObj, sshOptions, evgHome) if err != nil { return "", fmt.Errorf("error prepping remote host %v: %v", hostObj.Id, err) } evergreen.Logger.Logf(slogger.INFO, "Prepping host finished successfully") // start the agent on the remote machine evergreen.Logger.Logf(slogger.INFO, "Starting agent on host %v for task %v...", hostObj.Id, taskToRun.Id) err = self.startAgentOnRemote(settings, &taskToRun, &hostObj, sshOptions) if err != nil { return "", fmt.Errorf("error starting agent on %v for task %v: %v", hostObj.Id, taskToRun.Id, err) } evergreen.Logger.Logf(slogger.INFO, "Agent successfully started") return agentRevision, nil }
func TestGetVersionStatus(t *testing.T) { userManager, err := auth.LoadUserManager(versionTestConfig.AuthConfig) testutil.HandleTestingErr(err, t, "Failure in loading UserManager from config") uis := UIServer{ RootURL: versionTestConfig.Ui.Url, Settings: *versionTestConfig, UserManager: userManager, } home := evergreen.FindEvergreenHome() uis.Render = render.New(render.Options{ Directory: filepath.Join(home, WebRootPath, Templates), DisableCache: true, Funcs: nil, }) router, err := uis.NewRouter() testutil.HandleTestingErr(err, t, "Failure in uis.NewRouter()") Convey("When finding the status of a particular version", t, func() { testutil.HandleTestingErr(db.Clear(build.Collection), t, "Error clearing '%v' collection", build.Collection) versionId := "my-version" task := build.TaskCache{ Id: "some-task-id", DisplayName: "some-task-name", Status: "success", TimeTaken: time.Duration(100 * time.Millisecond), } build := &build.Build{ Id: "some-build-id", Version: versionId, BuildVariant: "some-build-variant", DisplayName: "Some Build Variant", Tasks: []build.TaskCache{task}, } So(build.Insert(), ShouldBeNil) Convey("grouped by tasks", func() { groupBy := "tasks" url, err := router.Get("version_status").URL("version_id", versionId) So(err, ShouldBeNil) query := url.Query() query.Set("groupby", groupBy) url.RawQuery = query.Encode() request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusOK) Convey("response should match contents of database", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) So(jsonBody["version_id"], ShouldEqual, versionId) _jsonTasks, ok := jsonBody["tasks"] So(ok, ShouldBeTrue) jsonTasks, ok := _jsonTasks.(map[string]interface{}) So(ok, ShouldBeTrue) So(len(jsonTasks), ShouldEqual, 1) _jsonTask, ok := jsonTasks[task.DisplayName] So(ok, ShouldBeTrue) jsonTask, ok := _jsonTask.(map[string]interface{}) So(ok, ShouldBeTrue) _jsonBuild, ok := jsonTask[build.BuildVariant] So(ok, ShouldBeTrue) jsonBuild, ok := _jsonBuild.(map[string]interface{}) So(ok, ShouldBeTrue) So(jsonBuild["task_id"], ShouldEqual, task.Id) So(jsonBuild["status"], ShouldEqual, task.Status) So(jsonBuild["time_taken"], ShouldEqual, task.TimeTaken) }) Convey("is the default option", func() { url, err := router.Get("version_status").URL("version_id", versionId) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) _response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(_response, request) So(_response, ShouldResemble, response) }) }) Convey("grouped by builds", func() { groupBy := "builds" url, err := router.Get("version_status").URL("version_id", versionId) So(err, ShouldBeNil) query := url.Query() query.Set("groupby", groupBy) url.RawQuery = query.Encode() request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusOK) Convey("response should match contents of database", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) So(jsonBody["version_id"], ShouldEqual, versionId) _jsonBuilds, ok := jsonBody["builds"] So(ok, ShouldBeTrue) jsonBuilds, ok := _jsonBuilds.(map[string]interface{}) So(ok, ShouldBeTrue) So(len(jsonBuilds), ShouldEqual, 1) _jsonBuild, ok := jsonBuilds[build.BuildVariant] So(ok, ShouldBeTrue) jsonBuild, ok := _jsonBuild.(map[string]interface{}) So(ok, ShouldBeTrue) _jsonTask, ok := jsonBuild[task.DisplayName] So(ok, ShouldBeTrue) jsonTask, ok := _jsonTask.(map[string]interface{}) So(ok, ShouldBeTrue) So(jsonTask["task_id"], ShouldEqual, task.Id) So(jsonTask["status"], ShouldEqual, task.Status) So(jsonTask["time_taken"], ShouldEqual, task.TimeTaken) }) }) Convey("grouped by an invalid option", func() { groupBy := "invalidOption" url, err := router.Get("version_status").URL("version_id", versionId) So(err, ShouldBeNil) query := url.Query() query.Set("groupby", groupBy) url.RawQuery = query.Encode() request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusBadRequest) var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) So(jsonBody["message"], ShouldEqual, fmt.Sprintf("Invalid groupby parameter '%v'", groupBy)) }) }) Convey("When finding the status of a nonexistent version", t, func() { versionId := "not-present" Convey("grouped by tasks", func() { groupBy := "tasks" url, err := router.Get("version_status").URL("version_id", versionId) So(err, ShouldBeNil) query := url.Query() query.Set("groupby", groupBy) url.RawQuery = query.Encode() request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusOK) Convey("response should contain a sensible error message", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) _jsonTasks, ok := jsonBody["tasks"] So(ok, ShouldBeTrue) jsonTasks, ok := _jsonTasks.(map[string]interface{}) So(ok, ShouldBeTrue) So(jsonTasks, ShouldBeEmpty) }) }) Convey("grouped by builds", func() { versionId := "not-present" groupBy := "builds" url, err := router.Get("version_status").URL("version_id", versionId) So(err, ShouldBeNil) query := url.Query() query.Set("groupby", groupBy) url.RawQuery = query.Encode() request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusOK) Convey("response should contain a sensible error message", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) _jsonBuilds, ok := jsonBody["builds"] So(ok, ShouldBeTrue) jsonBuilds, ok := _jsonBuilds.(map[string]interface{}) So(ok, ShouldBeTrue) So(jsonBuilds, ShouldBeEmpty) }) }) }) }
func TestGetTaskInfo(t *testing.T) { userManager, err := auth.LoadUserManager(taskTestConfig.AuthConfig) testutil.HandleTestingErr(err, t, "Failure in loading UserManager from config") uis := UIServer{ RootURL: taskTestConfig.Ui.Url, Settings: *taskTestConfig, UserManager: userManager, } home := evergreen.FindEvergreenHome() uis.Render = render.New(render.Options{ Directory: filepath.Join(home, WebRootPath, Templates), DisableCache: true, Funcs: nil, }) router, err := uis.NewRouter() testutil.HandleTestingErr(err, t, "Failure in uis.NewRouter()") Convey("When finding info on a particular task", t, func() { testutil.HandleTestingErr(db.Clear(model.TasksCollection), t, "Error clearing '%v' collection", model.TasksCollection) taskId := "my-task" versionId := "my-version" projectName := "project_test" testResult := model.TestResult{ Status: "success", TestFile: "some-test", URL: "some-url", StartTime: float64(time.Now().Add(-9 * time.Minute).Unix()), EndTime: float64(time.Now().Add(-1 * time.Minute).Unix()), } task := &model.Task{ Id: taskId, CreateTime: time.Now().Add(-20 * time.Minute), ScheduledTime: time.Now().Add(-15 * time.Minute), DispatchTime: time.Now().Add(-14 * time.Minute), StartTime: time.Now().Add(-10 * time.Minute), FinishTime: time.Now().Add(-5 * time.Second), PushTime: time.Now().Add(-1 * time.Millisecond), Version: versionId, Project: projectName, Revision: fmt.Sprintf("%x", rand.Int()), Priority: 10, LastHeartbeat: time.Now(), Activated: false, BuildId: "some-build-id", DistroId: "some-distro-id", BuildVariant: "some-build-variant", DependsOn: []model.Dependency{{"some-other-task", ""}}, DisplayName: "My task", HostId: "some-host-id", Restarts: 0, Execution: 0, Archived: false, RevisionOrderNumber: 42, Requester: evergreen.RepotrackerVersionRequester, Status: "success", Details: apimodels.TaskEndDetail{ TimedOut: false, Description: "some-stage", }, Aborted: false, TimeTaken: time.Duration(100 * time.Millisecond), ExpectedDuration: time.Duration(99 * time.Millisecond), TestResults: []model.TestResult{testResult}, MinQueuePos: 0, } So(task.Insert(), ShouldBeNil) file := artifact.File{ Name: "Some Artifact", Link: "some-url", } artifact := artifact.Entry{ TaskId: taskId, Files: []artifact.File{file}, } So(artifact.Upsert(), ShouldBeNil) url, err := router.Get("task_info").URL("task_id", taskId) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusOK) Convey("response should match contents of database", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) Println(string(response.Body.Bytes())) var rawJsonBody map[string]*json.RawMessage err = json.Unmarshal(response.Body.Bytes(), &rawJsonBody) So(err, ShouldBeNil) So(jsonBody["id"], ShouldEqual, task.Id) var createTime time.Time err = json.Unmarshal(*rawJsonBody["create_time"], &createTime) So(err, ShouldBeNil) So(createTime, ShouldHappenWithin, rest.TimePrecision, task.CreateTime) var scheduledTime time.Time err = json.Unmarshal(*rawJsonBody["scheduled_time"], &scheduledTime) So(err, ShouldBeNil) So(scheduledTime, ShouldHappenWithin, rest.TimePrecision, task.ScheduledTime) var dispatchTime time.Time err = json.Unmarshal(*rawJsonBody["dispatch_time"], &dispatchTime) So(err, ShouldBeNil) So(dispatchTime, ShouldHappenWithin, rest.TimePrecision, task.DispatchTime) var startTime time.Time err = json.Unmarshal(*rawJsonBody["start_time"], &startTime) So(err, ShouldBeNil) So(startTime, ShouldHappenWithin, rest.TimePrecision, task.StartTime) var finishTime time.Time err = json.Unmarshal(*rawJsonBody["finish_time"], &finishTime) So(err, ShouldBeNil) So(finishTime, ShouldHappenWithin, rest.TimePrecision, task.FinishTime) var pushTime time.Time err = json.Unmarshal(*rawJsonBody["push_time"], &pushTime) So(err, ShouldBeNil) So(pushTime, ShouldHappenWithin, rest.TimePrecision, task.PushTime) So(jsonBody["version"], ShouldEqual, task.Version) So(jsonBody["project"], ShouldEqual, task.Project) So(jsonBody["revision"], ShouldEqual, task.Revision) So(jsonBody["priority"], ShouldEqual, task.Priority) var lastHeartbeat time.Time err = json.Unmarshal(*rawJsonBody["last_heartbeat"], &lastHeartbeat) So(err, ShouldBeNil) So(lastHeartbeat, ShouldHappenWithin, rest.TimePrecision, task.LastHeartbeat) So(jsonBody["activated"], ShouldEqual, task.Activated) So(jsonBody["build_id"], ShouldEqual, task.BuildId) So(jsonBody["distro"], ShouldEqual, task.DistroId) So(jsonBody["build_variant"], ShouldEqual, task.BuildVariant) var dependsOn []model.Dependency So(rawJsonBody["depends_on"], ShouldNotBeNil) err = json.Unmarshal(*rawJsonBody["depends_on"], &dependsOn) So(err, ShouldBeNil) So(dependsOn, ShouldResemble, task.DependsOn) So(jsonBody["display_name"], ShouldEqual, task.DisplayName) So(jsonBody["host_id"], ShouldEqual, task.HostId) So(jsonBody["restarts"], ShouldEqual, task.Restarts) So(jsonBody["execution"], ShouldEqual, task.Execution) So(jsonBody["archived"], ShouldEqual, task.Archived) So(jsonBody["order"], ShouldEqual, task.RevisionOrderNumber) So(jsonBody["requester"], ShouldEqual, task.Requester) So(jsonBody["status"], ShouldEqual, task.Status) _jsonStatusDetails, ok := jsonBody["status_details"] So(ok, ShouldBeTrue) jsonStatusDetails, ok := _jsonStatusDetails.(map[string]interface{}) So(ok, ShouldBeTrue) So(jsonStatusDetails["timed_out"], ShouldEqual, task.Details.TimedOut) So(jsonStatusDetails["timeout_stage"], ShouldEqual, task.Details.Description) So(jsonBody["aborted"], ShouldEqual, task.Aborted) So(jsonBody["time_taken"], ShouldEqual, task.TimeTaken) So(jsonBody["expected_duration"], ShouldEqual, task.ExpectedDuration) _jsonTestResults, ok := jsonBody["test_results"] So(ok, ShouldBeTrue) jsonTestResults, ok := _jsonTestResults.(map[string]interface{}) So(ok, ShouldBeTrue) So(len(jsonTestResults), ShouldEqual, 1) _jsonTestResult, ok := jsonTestResults[testResult.TestFile] So(ok, ShouldBeTrue) jsonTestResult, ok := _jsonTestResult.(map[string]interface{}) So(ok, ShouldBeTrue) So(jsonTestResult["status"], ShouldEqual, testResult.Status) So(jsonTestResult["time_taken"], ShouldNotBeNil) // value correctness is unchecked _jsonTestResultLogs, ok := jsonTestResult["logs"] So(ok, ShouldBeTrue) jsonTestResultLogs, ok := _jsonTestResultLogs.(map[string]interface{}) So(ok, ShouldBeTrue) So(jsonTestResultLogs["url"], ShouldEqual, testResult.URL) So(jsonBody["min_queue_pos"], ShouldEqual, task.MinQueuePos) var jsonFiles []map[string]interface{} err = json.Unmarshal(*rawJsonBody["files"], &jsonFiles) So(err, ShouldBeNil) So(len(jsonFiles), ShouldEqual, 1) jsonFile := jsonFiles[0] So(jsonFile["name"], ShouldEqual, file.Name) So(jsonFile["url"], ShouldEqual, file.Link) }) }) Convey("When finding info on a nonexistent task", t, func() { taskId := "not-present" url, err := router.Get("task_info").URL("task_id", taskId) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusNotFound) Convey("response should contain a sensible error message", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) So(jsonBody["message"], ShouldEqual, fmt.Sprintf("Error finding task '%v'", taskId)) }) }) }
func TestGetBuildInfo(t *testing.T) { userManager, err := auth.LoadUserManager(buildTestConfig.AuthConfig) testutil.HandleTestingErr(err, t, "Failure in loading UserManager from config") uis := UIServer{ RootURL: buildTestConfig.Ui.Url, Settings: *buildTestConfig, UserManager: userManager, } uis.InitPlugins() home := evergreen.FindEvergreenHome() uis.Render = render.New(render.Options{ Directory: filepath.Join(home, WebRootPath, Templates), DisableCache: true, }) router, err := uis.NewRouter() testutil.HandleTestingErr(err, t, "Failed to create ui server router") Convey("When finding info on a particular build", t, func() { testutil.HandleTestingErr(db.Clear(build.Collection), t, "Error clearing '%v' collection", build.Collection) buildId := "my-build" versionId := "my-version" projectName := "mci-test" err := modelutil.CreateTestLocalConfig(buildTestConfig, "mci-test", "") So(err, ShouldBeNil) err = modelutil.CreateTestLocalConfig(buildTestConfig, "render", "") So(err, ShouldBeNil) err = modelutil.CreateTestLocalConfig(buildTestConfig, "project_test", "") task := build.TaskCache{ Id: "some-task-id", DisplayName: "some-task-name", Status: "success", TimeTaken: time.Duration(100 * time.Millisecond), } build := &build.Build{ Id: buildId, CreateTime: time.Now().Add(-20 * time.Minute), StartTime: time.Now().Add(-10 * time.Minute), FinishTime: time.Now().Add(-5 * time.Second), PushTime: time.Now().Add(-1 * time.Millisecond), Version: versionId, Project: projectName, Revision: fmt.Sprintf("%x", rand.Int()), BuildVariant: "some-build-variant", BuildNumber: "42", Status: "success", Activated: true, ActivatedTime: time.Now().Add(-15 * time.Minute), RevisionOrderNumber: rand.Int(), Tasks: []build.TaskCache{task}, TimeTaken: time.Duration(10 * time.Minute), DisplayName: "My build", Requester: evergreen.RepotrackerVersionRequester, } So(build.Insert(), ShouldBeNil) url, err := router.Get("build_info").URL("build_id", buildId) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusOK) Convey("response should match contents of database", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) var rawJsonBody map[string]*json.RawMessage err = json.Unmarshal(response.Body.Bytes(), &rawJsonBody) So(err, ShouldBeNil) So(jsonBody["id"], ShouldEqual, build.Id) var createTime time.Time err = json.Unmarshal(*rawJsonBody["create_time"], &createTime) So(err, ShouldBeNil) So(createTime, ShouldHappenWithin, TimePrecision, build.CreateTime) var startTime time.Time err = json.Unmarshal(*rawJsonBody["start_time"], &startTime) So(err, ShouldBeNil) So(startTime, ShouldHappenWithin, TimePrecision, build.StartTime) var finishTime time.Time err = json.Unmarshal(*rawJsonBody["finish_time"], &finishTime) So(err, ShouldBeNil) So(finishTime, ShouldHappenWithin, TimePrecision, build.FinishTime) var pushTime time.Time err = json.Unmarshal(*rawJsonBody["push_time"], &pushTime) So(err, ShouldBeNil) So(pushTime, ShouldHappenWithin, TimePrecision, build.PushTime) So(jsonBody["version"], ShouldEqual, build.Version) So(jsonBody["project"], ShouldEqual, build.Project) So(jsonBody["revision"], ShouldEqual, build.Revision) So(jsonBody["variant"], ShouldEqual, build.BuildVariant) So(jsonBody["number"], ShouldEqual, build.BuildNumber) So(jsonBody["status"], ShouldEqual, build.Status) So(jsonBody["activated"], ShouldEqual, build.Activated) var activatedTime time.Time err = json.Unmarshal(*rawJsonBody["activated_time"], &activatedTime) So(err, ShouldBeNil) So(activatedTime, ShouldHappenWithin, TimePrecision, build.ActivatedTime) So(jsonBody["order"], ShouldEqual, build.RevisionOrderNumber) _jsonTasks, ok := jsonBody["tasks"] So(ok, ShouldBeTrue) jsonTasks, ok := _jsonTasks.(map[string]interface{}) So(ok, ShouldBeTrue) So(len(jsonTasks), ShouldEqual, 1) _jsonTask, ok := jsonTasks[task.DisplayName] So(ok, ShouldBeTrue) jsonTask, ok := _jsonTask.(map[string]interface{}) So(ok, ShouldBeTrue) So(jsonTask["task_id"], ShouldEqual, task.Id) So(jsonTask["status"], ShouldEqual, task.Status) So(jsonTask["time_taken"], ShouldEqual, task.TimeTaken) So(jsonBody["time_taken"], ShouldEqual, build.TimeTaken) So(jsonBody["name"], ShouldEqual, build.DisplayName) So(jsonBody["requester"], ShouldEqual, build.Requester) }) }) Convey("When finding info on a nonexistent build", t, func() { buildId := "not-present" url, err := router.Get("build_info").URL("build_id", buildId) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusNotFound) Convey("response should contain a sensible error message", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) So(len(jsonBody["message"].(string)), ShouldBeGreaterThan, 0) }) }) }
func init() { evgHome := evergreen.FindEvergreenHome() goxc = filepath.Join(evgHome, "src/github.com/laher/goxc/goxc.go") }
func TestActivateVersion(t *testing.T) { uis := UIServer{ RootURL: versionTestConfig.Ui.Url, Settings: *versionTestConfig, UserManager: MockUserManager{}, } home := evergreen.FindEvergreenHome() uis.Render = render.New(render.Options{ Directory: filepath.Join(home, WebRootPath, Templates), DisableCache: true, }) uis.InitPlugins() router, err := uis.NewRouter() testutil.HandleTestingErr(err, t, "Failed to create ui server router") n := negroni.New() n.Use(negroni.HandlerFunc(UserMiddleware(uis.UserManager))) n.UseHandler(router) Convey("When marking a particular version as active", t, func() { testutil.HandleTestingErr(db.ClearCollections(version.Collection, build.Collection), t, "Error clearing collections") versionId := "my-version" projectName := "project_test" build := &build.Build{ Id: "some-build-id", BuildVariant: "some-build-variant", } So(build.Insert(), ShouldBeNil) v := &version.Version{ Id: versionId, CreateTime: time.Now().Add(-20 * time.Minute), StartTime: time.Now().Add(-10 * time.Minute), FinishTime: time.Now().Add(-5 * time.Second), Revision: fmt.Sprintf("%x", rand.Int()), Author: "some-author", AuthorEmail: "some-email", Message: "some-message", Status: "success", BuildIds: []string{build.Id}, BuildVariants: []version.BuildStatus{{"some-build-variant", true, time.Now().Add(-20 * time.Minute), "some-build-id"}}, RevisionOrderNumber: rand.Int(), Owner: "some-owner", Repo: "some-repo", Branch: "some-branch", RepoKind: "github", Identifier: projectName, Remote: false, RemotePath: "", Requester: evergreen.RepotrackerVersionRequester, } So(v.Insert(), ShouldBeNil) url, err := router.Get("version_info").URL("version_id", versionId) So(err, ShouldBeNil) var body = map[string]interface{}{ "activated": true, } jsonBytes, err := json.Marshal(body) So(err, ShouldBeNil) bodyReader := bytes.NewReader(jsonBytes) request, err := http.NewRequest("PATCH", url.String(), bodyReader) So(err, ShouldBeNil) // add auth cookie--this can be anything if we are using a MockUserManager request.AddCookie(&http.Cookie{Name: evergreen.AuthTokenCookie, Value: "token"}) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function n.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusOK) validateVersionInfo(v, response) }) Convey("When marking a nonexistent version as active", t, func() { versionId := "not-present" url, err := router.Get("version_info").URL("version_id", versionId) So(err, ShouldBeNil) var body = map[string]interface{}{ "activated": true, } jsonBytes, err := json.Marshal(body) So(err, ShouldBeNil) bodyReader := bytes.NewReader(jsonBytes) request, err := http.NewRequest("PATCH", url.String(), bodyReader) So(err, ShouldBeNil) response := httptest.NewRecorder() // add auth cookie--this can be anything if we are using a MockUserManager request.AddCookie(&http.Cookie{Name: evergreen.AuthTokenCookie, Value: "token"}) n.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusNotFound) Convey("response should contain a sensible error message", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) So(len(jsonBody["message"].(string)), ShouldBeGreaterThan, 0) }) }) Convey("When modifying a version without credentials", t, func() { versionId := "not-present" url, err := router.Get("version_info").URL("version_id", versionId) So(err, ShouldBeNil) var body = map[string]interface{}{ "activated": true, } jsonBytes, err := json.Marshal(body) So(err, ShouldBeNil) bodyReader := bytes.NewReader(jsonBytes) request, err := http.NewRequest("PATCH", url.String(), bodyReader) So(err, ShouldBeNil) response := httptest.NewRecorder() n.ServeHTTP(response, request) Convey("response should indicate a permission error", func() { So(response.Code, ShouldEqual, http.StatusUnauthorized) }) }) }
func TestLocalCommands(t *testing.T) { Convey("When running local commands", t, func() { Convey("the preparation step should replace expansions and forward"+ " slashes in the command string", func() { command := &LocalCommand{ CmdString: "one ${two} \\three${four|five}", } expansions := NewExpansions(map[string]string{ "two": "TWO", "six": "SIX", }) // run the preparation stage, and make sure the replacements are // correctly made So(command.PrepToRun(expansions), ShouldBeNil) So(command.CmdString, ShouldEqual, "one TWO /threefive") }) Convey("the specified environment should be used", func() { stdout := &CacheLastWritten{} command := &LocalCommand{ CmdString: "echo $local_command_test", Stdout: stdout, Stderr: ioutil.Discard, } // get the current env command.Environment = os.Environ() // run the command - the environment variable should be empty So(command.Run(), ShouldBeNil) So(string(stdout.LastWritten), ShouldEqual, "\n") // add the environment variable to the env command.Environment = append(command.Environment, "local_command_test=hello") // run the command again - the environment variable should be set // correctly So(command.Run(), ShouldBeNil) So(string(stdout.LastWritten), ShouldEqual, "hello\n") }) Convey("the specified working directory should be used", func() { stdout := &CacheLastWritten{} evgHome := evergreen.FindEvergreenHome() workingDir := filepath.Join(evgHome, "command/testdata") command := &LocalCommand{ CmdString: "pwd", Stdout: stdout, Stderr: ioutil.Discard, WorkingDirectory: workingDir, } // run the command - the working directory should be as specified So(command.Run(), ShouldBeNil) So(string(stdout.LastWritten), ShouldEqual, workingDir+"\n") }) }) }
func TestGetBuildStatus(t *testing.T) { userManager, err := auth.LoadUserManager(buildTestConfig.AuthConfig) testutil.HandleTestingErr(err, t, "Failure in loading UserManager from config") uis := UIServer{ RootURL: buildTestConfig.Ui.Url, Settings: *buildTestConfig, UserManager: userManager, } home := evergreen.FindEvergreenHome() uis.Render = render.New(render.Options{ Directory: filepath.Join(home, WebRootPath, Templates), DisableCache: true, }) uis.InitPlugins() router, err := uis.NewRouter() testutil.HandleTestingErr(err, t, "Failed to create ui server router") Convey("When finding the status of a particular build", t, func() { testutil.HandleTestingErr(db.Clear(build.Collection), t, "Error clearing '%v' collection", build.Collection) buildId := "my-build" versionId := "my-version" task := build.TaskCache{ Id: "some-task-id", DisplayName: "some-task-name", Status: "success", TimeTaken: time.Duration(100 * time.Millisecond), } build := &build.Build{ Id: buildId, Version: versionId, BuildVariant: "some-build-variant", DisplayName: "Some Build Variant", Tasks: []build.TaskCache{task}, } So(build.Insert(), ShouldBeNil) url, err := router.Get("build_status").URL("build_id", buildId) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusOK) Convey("response should match contents of database", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) var rawJsonBody map[string]*json.RawMessage err = json.Unmarshal(response.Body.Bytes(), &rawJsonBody) So(err, ShouldBeNil) So(jsonBody["build_id"], ShouldEqual, build.Id) So(jsonBody["build_variant"], ShouldEqual, build.BuildVariant) _jsonTasks, ok := jsonBody["tasks"] So(ok, ShouldBeTrue) jsonTasks, ok := _jsonTasks.(map[string]interface{}) So(ok, ShouldBeTrue) So(len(jsonTasks), ShouldEqual, 1) _jsonTask, ok := jsonTasks[task.DisplayName] So(ok, ShouldBeTrue) jsonTask, ok := _jsonTask.(map[string]interface{}) So(ok, ShouldBeTrue) So(jsonTask["task_id"], ShouldEqual, task.Id) So(jsonTask["status"], ShouldEqual, task.Status) So(jsonTask["time_taken"], ShouldEqual, task.TimeTaken) }) }) Convey("When finding the status of a nonexistent build", t, func() { buildId := "not-present" url, err := router.Get("build_status").URL("build_id", buildId) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusNotFound) Convey("response should contain a sensible error message", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) So(len(jsonBody["message"].(string)), ShouldBeGreaterThan, 0) }) }) }
func TestGetVersionInfo(t *testing.T) { uis := UIServer{ RootURL: versionTestConfig.Ui.Url, Settings: *versionTestConfig, UserManager: testutil.MockUserManager{}, } home := evergreen.FindEvergreenHome() uis.Render = render.New(render.Options{ Directory: filepath.Join(home, WebRootPath, Templates), DisableCache: true, }) router, err := uis.NewRouter() testutil.HandleTestingErr(err, t, "Failure in uis.NewRouter()") err = testutil.CreateTestLocalConfig(buildTestConfig, "mci-test", "") testutil.HandleTestingErr(err, t, "Error loading local config mci-test") err = testutil.CreateTestLocalConfig(buildTestConfig, "render", "") testutil.HandleTestingErr(err, t, "Error loading local config render") Convey("When finding info on a particular version", t, func() { testutil.HandleTestingErr(db.Clear(version.Collection), t, "Error clearing '%v' collection", version.Collection) versionId := "my-version" projectName := "project_test" err = testutil.CreateTestLocalConfig(buildTestConfig, projectName, "") So(err, ShouldBeNil) v := &version.Version{ Id: versionId, CreateTime: time.Now().Add(-20 * time.Minute), StartTime: time.Now().Add(-10 * time.Minute), FinishTime: time.Now().Add(-5 * time.Second), Revision: fmt.Sprintf("%x", rand.Int()), Author: "some-author", AuthorEmail: "some-email", Message: "some-message", Status: "success", BuildIds: []string{"some-build-id"}, BuildVariants: []version.BuildStatus{{"some-build-variant", true, time.Now().Add(-20 * time.Minute), "some-build-id"}}, RevisionOrderNumber: rand.Int(), Owner: "some-owner", Repo: "some-repo", Branch: "some-branch", RepoKind: "github", Identifier: versionId, Remote: false, RemotePath: "", Requester: evergreen.RepotrackerVersionRequester, } So(v.Insert(), ShouldBeNil) url, err := router.Get("version_info").URL("version_id", versionId) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) Println(response.Body) So(response.Code, ShouldEqual, http.StatusOK) validateVersionInfo(v, response) }) Convey("When finding info on a nonexistent version", t, func() { versionId := "not-present" url, err := router.Get("version_info").URL("version_id", versionId) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusNotFound) Convey("response should contain a sensible error message", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) So(len(jsonBody["message"].(string)), ShouldBeGreaterThan, 0) }) }) }
func TestLocalCommands(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("shell command test doesn't make sense on windows") } Convey("When running local commands", t, func() { Convey("the preparation step should replace expansions and forward"+ " slashes in the command string", func() { command := &LocalCommand{ CmdString: "one ${two} \\three${four|five}", } expansions := NewExpansions(map[string]string{ "two": "TWO", "six": "SIX", }) // run the preparation stage, and make sure the replacements are // correctly made So(command.PrepToRun(expansions), ShouldBeNil) So(command.CmdString, ShouldEqual, "one TWO \\threefive") }) Convey("the specified environment should be used", func() { stdout := &CacheLastWritten{} command := &LocalCommand{ CmdString: "echo $local_command_test", Stdout: stdout, Stderr: ioutil.Discard, } // get the current env command.Environment = os.Environ() // run the command - the environment variable should be empty So(command.Run(), ShouldBeNil) So(string(stdout.LastWritten), ShouldEqual, "\n") // add the environment variable to the env command.Environment = append(command.Environment, "local_command_test=hello") // run the command again - the environment variable should be set // correctly So(command.Run(), ShouldBeNil) So(string(stdout.LastWritten), ShouldEqual, "hello\n") }) Convey("the specified working directory should be used", func() { stdout := &CacheLastWritten{} workingDir, err := filepath.Abs(evergreen.FindEvergreenHome()) So(err, ShouldBeNil) command := &LocalCommand{ CmdString: "pwd", Stdout: stdout, Stderr: ioutil.Discard, WorkingDirectory: workingDir, } // run the command - the working directory should be as specified So(command.Run(), ShouldBeNil) reportedPwd := string(stdout.LastWritten) reportedPwd = reportedPwd[:len(reportedPwd)-1] reportedPwd, err = filepath.EvalSymlinks(reportedPwd) So(err, ShouldBeNil) So(reportedPwd, ShouldEqual, workingDir) }) Convey("the specified shell should be used", func() { for _, sh := range []string{"bash", "sh", "/bin/bash", "/bin/sh"} { stdout := &CacheLastWritten{} command := &LocalCommand{ Shell: sh, CmdString: "echo $0", Stdout: stdout, Stderr: ioutil.Discard, } So(command.Run(), ShouldBeNil) So(string(stdout.LastWritten), ShouldEqual, sh+"\n") } }) Convey("if not specified, sh should be used", func() { stdout := &CacheLastWritten{} command := &LocalCommand{ CmdString: "echo $0", Stdout: stdout, Stderr: ioutil.Discard, } So(command.Run(), ShouldBeNil) So(string(stdout.LastWritten), ShouldEqual, "sh\n") }) Convey("when specified, local command can also use python", func() { stdout := &CacheLastWritten{} command := &LocalCommand{ Shell: "python", CmdString: "print('hello world')", Stdout: stdout, Stderr: ioutil.Discard, } So(command.Run(), ShouldBeNil) So(string(stdout.LastWritten), ShouldEqual, "hello world\n") }) }) }
func TemplateRoot(name string) string { return filepath.Join(evergreen.FindEvergreenHome(), "ui", "plugins", name, "templates") }
func TestAgentBasedHostGateway(t *testing.T) { var hostGateway *AgentBasedHostGateway SkipConvey("When checking if the agent needs to be built", t, func() { hostGateway = &AgentBasedHostGateway{} Convey("a non-existent executables directory should cause the agent"+ " to need to be built", func() { hostGateway.ExecutablesDir = "/foo/bar/baz/foo/bar" needsBuild, err := hostGateway.AgentNeedsBuild() So(err, ShouldBeNil) So(needsBuild, ShouldBeTrue) }) Convey("an out-of-date last-built version of the agent should cause"+ " the agent to need to be built", func() { hostGateway.ExecutablesDir = "/" // just needs to exist // store the "last built hash" as something different than the // current one So(db.StoreLastAgentBuild("fedcba"), ShouldBeNil) needsBuild, err := hostGateway.AgentNeedsBuild() So(err, ShouldBeNil) So(needsBuild, ShouldBeTrue) }) Convey("an up-to-date last-built version of the agent should cause"+ " the agent to not need to be built", func() { hostGateway.ExecutablesDir = "/" // just needs to exist // compute and cache the current hash of the agent package agentHash, err := util.CurrentGitHash(hostGateway.AgentPackageDir) So(err, ShouldBeNil) // store the "last built hash" as the same as the current one So(db.StoreLastAgentBuild(agentHash), ShouldBeNil) needsBuild, err := hostGateway.AgentNeedsBuild() So(err, ShouldBeNil) So(needsBuild, ShouldBeFalse) }) }) SkipConvey("When building the agent", t, func() { hostGateway = &AgentBasedHostGateway{} So(db.StoreLastAgentBuild("abcdef"), ShouldBeNil) Convey("a nil AgentCompiler should cause a panic", func() { So(func() { hostGateway.buildAgent() }, ShouldPanic) }) Convey("a failed compilation should error and cause the build to not"+ " be recorded as successful", func() { // attempt to compile hostGateway.currentAgentHash = "fedcba" hostGateway.Compiler = &FailingAgentCompiler{} So(hostGateway.buildAgent(), ShouldNotBeNil) // make sure the last built hash was not updated lastBuiltHash, err := db.GetLastAgentBuild() So(err, ShouldBeNil) So(lastBuiltHash, ShouldEqual, "abcdef") }) Convey("a successful compilation should cause the build to be"+ " recorded as successful", func() { // attempt to compile hostGateway.currentAgentHash = "fedcba" hostGateway.Compiler = &SucceedingAgentCompiler{} So(hostGateway.buildAgent(), ShouldBeNil) // make sure the last built hash was updated lastBuiltHash, err := db.GetLastAgentBuild() So(err, ShouldBeNil) So(lastBuiltHash, ShouldEqual, "fedcba") }) }) Convey("When prepping the remote machine", t, func() { Convey("the remote shell should be created, and the config directory"+ " and agent binaries should be copied over to it", func() { hostGateway = &AgentBasedHostGateway{ Compiler: &SucceedingAgentCompiler{}, } // create a mock config directory, mock executables // directory, and mock remote shell evgHome := evergreen.FindEvergreenHome() tmpBase := filepath.Join(evgHome, "taskrunner/testdata/tmp") mockConfigDir := filepath.Join(tmpBase, "mock_config_dir") hostGatewayTestConf.ConfigDir = mockConfigDir mockExecutablesDir := filepath.Join(tmpBase, "mock_executables_dir") hostGateway.ExecutablesDir = mockExecutablesDir mockExecutable := filepath.Join(mockExecutablesDir, "main") mockRemoteShell := filepath.Join(tmpBase, "mock_remote_shell") evergreen.RemoteShell = mockRemoteShell // prevent permissions issues syscall.Umask(0000) // remove the directories, if they exist (start clean) exists, err := util.FileExists(tmpBase) So(err, ShouldBeNil) if exists { So(os.RemoveAll(tmpBase), ShouldBeNil) } So(os.MkdirAll(tmpBase, 0777), ShouldBeNil) // create the config and executables directories, as well as a // mock executable, to copy over So(os.Mkdir(mockConfigDir, 0777), ShouldBeNil) So(os.Mkdir(mockExecutablesDir, 0777), ShouldBeNil) So(ioutil.WriteFile(mockExecutable, []byte("run me"), 0777), ShouldBeNil) // mock up a host for localhost localhost := host.Host{ Host: command.TestRemote, User: command.TestRemoteUser, } // prep the "remote" host _, err = hostGateway.prepRemoteHost(hostGatewayTestConf, localhost, []string{"-i", command.TestRemoteKey}, "") So(err, ShouldBeNil) // make sure the correct files were created and copied over exists, err = util.FileExists(filepath.Join(mockRemoteShell, "mock_config_dir")) So(err, ShouldBeNil) So(exists, ShouldBeTrue) exists, err = util.FileExists(filepath.Join(mockRemoteShell, "main")) So(err, ShouldBeNil) So(exists, ShouldBeTrue) }) }) }
func TestGetProjectInfo(t *testing.T) { uis := UIServer{ RootURL: projectTestConfig.Ui.Url, Settings: *projectTestConfig, UserManager: testutil.MockUserManager{}, } home := evergreen.FindEvergreenHome() uis.Render = render.New(render.Options{ Directory: filepath.Join(home, WebRootPath, Templates), DisableCache: true, Funcs: nil, }) router, err := uis.NewRouter() testutil.HandleTestingErr(err, t, "error setting up router") n := negroni.New() n.Use(negroni.HandlerFunc(UserMiddleware(uis.UserManager))) n.UseHandler(router) Convey("When loading a public project, it should be found", t, func() { testutil.HandleTestingErr(db.Clear(model.ProjectRefCollection), t, "Error clearing '%v' collection", model.ProjectRefCollection) publicId := "pub" public := &model.ProjectRef{ Identifier: publicId, Repo: "repo1", LocalConfig: "buildvariants:\n - name: ubuntu", } So(public.Insert(), ShouldBeNil) url, err := router.Get("project_info").URL("project_id", publicId) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() Convey("by a public user", func() { n.ServeHTTP(response, request) outRef := &model.ProjectRef{} So(response.Code, ShouldEqual, http.StatusOK) So(json.Unmarshal(response.Body.Bytes(), outRef), ShouldBeNil) So(outRef, ShouldResemble, public) }) Convey("and a logged-in user", func() { request.AddCookie(&http.Cookie{Name: evergreen.AuthTokenCookie, Value: "token"}) n.ServeHTTP(response, request) outRef := &model.ProjectRef{} So(response.Code, ShouldEqual, http.StatusOK) So(json.Unmarshal(response.Body.Bytes(), outRef), ShouldBeNil) So(outRef, ShouldResemble, public) }) }) Convey("When loading a private project", t, func() { testutil.HandleTestingErr(db.Clear(model.ProjectRefCollection), t, "Error clearing '%v' collection", model.ProjectRefCollection) privateId := "priv" private := &model.ProjectRef{ Identifier: privateId, Private: true, Repo: "repo1", } So(private.Insert(), ShouldBeNil) Convey("users who are not logged in should be denied with a 302", func() { url, err := router.Get("project_info").URL("project_id", privateId) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() n.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusFound) }) Convey("users who are logged in should be able to access the project", func() { url, err := router.Get("project_info").URL("project_id", privateId) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) // add auth cookie--this can be anything if we are using a MockUserManager request.AddCookie(&http.Cookie{Name: evergreen.AuthTokenCookie, Value: "token"}) response := httptest.NewRecorder() n.ServeHTTP(response, request) outRef := &model.ProjectRef{} So(response.Code, ShouldEqual, http.StatusOK) So(json.Unmarshal(response.Body.Bytes(), outRef), ShouldBeNil) So(outRef, ShouldResemble, private) }) }) Convey("When finding info on a nonexistent project", t, func() { url, err := router.Get("project_info").URL("project_id", "nope") So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() Convey("response should contain a sensible error message", func() { Convey("for a public user", func() { n.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusNotFound) var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) So(len(jsonBody["message"].(string)), ShouldBeGreaterThan, 0) }) Convey("and a logged-in user", func() { request.AddCookie(&http.Cookie{Name: evergreen.AuthTokenCookie, Value: "token"}) n.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusNotFound) var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) So(len(jsonBody["message"].(string)), ShouldBeGreaterThan, 0) }) }) }) }
func TestGetTaskStatus(t *testing.T) { userManager, err := auth.LoadUserManager(taskTestConfig.AuthConfig) testutil.HandleTestingErr(err, t, "Failure in loading UserManager from config") uis := UIServer{ RootURL: taskTestConfig.Ui.Url, Settings: *taskTestConfig, UserManager: userManager, } home := evergreen.FindEvergreenHome() uis.Render = render.New(render.Options{ Directory: filepath.Join(home, WebRootPath, Templates), DisableCache: true, Funcs: nil, }) router, err := uis.NewRouter() testutil.HandleTestingErr(err, t, "Failure in uis.NewRouter()") Convey("When finding the status of a particular task", t, func() { testutil.HandleTestingErr(db.Clear(model.TasksCollection), t, "Error clearing '%v' collection", model.TasksCollection) taskId := "my-task" testResult := model.TestResult{ Status: "success", TestFile: "some-test", URL: "some-url", StartTime: float64(time.Now().Add(-9 * time.Minute).Unix()), EndTime: float64(time.Now().Add(-1 * time.Minute).Unix()), } task := &model.Task{ Id: taskId, DisplayName: "My task", Status: "success", Details: apimodels.TaskEndDetail{ TimedOut: false, Description: "some-stage", }, TestResults: []model.TestResult{testResult}, } So(task.Insert(), ShouldBeNil) url, err := router.Get("task_status").URL("task_id", taskId) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusOK) Convey("response should match contents of database", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) var rawJsonBody map[string]*json.RawMessage err = json.Unmarshal(response.Body.Bytes(), &rawJsonBody) So(err, ShouldBeNil) So(jsonBody["task_id"], ShouldEqual, task.Id) So(jsonBody["task_name"], ShouldEqual, task.DisplayName) So(jsonBody["status"], ShouldEqual, task.Status) _jsonStatusDetails, ok := jsonBody["status_details"] So(ok, ShouldBeTrue) jsonStatusDetails, ok := _jsonStatusDetails.(map[string]interface{}) So(ok, ShouldBeTrue) So(jsonStatusDetails["timed_out"], ShouldEqual, task.Details.TimedOut) So(jsonStatusDetails["timeout_stage"], ShouldEqual, task.Details.Description) _jsonTestResults, ok := jsonBody["tests"] So(ok, ShouldBeTrue) jsonTestResults, ok := _jsonTestResults.(map[string]interface{}) So(ok, ShouldBeTrue) So(len(jsonTestResults), ShouldEqual, 1) _jsonTestResult, ok := jsonTestResults[testResult.TestFile] So(ok, ShouldBeTrue) jsonTestResult, ok := _jsonTestResult.(map[string]interface{}) So(ok, ShouldBeTrue) So(jsonTestResult["status"], ShouldEqual, testResult.Status) So(jsonTestResult["time_taken"], ShouldNotBeNil) // value correctness is unchecked _jsonTestResultLogs, ok := jsonTestResult["logs"] So(ok, ShouldBeTrue) jsonTestResultLogs, ok := _jsonTestResultLogs.(map[string]interface{}) So(ok, ShouldBeTrue) So(jsonTestResultLogs["url"], ShouldEqual, testResult.URL) }) }) Convey("When finding the status of a nonexistent task", t, func() { taskId := "not-present" url, err := router.Get("task_status").URL("task_id", taskId) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusNotFound) Convey("response should contain a sensible error message", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) So(jsonBody["message"], ShouldEqual, fmt.Sprintf("Error finding task '%v'", taskId)) }) }) }
func TestAgentBasedHostGateway(t *testing.T) { var hostGateway *AgentBasedHostGateway Convey("When prepping the remote machine", t, func() { Convey("the remote shell should be created, and the config directory"+ " and agent binaries should be copied over to it", func() { hostGateway = &AgentBasedHostGateway{ Compiler: &SucceedingAgentCompiler{}, } // create a mock config directory, mock executables // directory, and mock remote shell evgHome := evergreen.FindEvergreenHome() tmpBase := filepath.Join(evgHome, "taskrunner/testdata/tmp") mockConfigDir := filepath.Join(tmpBase, "mock_config_dir") hostGatewayTestConf.ConfigDir = mockConfigDir mockExecutablesDir := filepath.Join(tmpBase, "mock_executables_dir") hostGateway.ExecutablesDir = mockExecutablesDir mockExecutable := filepath.Join(mockExecutablesDir, "main") mockRemoteShell := filepath.Join(tmpBase, "mock_remote_shell") evergreen.RemoteShell = mockRemoteShell // prevent permissions issues syscall.Umask(0000) // remove the directories, if they exist (start clean) exists, err := util.FileExists(tmpBase) So(err, ShouldBeNil) if exists { So(os.RemoveAll(tmpBase), ShouldBeNil) } So(os.MkdirAll(tmpBase, 0777), ShouldBeNil) // create the config and executables directories, as well as a // mock executable, to copy over So(os.Mkdir(mockConfigDir, 0777), ShouldBeNil) So(os.Mkdir(mockExecutablesDir, 0777), ShouldBeNil) So(ioutil.WriteFile(mockExecutable, []byte("run me"), 0777), ShouldBeNil) // mock up a host for localhost localhost := host.Host{ Host: command.TestRemote, User: command.TestRemoteUser, } // prep the "remote" host _, err = hostGateway.prepRemoteHost(hostGatewayTestConf, localhost, []string{"-i", command.TestRemoteKey}, "") So(err, ShouldBeNil) // make sure the correct files were created and copied over exists, err = util.FileExists(filepath.Join(mockRemoteShell, "mock_config_dir")) So(err, ShouldBeNil) So(exists, ShouldBeTrue) exists, err = util.FileExists(filepath.Join(mockRemoteShell, "main")) So(err, ShouldBeNil) So(exists, ShouldBeTrue) }) }) }
func TestGetRecentVersions(t *testing.T) { userManager, err := auth.LoadUserManager(versionTestConfig.AuthConfig) testutil.HandleTestingErr(err, t, "Failure in loading UserManager from config") uis := UIServer{ RootURL: versionTestConfig.Ui.Url, Settings: *versionTestConfig, UserManager: userManager, } home := evergreen.FindEvergreenHome() uis.Render = render.New(render.Options{ Directory: filepath.Join(home, WebRootPath, Templates), DisableCache: true, Funcs: nil, }) router, err := uis.NewRouter() testutil.HandleTestingErr(err, t, "Failure in uis.NewRouter()") err = testutil.CreateTestLocalConfig(buildTestConfig, "mci-test", "") testutil.HandleTestingErr(err, t, "Error loading local config mci-test") err = testutil.CreateTestLocalConfig(buildTestConfig, "render", "") testutil.HandleTestingErr(err, t, "Error loading local config render") Convey("When finding recent versions", t, func() { testutil.HandleTestingErr(db.ClearCollections(version.Collection, build.Collection), t, "Error clearing '%v' collection", version.Collection) projectName := "project_test" err = testutil.CreateTestLocalConfig(buildTestConfig, projectName, "") So(err, ShouldBeNil) otherProjectName := "my-other-project" So(projectName, ShouldNotEqual, otherProjectName) // sanity-check buildIdPreface := "build-id-for-version%v" So(rest.NumRecentVersions, ShouldBeGreaterThan, 0) versions := make([]*version.Version, 0, rest.NumRecentVersions) // Insert a bunch of versions into the database for i := 0; i < rest.NumRecentVersions; i++ { v := &version.Version{ Id: fmt.Sprintf("version%v", i), Identifier: projectName, Author: fmt.Sprintf("author%v", i), Revision: fmt.Sprintf("%x", rand.Int()), Message: fmt.Sprintf("message%v", i), RevisionOrderNumber: i + 1, Requester: evergreen.RepotrackerVersionRequester, } So(v.Insert(), ShouldBeNil) versions = append(versions, v) } // Construct a version that should not be present in the response // since the length of the build ids slice is different than that // of the build variants slice earlyVersion := &version.Version{ Id: "some-id", Identifier: projectName, Author: "some-author", Revision: fmt.Sprintf("%x", rand.Int()), Message: "some-message", RevisionOrderNumber: 0, Requester: evergreen.RepotrackerVersionRequester, } So(earlyVersion.Insert(), ShouldBeNil) // Construct a version that should not be present in the response // since it belongs to a different project otherVersion := &version.Version{ Id: "some-other-id", Identifier: otherProjectName, Author: "some-other-author", Revision: fmt.Sprintf("%x", rand.Int()), Message: "some-other-message", RevisionOrderNumber: rest.NumRecentVersions + 1, Requester: evergreen.RepotrackerVersionRequester, } So(otherVersion.Insert(), ShouldBeNil) builds := make([]*build.Build, 0, rest.NumRecentVersions) task := build.TaskCache{ Id: "some-task-id", DisplayName: "some-task-name", Status: "success", TimeTaken: time.Duration(100 * time.Millisecond), } for i := 0; i < rest.NumRecentVersions; i++ { build := &build.Build{ Id: fmt.Sprintf(buildIdPreface, i), Version: versions[i].Id, BuildVariant: "some-build-variant", DisplayName: "Some Build Variant", Tasks: []build.TaskCache{task}, } So(build.Insert(), ShouldBeNil) builds = append(builds, build) } url, err := router.Get("recent_versions").URL("project_id", projectName) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusOK) Convey("response should match contents of database", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) var rawJsonBody map[string]*json.RawMessage err = json.Unmarshal(response.Body.Bytes(), &rawJsonBody) So(err, ShouldBeNil) So(jsonBody["project"], ShouldEqual, projectName) var jsonVersions []map[string]interface{} err = json.Unmarshal(*rawJsonBody["versions"], &jsonVersions) So(err, ShouldBeNil) So(len(jsonVersions), ShouldEqual, len(versions)) for i, v := range versions { jsonVersion := jsonVersions[len(jsonVersions)-i-1] // reverse order So(jsonVersion["version_id"], ShouldEqual, v.Id) So(jsonVersion["author"], ShouldEqual, v.Author) So(jsonVersion["revision"], ShouldEqual, v.Revision) So(jsonVersion["message"], ShouldEqual, v.Message) _jsonBuilds, ok := jsonVersion["builds"] So(ok, ShouldBeTrue) jsonBuilds, ok := _jsonBuilds.(map[string]interface{}) So(ok, ShouldBeTrue) So(len(jsonBuilds), ShouldEqual, 1) _jsonBuild, ok := jsonBuilds[builds[i].BuildVariant] So(ok, ShouldBeTrue) jsonBuild, ok := _jsonBuild.(map[string]interface{}) So(ok, ShouldBeTrue) So(jsonBuild["build_id"], ShouldEqual, builds[i].Id) So(jsonBuild["name"], ShouldEqual, builds[i].DisplayName) _jsonTasks, ok := jsonBuild["tasks"] So(ok, ShouldBeTrue) jsonTasks, ok := _jsonTasks.(map[string]interface{}) So(ok, ShouldBeTrue) So(len(jsonTasks), ShouldEqual, 1) _jsonTask, ok := jsonTasks[task.DisplayName] So(ok, ShouldBeTrue) jsonTask, ok := _jsonTask.(map[string]interface{}) So(ok, ShouldBeTrue) So(jsonTask["task_id"], ShouldEqual, task.Id) So(jsonTask["status"], ShouldEqual, task.Status) So(jsonTask["time_taken"], ShouldEqual, task.TimeTaken) } }) }) Convey("When finding recent versions for a nonexistent project", t, func() { projectName := "not-present" url, err := router.Get("recent_versions").URL("project_id", projectName) So(err, ShouldBeNil) request, err := http.NewRequest("GET", url.String(), nil) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusOK) Convey("response should contain no versions", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) var rawJsonBody map[string]*json.RawMessage err = json.Unmarshal(response.Body.Bytes(), &rawJsonBody) So(err, ShouldBeNil) So(jsonBody["project"], ShouldEqual, projectName) var jsonVersions []map[string]interface{} err = json.Unmarshal(*rawJsonBody["versions"], &jsonVersions) So(err, ShouldBeNil) So(jsonVersions, ShouldBeEmpty) }) }) }
func TestActivateVersion(t *testing.T) { userManager, err := auth.LoadUserManager(versionTestConfig.AuthConfig) testutil.HandleTestingErr(err, t, "Failure in loading UserManager from config") uis := UIServer{ RootURL: versionTestConfig.Ui.Url, Settings: *versionTestConfig, UserManager: userManager, } home := evergreen.FindEvergreenHome() uis.Render = render.New(render.Options{ Directory: filepath.Join(home, WebRootPath, Templates), DisableCache: true, Funcs: nil, }) router, err := uis.NewRouter() testutil.HandleTestingErr(err, t, "Failure in uis.NewRouter()") Convey("When marking a particular version as active", t, func() { testutil.HandleTestingErr(db.Clear(version.Collection), t, "Error clearing '%v' collection", version.Collection) versionId := "my-version" projectName := "project_test" build := &build.Build{ Id: "some-build-id", BuildVariant: "some-build-variant", } So(build.Insert(), ShouldBeNil) v := &version.Version{ Id: versionId, CreateTime: time.Now().Add(-20 * time.Minute), StartTime: time.Now().Add(-10 * time.Minute), FinishTime: time.Now().Add(-5 * time.Second), Revision: fmt.Sprintf("%x", rand.Int()), Author: "some-author", AuthorEmail: "some-email", Message: "some-message", Status: "success", BuildIds: []string{build.Id}, BuildVariants: []version.BuildStatus{{"some-build-variant", true, time.Now().Add(-20 * time.Minute), "some-build-id"}}, RevisionOrderNumber: rand.Int(), Owner: "some-owner", Repo: "some-repo", Branch: "some-branch", RepoKind: "github", Identifier: projectName, Remote: false, RemotePath: "", Requester: evergreen.RepotrackerVersionRequester, } So(v.Insert(), ShouldBeNil) url, err := router.Get("version_info").URL("version_id", versionId) So(err, ShouldBeNil) var body = map[string]interface{}{ "activated": true, } jsonBytes, err := json.Marshal(body) So(err, ShouldBeNil) bodyReader := bytes.NewReader(jsonBytes) request, err := http.NewRequest("PATCH", url.String(), bodyReader) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusOK) validateVersionInfo(v, response) }) Convey("When marking a nonexistent version as active", t, func() { versionId := "not-present" url, err := router.Get("version_info").URL("version_id", versionId) So(err, ShouldBeNil) var body = map[string]interface{}{ "activated": true, } jsonBytes, err := json.Marshal(body) So(err, ShouldBeNil) bodyReader := bytes.NewReader(jsonBytes) request, err := http.NewRequest("PATCH", url.String(), bodyReader) So(err, ShouldBeNil) response := httptest.NewRecorder() // Need match variables to be set so can call mux.Vars(request) // in the actual handler function router.ServeHTTP(response, request) So(response.Code, ShouldEqual, http.StatusNotFound) Convey("response should contain a sensible error message", func() { var jsonBody map[string]interface{} err = json.Unmarshal(response.Body.Bytes(), &jsonBody) So(err, ShouldBeNil) So(jsonBody["message"], ShouldEqual, fmt.Sprintf("Error finding version '%v'", versionId)) }) }) }
func TestScpCommand(t *testing.T) { Convey("With files to scp", t, func() { // the local files and target directory for scping evgHome := evergreen.FindEvergreenHome() tmpBase := filepath.Join(evgHome, "command/testdata/tmp") fileToScp := filepath.Join(tmpBase, "copy_me_please.txt") directoryToScp := filepath.Join(tmpBase, "copy_my_children_please") nestedFileToScp := filepath.Join(directoryToScp, "copy_me_too_please.txt") targetDirectory := filepath.Join(tmpBase, "feed_me_files") // remove the files and directories, if they exist (start clean) exists, err := util.FileExists(tmpBase) So(err, ShouldBeNil) if exists { So(os.RemoveAll(tmpBase), ShouldBeNil) } So(os.MkdirAll(tmpBase, 0777), ShouldBeNil) // prevent permissions issues syscall.Umask(0000) // create the files / directories to be used So(ioutil.WriteFile(fileToScp, []byte("hello"), 0777), ShouldBeNil) So(os.Mkdir(directoryToScp, 0777), ShouldBeNil) So(ioutil.WriteFile(nestedFileToScp, []byte("hi"), 0777), ShouldBeNil) So(os.Mkdir(targetDirectory, 0777), ShouldBeNil) Convey("when running scp commands", func() { Convey("copying files should work in both directions (local to"+ " remote and remote to local)", func() { // scp the file from local to remote scpCommand := &ScpCommand{ Source: fileToScp, Dest: targetDirectory, Stdout: ioutil.Discard, Stderr: ioutil.Discard, RemoteHostName: TestRemote, User: TestRemoteUser, Options: []string{"-i", TestRemoteKey}, SourceIsRemote: false, } So(scpCommand.Run(), ShouldBeNil) // make sure the file was scp-ed over newFileContents, err := ioutil.ReadFile( filepath.Join(targetDirectory, "copy_me_please.txt")) So(err, ShouldBeNil) So(newFileContents, ShouldResemble, []byte("hello")) // remove the file So(os.Remove(filepath.Join(targetDirectory, "copy_me_please.txt")), ShouldBeNil) // scp the file from remote to local scpCommand = &ScpCommand{ Source: fileToScp, Dest: targetDirectory, Stdout: ioutil.Discard, Stderr: ioutil.Discard, RemoteHostName: TestRemote, User: TestRemoteUser, Options: []string{"-i", TestRemoteKey}, SourceIsRemote: true, } So(scpCommand.Run(), ShouldBeNil) // make sure the file was scp-ed over newFileContents, err = ioutil.ReadFile( filepath.Join(targetDirectory, "copy_me_please.txt")) So(err, ShouldBeNil) So(newFileContents, ShouldResemble, []byte("hello")) }) Convey("additional scp options should be passed correctly to the"+ " command", func() { // scp recursively, using the -r flag scpCommand := &ScpCommand{ Source: directoryToScp, Dest: targetDirectory, Stdout: ioutil.Discard, Stderr: ioutil.Discard, RemoteHostName: TestRemote, User: TestRemoteUser, Options: []string{"-i", TestRemoteKey, "-r"}, SourceIsRemote: false, } So(scpCommand.Run(), ShouldBeNil) // make sure the entire directory was scp-ed over nestedFileContents, err := ioutil.ReadFile( filepath.Join(targetDirectory, "copy_my_children_please", "copy_me_too_please.txt")) So(err, ShouldBeNil) So(nestedFileContents, ShouldResemble, []byte("hi")) }) }) }) }
func TestGoxcAgentCompiler(t *testing.T) { var agentCompiler *GoxcAgentCompiler SkipConvey("When compiling the agent using goxc", t, func() { agentCompiler = &GoxcAgentCompiler{} Convey("binaries for the specified os targets and architectures"+ " should be built in the specified destination directory", func() { // create a fake go env for building evgHome := evergreen.FindEvergreenHome() mockGoPath := filepath.Join(evgHome, "src/github.com/evergreen-ci/evergreen/taskrunner/testdata/tmp/mockGoPath/") srcDir := filepath.Join(mockGoPath, "src") So(os.MkdirAll(srcDir, 0777), ShouldBeNil) binDir := filepath.Join(mockGoPath, "bin") So(os.MkdirAll(binDir, 0777), ShouldBeNil) pkgDir := filepath.Join(mockGoPath, "pkg") So(os.MkdirAll(pkgDir, 0777), ShouldBeNil) // add it to the GOPATH os.Setenv("GOPATH", os.Getenv("GOPATH")+":"+mockGoPath) // create a buildable main package inside of the source dir mainPackage := filepath.Join(srcDir, "main") So(os.MkdirAll(mainPackage, 0777), ShouldBeNil) fileContents := "package main\nimport ()\nfunc main(){}" So(ioutil.WriteFile(filepath.Join(mainPackage, "build_me.go"), []byte(fileContents), 0777), ShouldBeNil) // create the destination directory dstDir := filepath.Join(mockGoPath, "executables") // compile the source package So(agentCompiler.Compile(mainPackage, dstDir), ShouldBeNil) // make sure all of the necessary main files were created for _, execType := range []string{"darwin_386", "darwin_amd64", "linux_386", "linux_amd64", "windows_386", "windows_amd64"} { // windows binaries have .exe at the end binFile := "main" if strings.HasPrefix(execType, "windows") { binFile += ".exe" } // make sure the binary exists exists, err := util.FileExists(filepath.Join(dstDir, "snapshot", execType, binFile)) So(err, ShouldBeNil) So(exists, ShouldBeTrue) } // clean up, by removing the fake go path So(os.RemoveAll(mockGoPath), ShouldBeNil) }) }) }