// GetPanelConfig returns a plugin.PanelConfig struct representing panels
// that will be added to the Task and Build pages.
func (self *AttachPlugin) GetPanelConfig() (*plugin.PanelConfig, error) {
	return &plugin.PanelConfig{
		StaticRoot: plugin.StaticWebRootFromSourceFile(),
		Panels: []plugin.UIPanel{
			{
				Page:     plugin.TaskPage,
				Position: plugin.PageCenter,
				PanelHTML: "<div ng-include=\"'/plugin/attach/static/partials/task_files_panel.html'\" " +
					"ng-init='files=plugins.attach' ng-show='plugins.attach.length'></div>",
				DataFunc: func(context plugin.UIContext) (interface{}, error) {
					if context.Task == nil {
						return nil, nil
					}
					artifactEntry, err := artifact.FindOne(artifact.ByTaskId(context.Task.Id))
					if err != nil {
						return nil, fmt.Errorf("error finding artifact files for task: %v", err)
					}
					if artifactEntry == nil {
						return nil, nil
					}
					return stripHiddenFiles(artifactEntry.Files, context.User), nil
				},
			},
			{
				Page:     plugin.BuildPage,
				Position: plugin.PageLeft,
				PanelHTML: "<div ng-include=\"'/plugin/attach/static/partials/build_files_panel.html'\" " +
					"ng-init='filesByTask=plugins.attach' ng-show='plugins.attach.length'></div>",
				DataFunc: func(context plugin.UIContext) (interface{}, error) {
					if context.Build == nil {
						return nil, nil
					}
					taskArtifactFiles, err := artifact.FindAll(artifact.ByBuildId(context.Build.Id))
					if err != nil {
						return nil, fmt.Errorf("error finding artifact files for build: %v", err)
					}
					for i := range taskArtifactFiles {
						// remove hidden files if the user isn't logged in
						taskArtifactFiles[i].Files = stripHiddenFiles(taskArtifactFiles[i].Files, context.User)
					}
					return taskArtifactFiles, nil
				},
			},
		},
	}, nil
}
Beispiel #2
0
// Returns a JSON response with the marshalled output of the task
// specified in the request.
func (restapi restAPI) getTaskInfo(w http.ResponseWriter, r *http.Request) {
	projCtx := MustHaveProjectContext(r)
	srcTask := projCtx.Task
	if srcTask == nil {
		restapi.WriteJSON(w, http.StatusNotFound, responseError{Message: "error finding task"})
		return
	}

	destTask := &restTask{}
	destTask.Id = srcTask.Id
	destTask.CreateTime = srcTask.CreateTime
	destTask.ScheduledTime = srcTask.ScheduledTime
	destTask.DispatchTime = srcTask.DispatchTime
	destTask.StartTime = srcTask.StartTime
	destTask.FinishTime = srcTask.FinishTime
	destTask.PushTime = srcTask.PushTime
	destTask.Version = srcTask.Version
	destTask.Project = srcTask.Project
	destTask.Revision = srcTask.Revision
	destTask.Priority = srcTask.Priority
	destTask.LastHeartbeat = srcTask.LastHeartbeat
	destTask.Activated = srcTask.Activated
	destTask.BuildId = srcTask.BuildId
	destTask.DistroId = srcTask.DistroId
	destTask.BuildVariant = srcTask.BuildVariant
	destTask.DependsOn = srcTask.DependsOn
	destTask.DisplayName = srcTask.DisplayName
	destTask.HostId = srcTask.HostId
	destTask.Restarts = srcTask.Restarts
	destTask.Execution = srcTask.Execution
	destTask.Archived = srcTask.Archived
	destTask.RevisionOrderNumber = srcTask.RevisionOrderNumber
	destTask.Requester = srcTask.Requester
	destTask.Status = srcTask.Status
	destTask.Aborted = srcTask.Aborted
	destTask.TimeTaken = srcTask.TimeTaken
	destTask.ExpectedDuration = srcTask.ExpectedDuration
	destTask.MinQueuePos = srcTask.MinQueuePos

	// Copy over the status details
	destTask.StatusDetails.TimedOut = srcTask.Details.TimedOut
	destTask.StatusDetails.TimeoutStage = srcTask.Details.Description

	// Copy over the test results
	destTask.TestResults = make(taskTestResultsByName, len(srcTask.TestResults))
	for _, _testResult := range srcTask.TestResults {
		numSecs := _testResult.EndTime - _testResult.StartTime
		testResult := taskTestResult{
			Status:    _testResult.Status,
			TimeTaken: time.Duration(numSecs * float64(time.Second)),
			Logs:      taskTestLogURL{_testResult.URL},
		}
		destTask.TestResults[_testResult.TestFile] = testResult
	}

	// Copy over artifacts and binaries
	entries, err := artifact.FindAll(artifact.ByTaskId(srcTask.Id))
	if err != nil {
		msg := fmt.Sprintf("Error finding task '%v'", srcTask.Id)
		evergreen.Logger.Logf(slogger.ERROR, "%v: %v", msg, err)
		restapi.WriteJSON(w, http.StatusInternalServerError, responseError{Message: msg})
		return

	}
	for _, entry := range entries {
		for _, _file := range entry.Files {
			file := taskFile{
				Name: _file.Name,
				URL:  _file.Link,
			}
			destTask.Files = append(destTask.Files, file)
		}
	}

	restapi.WriteJSON(w, http.StatusOK, destTask)
	return

}
func TestPushTask(t *testing.T) {
	testConfig := evergreen.TestConfig()
	setupTlsConfigs(t)
	db.SetGlobalSessionProvider(db.SessionFactoryFromConfig(testConfig))
	testutil.ConfigureIntegrationTest(t, testConfig, "TestPushTask")
	for tlsString, tlsConfig := range tlsConfigs {
		for _, testSetup := range testSetups {
			Convey(testSetup.testSpec, t, func() {
				Convey("With agent running a push task "+tlsString, func() {
					testTask, _, err := setupAPITestData(testConfig, evergreen.PushStage,
						"linux-64", false, t)
					testutil.HandleTestingErr(err, t, "Error setting up test data: %v", err)
					testutil.HandleTestingErr(db.ClearCollections(artifact.Collection), t, "can't clear files collection")
					testServer, err := apiserver.CreateTestServer(testConfig, tlsConfig, plugin.Published, Verbose)
					testutil.HandleTestingErr(err, t, "Couldn't create apiserver: %v", err)
					testAgent, err := New(testServer.URL, testTask.Id, testTask.Secret, "", testConfig.Expansions["api_httpscert"])
					testutil.HandleTestingErr(err, t, "Error making test agent: %v", err)

					// actually run the task.
					// this function won't return until the whole thing is done.
					testAgent.RunTask()
					time.Sleep(100 * time.Millisecond)
					testAgent.APILogger.FlushAndWait()
					printLogsForTask(testTask.Id)
					newDate := testAgent.taskConfig.Expansions.Get("new_date")

					Convey("all scripts in task should have been run successfully", func() {
						So(scanLogsForTask(testTask.Id, "executing the pre-run script!"), ShouldBeTrue)
						So(scanLogsForTask(testTask.Id, "executing the post-run script!"), ShouldBeTrue)

						So(scanLogsForTask(testTask.Id, "push task pre-run!"), ShouldBeTrue)
						So(scanLogsForTask(testTask.Id, "push task post-run!"), ShouldBeTrue)

						Convey("s3.put attaches task file properly", func() {
							entry, err := artifact.FindOne(artifact.ByTaskId(testTask.Id))
							So(err, ShouldBeNil)
							So(len(entry.Files), ShouldEqual, 2)
							for _, element := range entry.Files {
								So(element.Name, ShouldNotEqual, "")
							}
							So(entry.Files[0].Name, ShouldEqual, "push_file")
							link := "https://s3.amazonaws.com/build-push-testing/pushtest-stage/unittest-testTaskId-DISTRO_EXP-BUILDVAR_EXP-FILE_EXP.txt"
							So(entry.Files[0].Link, ShouldEqual, link)
						})
						Convey("s3.copy attached task file properly", func() {
							entry, err := artifact.FindOne(artifact.ByTaskId(testTask.Id))
							So(err, ShouldBeNil)
							So(len(entry.Files), ShouldNotEqual, 0)
							So(entry.Files[0].Name, ShouldEqual, "push_file")
							So(entry.Files[1].Name, ShouldEqual, "copy_file")
							So(entry.Files[0].Link, ShouldEqual, "https://s3.amazonaws.com/build-push-testing/pushtest-stage/unittest-testTaskId-DISTRO_EXP-BUILDVAR_EXP-FILE_EXP.txt")
							So(entry.Files[1].Link, ShouldEqual,
								"https://s3.amazonaws.com/build-push-testing/pushtest/unittest-DISTRO_EXP-BUILDVAR_EXP-FILE_EXP-latest.txt")
						})

						testTask, err = model.FindTask(testTask.Id)
						testutil.HandleTestingErr(err, t, "Error finding test task: %v", err)
						So(testTask.Status, ShouldEqual, evergreen.TaskSucceeded)

						// Check the file written to s3 is what we expected
						auth := &aws.Auth{
							AccessKey: testConfig.Providers.AWS.Id,
							SecretKey: testConfig.Providers.AWS.Secret,
						}

						// check the staging location first
						filebytes, err := getS3FileBytes(auth, "build-push-testing", "/pushtest-stage/unittest-testTaskId-DISTRO_EXP-BUILDVAR_EXP-FILE_EXP.txt")
						testutil.HandleTestingErr(err, t, "Failed to get file from s3: %v", err)
						So(string(filebytes), ShouldEqual, newDate+"\n")

						// now check remote location (after copy)
						filebytes, err = getS3FileBytes(auth, "build-push-testing", "/pushtest/unittest-DISTRO_EXP-BUILDVAR_EXP-FILE_EXP-latest.txt")

						testutil.HandleTestingErr(err, t, "Failed to get remote file from s3: %v", err)
						So(string(filebytes), ShouldEqual, newDate+"\n")
					})
				})
			})
		}
	}
}
Beispiel #4
0
// Returns a JSON response with the marshalled output of the task
// specified in the request.
func (restapi restAPI) getTaskInfo(w http.ResponseWriter, r *http.Request) {
	taskId := mux.Vars(r)["task_id"]

	srcTask, err := model.FindTask(taskId)
	if err != nil || srcTask == nil {
		msg := fmt.Sprintf("Error finding task '%v'", taskId)
		statusCode := http.StatusNotFound

		if err != nil {
			evergreen.Logger.Logf(slogger.ERROR, "%v: %v", msg, err)
			statusCode = http.StatusInternalServerError
		}

		restapi.WriteJSON(w, statusCode, responseError{Message: msg})
		return

	}

	destTask := &task{}
	// Copy the contents from the database into our local task type
	err = angier.TransferByFieldNames(srcTask, destTask)
	if err != nil {
		msg := fmt.Sprintf("Error finding task '%v'", taskId)
		evergreen.Logger.Logf(slogger.ERROR, "%v: %v", msg, err)
		restapi.WriteJSON(w, http.StatusInternalServerError, responseError{Message: msg})
		return

	}

	// Copy over the status details
	destTask.StatusDetails.TimedOut = srcTask.StatusDetails.TimedOut
	destTask.StatusDetails.TimeoutStage = srcTask.StatusDetails.TimeoutStage

	// Copy over the test results
	destTask.TestResults = make(taskTestResultsByName, len(srcTask.TestResults))
	for _, _testResult := range srcTask.TestResults {
		numSecs := _testResult.EndTime - _testResult.StartTime
		testResult := taskTestResult{
			Status:    _testResult.Status,
			TimeTaken: time.Duration(numSecs * float64(time.Second)),
			Logs:      taskTestLogURL{_testResult.URL},
		}
		destTask.TestResults[_testResult.TestFile] = testResult
	}

	// Copy over artifacts and binaries
	entries, err := artifact.FindAll(artifact.ByTaskId(taskId))
	if err != nil {
		msg := fmt.Sprintf("Error finding task '%v'", taskId)
		evergreen.Logger.Logf(slogger.ERROR, "%v: %v", msg, err)
		restapi.WriteJSON(w, http.StatusInternalServerError, responseError{Message: msg})
		return

	}
	for _, entry := range entries {
		for _, _file := range entry.Files {
			file := taskFile{
				Name: _file.Name,
				URL:  _file.Link,
			}
			destTask.Files = append(destTask.Files, file)
		}
	}

	restapi.WriteJSON(w, http.StatusOK, destTask)
	return

}
Beispiel #5
0
func TestAttachFilesApi(t *testing.T) {
	testConfig := evergreen.TestConfig()
	Convey("With a running api server and installed api hook", t, func() {
		reset(t)
		taskConfig, _ := plugintest.CreateTestConfig("testdata/plugin_attach_files.yml", t)
		registry := plugin.NewSimpleRegistry()
		attachPlugin := &AttachPlugin{}
		err := registry.Register(attachPlugin)
		testutil.HandleTestingErr(err, t, "Couldn't register patch plugin")
		server, err := apiserver.CreateTestServer(testConfig, nil, plugin.APIPlugins, true)
		testutil.HandleTestingErr(err, t, "Couldn't set up testing server")
		sliceAppender := &evergreen.SliceAppender{[]*slogger.Log{}}
		logger := agent.NewTestLogger(sliceAppender)

		testTask := task.Task{Id: "test1", DisplayName: "TASK!!!", BuildId: "build1"}
		testutil.HandleTestingErr(testTask.Insert(), t, "couldn't insert test task")
		taskConfig.Task = &testTask

		httpCom := plugintest.TestAgentCommunicator(testTask.Id, testTask.Secret, server.URL)
		pluginCom := &agent.TaskJSONCommunicator{attachPlugin.Name(), httpCom}

		Convey("using a well-formed api call", func() {
			testCommand := AttachTaskFilesCommand{
				artifact.Params{
					"upload":   "gopher://evergreen.equipment",
					"coverage": "http://www.blankets.com",
				},
			}
			err := testCommand.SendTaskFiles(taskConfig, logger, pluginCom)
			So(err, ShouldBeNil)

			Convey("the given values should be written to the db", func() {
				entry, err := artifact.FindOne(artifact.ByTaskId(testTask.Id))
				So(err, ShouldBeNil)
				So(entry, ShouldNotBeNil)
				So(entry.TaskId, ShouldEqual, testTask.Id)
				So(entry.TaskDisplayName, ShouldEqual, testTask.DisplayName)
				So(entry.BuildId, ShouldEqual, testTask.BuildId)
				So(len(entry.Files), ShouldEqual, 2)
			})

			Convey("with a second api call", func() {
				testCommand := AttachTaskFilesCommand{
					artifact.Params{
						"3x5":      "15",
						"$b.o.o.l": "{\"json\":false}",
						"coverage": "http://tumblr.com/tagged/tarp",
					},
				}
				err := testCommand.SendTaskFiles(taskConfig, logger, pluginCom)
				So(err, ShouldBeNil)
				entry, err := artifact.FindOne(artifact.ByTaskId(testTask.Id))
				So(err, ShouldBeNil)
				So(entry, ShouldNotBeNil)

				Convey("new values should be added", func() {
					Convey("and old values should still remain", func() {
						So(len(entry.Files), ShouldEqual, 5)
					})
				})
			})
		})

		Convey("but the following malformed calls should fail:", func() {
			Convey("- calls with garbage content", func() {
				resp, err := pluginCom.TaskPostJSON(
					AttachTaskFilesAPIEndpoint,
					"I am not a proper post request for this endpoint",
				)
				So(err, ShouldBeNil)
				So(resp, ShouldNotBeNil)
				So(resp.StatusCode, ShouldEqual, http.StatusBadRequest)
			})

			Convey("- calls with nested subdocs", func() {
				resp, err := pluginCom.TaskPostJSON(
					AttachTaskFilesAPIEndpoint,
					map[string]interface{}{
						"cool": map[string]interface{}{
							"this_is": "a",
							"broken":  "test",
						},
					})
				So(err, ShouldBeNil)
				So(resp, ShouldNotBeNil)
				So(resp.StatusCode, ShouldEqual, http.StatusBadRequest)
			})
		})
	})
}
Beispiel #6
0
func TestAttachTaskFilesPlugin(t *testing.T) {
	testConfig := evergreen.TestConfig()
	Convey("With attach plugin installed into plugin registry", t, func() {
		registry := plugin.NewSimpleRegistry()
		attachPlugin := &AttachPlugin{}
		err := registry.Register(attachPlugin)
		testutil.HandleTestingErr(err, t, "Couldn't register plugin %v")

		server, err := apiserver.CreateTestServer(testConfig, nil, plugin.APIPlugins, true)
		testutil.HandleTestingErr(err, t, "Couldn't set up testing server")
		httpCom := plugintest.TestAgentCommunicator("testTaskId", "testTaskSecret", server.URL)

		sliceAppender := &evergreen.SliceAppender{[]*slogger.Log{}}
		logger := agent.NewTestLogger(sliceAppender)
		Convey("all commands in test project should execute successfully", func() {
			taskConfig, _ := plugintest.CreateTestConfig("testdata/plugin_attach_files.yml", t)
			_, _, err = plugintest.SetupAPITestData("testTask", true, t)
			testutil.HandleTestingErr(err, t, "Couldn't set up test documents")

			for _, task := range taskConfig.Project.Tasks {
				So(len(task.Commands), ShouldNotEqual, 0)
				for _, command := range task.Commands {
					pluginCmds, err := registry.GetCommands(command, taskConfig.Project.Functions)
					testutil.HandleTestingErr(err, t, "Couldn't get plugin command: %v")
					So(pluginCmds, ShouldNotBeNil)
					So(err, ShouldBeNil)
					pluginCom := &agent.TaskJSONCommunicator{pluginCmds[0].Plugin(), httpCom}
					err = pluginCmds[0].Execute(logger, pluginCom, taskConfig, make(chan bool))
					So(err, ShouldBeNil)
				}
			}

			Convey("and these file entry fields should exist in the db:", func() {
				entry, err := artifact.FindOne(artifact.ByTaskId("testTaskId"))
				So(err, ShouldBeNil)
				So(entry, ShouldNotBeNil)
				So(entry.TaskDisplayName, ShouldEqual, "testTask")
				So(len(entry.Files), ShouldEqual, 5)

				var regular artifact.File
				var expansion artifact.File
				var overwritten artifact.File

				for _, file := range entry.Files {
					switch file.Name {
					case "file1":
						expansion = file
					case "file2":
						overwritten = file
					case "file3":
						regular = file
					}
				}
				Convey("- regular link", func() {
					So(regular, ShouldResemble,
						artifact.File{"file3", "http://kyle.diamonds", ""})
				})

				Convey("- link with expansion", func() {
					So(expansion, ShouldResemble,
						artifact.File{"file1", "i am a FILE!", ""})
				})

				Convey("- link that is overwritten", func() {
					So(overwritten, ShouldResemble,
						artifact.File{"file2", "replaced!", ""})
				})
			})
		})
	})
}