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

     1  package service
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"math/rand"
     8  	"net/http"
     9  	"net/http/httptest"
    10  	"path/filepath"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/codegangsta/negroni"
    15  	"github.com/evergreen-ci/evergreen"
    16  	"github.com/evergreen-ci/evergreen/auth"
    17  	"github.com/evergreen-ci/evergreen/db"
    18  	"github.com/evergreen-ci/evergreen/model/build"
    19  	modelutil "github.com/evergreen-ci/evergreen/model/testutil"
    20  	"github.com/evergreen-ci/evergreen/model/version"
    21  	serviceutil "github.com/evergreen-ci/evergreen/service/testutil"
    22  	"github.com/evergreen-ci/evergreen/testutil"
    23  	"github.com/evergreen-ci/render"
    24  	. "github.com/smartystreets/goconvey/convey"
    25  )
    26  
    27  var versionTestConfig = testutil.TestConfig()
    28  
    29  func init() {
    30  	db.SetGlobalSessionProvider(db.SessionFactoryFromConfig(versionTestConfig))
    31  }
    32  
    33  func TestGetRecentVersions(t *testing.T) {
    34  
    35  	userManager, err := auth.LoadUserManager(versionTestConfig.AuthConfig)
    36  	testutil.HandleTestingErr(err, t, "Failure in loading UserManager from config")
    37  
    38  	uis := UIServer{
    39  		RootURL:     versionTestConfig.Ui.Url,
    40  		Settings:    *versionTestConfig,
    41  		UserManager: userManager,
    42  	}
    43  
    44  	home := evergreen.FindEvergreenHome()
    45  
    46  	uis.Render = render.New(render.Options{
    47  		Directory:    filepath.Join(home, WebRootPath, Templates),
    48  		DisableCache: true,
    49  	})
    50  	testutil.HandleTestingErr(uis.InitPlugins(), t, "problem loading plugins")
    51  
    52  	router, err := uis.NewRouter()
    53  	testutil.HandleTestingErr(err, t, "Failed to create ui server router")
    54  
    55  	err = modelutil.CreateTestLocalConfig(buildTestConfig, "mci-test", "")
    56  	testutil.HandleTestingErr(err, t, "Error loading local config mci-test")
    57  
    58  	err = modelutil.CreateTestLocalConfig(buildTestConfig, "render", "")
    59  	testutil.HandleTestingErr(err, t, "Error loading local config render")
    60  
    61  	Convey("When finding recent versions", t, func() {
    62  		testutil.HandleTestingErr(db.ClearCollections(version.Collection, build.Collection), t,
    63  			"Error clearing '%v' collection", version.Collection)
    64  
    65  		projectName := "project_test"
    66  
    67  		err = modelutil.CreateTestLocalConfig(buildTestConfig, projectName, "")
    68  		So(err, ShouldBeNil)
    69  		otherProjectName := "my-other-project"
    70  		So(projectName, ShouldNotEqual, otherProjectName) // sanity-check
    71  
    72  		buildIdPreface := "build-id-for-version%v"
    73  
    74  		So(NumRecentVersions, ShouldBeGreaterThan, 0)
    75  		versions := make([]*version.Version, 0, NumRecentVersions)
    76  
    77  		// Insert a bunch of versions into the database
    78  		for i := 0; i < NumRecentVersions; i++ {
    79  			v := &version.Version{
    80  				Id:                  fmt.Sprintf("version%v", i),
    81  				Identifier:          projectName,
    82  				Author:              fmt.Sprintf("author%v", i),
    83  				Revision:            fmt.Sprintf("%x", rand.Int()),
    84  				Message:             fmt.Sprintf("message%v", i),
    85  				RevisionOrderNumber: i + 1,
    86  				Requester:           evergreen.RepotrackerVersionRequester,
    87  			}
    88  			So(v.Insert(), ShouldBeNil)
    89  			versions = append(versions, v)
    90  		}
    91  
    92  		// Construct a version that should not be present in the response
    93  		// since the length of the build ids slice is different than that
    94  		// of the build variants slice
    95  		earlyVersion := &version.Version{
    96  			Id:                  "some-id",
    97  			Identifier:          projectName,
    98  			Author:              "some-author",
    99  			Revision:            fmt.Sprintf("%x", rand.Int()),
   100  			Message:             "some-message",
   101  			RevisionOrderNumber: 0,
   102  			Requester:           evergreen.RepotrackerVersionRequester,
   103  		}
   104  		So(earlyVersion.Insert(), ShouldBeNil)
   105  
   106  		// Construct a version that should not be present in the response
   107  		// since it belongs to a different project
   108  		otherVersion := &version.Version{
   109  			Id:                  "some-other-id",
   110  			Identifier:          otherProjectName,
   111  			Author:              "some-other-author",
   112  			Revision:            fmt.Sprintf("%x", rand.Int()),
   113  			Message:             "some-other-message",
   114  			RevisionOrderNumber: NumRecentVersions + 1,
   115  			Requester:           evergreen.RepotrackerVersionRequester,
   116  		}
   117  		So(otherVersion.Insert(), ShouldBeNil)
   118  
   119  		builds := make([]*build.Build, 0, NumRecentVersions)
   120  		task := build.TaskCache{
   121  			Id:          "some-task-id",
   122  			DisplayName: "some-task-name",
   123  			Status:      "success",
   124  			TimeTaken:   time.Duration(100 * time.Millisecond),
   125  		}
   126  
   127  		for i := 0; i < NumRecentVersions; i++ {
   128  			build := &build.Build{
   129  				Id:           fmt.Sprintf(buildIdPreface, i),
   130  				Version:      versions[i].Id,
   131  				BuildVariant: "some-build-variant",
   132  				DisplayName:  "Some Build Variant",
   133  				Tasks:        []build.TaskCache{task},
   134  			}
   135  			So(build.Insert(), ShouldBeNil)
   136  			builds = append(builds, build)
   137  		}
   138  
   139  		url, err := router.Get("recent_versions").URL("project_id", projectName)
   140  		So(err, ShouldBeNil)
   141  
   142  		request, err := http.NewRequest("GET", url.String(), nil)
   143  		So(err, ShouldBeNil)
   144  
   145  		response := httptest.NewRecorder()
   146  		// Need match variables to be set so can call mux.Vars(request)
   147  		// in the actual handler function
   148  		router.ServeHTTP(response, request)
   149  
   150  		So(response.Code, ShouldEqual, http.StatusOK)
   151  
   152  		Convey("response should match contents of database", func() {
   153  			var jsonBody map[string]interface{}
   154  			err = json.Unmarshal(response.Body.Bytes(), &jsonBody)
   155  			So(err, ShouldBeNil)
   156  
   157  			var rawJsonBody map[string]*json.RawMessage
   158  			err = json.Unmarshal(response.Body.Bytes(), &rawJsonBody)
   159  			So(err, ShouldBeNil)
   160  
   161  			So(jsonBody["project"], ShouldEqual, projectName)
   162  
   163  			var jsonVersions []map[string]interface{}
   164  			err = json.Unmarshal(*rawJsonBody["versions"], &jsonVersions)
   165  			So(err, ShouldBeNil)
   166  			So(len(jsonVersions), ShouldEqual, len(versions))
   167  
   168  			for i, v := range versions {
   169  				jsonVersion := jsonVersions[len(jsonVersions)-i-1] // reverse order
   170  
   171  				So(jsonVersion["version_id"], ShouldEqual, v.Id)
   172  				So(jsonVersion["author"], ShouldEqual, v.Author)
   173  				So(jsonVersion["revision"], ShouldEqual, v.Revision)
   174  				So(jsonVersion["message"], ShouldEqual, v.Message)
   175  
   176  				_jsonBuilds, ok := jsonVersion["builds"]
   177  				So(ok, ShouldBeTrue)
   178  				jsonBuilds, ok := _jsonBuilds.(map[string]interface{})
   179  				So(ok, ShouldBeTrue)
   180  				So(len(jsonBuilds), ShouldEqual, 1)
   181  
   182  				_jsonBuild, ok := jsonBuilds[builds[i].BuildVariant]
   183  				So(ok, ShouldBeTrue)
   184  				jsonBuild, ok := _jsonBuild.(map[string]interface{})
   185  				So(ok, ShouldBeTrue)
   186  
   187  				So(jsonBuild["build_id"], ShouldEqual, builds[i].Id)
   188  				So(jsonBuild["name"], ShouldEqual, builds[i].DisplayName)
   189  
   190  				_jsonTasks, ok := jsonBuild["tasks"]
   191  				So(ok, ShouldBeTrue)
   192  				jsonTasks, ok := _jsonTasks.(map[string]interface{})
   193  				So(ok, ShouldBeTrue)
   194  				So(len(jsonTasks), ShouldEqual, 1)
   195  
   196  				_jsonTask, ok := jsonTasks[task.DisplayName]
   197  				So(ok, ShouldBeTrue)
   198  				jsonTask, ok := _jsonTask.(map[string]interface{})
   199  				So(ok, ShouldBeTrue)
   200  
   201  				So(jsonTask["task_id"], ShouldEqual, task.Id)
   202  				So(jsonTask["status"], ShouldEqual, task.Status)
   203  				So(jsonTask["time_taken"], ShouldEqual, task.TimeTaken)
   204  			}
   205  		})
   206  	})
   207  
   208  	Convey("When finding recent versions for a nonexistent project", t, func() {
   209  		projectName := "not-present"
   210  
   211  		url, err := router.Get("recent_versions").URL("project_id", projectName)
   212  		So(err, ShouldBeNil)
   213  
   214  		request, err := http.NewRequest("GET", url.String(), nil)
   215  		So(err, ShouldBeNil)
   216  
   217  		response := httptest.NewRecorder()
   218  		// Need match variables to be set so can call mux.Vars(request)
   219  		// in the actual handler function
   220  		router.ServeHTTP(response, request)
   221  
   222  		So(response.Code, ShouldEqual, http.StatusOK)
   223  
   224  		Convey("response should contain no versions", func() {
   225  			var jsonBody map[string]interface{}
   226  			err = json.Unmarshal(response.Body.Bytes(), &jsonBody)
   227  			So(err, ShouldBeNil)
   228  
   229  			var rawJsonBody map[string]*json.RawMessage
   230  			err = json.Unmarshal(response.Body.Bytes(), &rawJsonBody)
   231  			So(err, ShouldBeNil)
   232  
   233  			So(jsonBody["project"], ShouldEqual, projectName)
   234  
   235  			var jsonVersions []map[string]interface{}
   236  			err = json.Unmarshal(*rawJsonBody["versions"], &jsonVersions)
   237  			So(err, ShouldBeNil)
   238  			So(jsonVersions, ShouldBeEmpty)
   239  		})
   240  	})
   241  }
   242  
   243  func TestGetVersionInfo(t *testing.T) {
   244  
   245  	uis := UIServer{
   246  		RootURL:     versionTestConfig.Ui.Url,
   247  		Settings:    *versionTestConfig,
   248  		UserManager: serviceutil.MockUserManager{},
   249  	}
   250  	home := evergreen.FindEvergreenHome()
   251  
   252  	uis.Render = render.New(render.Options{
   253  		Directory:    filepath.Join(home, WebRootPath, Templates),
   254  		DisableCache: true,
   255  	})
   256  	testutil.HandleTestingErr(uis.InitPlugins(), t, "problem loading plugins")
   257  
   258  	router, err := uis.NewRouter()
   259  	testutil.HandleTestingErr(err, t, "Failed to create ui server router")
   260  
   261  	err = modelutil.CreateTestLocalConfig(buildTestConfig, "mci-test", "")
   262  	testutil.HandleTestingErr(err, t, "Error loading local config mci-test")
   263  
   264  	err = modelutil.CreateTestLocalConfig(buildTestConfig, "render", "")
   265  	testutil.HandleTestingErr(err, t, "Error loading local config render")
   266  
   267  	Convey("When finding info on a particular version", t, func() {
   268  		testutil.HandleTestingErr(db.Clear(version.Collection), t,
   269  			"Error clearing '%v' collection", version.Collection)
   270  
   271  		versionId := "my-version"
   272  		projectName := "project_test"
   273  
   274  		err = modelutil.CreateTestLocalConfig(buildTestConfig, projectName, "")
   275  		So(err, ShouldBeNil)
   276  
   277  		v := &version.Version{
   278  			Id:                  versionId,
   279  			CreateTime:          time.Now().Add(-20 * time.Minute),
   280  			StartTime:           time.Now().Add(-10 * time.Minute),
   281  			FinishTime:          time.Now().Add(-5 * time.Second),
   282  			Revision:            fmt.Sprintf("%x", rand.Int()),
   283  			Author:              "some-author",
   284  			AuthorEmail:         "some-email",
   285  			Message:             "some-message",
   286  			Status:              "success",
   287  			BuildIds:            []string{"some-build-id"},
   288  			BuildVariants:       []version.BuildStatus{{"some-build-variant", true, time.Now().Add(-20 * time.Minute), "some-build-id"}},
   289  			RevisionOrderNumber: rand.Int(),
   290  			Owner:               "some-owner",
   291  			Repo:                "some-repo",
   292  			Branch:              "some-branch",
   293  			RepoKind:            "github",
   294  			Identifier:          versionId,
   295  			Remote:              false,
   296  			RemotePath:          "",
   297  			Requester:           evergreen.RepotrackerVersionRequester,
   298  		}
   299  		So(v.Insert(), ShouldBeNil)
   300  
   301  		url, err := router.Get("version_info").URL("version_id", versionId)
   302  		So(err, ShouldBeNil)
   303  
   304  		request, err := http.NewRequest("GET", url.String(), nil)
   305  		So(err, ShouldBeNil)
   306  
   307  		response := httptest.NewRecorder()
   308  		// Need match variables to be set so can call mux.Vars(request)
   309  		// in the actual handler function
   310  		router.ServeHTTP(response, request)
   311  
   312  		fmt.Println(response.Body)
   313  
   314  		So(response.Code, ShouldEqual, http.StatusOK)
   315  		validateVersionInfo(v, response)
   316  	})
   317  
   318  	Convey("When finding info on a nonexistent version", t, func() {
   319  		versionId := "not-present"
   320  
   321  		url, err := router.Get("version_info").URL("version_id", versionId)
   322  		So(err, ShouldBeNil)
   323  
   324  		request, err := http.NewRequest("GET", url.String(), nil)
   325  		So(err, ShouldBeNil)
   326  
   327  		response := httptest.NewRecorder()
   328  		// Need match variables to be set so can call mux.Vars(request)
   329  		// in the actual handler function
   330  		router.ServeHTTP(response, request)
   331  
   332  		So(response.Code, ShouldEqual, http.StatusNotFound)
   333  
   334  		Convey("response should contain a sensible error message", func() {
   335  			var jsonBody map[string]interface{}
   336  			err = json.Unmarshal(response.Body.Bytes(), &jsonBody)
   337  			So(err, ShouldBeNil)
   338  			So(len(jsonBody["message"].(string)), ShouldBeGreaterThan, 0)
   339  		})
   340  	})
   341  }
   342  
   343  func TestGetVersionInfoViaRevision(t *testing.T) {
   344  
   345  	userManager, err := auth.LoadUserManager(versionTestConfig.AuthConfig)
   346  	testutil.HandleTestingErr(err, t, "Failure in loading UserManager from config")
   347  
   348  	uis := UIServer{
   349  		RootURL:     versionTestConfig.Ui.Url,
   350  		Settings:    *versionTestConfig,
   351  		UserManager: userManager,
   352  	}
   353  
   354  	home := evergreen.FindEvergreenHome()
   355  
   356  	uis.Render = render.New(render.Options{
   357  		Directory:    filepath.Join(home, WebRootPath, Templates),
   358  		DisableCache: true,
   359  	})
   360  	testutil.HandleTestingErr(uis.InitPlugins(), t, "problem loading plugins")
   361  
   362  	router, err := uis.NewRouter()
   363  	testutil.HandleTestingErr(err, t, "Failed to create ui server router")
   364  
   365  	projectName := "project_test"
   366  
   367  	Convey("When finding info on a particular version by its revision", t, func() {
   368  		testutil.HandleTestingErr(db.Clear(version.Collection), t,
   369  			"Error clearing '%v' collection", version.Collection)
   370  
   371  		versionId := "my-version"
   372  		revision := fmt.Sprintf("%x", rand.Int())
   373  
   374  		v := &version.Version{
   375  			Id:                  versionId,
   376  			CreateTime:          time.Now().Add(-20 * time.Minute),
   377  			StartTime:           time.Now().Add(-10 * time.Minute),
   378  			FinishTime:          time.Now().Add(-5 * time.Second),
   379  			Revision:            revision,
   380  			Author:              "some-author",
   381  			AuthorEmail:         "some-email",
   382  			Message:             "some-message",
   383  			Status:              "success",
   384  			BuildIds:            []string{"some-build-id"},
   385  			BuildVariants:       []version.BuildStatus{{"some-build-variant", true, time.Now().Add(-20 * time.Minute), "some-build-id"}},
   386  			RevisionOrderNumber: rand.Int(),
   387  			Owner:               "some-owner",
   388  			Repo:                "some-repo",
   389  			Branch:              "some-branch",
   390  			RepoKind:            "github",
   391  			Identifier:          projectName,
   392  			Remote:              false,
   393  			RemotePath:          "",
   394  			Requester:           evergreen.RepotrackerVersionRequester,
   395  		}
   396  		So(v.Insert(), ShouldBeNil)
   397  
   398  		url, err := router.Get("version_info_via_revision").URL(
   399  			"project_id", projectName, "revision", revision)
   400  		So(err, ShouldBeNil)
   401  
   402  		request, err := http.NewRequest("GET", url.String(), nil)
   403  		So(err, ShouldBeNil)
   404  
   405  		response := httptest.NewRecorder()
   406  		// Need match variables to be set so can call mux.Vars(request)
   407  		// in the actual handler function
   408  		router.ServeHTTP(response, request)
   409  
   410  		So(response.Code, ShouldEqual, http.StatusOK)
   411  		validateVersionInfo(v, response)
   412  	})
   413  
   414  	Convey("When finding info on a nonexistent version by its revision", t, func() {
   415  		revision := "not-present"
   416  
   417  		url, err := router.Get("version_info_via_revision").URL(
   418  			"project_id", projectName, "revision", revision)
   419  		So(err, ShouldBeNil)
   420  
   421  		request, err := http.NewRequest("GET", url.String(), nil)
   422  		So(err, ShouldBeNil)
   423  
   424  		response := httptest.NewRecorder()
   425  		// Need match variables to be set so can call mux.Vars(request)
   426  		// in the actual handler function
   427  		router.ServeHTTP(response, request)
   428  
   429  		So(response.Code, ShouldEqual, http.StatusNotFound)
   430  
   431  		Convey("response should contain a sensible error message", func() {
   432  			var jsonBody map[string]interface{}
   433  			err = json.Unmarshal(response.Body.Bytes(), &jsonBody)
   434  			So(err, ShouldBeNil)
   435  			So(len(jsonBody["message"].(string)), ShouldBeGreaterThan, 0)
   436  		})
   437  	})
   438  }
   439  
   440  func TestActivateVersion(t *testing.T) {
   441  
   442  	uis := UIServer{
   443  		RootURL:     versionTestConfig.Ui.Url,
   444  		Settings:    *versionTestConfig,
   445  		UserManager: serviceutil.MockUserManager{},
   446  	}
   447  
   448  	home := evergreen.FindEvergreenHome()
   449  
   450  	uis.Render = render.New(render.Options{
   451  		Directory:    filepath.Join(home, WebRootPath, Templates),
   452  		DisableCache: true,
   453  	})
   454  	testutil.HandleTestingErr(uis.InitPlugins(), t, "problem loading plugins")
   455  
   456  	router, err := uis.NewRouter()
   457  	testutil.HandleTestingErr(err, t, "Failed to create ui server router")
   458  
   459  	n := negroni.New()
   460  	n.Use(negroni.HandlerFunc(UserMiddleware(uis.UserManager)))
   461  	n.UseHandler(router)
   462  
   463  	Convey("When marking a particular version as active", t, func() {
   464  		testutil.HandleTestingErr(db.ClearCollections(version.Collection, build.Collection), t,
   465  			"Error clearing collections")
   466  
   467  		versionId := "my-version"
   468  		projectName := "project_test"
   469  
   470  		build := &build.Build{
   471  			Id:           "some-build-id",
   472  			BuildVariant: "some-build-variant",
   473  		}
   474  		So(build.Insert(), ShouldBeNil)
   475  
   476  		v := &version.Version{
   477  			Id:                  versionId,
   478  			CreateTime:          time.Now().Add(-20 * time.Minute),
   479  			StartTime:           time.Now().Add(-10 * time.Minute),
   480  			FinishTime:          time.Now().Add(-5 * time.Second),
   481  			Revision:            fmt.Sprintf("%x", rand.Int()),
   482  			Author:              "some-author",
   483  			AuthorEmail:         "some-email",
   484  			Message:             "some-message",
   485  			Status:              "success",
   486  			BuildIds:            []string{build.Id},
   487  			BuildVariants:       []version.BuildStatus{{"some-build-variant", true, time.Now().Add(-20 * time.Minute), "some-build-id"}},
   488  			RevisionOrderNumber: rand.Int(),
   489  			Owner:               "some-owner",
   490  			Repo:                "some-repo",
   491  			Branch:              "some-branch",
   492  			RepoKind:            "github",
   493  			Identifier:          projectName,
   494  			Remote:              false,
   495  			RemotePath:          "",
   496  			Requester:           evergreen.RepotrackerVersionRequester,
   497  		}
   498  		So(v.Insert(), ShouldBeNil)
   499  
   500  		url, err := router.Get("version_info").URL("version_id", versionId)
   501  		So(err, ShouldBeNil)
   502  
   503  		var body = map[string]interface{}{
   504  			"activated": true,
   505  		}
   506  		jsonBytes, err := json.Marshal(body)
   507  		So(err, ShouldBeNil)
   508  		bodyReader := bytes.NewReader(jsonBytes)
   509  
   510  		request, err := http.NewRequest("PATCH", url.String(), bodyReader)
   511  		So(err, ShouldBeNil)
   512  		// add auth cookie--this can be anything if we are using a MockUserManager
   513  		request.AddCookie(&http.Cookie{Name: evergreen.AuthTokenCookie, Value: "token"})
   514  
   515  		response := httptest.NewRecorder()
   516  		// Need match variables to be set so can call mux.Vars(request)
   517  		// in the actual handler function
   518  		n.ServeHTTP(response, request)
   519  
   520  		So(response.Code, ShouldEqual, http.StatusOK)
   521  
   522  		validateVersionInfo(v, response)
   523  	})
   524  
   525  	Convey("When marking a nonexistent version as active", t, func() {
   526  		versionId := "not-present"
   527  
   528  		url, err := router.Get("version_info").URL("version_id", versionId)
   529  		So(err, ShouldBeNil)
   530  
   531  		var body = map[string]interface{}{
   532  			"activated": true,
   533  		}
   534  		jsonBytes, err := json.Marshal(body)
   535  		So(err, ShouldBeNil)
   536  		bodyReader := bytes.NewReader(jsonBytes)
   537  
   538  		request, err := http.NewRequest("PATCH", url.String(), bodyReader)
   539  		So(err, ShouldBeNil)
   540  
   541  		response := httptest.NewRecorder()
   542  		// add auth cookie--this can be anything if we are using a MockUserManager
   543  		request.AddCookie(&http.Cookie{Name: evergreen.AuthTokenCookie, Value: "token"})
   544  		n.ServeHTTP(response, request)
   545  
   546  		So(response.Code, ShouldEqual, http.StatusNotFound)
   547  
   548  		Convey("response should contain a sensible error message", func() {
   549  			var jsonBody map[string]interface{}
   550  			err = json.Unmarshal(response.Body.Bytes(), &jsonBody)
   551  			So(err, ShouldBeNil)
   552  			So(len(jsonBody["message"].(string)), ShouldBeGreaterThan, 0)
   553  		})
   554  	})
   555  
   556  	Convey("When modifying a version without credentials", t, func() {
   557  		versionId := "not-present"
   558  
   559  		url, err := router.Get("version_info").URL("version_id", versionId)
   560  		So(err, ShouldBeNil)
   561  
   562  		var body = map[string]interface{}{
   563  			"activated": true,
   564  		}
   565  		jsonBytes, err := json.Marshal(body)
   566  		So(err, ShouldBeNil)
   567  		bodyReader := bytes.NewReader(jsonBytes)
   568  
   569  		request, err := http.NewRequest("PATCH", url.String(), bodyReader)
   570  		So(err, ShouldBeNil)
   571  
   572  		response := httptest.NewRecorder()
   573  		n.ServeHTTP(response, request)
   574  
   575  		Convey("response should indicate a permission error", func() {
   576  			So(response.Code, ShouldEqual, http.StatusUnauthorized)
   577  		})
   578  	})
   579  }
   580  
   581  func TestGetVersionStatus(t *testing.T) {
   582  
   583  	userManager, err := auth.LoadUserManager(versionTestConfig.AuthConfig)
   584  	testutil.HandleTestingErr(err, t, "Failure in loading UserManager from config")
   585  
   586  	uis := UIServer{
   587  		RootURL:     versionTestConfig.Ui.Url,
   588  		Settings:    *versionTestConfig,
   589  		UserManager: userManager,
   590  	}
   591  
   592  	home := evergreen.FindEvergreenHome()
   593  
   594  	uis.Render = render.New(render.Options{
   595  		Directory:    filepath.Join(home, WebRootPath, Templates),
   596  		DisableCache: true,
   597  	})
   598  	testutil.HandleTestingErr(uis.InitPlugins(), t, "problem loading plugins")
   599  
   600  	router, err := uis.NewRouter()
   601  	testutil.HandleTestingErr(err, t, "Failed to create ui server router")
   602  
   603  	Convey("When finding the status of a particular version", t, func() {
   604  		testutil.HandleTestingErr(db.Clear(build.Collection), t,
   605  			"Error clearing '%v' collection", build.Collection)
   606  
   607  		versionId := "my-version"
   608  
   609  		task := build.TaskCache{
   610  			Id:          "some-task-id",
   611  			DisplayName: "some-task-name",
   612  			Status:      "success",
   613  			TimeTaken:   time.Duration(100 * time.Millisecond),
   614  		}
   615  		build := &build.Build{
   616  			Id:           "some-build-id",
   617  			Version:      versionId,
   618  			BuildVariant: "some-build-variant",
   619  			DisplayName:  "Some Build Variant",
   620  			Tasks:        []build.TaskCache{task},
   621  		}
   622  		So(build.Insert(), ShouldBeNil)
   623  
   624  		Convey("grouped by tasks", func() {
   625  			groupBy := "tasks"
   626  
   627  			url, err := router.Get("version_status").URL("version_id", versionId)
   628  			So(err, ShouldBeNil)
   629  
   630  			query := url.Query()
   631  			query.Set("groupby", groupBy)
   632  			url.RawQuery = query.Encode()
   633  
   634  			request, err := http.NewRequest("GET", url.String(), nil)
   635  			So(err, ShouldBeNil)
   636  
   637  			response := httptest.NewRecorder()
   638  			// Need match variables to be set so can call mux.Vars(request)
   639  			// in the actual handler function
   640  			router.ServeHTTP(response, request)
   641  
   642  			So(response.Code, ShouldEqual, http.StatusOK)
   643  
   644  			Convey("response should match contents of database", func() {
   645  				var jsonBody map[string]interface{}
   646  				err = json.Unmarshal(response.Body.Bytes(), &jsonBody)
   647  				So(err, ShouldBeNil)
   648  
   649  				So(jsonBody["version_id"], ShouldEqual, versionId)
   650  
   651  				_jsonTasks, ok := jsonBody["tasks"]
   652  				So(ok, ShouldBeTrue)
   653  				jsonTasks, ok := _jsonTasks.(map[string]interface{})
   654  				So(ok, ShouldBeTrue)
   655  				So(len(jsonTasks), ShouldEqual, 1)
   656  
   657  				_jsonTask, ok := jsonTasks[task.DisplayName]
   658  				So(ok, ShouldBeTrue)
   659  				jsonTask, ok := _jsonTask.(map[string]interface{})
   660  				So(ok, ShouldBeTrue)
   661  
   662  				_jsonBuild, ok := jsonTask[build.BuildVariant]
   663  				So(ok, ShouldBeTrue)
   664  				jsonBuild, ok := _jsonBuild.(map[string]interface{})
   665  				So(ok, ShouldBeTrue)
   666  
   667  				So(jsonBuild["task_id"], ShouldEqual, task.Id)
   668  				So(jsonBuild["status"], ShouldEqual, task.Status)
   669  				So(jsonBuild["time_taken"], ShouldEqual, task.TimeTaken)
   670  			})
   671  
   672  			Convey("is the default option", func() {
   673  				url, err := router.Get("version_status").URL("version_id", versionId)
   674  				So(err, ShouldBeNil)
   675  
   676  				request, err := http.NewRequest("GET", url.String(), nil)
   677  				So(err, ShouldBeNil)
   678  
   679  				_response := httptest.NewRecorder()
   680  				// Need match variables to be set so can call mux.Vars(request)
   681  				// in the actual handler function
   682  				router.ServeHTTP(_response, request)
   683  
   684  				So(_response, ShouldResemble, response)
   685  			})
   686  		})
   687  
   688  		Convey("grouped by builds", func() {
   689  			groupBy := "builds"
   690  
   691  			url, err := router.Get("version_status").URL("version_id", versionId)
   692  			So(err, ShouldBeNil)
   693  
   694  			query := url.Query()
   695  			query.Set("groupby", groupBy)
   696  			url.RawQuery = query.Encode()
   697  
   698  			request, err := http.NewRequest("GET", url.String(), nil)
   699  			So(err, ShouldBeNil)
   700  
   701  			response := httptest.NewRecorder()
   702  			// Need match variables to be set so can call mux.Vars(request)
   703  			// in the actual handler function
   704  			router.ServeHTTP(response, request)
   705  
   706  			So(response.Code, ShouldEqual, http.StatusOK)
   707  
   708  			Convey("response should match contents of database", func() {
   709  				var jsonBody map[string]interface{}
   710  				err = json.Unmarshal(response.Body.Bytes(), &jsonBody)
   711  				So(err, ShouldBeNil)
   712  
   713  				So(jsonBody["version_id"], ShouldEqual, versionId)
   714  
   715  				_jsonBuilds, ok := jsonBody["builds"]
   716  				So(ok, ShouldBeTrue)
   717  				jsonBuilds, ok := _jsonBuilds.(map[string]interface{})
   718  				So(ok, ShouldBeTrue)
   719  				So(len(jsonBuilds), ShouldEqual, 1)
   720  
   721  				_jsonBuild, ok := jsonBuilds[build.BuildVariant]
   722  				So(ok, ShouldBeTrue)
   723  				jsonBuild, ok := _jsonBuild.(map[string]interface{})
   724  				So(ok, ShouldBeTrue)
   725  
   726  				_jsonTask, ok := jsonBuild[task.DisplayName]
   727  				So(ok, ShouldBeTrue)
   728  				jsonTask, ok := _jsonTask.(map[string]interface{})
   729  				So(ok, ShouldBeTrue)
   730  
   731  				So(jsonTask["task_id"], ShouldEqual, task.Id)
   732  				So(jsonTask["status"], ShouldEqual, task.Status)
   733  				So(jsonTask["time_taken"], ShouldEqual, task.TimeTaken)
   734  			})
   735  		})
   736  
   737  		Convey("grouped by an invalid option", func() {
   738  			groupBy := "invalidOption"
   739  
   740  			url, err := router.Get("version_status").URL("version_id", versionId)
   741  			So(err, ShouldBeNil)
   742  
   743  			query := url.Query()
   744  			query.Set("groupby", groupBy)
   745  			url.RawQuery = query.Encode()
   746  
   747  			request, err := http.NewRequest("GET", url.String(), nil)
   748  			So(err, ShouldBeNil)
   749  
   750  			response := httptest.NewRecorder()
   751  			// Need match variables to be set so can call mux.Vars(request)
   752  			// in the actual handler function
   753  			router.ServeHTTP(response, request)
   754  
   755  			So(response.Code, ShouldEqual, http.StatusBadRequest)
   756  
   757  			var jsonBody map[string]interface{}
   758  			err = json.Unmarshal(response.Body.Bytes(), &jsonBody)
   759  			So(err, ShouldBeNil)
   760  
   761  			So(jsonBody["message"], ShouldEqual,
   762  				fmt.Sprintf("Invalid groupby parameter '%v'", groupBy))
   763  		})
   764  	})
   765  
   766  	Convey("When finding the status of a nonexistent version", t, func() {
   767  		versionId := "not-present"
   768  
   769  		Convey("grouped by tasks", func() {
   770  			groupBy := "tasks"
   771  
   772  			url, err := router.Get("version_status").URL("version_id", versionId)
   773  			So(err, ShouldBeNil)
   774  
   775  			query := url.Query()
   776  			query.Set("groupby", groupBy)
   777  			url.RawQuery = query.Encode()
   778  
   779  			request, err := http.NewRequest("GET", url.String(), nil)
   780  			So(err, ShouldBeNil)
   781  
   782  			response := httptest.NewRecorder()
   783  			// Need match variables to be set so can call mux.Vars(request)
   784  			// in the actual handler function
   785  			router.ServeHTTP(response, request)
   786  
   787  			So(response.Code, ShouldEqual, http.StatusOK)
   788  
   789  			Convey("response should contain a sensible error message", func() {
   790  				var jsonBody map[string]interface{}
   791  				err = json.Unmarshal(response.Body.Bytes(), &jsonBody)
   792  				So(err, ShouldBeNil)
   793  
   794  				_jsonTasks, ok := jsonBody["tasks"]
   795  				So(ok, ShouldBeTrue)
   796  				jsonTasks, ok := _jsonTasks.(map[string]interface{})
   797  				So(ok, ShouldBeTrue)
   798  				So(jsonTasks, ShouldBeEmpty)
   799  			})
   800  		})
   801  
   802  		Convey("grouped by builds", func() {
   803  			versionId := "not-present"
   804  			groupBy := "builds"
   805  
   806  			url, err := router.Get("version_status").URL("version_id", versionId)
   807  			So(err, ShouldBeNil)
   808  
   809  			query := url.Query()
   810  			query.Set("groupby", groupBy)
   811  			url.RawQuery = query.Encode()
   812  
   813  			request, err := http.NewRequest("GET", url.String(), nil)
   814  			So(err, ShouldBeNil)
   815  
   816  			response := httptest.NewRecorder()
   817  			// Need match variables to be set so can call mux.Vars(request)
   818  			// in the actual handler function
   819  			router.ServeHTTP(response, request)
   820  
   821  			So(response.Code, ShouldEqual, http.StatusOK)
   822  
   823  			Convey("response should contain a sensible error message", func() {
   824  				var jsonBody map[string]interface{}
   825  				err = json.Unmarshal(response.Body.Bytes(), &jsonBody)
   826  				So(err, ShouldBeNil)
   827  
   828  				_jsonBuilds, ok := jsonBody["builds"]
   829  				So(ok, ShouldBeTrue)
   830  				jsonBuilds, ok := _jsonBuilds.(map[string]interface{})
   831  				So(ok, ShouldBeTrue)
   832  				So(jsonBuilds, ShouldBeEmpty)
   833  			})
   834  		})
   835  	})
   836  }
   837  
   838  func validateVersionInfo(v *version.Version, response *httptest.ResponseRecorder) {
   839  	Convey("response should match contents of database", func() {
   840  		var jsonBody map[string]interface{}
   841  		err := json.Unmarshal(response.Body.Bytes(), &jsonBody)
   842  		So(err, ShouldBeNil)
   843  
   844  		var rawJsonBody map[string]*json.RawMessage
   845  		err = json.Unmarshal(response.Body.Bytes(), &rawJsonBody)
   846  		So(err, ShouldBeNil)
   847  
   848  		So(jsonBody["id"], ShouldEqual, v.Id)
   849  
   850  		var createTime time.Time
   851  		err = json.Unmarshal(*rawJsonBody["create_time"], &createTime)
   852  		So(err, ShouldBeNil)
   853  		So(createTime, ShouldHappenWithin, TimePrecision, v.CreateTime)
   854  
   855  		var startTime time.Time
   856  		err = json.Unmarshal(*rawJsonBody["start_time"], &startTime)
   857  		So(err, ShouldBeNil)
   858  		So(startTime, ShouldHappenWithin, TimePrecision, v.StartTime)
   859  
   860  		var finishTime time.Time
   861  		err = json.Unmarshal(*rawJsonBody["finish_time"], &finishTime)
   862  		So(err, ShouldBeNil)
   863  		So(finishTime, ShouldHappenWithin, TimePrecision, v.FinishTime)
   864  
   865  		So(jsonBody["project"], ShouldEqual, v.Identifier)
   866  		So(jsonBody["revision"], ShouldEqual, v.Revision)
   867  		So(jsonBody["author"], ShouldEqual, v.Author)
   868  		So(jsonBody["author_email"], ShouldEqual, v.AuthorEmail)
   869  		So(jsonBody["message"], ShouldEqual, v.Message)
   870  		So(jsonBody["status"], ShouldEqual, v.Status)
   871  
   872  		var buildIds []string
   873  		err = json.Unmarshal(*rawJsonBody["builds"], &buildIds)
   874  		So(err, ShouldBeNil)
   875  		So(buildIds, ShouldResemble, v.BuildIds)
   876  
   877  		var buildVariants []string
   878  		err = json.Unmarshal(*rawJsonBody["build_variants"], &buildVariants)
   879  		So(err, ShouldBeNil)
   880  		So(buildVariants[0], ShouldResemble, v.BuildVariants[0].BuildVariant)
   881  
   882  		So(jsonBody["order"], ShouldEqual, v.RevisionOrderNumber)
   883  		So(jsonBody["owner_name"], ShouldEqual, v.Owner)
   884  		So(jsonBody["repo_name"], ShouldEqual, v.Repo)
   885  		So(jsonBody["branch_name"], ShouldEqual, v.Branch)
   886  		So(jsonBody["repo_kind"], ShouldEqual, v.RepoKind)
   887  		So(jsonBody["identifier"], ShouldEqual, v.Identifier)
   888  		So(jsonBody["remote"], ShouldEqual, v.Remote)
   889  		So(jsonBody["remote_path"], ShouldEqual, v.RemotePath)
   890  		So(jsonBody["requester"], ShouldEqual, v.Requester)
   891  	})
   892  }