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

     1  package cli
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/evergreen-ci/evergreen"
    12  	"github.com/evergreen-ci/evergreen/db"
    13  	"github.com/evergreen-ci/evergreen/model"
    14  	"github.com/evergreen-ci/evergreen/model/artifact"
    15  	"github.com/evergreen-ci/evergreen/model/build"
    16  	"github.com/evergreen-ci/evergreen/model/patch"
    17  	"github.com/evergreen-ci/evergreen/model/task"
    18  	"github.com/evergreen-ci/evergreen/model/user"
    19  	"github.com/evergreen-ci/evergreen/model/version"
    20  	"github.com/evergreen-ci/evergreen/plugin"
    21  	"github.com/evergreen-ci/evergreen/service"
    22  	"github.com/evergreen-ci/evergreen/testutil"
    23  	. "github.com/smartystreets/goconvey/convey"
    24  	"gopkg.in/mgo.v2/bson"
    25  	"gopkg.in/yaml.v2"
    26  )
    27  
    28  var testConfig = testutil.TestConfig()
    29  
    30  var testPatch = `diff --git a/README.md b/README.md
    31  index e69de29..e5dcf0f 100644
    32  --- a/README.md
    33  +++ b/README.md
    34  @@ -0,0 +1,2 @@
    35  +
    36  +sdgs
    37  `
    38  
    39  var testModulePatch = `
    40  diff --git a/blah.md b/blah.md
    41  new file mode 100644
    42  index 0000000..ce01362
    43  --- /dev/null
    44  +++ b/blah.md
    45  @@ -0,0 +1 @@
    46  +hello
    47  `
    48  
    49  var emptyPatch = ``
    50  
    51  func init() {
    52  	db.SetGlobalSessionProvider(db.SessionFactoryFromConfig(testConfig))
    53  }
    54  
    55  type cliTestHarness struct {
    56  	testServer       *service.TestServer
    57  	settingsFilePath string
    58  }
    59  
    60  func setupCLITestHarness() cliTestHarness {
    61  	// create a test API server
    62  	testServer, err := service.CreateTestServer(testConfig, nil, plugin.APIPlugins)
    63  	So(err, ShouldBeNil)
    64  	So(
    65  		db.ClearCollections(
    66  			task.Collection,
    67  			build.Collection,
    68  			user.Collection,
    69  			patch.Collection,
    70  			model.ProjectRefCollection,
    71  			artifact.Collection,
    72  			version.Collection,
    73  		),
    74  		ShouldBeNil)
    75  	So(db.Clear(patch.Collection), ShouldBeNil)
    76  	So(db.Clear(model.ProjectRefCollection), ShouldBeNil)
    77  	So((&user.DBUser{Id: "testuser", APIKey: "testapikey", EmailAddress: "tester@mongodb.com"}).Insert(), ShouldBeNil)
    78  	localConfBytes, err := ioutil.ReadFile(filepath.Join(testutil.GetDirectoryOfFile(), "testdata", "sample.yml"))
    79  	So(err, ShouldBeNil)
    80  
    81  	projectRef := &model.ProjectRef{
    82  		Identifier:  "sample",
    83  		Owner:       "evergreen-ci",
    84  		Repo:        "sample",
    85  		RepoKind:    "github",
    86  		Branch:      "master",
    87  		RemotePath:  "evergreen.yml",
    88  		LocalConfig: string(localConfBytes),
    89  		Enabled:     true,
    90  		BatchTime:   180,
    91  	}
    92  	So(projectRef.Insert(), ShouldBeNil)
    93  
    94  	// create a settings file for the command line client
    95  	settings := model.CLISettings{
    96  		APIServerHost: testServer.URL + "/api",
    97  		UIServerHost:  "http://dev-evg.mongodb.com",
    98  		APIKey:        "testapikey",
    99  		User:          "testuser",
   100  	}
   101  	settingsFile, err := ioutil.TempFile("", "settings")
   102  	So(err, ShouldBeNil)
   103  	settingsBytes, err := yaml.Marshal(settings)
   104  	So(err, ShouldBeNil)
   105  	_, err = settingsFile.Write(settingsBytes)
   106  	So(err, ShouldBeNil)
   107  	So(settingsFile.Close(), ShouldBeNil)
   108  	return cliTestHarness{testServer, settingsFile.Name()}
   109  }
   110  
   111  func TestCLIFetchSource(t *testing.T) {
   112  	testutil.ConfigureIntegrationTest(t, testConfig, "TestCLIFetchSource")
   113  	Convey("with a task containing patches and modules", t, func() {
   114  		testSetup := setupCLITestHarness()
   115  		defer testSetup.testServer.Close()
   116  		err := os.RemoveAll("source-patch-1_sample")
   117  		So(err, ShouldBeNil)
   118  
   119  		// first, create a patch
   120  		patchSub := patchSubmission{"sample",
   121  			testPatch,
   122  			"sample patch",
   123  			"3c7bfeb82d492dc453e7431be664539c35b5db4b",
   124  			"all",
   125  			[]string{"all"},
   126  			false}
   127  
   128  		// Set up a test patch that contains module changes
   129  		ac, rc, _, err := getAPIClients(&Options{testSetup.settingsFilePath})
   130  		So(err, ShouldBeNil)
   131  		newPatch, err := ac.PutPatch(patchSub)
   132  		So(err, ShouldBeNil)
   133  		_, err = ac.GetPatches(0)
   134  		So(err, ShouldBeNil)
   135  		So(ac.UpdatePatchModule(newPatch.Id.Hex(), "render-module", testModulePatch, "1e5232709595db427893826ce19289461cba3f75"),
   136  			ShouldBeNil)
   137  		So(ac.FinalizePatch(newPatch.Id.Hex()), ShouldBeNil)
   138  
   139  		patches, err := ac.GetPatches(0)
   140  		So(err, ShouldBeNil)
   141  		testTask, err := task.FindOne(
   142  			db.Query(bson.M{
   143  				task.VersionKey:      patches[0].Version,
   144  				task.BuildVariantKey: "ubuntu",
   145  			}))
   146  		So(err, ShouldBeNil)
   147  		So(testTask, ShouldNotBeNil)
   148  
   149  		err = fetchSource(ac, rc, "", testTask.Id, false)
   150  		So(err, ShouldBeNil)
   151  
   152  		fileStat, err := os.Stat("./source-patch-1_sample/README.md")
   153  		So(err, ShouldBeNil)
   154  		// If patch was applied correctly, README.md will have a non-zero size
   155  		So(fileStat.Size, ShouldNotEqual, 0)
   156  		// If module was fetched, "render" directory should have been created.
   157  		// The "blah.md" file should have been created if the patch was applied successfully.
   158  		fileStat, err = os.Stat("./source-patch-1_sample/modules/render-module/blah.md")
   159  		So(err, ShouldBeNil)
   160  		So(fileStat.Size, ShouldNotEqual, 0)
   161  
   162  	})
   163  }
   164  
   165  func TestCLIFetchArtifacts(t *testing.T) {
   166  	testutil.ConfigureIntegrationTest(t, testConfig, "TestCLIFetchArtifacts")
   167  	Convey("with API test server running", t, func() {
   168  		testSetup := setupCLITestHarness()
   169  		defer testSetup.testServer.Close()
   170  
   171  		err := os.RemoveAll("artifacts-abcdef-rest_task_variant_task_one")
   172  		So(err, ShouldBeNil)
   173  		err = os.RemoveAll("artifacts-abcdef-rest_task_variant_task_two")
   174  		So(err, ShouldBeNil)
   175  
   176  		err = (&task.Task{
   177  			Id:           "rest_task_test_id1",
   178  			BuildVariant: "rest_task_variant",
   179  			Revision:     "abcdef1234",
   180  			DependsOn:    []task.Dependency{{TaskId: "rest_task_test_id2"}},
   181  			DisplayName:  "task_one",
   182  		}).Insert()
   183  		So(err, ShouldBeNil)
   184  
   185  		err = (&task.Task{
   186  			Id:           "rest_task_test_id2",
   187  			Revision:     "abcdef1234",
   188  			BuildVariant: "rest_task_variant",
   189  			DependsOn:    []task.Dependency{},
   190  			DisplayName:  "task_two",
   191  		}).Insert()
   192  
   193  		err = (&artifact.Entry{
   194  			TaskId:          "rest_task_test_id1",
   195  			TaskDisplayName: "task_one",
   196  			Files:           []artifact.File{{Link: "http://www.google.com/robots.txt"}},
   197  		}).Upsert()
   198  		So(err, ShouldBeNil)
   199  
   200  		err = (&artifact.Entry{
   201  			TaskId:          "rest_task_test_id2",
   202  			TaskDisplayName: "task_two",
   203  			Files:           []artifact.File{{Link: "http://www.google.com/humans.txt"}},
   204  		}).Upsert()
   205  		So(err, ShouldBeNil)
   206  
   207  		_, rc, _, err := getAPIClients(&Options{testSetup.settingsFilePath})
   208  		So(err, ShouldBeNil)
   209  
   210  		Convey("shallow fetch artifacts should download a single task's artifacts successfully", func() {
   211  			err = fetchArtifacts(rc, "rest_task_test_id1", "", true)
   212  			So(err, ShouldBeNil)
   213  			// downloaded file should exist where we expect
   214  			fileStat, err := os.Stat("./artifacts-abcdef-rest_task_variant_task_one/robots.txt")
   215  			So(err, ShouldBeNil)
   216  			So(fileStat.Size(), ShouldBeGreaterThan, 0)
   217  
   218  			fileStat, err = os.Stat("./rest_task_variant_task_two/humans.txt")
   219  			So(os.IsNotExist(err), ShouldBeTrue)
   220  			Convey("deep fetch artifacts should also download artifacts from dependency", func() {
   221  				err = fetchArtifacts(rc, "rest_task_test_id1", "", false)
   222  				So(err, ShouldBeNil)
   223  				fileStat, err = os.Stat("./artifacts-abcdef-rest_task_variant_task_two/humans.txt")
   224  				So(os.IsNotExist(err), ShouldBeFalse)
   225  			})
   226  		})
   227  	})
   228  }
   229  
   230  func TestCLITestHistory(t *testing.T) {
   231  	testutil.ConfigureIntegrationTest(t, testConfig, "TestCLITestHistory")
   232  	Convey("with API test server running", t, func() {
   233  		testSetup := setupCLITestHarness()
   234  		defer testSetup.testServer.Close()
   235  
   236  		Convey("with a set of tasks being inserted into the database", func() {
   237  			now := time.Now()
   238  			revisionBeginning := "101112dfac9f1251466afe7c4bf9f56b"
   239  			project := "sample"
   240  			testVersion := version.Version{
   241  				Id:                  "version1",
   242  				Revision:            fmt.Sprintf("%vversion1", revisionBeginning),
   243  				RevisionOrderNumber: 1,
   244  				Identifier:          project,
   245  				Requester:           evergreen.RepotrackerVersionRequester,
   246  			}
   247  			So(testVersion.Insert(), ShouldBeNil)
   248  			testVersion2 := version.Version{
   249  				Id:                  "version2",
   250  				Revision:            fmt.Sprintf("%vversion2", revisionBeginning),
   251  				RevisionOrderNumber: 2,
   252  				Identifier:          project,
   253  				Requester:           evergreen.RepotrackerVersionRequester,
   254  			}
   255  			So(testVersion2.Insert(), ShouldBeNil)
   256  			testVersion3 := version.Version{
   257  				Id:                  "version3",
   258  				Revision:            fmt.Sprintf("%vversion3", revisionBeginning),
   259  				RevisionOrderNumber: 4,
   260  				Identifier:          project,
   261  				Requester:           evergreen.RepotrackerVersionRequester,
   262  			}
   263  			So(testVersion3.Insert(), ShouldBeNil)
   264  			// create tasks with three different display names that start and finish at various times
   265  			for i := 0; i < 10; i++ {
   266  				startTime := now.Add(time.Minute * time.Duration(i))
   267  				endTime := now.Add(time.Minute * time.Duration(i+1))
   268  				passingResult := task.TestResult{
   269  					TestFile:  "passingTest",
   270  					Status:    evergreen.TestSucceededStatus,
   271  					StartTime: float64(startTime.Unix()),
   272  					EndTime:   float64(endTime.Unix()),
   273  				}
   274  				failedResult := task.TestResult{
   275  					TestFile:  "failingTest",
   276  					Status:    evergreen.TestFailedStatus,
   277  					StartTime: float64(startTime.Unix()),
   278  					EndTime:   float64(endTime.Unix()),
   279  				}
   280  				t := task.Task{
   281  					Id:           fmt.Sprintf("task_%v", i),
   282  					Project:      project,
   283  					DisplayName:  fmt.Sprintf("testTask_%v", i%3),
   284  					Revision:     fmt.Sprintf("%vversion%v", revisionBeginning, i%3),
   285  					Version:      fmt.Sprintf("version%v", i%3),
   286  					BuildVariant: "osx",
   287  					Status:       evergreen.TaskFailed,
   288  					TestResults:  []task.TestResult{passingResult, failedResult},
   289  				}
   290  				So(t.Insert(), ShouldBeNil)
   291  			}
   292  
   293  			Convey("with a CLI test history command with tasks, executing should set defaults and print out results", func() {
   294  				thc := TestHistoryCommand{
   295  					GlobalOpts: &Options{testSetup.settingsFilePath},
   296  					Project:    project,
   297  					Tasks:      []string{"testTask_1"},
   298  					Limit:      20,
   299  				}
   300  				So(thc.Execute([]string{}), ShouldBeNil)
   301  			})
   302  		})
   303  	})
   304  
   305  }
   306  
   307  func TestCLIFunctions(t *testing.T) {
   308  	testutil.ConfigureIntegrationTest(t, testConfig, "TestCLIFunctions")
   309  
   310  	var patches []patch.Patch
   311  
   312  	Convey("with API test server running", t, func() {
   313  		testSetup := setupCLITestHarness()
   314  		defer testSetup.testServer.Close()
   315  
   316  		ac, _, _, err := getAPIClients(&Options{testSetup.settingsFilePath})
   317  		So(err, ShouldBeNil)
   318  
   319  		Convey("check that creating a patch works", func() {
   320  			Convey("user should start with no patches present", func() {
   321  				patches, err = ac.GetPatches(0)
   322  				So(err, ShouldBeNil)
   323  				So(len(patches), ShouldEqual, 0)
   324  			})
   325  
   326  			Convey("Creating a simple patch should be successful", func() {
   327  				patchSub := patchSubmission{"sample",
   328  					testPatch,
   329  					"sample patch",
   330  					"3c7bfeb82d492dc453e7431be664539c35b5db4b",
   331  					"all",
   332  					[]string{"all"},
   333  					false}
   334  
   335  				newPatch, err := ac.PutPatch(patchSub)
   336  				So(err, ShouldBeNil)
   337  
   338  				Convey("Newly created patch should be fetchable via API", func() {
   339  					patches, err = ac.GetPatches(0)
   340  					So(err, ShouldBeNil)
   341  					So(len(patches), ShouldEqual, 1)
   342  				})
   343  
   344  				Convey("Adding a module to the patch should work", func() {
   345  					err = ac.UpdatePatchModule(newPatch.Id.Hex(), "render-module", testPatch, "1e5232709595db427893826ce19289461cba3f75")
   346  					So(err, ShouldBeNil)
   347  					patches, err = ac.GetPatches(0)
   348  					So(err, ShouldBeNil)
   349  					So(patches[0].Patches[0].ModuleName, ShouldEqual, "")
   350  					So(patches[0].Patches[1].ModuleName, ShouldEqual, "render-module")
   351  					Convey("Removing the module from the patch should work", func() {
   352  						So(ac.DeletePatchModule(newPatch.Id.Hex(), "render-module"), ShouldBeNil)
   353  						patches, err = ac.GetPatches(0)
   354  						So(err, ShouldBeNil)
   355  						So(len(patches[0].Patches), ShouldEqual, 1)
   356  						Convey("Finalizing the patch should work", func() {
   357  							// First double check that the patch starts with no "version" field
   358  							So(patches[0].Version, ShouldEqual, "")
   359  							So(ac.FinalizePatch(newPatch.Id.Hex()), ShouldBeNil)
   360  							patches, err = ac.GetPatches(0)
   361  							So(err, ShouldBeNil)
   362  							// After finalizing, the patch should now have a version populated
   363  							So(patches[0].Version, ShouldNotEqual, "")
   364  							Convey("Canceling the patch should work", func() {
   365  								So(ac.CancelPatch(newPatch.Id.Hex()), ShouldBeNil)
   366  								patches, err = ac.GetPatches(0)
   367  								So(err, ShouldBeNil)
   368  								// After canceling, tasks in the version should be deactivated
   369  								tasks, err := task.Find(task.ByVersion(patches[0].Version))
   370  								So(err, ShouldBeNil)
   371  								for _, t := range tasks {
   372  									So(t.Activated, ShouldBeFalse)
   373  								}
   374  							})
   375  						})
   376  					})
   377  				})
   378  			})
   379  
   380  			Convey("Creating a patch without variants should be successful", func() {
   381  				patchSub := patchSubmission{
   382  					"sample",
   383  					testPatch,
   384  					"sample patch",
   385  					"3c7bfeb82d492dc453e7431be664539c35b5db4b",
   386  					"all",
   387  					[]string{},
   388  					false,
   389  				}
   390  				_, err := ac.PutPatch(patchSub)
   391  				So(err, ShouldBeNil)
   392  			})
   393  
   394  			Convey("Creating a complex patch should be successful", func() {
   395  				patchSub := patchSubmission{"sample",
   396  					testPatch,
   397  					"sample patch #2",
   398  					"3c7bfeb82d492dc453e7431be664539c35b5db4b",
   399  					"osx-108",
   400  					[]string{"failing_test"},
   401  					false}
   402  
   403  				_, err := ac.PutPatch(patchSub)
   404  				So(err, ShouldBeNil)
   405  
   406  				Convey("Newly created patch should be fetchable via API", func() {
   407  					patches, err = ac.GetPatches(1)
   408  					So(err, ShouldBeNil)
   409  					So(len(patches), ShouldEqual, 1)
   410  					So(len(patches[0].BuildVariants), ShouldEqual, 1)
   411  					So(patches[0].BuildVariants[0], ShouldEqual, "osx-108")
   412  					So(len(patches[0].Tasks), ShouldEqual, 2)
   413  					So(patches[0].Tasks, ShouldContain, "failing_test")
   414  					Convey("and have expanded dependencies", func() {
   415  						So(patches[0].Tasks, ShouldContain, "compile")
   416  					})
   417  
   418  					Convey("putting the patch again", func() {
   419  						_, err := ac.PutPatch(patchSub)
   420  						So(err, ShouldBeNil)
   421  						Convey("GetPatches where n=1 should return 1 patch", func() {
   422  							patches, err = ac.GetPatches(1)
   423  							So(err, ShouldBeNil)
   424  							So(len(patches), ShouldEqual, 1)
   425  						})
   426  						Convey("GetPatches where n=2 should return 2 patches", func() {
   427  							patches, err = ac.GetPatches(2)
   428  							So(err, ShouldBeNil)
   429  							So(len(patches), ShouldEqual, 2)
   430  						})
   431  					})
   432  				})
   433  			})
   434  
   435  			Convey("Creating an empty patch should not error out anything", func() {
   436  				patchSub := patchSubmission{
   437  					projectId:   "sample",
   438  					patchData:   emptyPatch,
   439  					description: "sample patch",
   440  					base:        "3c7bfeb82d492dc453e7431be664539c35b5db4b",
   441  					variants:    "all",
   442  					tasks:       []string{"all"},
   443  					finalize:    false}
   444  
   445  				newPatch, err := ac.PutPatch(patchSub)
   446  				So(err, ShouldBeNil)
   447  
   448  				Convey("Newly created patch should be fetchable via API", func() {
   449  					patches, err = ac.GetPatches(0)
   450  					So(err, ShouldBeNil)
   451  					So(len(patches), ShouldEqual, 1)
   452  				})
   453  
   454  				Convey("Adding a module to the patch should still work as designed even with empty patch", func() {
   455  					err = ac.UpdatePatchModule(newPatch.Id.Hex(), "render-module", emptyPatch, "1e5232709595db427893826ce19289461cba3f75")
   456  					So(err, ShouldBeNil)
   457  					patches, err := ac.GetPatches(0)
   458  					So(err, ShouldBeNil)
   459  					So(patches[0].Patches[0].ModuleName, ShouldEqual, "")
   460  					So(patches[0].Patches[1].ModuleName, ShouldEqual, "render-module")
   461  					Convey("Removing the module from the patch should work as designed even with empty patch", func() {
   462  						So(ac.DeletePatchModule(newPatch.Id.Hex(), "render-module"), ShouldBeNil)
   463  						patches, err := ac.GetPatches(0)
   464  						So(err, ShouldBeNil)
   465  						So(len(patches[0].Patches), ShouldEqual, 1)
   466  						Convey("Finalizing the patch should start with no version field and then be populated", func() {
   467  							So(patches[0].Version, ShouldEqual, "")
   468  							So(ac.FinalizePatch(newPatch.Id.Hex()), ShouldBeNil)
   469  							patches, err := ac.GetPatches(0)
   470  							So(err, ShouldBeNil)
   471  							So(patches[0].Version, ShouldNotEqual, "")
   472  							Convey("Canceling the patch should work and the version should be deactivated", func() {
   473  								So(ac.CancelPatch(newPatch.Id.Hex()), ShouldBeNil)
   474  								patches, err := ac.GetPatches(0)
   475  								So(err, ShouldBeNil)
   476  								tasks, err := task.Find(task.ByVersion(patches[0].Version))
   477  								So(err, ShouldBeNil)
   478  								for _, t := range tasks {
   479  									So(t.Activated, ShouldBeFalse)
   480  								}
   481  							})
   482  						})
   483  					})
   484  				})
   485  			})
   486  			Convey("Listing variants or tasks for a project should list all variants", func() {
   487  				tasks, err := ac.ListTasks("sample")
   488  				So(err, ShouldBeNil)
   489  				So(tasks, ShouldNotBeEmpty)
   490  				So(len(tasks), ShouldEqual, 4)
   491  			})
   492  			Convey("Listing variants for a project should list all variants", func() {
   493  
   494  				variants, err := ac.ListVariants("sample")
   495  				So(err, ShouldBeNil)
   496  				So(variants, ShouldNotBeEmpty)
   497  				So(len(variants), ShouldEqual, 2)
   498  			})
   499  			Convey("Creating a patch using 'all' as variants should schedule all variants", func() {
   500  				patchSub := patchSubmission{"sample",
   501  					testPatch,
   502  					"sample patch #2",
   503  					"3c7bfeb82d492dc453e7431be664539c35b5db4b",
   504  					"all",
   505  					[]string{"failing_test"},
   506  					false}
   507  
   508  				_, err := ac.PutPatch(patchSub)
   509  				So(err, ShouldBeNil)
   510  
   511  				Convey("Newly created patch should be fetchable via API", func() {
   512  					patches, err := ac.GetPatches(1)
   513  					So(err, ShouldBeNil)
   514  					So(len(patches), ShouldEqual, 1)
   515  					So(len(patches[0].BuildVariants), ShouldEqual, 2)
   516  					So(patches[0].BuildVariants, ShouldContain, "osx-108")
   517  					So(patches[0].BuildVariants, ShouldContain, "ubuntu")
   518  					So(len(patches[0].Tasks), ShouldEqual, 2)
   519  					So(patches[0].Tasks, ShouldContain, "failing_test")
   520  					Convey("and have expanded dependencies", func() {
   521  						So(patches[0].Tasks, ShouldContain, "compile")
   522  					})
   523  				})
   524  			})
   525  
   526  			Convey("Creating a patch using 'all' as tasks should schedule all tasks", func() {
   527  				patchSub := patchSubmission{"sample",
   528  					testPatch,
   529  					"sample patch #2",
   530  					"3c7bfeb82d492dc453e7431be664539c35b5db4b",
   531  					"osx-108",
   532  					[]string{"all"},
   533  					false}
   534  
   535  				_, err := ac.PutPatch(patchSub)
   536  				So(err, ShouldBeNil)
   537  
   538  				Convey("Newly created patch should be fetchable via API", func() {
   539  					patches, err := ac.GetPatches(1)
   540  					So(err, ShouldBeNil)
   541  					So(len(patches), ShouldEqual, 1)
   542  					So(len(patches[0].BuildVariants), ShouldEqual, 1)
   543  					So(patches[0].BuildVariants[0], ShouldEqual, "osx-108")
   544  					So(len(patches[0].Tasks), ShouldEqual, 4)
   545  					So(patches[0].Tasks, ShouldContain, "compile")
   546  					So(patches[0].Tasks, ShouldContain, "passing_test")
   547  					So(patches[0].Tasks, ShouldContain, "failing_test")
   548  					So(patches[0].Tasks, ShouldContain, "timeout_test")
   549  				})
   550  			})
   551  
   552  		})
   553  	})
   554  }