github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/service/rest_task_test.go (about)

     1  package service
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"math/rand"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"path/filepath"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/evergreen-ci/evergreen"
    14  	"github.com/evergreen-ci/evergreen/apimodels"
    15  	"github.com/evergreen-ci/evergreen/auth"
    16  	"github.com/evergreen-ci/evergreen/db"
    17  	"github.com/evergreen-ci/evergreen/model/artifact"
    18  	"github.com/evergreen-ci/evergreen/model/task"
    19  	"github.com/evergreen-ci/evergreen/testutil"
    20  	"github.com/evergreen-ci/render"
    21  	. "github.com/smartystreets/goconvey/convey"
    22  )
    23  
    24  var taskTestConfig = testutil.TestConfig()
    25  
    26  func init() {
    27  	db.SetGlobalSessionProvider(db.SessionFactoryFromConfig(taskTestConfig))
    28  }
    29  
    30  func insertTaskForTesting(taskId, versionId, projectName string, testResult task.TestResult) (*task.Task, error) {
    31  	task := &task.Task{
    32  		Id:                  taskId,
    33  		CreateTime:          time.Now().Add(-20 * time.Minute),
    34  		ScheduledTime:       time.Now().Add(-15 * time.Minute),
    35  		DispatchTime:        time.Now().Add(-14 * time.Minute),
    36  		StartTime:           time.Now().Add(-10 * time.Minute),
    37  		FinishTime:          time.Now().Add(-5 * time.Second),
    38  		PushTime:            time.Now().Add(-1 * time.Millisecond),
    39  		Version:             versionId,
    40  		Project:             projectName,
    41  		Revision:            fmt.Sprintf("%x", rand.Int()),
    42  		Priority:            10,
    43  		LastHeartbeat:       time.Now(),
    44  		Activated:           false,
    45  		BuildId:             "some-build-id",
    46  		DistroId:            "some-distro-id",
    47  		BuildVariant:        "some-build-variant",
    48  		DependsOn:           []task.Dependency{{"some-other-task", ""}},
    49  		DisplayName:         "My task",
    50  		HostId:              "some-host-id",
    51  		Restarts:            0,
    52  		Execution:           0,
    53  		Archived:            false,
    54  		RevisionOrderNumber: 42,
    55  		Requester:           evergreen.RepotrackerVersionRequester,
    56  		Status:              "success",
    57  		Details: apimodels.TaskEndDetail{
    58  			TimedOut:    false,
    59  			Description: "some-stage",
    60  		},
    61  		Aborted:          false,
    62  		TimeTaken:        time.Duration(100 * time.Millisecond),
    63  		ExpectedDuration: time.Duration(99 * time.Millisecond),
    64  		TestResults:      []task.TestResult{testResult},
    65  	}
    66  
    67  	return task, task.Insert()
    68  }
    69  
    70  func TestGetTaskInfo(t *testing.T) {
    71  
    72  	userManager, err := auth.LoadUserManager(taskTestConfig.AuthConfig)
    73  	testutil.HandleTestingErr(err, t, "Failure in loading UserManager from config")
    74  
    75  	uis := UIServer{
    76  		RootURL:     taskTestConfig.Ui.Url,
    77  		Settings:    *taskTestConfig,
    78  		UserManager: userManager,
    79  	}
    80  
    81  	home := evergreen.FindEvergreenHome()
    82  
    83  	uis.Render = render.New(render.Options{
    84  		Directory:    filepath.Join(home, WebRootPath, Templates),
    85  		DisableCache: true,
    86  	})
    87  	testutil.HandleTestingErr(uis.InitPlugins(), t, "problem loading plugins")
    88  	router, err := uis.NewRouter()
    89  	testutil.HandleTestingErr(err, t, "Failed to create ui server router")
    90  
    91  	Convey("When finding info on a particular task", t, func() {
    92  		testutil.HandleTestingErr(db.Clear(task.Collection), t,
    93  			"Error clearing '%v' collection", task.Collection)
    94  
    95  		taskId := "my-task"
    96  		versionId := "my-version"
    97  		projectName := "project_test"
    98  
    99  		testResult := task.TestResult{
   100  			Status:    "success",
   101  			TestFile:  "some-test",
   102  			URL:       "some-url",
   103  			StartTime: float64(time.Now().Add(-9 * time.Minute).Unix()),
   104  			EndTime:   float64(time.Now().Add(-1 * time.Minute).Unix()),
   105  		}
   106  		testTask, err := insertTaskForTesting(taskId, versionId, projectName, testResult)
   107  		So(err, ShouldBeNil)
   108  
   109  		file := artifact.File{
   110  			Name: "Some Artifact",
   111  			Link: "some-url",
   112  		}
   113  		artifact := artifact.Entry{
   114  			TaskId: taskId,
   115  			Files:  []artifact.File{file},
   116  		}
   117  		So(artifact.Upsert(), ShouldBeNil)
   118  
   119  		url, err := router.Get("task_info").URL("task_id", taskId)
   120  		So(err, ShouldBeNil)
   121  
   122  		request, err := http.NewRequest("GET", url.String(), nil)
   123  		So(err, ShouldBeNil)
   124  
   125  		response := httptest.NewRecorder()
   126  		// Need match variables to be set so can call mux.Vars(request)
   127  		// in the actual handler function
   128  		router.ServeHTTP(response, request)
   129  
   130  		So(response.Code, ShouldEqual, http.StatusOK)
   131  
   132  		Convey("response should match contents of database", func() {
   133  			var jsonBody map[string]interface{}
   134  			err = json.Unmarshal(response.Body.Bytes(), &jsonBody)
   135  			So(err, ShouldBeNil)
   136  			fmt.Println(string(response.Body.Bytes()))
   137  
   138  			rawJSONBody := map[string]*json.RawMessage{}
   139  			err = json.Unmarshal(response.Body.Bytes(), &rawJSONBody)
   140  			So(err, ShouldBeNil)
   141  
   142  			So(jsonBody["id"], ShouldEqual, testTask.Id)
   143  
   144  			var createTime time.Time
   145  			err = json.Unmarshal(*rawJSONBody["create_time"], &createTime)
   146  			So(err, ShouldBeNil)
   147  			So(createTime, ShouldHappenWithin, TimePrecision, testTask.CreateTime)
   148  
   149  			var scheduledTime time.Time
   150  			err = json.Unmarshal(*rawJSONBody["scheduled_time"], &scheduledTime)
   151  			So(err, ShouldBeNil)
   152  			So(scheduledTime, ShouldHappenWithin, TimePrecision, testTask.ScheduledTime)
   153  
   154  			var dispatchTime time.Time
   155  			err = json.Unmarshal(*rawJSONBody["dispatch_time"], &dispatchTime)
   156  			So(err, ShouldBeNil)
   157  			So(dispatchTime, ShouldHappenWithin, TimePrecision, testTask.DispatchTime)
   158  
   159  			var startTime time.Time
   160  			err = json.Unmarshal(*rawJSONBody["start_time"], &startTime)
   161  			So(err, ShouldBeNil)
   162  			So(startTime, ShouldHappenWithin, TimePrecision, testTask.StartTime)
   163  
   164  			var finishTime time.Time
   165  			err = json.Unmarshal(*rawJSONBody["finish_time"], &finishTime)
   166  			So(err, ShouldBeNil)
   167  			So(finishTime, ShouldHappenWithin, TimePrecision, testTask.FinishTime)
   168  
   169  			var pushTime time.Time
   170  			err = json.Unmarshal(*rawJSONBody["push_time"], &pushTime)
   171  			So(err, ShouldBeNil)
   172  			So(pushTime, ShouldHappenWithin, TimePrecision, testTask.PushTime)
   173  
   174  			So(jsonBody["version"], ShouldEqual, testTask.Version)
   175  			So(jsonBody["project"], ShouldEqual, testTask.Project)
   176  			So(jsonBody["revision"], ShouldEqual, testTask.Revision)
   177  			So(jsonBody["priority"], ShouldEqual, testTask.Priority)
   178  
   179  			var lastHeartbeat time.Time
   180  			err = json.Unmarshal(*rawJSONBody["last_heartbeat"], &lastHeartbeat)
   181  			So(err, ShouldBeNil)
   182  			So(lastHeartbeat, ShouldHappenWithin, TimePrecision, testTask.LastHeartbeat)
   183  
   184  			So(jsonBody["activated"], ShouldEqual, testTask.Activated)
   185  			So(jsonBody["build_id"], ShouldEqual, testTask.BuildId)
   186  			So(jsonBody["distro"], ShouldEqual, testTask.DistroId)
   187  			So(jsonBody["build_variant"], ShouldEqual, testTask.BuildVariant)
   188  
   189  			var dependsOn []task.Dependency
   190  			So(rawJSONBody["depends_on"], ShouldNotBeNil)
   191  			err = json.Unmarshal(*rawJSONBody["depends_on"], &dependsOn)
   192  			So(err, ShouldBeNil)
   193  			So(dependsOn, ShouldResemble, testTask.DependsOn)
   194  
   195  			So(jsonBody["display_name"], ShouldEqual, testTask.DisplayName)
   196  			So(jsonBody["host_id"], ShouldEqual, testTask.HostId)
   197  			So(jsonBody["restarts"], ShouldEqual, testTask.Restarts)
   198  			So(jsonBody["execution"], ShouldEqual, testTask.Execution)
   199  			So(jsonBody["archived"], ShouldEqual, testTask.Archived)
   200  			So(jsonBody["order"], ShouldEqual, testTask.RevisionOrderNumber)
   201  			So(jsonBody["requester"], ShouldEqual, testTask.Requester)
   202  			So(jsonBody["status"], ShouldEqual, testTask.Status)
   203  
   204  			_jsonStatusDetails, ok := jsonBody["status_details"]
   205  			So(ok, ShouldBeTrue)
   206  			jsonStatusDetails, ok := _jsonStatusDetails.(map[string]interface{})
   207  			So(ok, ShouldBeTrue)
   208  
   209  			So(jsonStatusDetails["timed_out"], ShouldEqual, testTask.Details.TimedOut)
   210  			So(jsonStatusDetails["timeout_stage"], ShouldEqual, testTask.Details.Description)
   211  
   212  			So(jsonBody["aborted"], ShouldEqual, testTask.Aborted)
   213  			So(jsonBody["time_taken"], ShouldEqual, testTask.TimeTaken)
   214  			So(jsonBody["expected_duration"], ShouldEqual, testTask.ExpectedDuration)
   215  
   216  			_jsonTestResults, ok := jsonBody["test_results"]
   217  			So(ok, ShouldBeTrue)
   218  			jsonTestResults, ok := _jsonTestResults.(map[string]interface{})
   219  			So(ok, ShouldBeTrue)
   220  			So(len(jsonTestResults), ShouldEqual, 1)
   221  
   222  			_jsonTestResult, ok := jsonTestResults[testResult.TestFile]
   223  			So(ok, ShouldBeTrue)
   224  			jsonTestResult, ok := _jsonTestResult.(map[string]interface{})
   225  			So(ok, ShouldBeTrue)
   226  
   227  			So(jsonTestResult["status"], ShouldEqual, testResult.Status)
   228  			So(jsonTestResult["time_taken"], ShouldNotBeNil) // value correctness is unchecked
   229  
   230  			_jsonTestResultLogs, ok := jsonTestResult["logs"]
   231  			So(ok, ShouldBeTrue)
   232  			jsonTestResultLogs, ok := _jsonTestResultLogs.(map[string]interface{})
   233  			So(ok, ShouldBeTrue)
   234  
   235  			So(jsonTestResultLogs["url"], ShouldEqual, testResult.URL)
   236  
   237  			var jsonFiles []map[string]interface{}
   238  			err = json.Unmarshal(*rawJSONBody["files"], &jsonFiles)
   239  			So(err, ShouldBeNil)
   240  			So(len(jsonFiles), ShouldEqual, 1)
   241  
   242  			jsonFile := jsonFiles[0]
   243  			So(jsonFile["name"], ShouldEqual, file.Name)
   244  			So(jsonFile["url"], ShouldEqual, file.Link)
   245  		})
   246  	})
   247  
   248  	Convey("When finding info on a nonexistent task", t, func() {
   249  		taskId := "not-present"
   250  
   251  		url, err := router.Get("task_info").URL("task_id", taskId)
   252  		So(err, ShouldBeNil)
   253  
   254  		request, err := http.NewRequest("GET", url.String(), nil)
   255  		So(err, ShouldBeNil)
   256  
   257  		response := httptest.NewRecorder()
   258  		// Need match variables to be set so can call mux.Vars(request)
   259  		// in the actual handler function
   260  		router.ServeHTTP(response, request)
   261  
   262  		So(response.Code, ShouldEqual, http.StatusNotFound)
   263  
   264  		Convey("response should contain a sensible error message", func() {
   265  			var jsonBody map[string]interface{}
   266  			err = json.Unmarshal(response.Body.Bytes(), &jsonBody)
   267  			So(err, ShouldBeNil)
   268  			So(len(jsonBody["message"].(string)), ShouldBeGreaterThan, 0)
   269  		})
   270  	})
   271  }
   272  
   273  func TestGetTaskStatus(t *testing.T) {
   274  
   275  	userManager, err := auth.LoadUserManager(taskTestConfig.AuthConfig)
   276  	testutil.HandleTestingErr(err, t, "Failure in loading UserManager from config")
   277  
   278  	uis := UIServer{
   279  		RootURL:     taskTestConfig.Ui.Url,
   280  		Settings:    *taskTestConfig,
   281  		UserManager: userManager,
   282  	}
   283  
   284  	home := evergreen.FindEvergreenHome()
   285  
   286  	uis.Render = render.New(render.Options{
   287  		Directory:    filepath.Join(home, WebRootPath, Templates),
   288  		DisableCache: true,
   289  	})
   290  	testutil.HandleTestingErr(uis.InitPlugins(), t, "problem loading plugins")
   291  
   292  	router, err := uis.NewRouter()
   293  	testutil.HandleTestingErr(err, t, "Failed to create ui server router")
   294  
   295  	Convey("When finding the status of a particular task", t, func() {
   296  		testutil.HandleTestingErr(db.Clear(task.Collection), t,
   297  			"Error clearing '%v' collection", task.Collection)
   298  
   299  		taskId := "my-task"
   300  
   301  		testResult := task.TestResult{
   302  			Status:    "success",
   303  			TestFile:  "some-test",
   304  			URL:       "some-url",
   305  			StartTime: float64(time.Now().Add(-9 * time.Minute).Unix()),
   306  			EndTime:   float64(time.Now().Add(-1 * time.Minute).Unix()),
   307  		}
   308  		testTask := &task.Task{
   309  			Id:          taskId,
   310  			DisplayName: "My task",
   311  			Status:      "success",
   312  			Details: apimodels.TaskEndDetail{
   313  				TimedOut:    false,
   314  				Description: "some-stage",
   315  			},
   316  			TestResults: []task.TestResult{testResult},
   317  		}
   318  		So(testTask.Insert(), ShouldBeNil)
   319  
   320  		url, err := router.Get("task_status").URL("task_id", taskId)
   321  		So(err, ShouldBeNil)
   322  
   323  		request, err := http.NewRequest("GET", url.String(), nil)
   324  		So(err, ShouldBeNil)
   325  
   326  		response := httptest.NewRecorder()
   327  		// Need match variables to be set so can call mux.Vars(request)
   328  		// in the actual handler function
   329  		router.ServeHTTP(response, request)
   330  
   331  		So(response.Code, ShouldEqual, http.StatusOK)
   332  
   333  		Convey("response should match contents of database", func() {
   334  			var jsonBody map[string]interface{}
   335  			err = json.Unmarshal(response.Body.Bytes(), &jsonBody)
   336  			So(err, ShouldBeNil)
   337  
   338  			rawJSONBody := map[string]*json.RawMessage{}
   339  			err = json.Unmarshal(response.Body.Bytes(), &rawJSONBody)
   340  			So(err, ShouldBeNil)
   341  
   342  			So(jsonBody["task_id"], ShouldEqual, testTask.Id)
   343  			So(jsonBody["task_name"], ShouldEqual, testTask.DisplayName)
   344  			So(jsonBody["status"], ShouldEqual, testTask.Status)
   345  
   346  			_jsonStatusDetails, ok := jsonBody["status_details"]
   347  			So(ok, ShouldBeTrue)
   348  			jsonStatusDetails, ok := _jsonStatusDetails.(map[string]interface{})
   349  			So(ok, ShouldBeTrue)
   350  
   351  			So(jsonStatusDetails["timed_out"], ShouldEqual, testTask.Details.TimedOut)
   352  			So(jsonStatusDetails["timeout_stage"], ShouldEqual, testTask.Details.Description)
   353  
   354  			_jsonTestResults, ok := jsonBody["tests"]
   355  			So(ok, ShouldBeTrue)
   356  			jsonTestResults, ok := _jsonTestResults.(map[string]interface{})
   357  			So(ok, ShouldBeTrue)
   358  			So(len(jsonTestResults), ShouldEqual, 1)
   359  
   360  			_jsonTestResult, ok := jsonTestResults[testResult.TestFile]
   361  			So(ok, ShouldBeTrue)
   362  			jsonTestResult, ok := _jsonTestResult.(map[string]interface{})
   363  			So(ok, ShouldBeTrue)
   364  
   365  			So(jsonTestResult["status"], ShouldEqual, testResult.Status)
   366  			So(jsonTestResult["time_taken"], ShouldNotBeNil) // value correctness is unchecked
   367  
   368  			_jsonTestResultLogs, ok := jsonTestResult["logs"]
   369  			So(ok, ShouldBeTrue)
   370  			jsonTestResultLogs, ok := _jsonTestResultLogs.(map[string]interface{})
   371  			So(ok, ShouldBeTrue)
   372  
   373  			So(jsonTestResultLogs["url"], ShouldEqual, testResult.URL)
   374  		})
   375  	})
   376  
   377  	Convey("When finding the status of a nonexistent task", t, func() {
   378  		taskId := "not-present"
   379  
   380  		url, err := router.Get("task_status").URL("task_id", taskId)
   381  		So(err, ShouldBeNil)
   382  
   383  		request, err := http.NewRequest("GET", url.String(), nil)
   384  		So(err, ShouldBeNil)
   385  
   386  		response := httptest.NewRecorder()
   387  		// Need match variables to be set so can call mux.Vars(request)
   388  		// in the actual handler function
   389  		router.ServeHTTP(response, request)
   390  
   391  		So(response.Code, ShouldEqual, http.StatusNotFound)
   392  
   393  		Convey("response should contain a sensible error message", func() {
   394  			var jsonBody map[string]interface{}
   395  			err = json.Unmarshal(response.Body.Bytes(), &jsonBody)
   396  			So(err, ShouldBeNil)
   397  			So(len(jsonBody["message"].(string)), ShouldBeGreaterThan, 0)
   398  		})
   399  	})
   400  }