func getTaskTriggerContext(task *model.Task) (*triggerContext, error) {
	ctx := triggerContext{task: task}
	tasks, err := model.FindTasks(lastFinishedQ(task.Project, task.DisplayName, task.BuildVariant, task.RevisionOrderNumber))
	if err != nil {
		return nil, err
	}
	if len(tasks) > 0 {
		ctx.previousCompleted = &tasks[0]
	}
	return &ctx, nil
}
func TestCLIFunctions(t *testing.T) {
	testutil.ConfigureIntegrationTest(t, testConfig, "TestCLIFunctions")

	Convey("with API test server running", t, func() {
		// create a test API server
		testServer, err := apiserver.CreateTestServer(testConfig, nil, plugin.APIPlugins, true)

		// create a test user
		So(db.Clear(user.Collection), ShouldBeNil)
		So(db.Clear(patch.Collection), ShouldBeNil)
		So(db.Clear(model.ProjectRefCollection), ShouldBeNil)
		So((&user.DBUser{Id: "testuser", APIKey: "testapikey", EmailAddress: "*****@*****.**"}).Insert(), ShouldBeNil)
		localConfBytes, err := ioutil.ReadFile("testdata/sample.yml")
		So(err, ShouldBeNil)

		projectRef := &model.ProjectRef{
			Identifier:  "sample",
			Owner:       "evergreen-ci",
			Repo:        "sample",
			RepoKind:    "github",
			Branch:      "master",
			RemotePath:  "evergreen.yml",
			LocalConfig: string(localConfBytes),
			Enabled:     true,
			BatchTime:   180,
		}
		So(projectRef.Insert(), ShouldBeNil)

		// create a settings file for the command line client
		settings := Settings{
			APIServerHost: testServer.URL + "/api",
			UIServerHost:  "http://dev-evg.mongodb.com",
			APIKey:        "testapikey",
			User:          "******",
		}
		settingsFile, err := ioutil.TempFile("", "settings")
		So(err, ShouldBeNil)
		settingsBytes, err := yaml.Marshal(settings)
		So(err, ShouldBeNil)
		_, err = settingsFile.Write(settingsBytes)
		So(err, ShouldBeNil)
		settingsFile.Close()
		t.Log("Wrote settings file to ", settingsFile.Name())

		ac, _, err := getAPIClient(&Options{settingsFile.Name()})
		So(err, ShouldBeNil)

		Convey("check that creating a patch works", func() {
			Convey("user should start with no patches present", func() {
				patches, err := ac.GetPatches()
				So(err, ShouldBeNil)
				So(len(patches), ShouldEqual, 0)
			})

			Convey("Creating a simple patch should be successful", func() {
				patchSub := patchSubmission{"sample",
					testPatch,
					"sample patch",
					"3c7bfeb82d492dc453e7431be664539c35b5db4b",
					"all",
					[]string{"all"},
					false}

				newPatch, err := ac.PutPatch(patchSub)
				So(err, ShouldBeNil)

				Convey("Newly created patch should be fetchable via API", func() {
					patches, err := ac.GetPatches()
					So(err, ShouldBeNil)
					So(len(patches), ShouldEqual, 1)
				})

				Convey("Adding a module to the patch should work", func() {
					err = ac.UpdatePatchModule(newPatch.Id.Hex(), "render-module", testPatch, "1e5232709595db427893826ce19289461cba3f75")
					So(err, ShouldBeNil)
					patches, err := ac.GetPatches()
					So(err, ShouldBeNil)
					So(patches[0].Patches[0].ModuleName, ShouldEqual, "")
					So(patches[0].Patches[1].ModuleName, ShouldEqual, "render-module")
					Convey("Removing the module from the patch should work", func() {
						So(ac.DeletePatchModule(newPatch.Id.Hex(), "render-module"), ShouldBeNil)
						patches, err := ac.GetPatches()
						So(err, ShouldBeNil)
						So(len(patches[0].Patches), ShouldEqual, 1)
						Convey("Finalizing the patch should work", func() {
							// First double check that the patch starts with no "version" field
							So(patches[0].Version, ShouldEqual, "")
							So(ac.FinalizePatch(newPatch.Id.Hex()), ShouldBeNil)
							patches, err := ac.GetPatches()
							So(err, ShouldBeNil)
							// After finalizing, the patch should now have a version populated
							So(patches[0].Version, ShouldNotEqual, "")
							Convey("Cancelling the patch should work", func() {
								So(ac.CancelPatch(newPatch.Id.Hex()), ShouldBeNil)
								patches, err := ac.GetPatches()
								So(err, ShouldBeNil)
								// After cancelling, tasks in the version should be deactivated
								tasks, err := model.FindTasks(db.Query(bson.M{model.TaskVersionKey: patches[0].Version}))
								So(err, ShouldBeNil)
								for _, t := range tasks {
									So(t.Activated, ShouldBeFalse)
								}
							})
						})
					})
				})
			})

			Convey("Creating a complex patch should be successful", func() {
				patchSub := patchSubmission{"sample",
					testPatch,
					"sample patch #2",
					"3c7bfeb82d492dc453e7431be664539c35b5db4b",
					"osx-108",
					[]string{"failing_test"},
					false}

				_, err := ac.PutPatch(patchSub)
				So(err, ShouldBeNil)

				Convey("Newly created patch should be fetchable via API", func() {
					patches, err := ac.GetPatches()
					Println(patches)
					So(err, ShouldBeNil)
					So(len(patches), ShouldEqual, 1)
					So(len(patches[0].BuildVariants), ShouldEqual, 1)
					So(patches[0].BuildVariants[0], ShouldEqual, "osx-108")
					So(len(patches[0].Tasks), ShouldEqual, 2)
					So(patches[0].Tasks, ShouldContain, "failing_test")
					Convey("and have expanded dependencies", func() {
						So(patches[0].Tasks, ShouldContain, "compile")
					})
				})
			})
		})
	})
}
Beispiel #3
0
// GetRoutes returns an API route for serving patch data.
func (jsp *JSONPlugin) GetAPIHandler() http.Handler {
	r := mux.NewRouter()
	r.HandleFunc("/tags/{task_name}/{name}", func(w http.ResponseWriter, r *http.Request) {
		t := plugin.GetTask(r)
		if t == nil {
			http.Error(w, "task not found", http.StatusNotFound)
			return
		}
		tagged := []TaskJSON{}
		jsonQuery := db.Query(bson.M{
			"project_id": t.Project,
			"variant":    t.BuildVariant,
			"task_name":  mux.Vars(r)["task_name"],
			"tag":        bson.M{"$exists": true, "$ne": ""},
			"name":       mux.Vars(r)["name"]})
		err := db.FindAllQ(collection, jsonQuery, &tagged)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		plugin.WriteJSON(w, http.StatusOK, tagged)
	})
	r.HandleFunc("/history/{task_name}/{name}", func(w http.ResponseWriter, r *http.Request) {
		t := plugin.GetTask(r)
		if t == nil {
			http.Error(w, "task not found", http.StatusNotFound)
			return
		}
		before := []TaskJSON{}
		jsonQuery := db.Query(bson.M{
			"project_id": t.Project,
			"variant":    t.BuildVariant,
			"order":      bson.M{"$lte": t.RevisionOrderNumber},
			"task_name":  mux.Vars(r)["task_name"],
			"is_patch":   false,
			"name":       mux.Vars(r)["name"]}).Sort([]string{"-order"}).Limit(100)
		err := db.FindAllQ(collection, jsonQuery, &before)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		//reverse order of "before" because we had to sort it backwards to apply the limit correctly:
		for i, j := 0, len(before)-1; i < j; i, j = i+1, j-1 {
			before[i], before[j] = before[j], before[i]
		}

		after := []TaskJSON{}
		jsonAfterQuery := db.Query(bson.M{
			"project_id": t.Project,
			"variant":    t.BuildVariant,
			"order":      bson.M{"$gt": t.RevisionOrderNumber},
			"task_name":  mux.Vars(r)["task_name"],
			"is_patch":   false,
			"name":       mux.Vars(r)["name"]}).Sort([]string{"order"}).Limit(100)
		err = db.FindAllQ(collection, jsonAfterQuery, &after)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		//concatenate before + after
		before = append(before, after...)
		plugin.WriteJSON(w, http.StatusOK, before)
	})

	r.HandleFunc("/data/{name}", func(w http.ResponseWriter, r *http.Request) {
		task := plugin.GetTask(r)
		if task == nil {
			http.Error(w, "task not found", http.StatusNotFound)
			return
		}
		name := mux.Vars(r)["name"]
		rawData := map[string]interface{}{}
		err := util.ReadJSONInto(r.Body, &rawData)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		jsonBlob := TaskJSON{
			TaskId:              task.Id,
			TaskName:            task.DisplayName,
			Name:                name,
			BuildId:             task.BuildId,
			Variant:             task.BuildVariant,
			ProjectId:           task.Project,
			VersionId:           task.Version,
			Revision:            task.Revision,
			RevisionOrderNumber: task.RevisionOrderNumber,
			Data:                rawData,
			IsPatch:             task.Requester == evergreen.PatchVersionRequester,
		}
		_, err = db.Upsert(collection, bson.M{"task_id": task.Id, "name": name}, jsonBlob)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		plugin.WriteJSON(w, http.StatusOK, "ok")
		return
	})

	r.HandleFunc("/data/{task_name}/{name}", func(w http.ResponseWriter, r *http.Request) {
		task := plugin.GetTask(r)
		if task == nil {
			http.Error(w, "task not found", http.StatusNotFound)
			return
		}
		name := mux.Vars(r)["name"]
		taskName := mux.Vars(r)["task_name"]
		var jsonForTask TaskJSON
		err := db.FindOneQ(collection, db.Query(bson.M{"version_id": task.Version, "build_id": task.BuildId, "name": name, "task_name": taskName}), &jsonForTask)
		if err != nil {
			if err == mgo.ErrNotFound {
				plugin.WriteJSON(w, http.StatusNotFound, nil)
				return
			}
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		plugin.WriteJSON(w, http.StatusOK, jsonForTask.Data)
	})
	r.HandleFunc("/data/{task_name}/{name}/{variant}", func(w http.ResponseWriter, r *http.Request) {
		task := plugin.GetTask(r)
		if task == nil {
			http.Error(w, "task not found", http.StatusNotFound)
			return
		}
		name := mux.Vars(r)["name"]
		taskName := mux.Vars(r)["task_name"]
		variantId := mux.Vars(r)["variant"]
		// Find the task for the other variant, if it exists
		ts, err := model.FindTasks(db.Query(bson.M{model.TaskVersionKey: task.Version, model.TaskBuildVariantKey: variantId, model.TaskDisplayNameKey: taskName}).Limit(1))
		if err != nil {
			if err == mgo.ErrNotFound {
				plugin.WriteJSON(w, http.StatusNotFound, nil)
				return
			}
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if len(ts) == 0 {
			plugin.WriteJSON(w, http.StatusNotFound, nil)
			return
		}
		otherVariantTask := ts[0]

		var jsonForTask TaskJSON
		err = db.FindOneQ(collection, db.Query(bson.M{"task_id": otherVariantTask.Id, "name": name}), &jsonForTask)
		if err != nil {
			if err == mgo.ErrNotFound {
				plugin.WriteJSON(w, http.StatusNotFound, nil)
				return
			}
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		plugin.WriteJSON(w, http.StatusOK, jsonForTask.Data)
	})
	return r
}