github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/repotracker/repotracker_test.go (about) 1 package repotracker 2 3 import ( 4 "testing" 5 "time" 6 7 "github.com/evergreen-ci/evergreen" 8 "github.com/evergreen-ci/evergreen/db" 9 "github.com/evergreen-ci/evergreen/model" 10 "github.com/evergreen-ci/evergreen/model/distro" 11 modelutil "github.com/evergreen-ci/evergreen/model/testutil" 12 "github.com/evergreen-ci/evergreen/model/version" 13 "github.com/evergreen-ci/evergreen/testutil" 14 "github.com/mongodb/grip" 15 "github.com/pkg/errors" 16 . "github.com/smartystreets/goconvey/convey" 17 ) 18 19 func init() { 20 db.SetGlobalSessionProvider(db.SessionFactoryFromConfig(testConfig)) 21 } 22 23 func TestFetchRevisions(t *testing.T) { 24 dropTestDB(t) 25 testutil.ConfigureIntegrationTest(t, testConfig, "TestFetchRevisions") 26 Convey("With a GithubRepositoryPoller with a valid OAuth token...", t, func() { 27 err := modelutil.CreateTestLocalConfig(testConfig, "mci-test", "") 28 So(err, ShouldBeNil) 29 30 resetProjectRefs() 31 32 grip.Alertf("project: %+v", projectRef) 33 repoTracker := RepoTracker{ 34 testConfig, 35 projectRef, 36 NewGithubRepositoryPoller(projectRef, testConfig.Credentials["github"]), 37 } 38 39 Convey("Fetching commits from the repository should not return any errors", func() { 40 So(repoTracker.FetchRevisions(10), ShouldBeNil) 41 }) 42 43 Convey("Only get 3 revisions from the given repository if given a "+ 44 "limit of 4 commits where only 3 exist", func() { 45 testutil.HandleTestingErr(repoTracker.FetchRevisions(4), t, 46 "Error running repository process %v") 47 numVersions, err := version.Count(version.All) 48 testutil.HandleTestingErr(err, t, "Error finding all versions") 49 So(numVersions, ShouldEqual, 3) 50 }) 51 52 Convey("Only get 2 revisions from the given repository if given a "+ 53 "limit of 2 commits where 3 exist", func() { 54 testutil.HandleTestingErr(repoTracker.FetchRevisions(2), t, 55 "Error running repository process %v") 56 numVersions, err := version.Count(version.All) 57 testutil.HandleTestingErr(err, t, "Error finding all versions") 58 So(numVersions, ShouldEqual, 2) 59 }) 60 61 Reset(func() { 62 dropTestDB(t) 63 }) 64 }) 65 } 66 67 func TestStoreRepositoryRevisions(t *testing.T) { 68 dropTestDB(t) 69 testutil.ConfigureIntegrationTest(t, testConfig, "TestStoreRepositoryRevisions") 70 Convey("When storing revisions gotten from a repository...", t, func() { 71 err := modelutil.CreateTestLocalConfig(testConfig, "mci-test", "") 72 So(err, ShouldBeNil) 73 repoTracker := RepoTracker{testConfig, projectRef, NewGithubRepositoryPoller(projectRef, 74 testConfig.Credentials["github"])} 75 76 // insert distros used in testing. 77 d := distro.Distro{Id: "test-distro-one"} 78 So(d.Insert(), ShouldBeNil) 79 d.Id = "test-distro-two" 80 So(d.Insert(), ShouldBeNil) 81 82 Convey("On storing a single repo revision, we expect a version to be created"+ 83 " in the database for this project, which should be retrieved when we search"+ 84 " for this project's most recent version", func() { 85 createTime := time.Now() 86 revisionOne := *createTestRevision("firstRevision", createTime) 87 revisions := []model.Revision{revisionOne} 88 89 resultVersion, err := repoTracker.StoreRevisions(revisions) 90 testutil.HandleTestingErr(err, t, "Error storing repository revisions %v") 91 92 newestVersion, err := version.FindOne(version.ByMostRecentForRequester(projectRef.String(), evergreen.RepotrackerVersionRequester)) 93 testutil.HandleTestingErr(err, t, "Error retreiving newest version %v") 94 95 So(resultVersion, ShouldResemble, newestVersion) 96 }) 97 98 Convey("On storing several repo revisions, we expect a version to be created "+ 99 "for each revision", func() { 100 createTime := time.Now() 101 laterCreateTime := createTime.Add(time.Duration(4 * time.Hour)) 102 103 revisionOne := *createTestRevision("one", laterCreateTime) 104 revisionTwo := *createTestRevision("two", createTime) 105 106 revisions := []model.Revision{revisionOne, revisionTwo} 107 108 _, err := repoTracker.StoreRevisions(revisions) 109 testutil.HandleTestingErr(err, t, "Error storing repository revisions %v") 110 111 versionOne, err := version.FindOne(version.ByProjectIdAndRevision(projectRef.Identifier, revisionOne.Revision)) 112 testutil.HandleTestingErr(err, t, "Error retrieving first stored version %v") 113 versionTwo, err := version.FindOne(version.ByProjectIdAndRevision(projectRef.Identifier, revisionTwo.Revision)) 114 testutil.HandleTestingErr(err, t, "Error retreiving second stored version %v") 115 116 So(versionOne.Revision, ShouldEqual, revisionOne.Revision) 117 So(versionTwo.Revision, ShouldEqual, revisionTwo.Revision) 118 }) 119 120 Reset(func() { 121 dropTestDB(t) 122 }) 123 }) 124 125 Convey("When storing versions from repositories with remote configuration files...", t, func() { 126 127 project := createTestProject(nil, nil) 128 129 revisions := []model.Revision{ 130 *createTestRevision("foo", time.Now().Add(1*time.Minute)), 131 } 132 133 poller := NewMockRepoPoller(project, revisions) 134 135 repoTracker := RepoTracker{ 136 testConfig, 137 &model.ProjectRef{ 138 Identifier: "testproject", 139 BatchTime: 10, 140 }, 141 poller, 142 } 143 144 // insert distros used in testing. 145 d := distro.Distro{Id: "test-distro-one"} 146 So(d.Insert(), ShouldBeNil) 147 d.Id = "test-distro-two" 148 So(d.Insert(), ShouldBeNil) 149 150 Convey("We should not fetch configs for versions we already have stored.", 151 func() { 152 So(poller.ConfigGets, ShouldBeZeroValue) 153 // Store revisions the first time 154 _, err := repoTracker.StoreRevisions(revisions) 155 So(err, ShouldBeNil) 156 // We should have fetched the config once for each revision 157 So(poller.ConfigGets, ShouldEqual, len(revisions)) 158 159 // Store them again 160 _, err = repoTracker.StoreRevisions(revisions) 161 So(err, ShouldBeNil) 162 // We shouldn't have fetched the config any additional times 163 // since we have already stored these versions 164 So(poller.ConfigGets, ShouldEqual, len(revisions)) 165 }, 166 ) 167 168 Convey("We should handle invalid configuration files gracefully by storing a stub version", func() { 169 errStrs := []string{"Someone dun' goof'd"} 170 poller.setNextError(projectConfigError{errStrs, []string{}}) 171 stubVersion, err := repoTracker.StoreRevisions(revisions) 172 // We want this error to get swallowed so a config error 173 // doesn't stop additional versions from getting created 174 So(err, ShouldBeNil) 175 So(stubVersion.Errors, ShouldResemble, errStrs) 176 So(len(stubVersion.BuildVariants), ShouldEqual, 0) 177 }) 178 179 Convey("Project configuration files with missing distros should still create versions", func() { 180 poller.addBadDistro("Cray-Y-MP") 181 v, err := repoTracker.StoreRevisions(revisions) 182 So(err, ShouldBeNil) 183 So(v, ShouldNotBeNil) 184 So(len(v.BuildVariants), ShouldBeGreaterThan, 0) 185 186 Convey("and log a warning", func() { 187 So(len(v.Warnings), ShouldEqual, 1) 188 So(v.Errors, ShouldBeNil) 189 }) 190 }) 191 192 Convey("If there is an error other than a config error while fetching a config, we should fail hard", 193 func() { 194 unexpectedError := errors.New("Something terrible has happened!!") 195 poller.setNextError(unexpectedError) 196 v, err := repoTracker.StoreRevisions(revisions) 197 So(v, ShouldBeNil) 198 So(err.Error(), ShouldEqual, unexpectedError.Error()) 199 }, 200 ) 201 202 Reset(func() { 203 dropTestDB(t) 204 }) 205 206 }) 207 } 208 209 func TestBatchTimes(t *testing.T) { 210 Convey("When deciding whether or not to activate variants for the most recently stored version", t, func() { 211 // We create a version with an activation time of now so that all the bvs have a last activation time of now. 212 previouslyActivatedVersion := version.Version{ 213 Id: "previously activated", 214 Identifier: "testproject", 215 BuildVariants: []version.BuildStatus{ 216 { 217 BuildVariant: "bv1", 218 Activated: true, 219 ActivateAt: time.Now(), 220 }, 221 { 222 BuildVariant: "bv2", 223 Activated: true, 224 ActivateAt: time.Now(), 225 }, 226 }, 227 RevisionOrderNumber: 0, 228 Requester: evergreen.RepotrackerVersionRequester, 229 } 230 231 So(previouslyActivatedVersion.Insert(), ShouldBeNil) 232 233 // insert distros used in testing. 234 d := distro.Distro{Id: "test-distro-one"} 235 So(d.Insert(), ShouldBeNil) 236 d.Id = "test-distro-two" 237 So(d.Insert(), ShouldBeNil) 238 239 Convey("If the project's batch time has not elapsed, and no buildvariants "+ 240 "have overridden their batch times, no variants should be activated", func() { 241 project := createTestProject(nil, nil) 242 revisions := []model.Revision{ 243 *createTestRevision("foo", time.Now()), 244 } 245 246 repoTracker := RepoTracker{ 247 testConfig, 248 &model.ProjectRef{ 249 Identifier: "testproject", 250 BatchTime: 1, 251 }, 252 NewMockRepoPoller(project, revisions), 253 } 254 v, err := repoTracker.StoreRevisions(revisions) 255 So(v, ShouldNotBeNil) 256 So(err, ShouldBeNil) 257 So(len(v.BuildVariants), ShouldEqual, 2) 258 So(repoTracker.activateElapsedBuilds(v), ShouldBeNil) 259 So(v.BuildVariants[0].Activated, ShouldBeFalse) 260 So(v.BuildVariants[1].Activated, ShouldBeFalse) 261 }) 262 263 Convey("If the project's batch time has elapsed, and no buildvariants "+ 264 "have overridden their batch times, all variants should be activated", func() { 265 project := createTestProject(nil, nil) 266 revisions := []model.Revision{ 267 *createTestRevision("bar", time.Now().Add(time.Duration(-6*time.Minute))), 268 } 269 repoTracker := RepoTracker{ 270 testConfig, 271 &model.ProjectRef{ 272 Identifier: "testproject", 273 BatchTime: 0, 274 }, 275 NewMockRepoPoller(project, revisions), 276 } 277 version, err := repoTracker.StoreRevisions(revisions) 278 So(version, ShouldNotBeNil) 279 So(err, ShouldBeNil) 280 So(repoTracker.activateElapsedBuilds(version), ShouldBeNil) 281 bv1, found := findStatus(version, "bv1") 282 So(found, ShouldBeTrue) 283 So(bv1.Activated, ShouldBeTrue) 284 bv2, found := findStatus(version, "bv2") 285 So(found, ShouldBeTrue) 286 So(bv2.Activated, ShouldBeTrue) 287 }) 288 289 Convey("If the project's batch time has elapsed, but both variants "+ 290 "have overridden their batch times (which have not elapsed)"+ 291 ", no variants should be activated", func() { 292 // need to assign pointer vals 293 twoforty := 240 294 onetwenty := 120 295 296 project := createTestProject(&twoforty, &onetwenty) 297 298 revisions := []model.Revision{ 299 *createTestRevision("baz", time.Now()), 300 } 301 302 repoTracker := RepoTracker{ 303 testConfig, 304 &model.ProjectRef{ 305 Identifier: "testproject", 306 BatchTime: 60, 307 }, 308 NewMockRepoPoller(project, revisions), 309 } 310 version, err := repoTracker.StoreRevisions(revisions) 311 So(version, ShouldNotBeNil) 312 So(err, ShouldBeNil) 313 So(repoTracker.activateElapsedBuilds(version), ShouldBeNil) 314 bv1, found := findStatus(version, "bv1") 315 So(found, ShouldBeTrue) 316 So(bv1.Activated, ShouldBeFalse) 317 bv2, found := findStatus(version, "bv2") 318 So(found, ShouldBeTrue) 319 So(bv2.Activated, ShouldBeFalse) 320 }) 321 322 Convey("If the project's batch time has not elapsed, but one variant "+ 323 "has overridden their batch times to be shorter"+ 324 ", that variant should be activated", func() { 325 zero := 0 326 327 project := createTestProject(&zero, nil) 328 329 revisions := []model.Revision{ 330 *createTestRevision("garply", time.Now()), 331 } 332 333 repoTracker := RepoTracker{ 334 testConfig, 335 &model.ProjectRef{ 336 Identifier: "testproject", 337 BatchTime: 60, 338 }, 339 NewMockRepoPoller(project, revisions), 340 } 341 version, err := repoTracker.StoreRevisions(revisions) 342 So(version, ShouldNotBeNil) 343 So(err, ShouldBeNil) 344 So(repoTracker.activateElapsedBuilds(version), ShouldBeNil) 345 bv1, found := findStatus(version, "bv1") 346 So(found, ShouldBeTrue) 347 So(bv1.Activated, ShouldBeTrue) 348 bv2, found := findStatus(version, "bv2") 349 So(found, ShouldBeTrue) 350 So(bv2, ShouldNotBeNil) 351 So(bv2.Activated, ShouldBeFalse) 352 }) 353 354 Reset(func() { 355 dropTestDB(t) 356 }) 357 }) 358 359 Convey("If the new revision adds a variant", t, func() { 360 previouslyActivatedVersion := version.Version{ 361 Id: "previously activated", 362 Identifier: "testproject", 363 BuildVariants: []version.BuildStatus{ 364 { 365 BuildVariant: "bv1", 366 Activated: true, 367 ActivateAt: time.Now(), 368 }, 369 // "bv2" will be added in a later revision 370 }, 371 RevisionOrderNumber: 0, 372 Requester: evergreen.RepotrackerVersionRequester, 373 } 374 So(previouslyActivatedVersion.Insert(), ShouldBeNil) 375 // insert distros used in testing. 376 d := distro.Distro{Id: "test-distro-one"} 377 So(d.Insert(), ShouldBeNil) 378 d.Id = "test-distro-two" 379 So(d.Insert(), ShouldBeNil) 380 zero := 0 381 project := createTestProject(&zero, nil) 382 revisions := []model.Revision{ 383 *createTestRevision("garply", time.Now()), 384 } 385 repoTracker := RepoTracker{ 386 testConfig, 387 &model.ProjectRef{ 388 Identifier: "testproject", 389 BatchTime: 60, 390 }, 391 NewMockRepoPoller(project, revisions), 392 } 393 version, err := repoTracker.StoreRevisions(revisions) 394 So(version, ShouldNotBeNil) 395 So(err, ShouldBeNil) 396 397 Convey("the new variant should activate immediately", func() { 398 So(repoTracker.activateElapsedBuilds(version), ShouldBeNil) 399 bv1, found := findStatus(version, "bv1") 400 So(found, ShouldBeTrue) 401 So(bv1.Activated, ShouldBeTrue) 402 bv2, found := findStatus(version, "bv2") 403 So(found, ShouldBeTrue) 404 So(bv2, ShouldNotBeNil) 405 So(bv2.Activated, ShouldBeTrue) 406 So(bv2.ActivateAt, ShouldResemble, bv1.ActivateAt) 407 }) 408 409 Reset(func() { 410 dropTestDB(t) 411 }) 412 }) 413 } 414 415 func findStatus(v *version.Version, buildVariant string) (*version.BuildStatus, bool) { 416 for _, status := range v.BuildVariants { 417 if status.BuildVariant == buildVariant { 418 return &status, true 419 } 420 } 421 return nil, false 422 } 423 424 func createTestRevision(revision string, 425 createTime time.Time) *model.Revision { 426 return &model.Revision{ 427 Author: "author", 428 AuthorEmail: "authorEmail", 429 RevisionMessage: "revisionMessage", 430 Revision: revision, 431 CreateTime: createTime, 432 } 433 } 434 435 func createTestProject(override1, override2 *int) *model.Project { 436 return &model.Project{ 437 BuildVariants: []model.BuildVariant{ 438 { 439 Name: "bv1", 440 DisplayName: "bv1", 441 BatchTime: override1, 442 Tasks: []model.BuildVariantTask{ 443 { 444 Name: "Unabhaengigkeitserklaerungen", 445 Distros: []string{"test-distro-one"}, 446 }, 447 }, 448 }, 449 { 450 Name: "bv2", 451 DisplayName: "bv2", 452 BatchTime: override2, 453 Tasks: []model.BuildVariantTask{ 454 { 455 Name: "Unabhaengigkeitserklaerungen", 456 Distros: []string{"test-distro-one"}, 457 }, 458 }, 459 }, 460 }, 461 Tasks: []model.ProjectTask{ 462 { 463 Name: "Unabhaengigkeitserklaerungen", 464 Commands: []model.PluginCommandConf{}, 465 }, 466 }, 467 } 468 }