github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/db/versions_db_test.go (about)

     1  package db_test
     2  
     3  import (
     4  	"context"
     5  	"database/sql"
     6  
     7  	. "github.com/onsi/ginkgo"
     8  	. "github.com/onsi/gomega"
     9  
    10  	"github.com/pf-qiu/concourse/v6/atc"
    11  	"github.com/pf-qiu/concourse/v6/atc/db"
    12  	"github.com/pf-qiu/concourse/v6/atc/db/dbtest"
    13  	gocache "github.com/patrickmn/go-cache"
    14  )
    15  
    16  var _ = Describe("VersionsDB", func() {
    17  	var vdb db.VersionsDB
    18  	var pageLimit int
    19  	var cache *gocache.Cache
    20  
    21  	var ctx context.Context
    22  
    23  	BeforeEach(func() {
    24  		pageLimit = 5
    25  		cache = gocache.New(-1, -1)
    26  		vdb = db.NewVersionsDB(dbConn, pageLimit, cache)
    27  
    28  		ctx = context.Background()
    29  	})
    30  
    31  	AfterEach(func() {
    32  		cache.Flush()
    33  	})
    34  
    35  	Describe("SuccessfulBuilds", func() {
    36  		var paginatedBuilds db.PaginatedBuilds
    37  
    38  		JustBeforeEach(func() {
    39  			paginatedBuilds = vdb.SuccessfulBuilds(ctx, defaultJob.ID())
    40  		})
    41  
    42  		Context("with one build", func() {
    43  			var build db.Build
    44  
    45  			BeforeEach(func() {
    46  				var err error
    47  				build, err = defaultJob.CreateBuild()
    48  				Expect(err).ToNot(HaveOccurred())
    49  
    50  				err = build.Finish(db.BuildStatusSucceeded)
    51  				Expect(err).ToNot(HaveOccurred())
    52  			})
    53  
    54  			It("returns the build and finishes", func() {
    55  				buildID, ok, err := paginatedBuilds.Next(ctx)
    56  				Expect(err).ToNot(HaveOccurred())
    57  				Expect(ok).To(BeTrue())
    58  				Expect(buildID).To(Equal(build.ID()))
    59  
    60  				buildID, ok, err = paginatedBuilds.Next(ctx)
    61  				Expect(err).ToNot(HaveOccurred())
    62  				Expect(ok).To(BeFalse())
    63  				Expect(buildID).To(BeZero())
    64  			})
    65  		})
    66  
    67  		Context("with the same number of builds as the page limit", func() {
    68  			var builds []db.Build
    69  
    70  			BeforeEach(func() {
    71  				builds = []db.Build{}
    72  
    73  				for i := 0; i < pageLimit; i++ {
    74  					build, err := defaultJob.CreateBuild()
    75  					Expect(err).ToNot(HaveOccurred())
    76  
    77  					err = build.Finish(db.BuildStatusSucceeded)
    78  					Expect(err).ToNot(HaveOccurred())
    79  
    80  					builds = append(builds, build)
    81  				}
    82  			})
    83  
    84  			It("returns all of the builds, newest first, and then finishes", func() {
    85  				for i := pageLimit - 1; i >= 0; i-- {
    86  					buildID, ok, err := paginatedBuilds.Next(ctx)
    87  					Expect(err).ToNot(HaveOccurred())
    88  					Expect(ok).To(BeTrue())
    89  					Expect(buildID).To(Equal(builds[i].ID()))
    90  				}
    91  
    92  				buildID, ok, err := paginatedBuilds.Next(ctx)
    93  				Expect(err).ToNot(HaveOccurred())
    94  				Expect(ok).To(BeFalse())
    95  				Expect(buildID).To(BeZero())
    96  			})
    97  		})
    98  
    99  		Context("with a page of filler and then rerun builds created after their original builds", func() {
   100  			var build1Succeeded db.Build
   101  			var build2Failed db.Build
   102  			var build3Succeeded db.Build
   103  			var build4Rerun2Succeeded db.Build
   104  			var build5Rerun2Succeeded db.Build
   105  			var build6Succeeded db.Build
   106  			var fillerBuilds []db.Build
   107  
   108  			BeforeEach(func() {
   109  				var err error
   110  				build1Succeeded, err = defaultJob.CreateBuild()
   111  				Expect(err).ToNot(HaveOccurred())
   112  				err = build1Succeeded.Finish(db.BuildStatusSucceeded)
   113  				Expect(err).ToNot(HaveOccurred())
   114  
   115  				build2Failed, err = defaultJob.CreateBuild()
   116  				Expect(err).ToNot(HaveOccurred())
   117  				err = build2Failed.Finish(db.BuildStatusFailed)
   118  				Expect(err).ToNot(HaveOccurred())
   119  
   120  				build3Succeeded, err = defaultJob.CreateBuild()
   121  				Expect(err).ToNot(HaveOccurred())
   122  				err = build3Succeeded.Finish(db.BuildStatusSucceeded)
   123  				Expect(err).ToNot(HaveOccurred())
   124  
   125  				build4Rerun2Succeeded, err = defaultJob.RerunBuild(build2Failed)
   126  				Expect(err).ToNot(HaveOccurred())
   127  				err = build4Rerun2Succeeded.Finish(db.BuildStatusSucceeded)
   128  				Expect(err).ToNot(HaveOccurred())
   129  
   130  				build5Rerun2Succeeded, err = defaultJob.RerunBuild(build2Failed)
   131  				Expect(err).ToNot(HaveOccurred())
   132  				err = build5Rerun2Succeeded.Finish(db.BuildStatusSucceeded)
   133  				Expect(err).ToNot(HaveOccurred())
   134  
   135  				build6Succeeded, err = defaultJob.CreateBuild()
   136  				Expect(err).ToNot(HaveOccurred())
   137  				err = build6Succeeded.Finish(db.BuildStatusSucceeded)
   138  				Expect(err).ToNot(HaveOccurred())
   139  
   140  				for i := 0; i < pageLimit; i++ {
   141  					build, err := defaultJob.CreateBuild()
   142  					Expect(err).ToNot(HaveOccurred())
   143  
   144  					err = build.Finish(db.BuildStatusSucceeded)
   145  					Expect(err).ToNot(HaveOccurred())
   146  
   147  					fillerBuilds = append(fillerBuilds, build)
   148  				}
   149  			})
   150  
   151  			It("returns all of the builds, newest first, with reruns relative to original build's order, and then finishes", func() {
   152  				for i := len(fillerBuilds) - 1; i >= 0; i-- {
   153  					buildID, ok, err := paginatedBuilds.Next(ctx)
   154  					Expect(err).ToNot(HaveOccurred())
   155  					Expect(ok).To(BeTrue())
   156  					Expect(buildID).To(Equal(fillerBuilds[i].ID()))
   157  				}
   158  
   159  				buildID, ok, err := paginatedBuilds.Next(ctx)
   160  				Expect(err).ToNot(HaveOccurred())
   161  				Expect(ok).To(BeTrue())
   162  				Expect(buildID).To(Equal(build6Succeeded.ID()))
   163  
   164  				buildID, ok, err = paginatedBuilds.Next(ctx)
   165  				Expect(err).ToNot(HaveOccurred())
   166  				Expect(ok).To(BeTrue())
   167  				Expect(buildID).To(Equal(build3Succeeded.ID()))
   168  
   169  				buildID, ok, err = paginatedBuilds.Next(ctx)
   170  				Expect(err).ToNot(HaveOccurred())
   171  				Expect(ok).To(BeTrue())
   172  				Expect(buildID).To(Equal(build5Rerun2Succeeded.ID()))
   173  
   174  				buildID, ok, err = paginatedBuilds.Next(ctx)
   175  				Expect(err).ToNot(HaveOccurred())
   176  				Expect(ok).To(BeTrue())
   177  				Expect(buildID).To(Equal(build4Rerun2Succeeded.ID()))
   178  
   179  				buildID, ok, err = paginatedBuilds.Next(ctx)
   180  				Expect(err).ToNot(HaveOccurred())
   181  				Expect(ok).To(BeTrue())
   182  				Expect(buildID).To(Equal(build1Succeeded.ID()))
   183  
   184  				buildID, ok, err = paginatedBuilds.Next(ctx)
   185  				Expect(err).ToNot(HaveOccurred())
   186  				Expect(ok).To(BeFalse())
   187  				Expect(buildID).To(BeZero())
   188  			})
   189  		})
   190  
   191  		Context("with rerun builds created after their original (failing) build", func() {
   192  			var build1Succeeded db.Build
   193  			var build2Failed db.Build
   194  			var build3Succeeded db.Build
   195  			var build4Rerun2Succeeded db.Build
   196  			var build5Rerun2Succeeded db.Build
   197  			var build6Succeeded db.Build
   198  
   199  			BeforeEach(func() {
   200  				var err error
   201  				build1Succeeded, err = defaultJob.CreateBuild()
   202  				Expect(err).ToNot(HaveOccurred())
   203  				err = build1Succeeded.Finish(db.BuildStatusSucceeded)
   204  				Expect(err).ToNot(HaveOccurred())
   205  
   206  				build2Failed, err = defaultJob.CreateBuild()
   207  				Expect(err).ToNot(HaveOccurred())
   208  				err = build2Failed.Finish(db.BuildStatusFailed)
   209  				Expect(err).ToNot(HaveOccurred())
   210  
   211  				build3Succeeded, err = defaultJob.CreateBuild()
   212  				Expect(err).ToNot(HaveOccurred())
   213  				err = build3Succeeded.Finish(db.BuildStatusSucceeded)
   214  				Expect(err).ToNot(HaveOccurred())
   215  
   216  				build4Rerun2Succeeded, err = defaultJob.RerunBuild(build2Failed)
   217  				Expect(err).ToNot(HaveOccurred())
   218  				err = build4Rerun2Succeeded.Finish(db.BuildStatusSucceeded)
   219  				Expect(err).ToNot(HaveOccurred())
   220  
   221  				build5Rerun2Succeeded, err = defaultJob.RerunBuild(build2Failed)
   222  				Expect(err).ToNot(HaveOccurred())
   223  				err = build5Rerun2Succeeded.Finish(db.BuildStatusSucceeded)
   224  				Expect(err).ToNot(HaveOccurred())
   225  
   226  				build6Succeeded, err = defaultJob.CreateBuild()
   227  				Expect(err).ToNot(HaveOccurred())
   228  				err = build6Succeeded.Finish(db.BuildStatusSucceeded)
   229  				Expect(err).ToNot(HaveOccurred())
   230  			})
   231  
   232  			It("returns all of the builds, newest first, with reruns relative to original build's order, and then finishes", func() {
   233  				buildID, ok, err := paginatedBuilds.Next(ctx)
   234  				Expect(err).ToNot(HaveOccurred())
   235  				Expect(ok).To(BeTrue())
   236  				Expect(buildID).To(Equal(build6Succeeded.ID()))
   237  
   238  				buildID, ok, err = paginatedBuilds.Next(ctx)
   239  				Expect(err).ToNot(HaveOccurred())
   240  				Expect(ok).To(BeTrue())
   241  				Expect(buildID).To(Equal(build3Succeeded.ID()))
   242  
   243  				buildID, ok, err = paginatedBuilds.Next(ctx)
   244  				Expect(err).ToNot(HaveOccurred())
   245  				Expect(ok).To(BeTrue())
   246  				Expect(buildID).To(Equal(build5Rerun2Succeeded.ID()))
   247  
   248  				buildID, ok, err = paginatedBuilds.Next(ctx)
   249  				Expect(err).ToNot(HaveOccurred())
   250  				Expect(ok).To(BeTrue())
   251  				Expect(buildID).To(Equal(build4Rerun2Succeeded.ID()))
   252  
   253  				buildID, ok, err = paginatedBuilds.Next(ctx)
   254  				Expect(err).ToNot(HaveOccurred())
   255  				Expect(ok).To(BeTrue())
   256  				Expect(buildID).To(Equal(build1Succeeded.ID()))
   257  
   258  				buildID, ok, err = paginatedBuilds.Next(ctx)
   259  				Expect(err).ToNot(HaveOccurred())
   260  				Expect(ok).To(BeFalse())
   261  				Expect(buildID).To(BeZero())
   262  			})
   263  		})
   264  
   265  		Context("with a rerun build of a failed build on the page limit boundary", func() {
   266  			var build1Failed db.Build
   267  			var fillerBuilds []db.Build
   268  			var build6Rerun1Succeeded db.Build
   269  
   270  			BeforeEach(func() {
   271  				var err error
   272  				build1Failed, err = defaultJob.CreateBuild()
   273  				Expect(err).ToNot(HaveOccurred())
   274  				err = build1Failed.Finish(db.BuildStatusFailed)
   275  				Expect(err).ToNot(HaveOccurred())
   276  
   277  				fillerBuilds = []db.Build{}
   278  
   279  				for i := 0; i < pageLimit-1; i++ {
   280  					build, err := defaultJob.CreateBuild()
   281  					Expect(err).ToNot(HaveOccurred())
   282  
   283  					err = build.Finish(db.BuildStatusSucceeded)
   284  					Expect(err).ToNot(HaveOccurred())
   285  
   286  					fillerBuilds = append(fillerBuilds, build)
   287  				}
   288  
   289  				build6Rerun1Succeeded, err = defaultJob.RerunBuild(build1Failed)
   290  				Expect(err).ToNot(HaveOccurred())
   291  				err = build6Rerun1Succeeded.Finish(db.BuildStatusSucceeded)
   292  				Expect(err).ToNot(HaveOccurred())
   293  			})
   294  
   295  			It("finishes after the rerun", func() {
   296  				for i := len(fillerBuilds) - 1; i >= 0; i-- {
   297  					buildID, ok, err := paginatedBuilds.Next(ctx)
   298  					Expect(err).ToNot(HaveOccurred())
   299  					Expect(ok).To(BeTrue())
   300  					Expect(buildID).To(Equal(fillerBuilds[i].ID()))
   301  				}
   302  
   303  				buildID, ok, err := paginatedBuilds.Next(ctx)
   304  				Expect(err).ToNot(HaveOccurred())
   305  				Expect(ok).To(BeTrue())
   306  				Expect(buildID).To(Equal(build6Rerun1Succeeded.ID()))
   307  
   308  				buildID, ok, err = paginatedBuilds.Next(ctx)
   309  				Expect(err).ToNot(HaveOccurred())
   310  				Expect(ok).To(BeFalse())
   311  				Expect(buildID).To(BeZero())
   312  			})
   313  		})
   314  
   315  		Context("with a rerun build of a succeeded build on the page limit boundary", func() {
   316  			var build1Succeeded db.Build
   317  			var fillerBuilds []db.Build
   318  			var build6Rerun1Succeeded db.Build
   319  
   320  			BeforeEach(func() {
   321  				var err error
   322  				build1Succeeded, err = defaultJob.CreateBuild()
   323  				Expect(err).ToNot(HaveOccurred())
   324  				err = build1Succeeded.Finish(db.BuildStatusSucceeded)
   325  				Expect(err).ToNot(HaveOccurred())
   326  
   327  				fillerBuilds = []db.Build{}
   328  
   329  				for i := 0; i < pageLimit-1; i++ {
   330  					build, err := defaultJob.CreateBuild()
   331  					Expect(err).ToNot(HaveOccurred())
   332  
   333  					err = build.Finish(db.BuildStatusSucceeded)
   334  					Expect(err).ToNot(HaveOccurred())
   335  
   336  					fillerBuilds = append(fillerBuilds, build)
   337  				}
   338  
   339  				build6Rerun1Succeeded, err = defaultJob.RerunBuild(build1Succeeded)
   340  				Expect(err).ToNot(HaveOccurred())
   341  				err = build6Rerun1Succeeded.Finish(db.BuildStatusSucceeded)
   342  				Expect(err).ToNot(HaveOccurred())
   343  			})
   344  
   345  			It("returns the original build after the rerun", func() {
   346  				for i := len(fillerBuilds) - 1; i >= 0; i-- {
   347  					buildID, ok, err := paginatedBuilds.Next(ctx)
   348  					Expect(err).ToNot(HaveOccurred())
   349  					Expect(ok).To(BeTrue())
   350  					Expect(buildID).To(Equal(fillerBuilds[i].ID()))
   351  				}
   352  
   353  				buildID, ok, err := paginatedBuilds.Next(ctx)
   354  				Expect(err).ToNot(HaveOccurred())
   355  				Expect(ok).To(BeTrue())
   356  				Expect(buildID).To(Equal(build6Rerun1Succeeded.ID()))
   357  
   358  				buildID, ok, err = paginatedBuilds.Next(ctx)
   359  				Expect(err).ToNot(HaveOccurred())
   360  				Expect(ok).To(BeTrue())
   361  				Expect(buildID).To(Equal(build1Succeeded.ID()))
   362  
   363  				buildID, ok, err = paginatedBuilds.Next(ctx)
   364  				Expect(err).ToNot(HaveOccurred())
   365  				Expect(ok).To(BeFalse())
   366  				Expect(buildID).To(BeZero())
   367  			})
   368  		})
   369  
   370  		Context("with multiple reruns of the same build crossing the page limit boundary", func() {
   371  			var build1Failed db.Build
   372  			var fillerBuilds []db.Build
   373  			var build6Rerun1Succeeded db.Build
   374  			var build7Rerun1Succeeded db.Build
   375  			var build8Rerun1Succeeded db.Build
   376  
   377  			BeforeEach(func() {
   378  				var err error
   379  				build1Failed, err = defaultJob.CreateBuild()
   380  				Expect(err).ToNot(HaveOccurred())
   381  				err = build1Failed.Finish(db.BuildStatusFailed)
   382  				Expect(err).ToNot(HaveOccurred())
   383  
   384  				fillerBuilds = []db.Build{}
   385  
   386  				for i := 0; i < pageLimit-1; i++ {
   387  					build, err := defaultJob.CreateBuild()
   388  					Expect(err).ToNot(HaveOccurred())
   389  
   390  					err = build.Finish(db.BuildStatusSucceeded)
   391  					Expect(err).ToNot(HaveOccurred())
   392  
   393  					fillerBuilds = append(fillerBuilds, build)
   394  				}
   395  
   396  				build6Rerun1Succeeded, err = defaultJob.RerunBuild(build1Failed)
   397  				Expect(err).ToNot(HaveOccurred())
   398  				err = build6Rerun1Succeeded.Finish(db.BuildStatusSucceeded)
   399  				Expect(err).ToNot(HaveOccurred())
   400  
   401  				build7Rerun1Succeeded, err = defaultJob.RerunBuild(build1Failed)
   402  				Expect(err).ToNot(HaveOccurred())
   403  				err = build7Rerun1Succeeded.Finish(db.BuildStatusSucceeded)
   404  				Expect(err).ToNot(HaveOccurred())
   405  
   406  				build8Rerun1Succeeded, err = defaultJob.RerunBuild(build1Failed)
   407  				Expect(err).ToNot(HaveOccurred())
   408  				err = build8Rerun1Succeeded.Finish(db.BuildStatusSucceeded)
   409  				Expect(err).ToNot(HaveOccurred())
   410  			})
   411  
   412  			It("returns all builds, and then all three reruns, and finishes", func() {
   413  				for i := len(fillerBuilds) - 1; i >= 0; i-- {
   414  					buildID, ok, err := paginatedBuilds.Next(ctx)
   415  					Expect(err).ToNot(HaveOccurred())
   416  					Expect(ok).To(BeTrue())
   417  					Expect(buildID).To(Equal(fillerBuilds[i].ID()))
   418  				}
   419  
   420  				buildID, ok, err := paginatedBuilds.Next(ctx)
   421  				Expect(err).ToNot(HaveOccurred())
   422  				Expect(ok).To(BeTrue())
   423  				Expect(buildID).To(Equal(build8Rerun1Succeeded.ID()))
   424  
   425  				buildID, ok, err = paginatedBuilds.Next(ctx)
   426  				Expect(err).ToNot(HaveOccurred())
   427  				Expect(ok).To(BeTrue())
   428  				Expect(buildID).To(Equal(build7Rerun1Succeeded.ID()))
   429  
   430  				buildID, ok, err = paginatedBuilds.Next(ctx)
   431  				Expect(err).ToNot(HaveOccurred())
   432  				Expect(ok).To(BeTrue())
   433  				Expect(buildID).To(Equal(build6Rerun1Succeeded.ID()))
   434  
   435  				buildID, ok, err = paginatedBuilds.Next(ctx)
   436  				Expect(err).ToNot(HaveOccurred())
   437  				Expect(ok).To(BeFalse())
   438  				Expect(buildID).To(BeZero())
   439  			})
   440  		})
   441  	})
   442  
   443  	Describe("UnusedBuilds", func() {
   444  		var lastUsedBuild db.BuildCursor
   445  		var paginatedBuilds db.PaginatedBuilds
   446  
   447  		BeforeEach(func() {
   448  			lastUsedBuild = db.BuildCursor{}
   449  		})
   450  
   451  		JustBeforeEach(func() {
   452  			var err error
   453  			paginatedBuilds, err = vdb.UnusedBuilds(ctx, defaultJob.ID(), lastUsedBuild)
   454  			Expect(err).ToNot(HaveOccurred())
   455  		})
   456  
   457  		Context("with one build, which was last used", func() {
   458  			var cursorBuild db.Build
   459  
   460  			BeforeEach(func() {
   461  				var err error
   462  				cursorBuild, err = defaultJob.CreateBuild()
   463  				Expect(err).ToNot(HaveOccurred())
   464  
   465  				err = cursorBuild.Finish(db.BuildStatusSucceeded)
   466  				Expect(err).ToNot(HaveOccurred())
   467  
   468  				lastUsedBuild = db.BuildCursor{
   469  					ID: cursorBuild.ID(),
   470  				}
   471  			})
   472  
   473  			It("returns the build and finishes", func() {
   474  				buildID, ok, err := paginatedBuilds.Next(ctx)
   475  				Expect(err).ToNot(HaveOccurred())
   476  				Expect(ok).To(BeTrue())
   477  				Expect(buildID).To(Equal(cursorBuild.ID()))
   478  
   479  				buildID, ok, err = paginatedBuilds.Next(ctx)
   480  				Expect(err).ToNot(HaveOccurred())
   481  				Expect(ok).To(BeFalse())
   482  				Expect(buildID).To(BeZero())
   483  			})
   484  		})
   485  
   486  		Context("with some older builds and some newer builds", func() {
   487  			var olderBuilds []db.Build
   488  			var cursorBuild db.Build
   489  			var newerBuilds []db.Build
   490  
   491  			BeforeEach(func() {
   492  				olderBuilds = []db.Build{}
   493  				for i := 0; i < pageLimit; i++ {
   494  					build, err := defaultJob.CreateBuild()
   495  					Expect(err).ToNot(HaveOccurred())
   496  
   497  					err = build.Finish(db.BuildStatusSucceeded)
   498  					Expect(err).ToNot(HaveOccurred())
   499  
   500  					olderBuilds = append(olderBuilds, build)
   501  				}
   502  
   503  				var err error
   504  				cursorBuild, err = defaultJob.CreateBuild()
   505  				Expect(err).ToNot(HaveOccurred())
   506  
   507  				err = cursorBuild.Finish(db.BuildStatusSucceeded)
   508  				Expect(err).ToNot(HaveOccurred())
   509  
   510  				lastUsedBuild = db.BuildCursor{
   511  					ID: cursorBuild.ID(),
   512  				}
   513  
   514  				newerBuilds = []db.Build{}
   515  				for i := 0; i < pageLimit; i++ {
   516  					build, err := defaultJob.CreateBuild()
   517  					Expect(err).ToNot(HaveOccurred())
   518  
   519  					err = build.Finish(db.BuildStatusSucceeded)
   520  					Expect(err).ToNot(HaveOccurred())
   521  
   522  					newerBuilds = append(newerBuilds, build)
   523  				}
   524  			})
   525  
   526  			It("returns newer builds, oldest to newest, followed by the cursor build and older builds, newest to oldest", func() {
   527  				for i := 0; i < len(newerBuilds); i++ {
   528  					buildID, ok, err := paginatedBuilds.Next(ctx)
   529  					Expect(err).ToNot(HaveOccurred())
   530  					Expect(ok).To(BeTrue())
   531  					Expect(buildID).To(Equal(newerBuilds[i].ID()))
   532  				}
   533  
   534  				buildID, ok, err := paginatedBuilds.Next(ctx)
   535  				Expect(err).ToNot(HaveOccurred())
   536  				Expect(ok).To(BeTrue())
   537  				Expect(buildID).To(Equal(cursorBuild.ID()))
   538  
   539  				for i := len(olderBuilds) - 1; i >= 0; i-- {
   540  					buildID, ok, err := paginatedBuilds.Next(ctx)
   541  					Expect(err).ToNot(HaveOccurred())
   542  					Expect(ok).To(BeTrue())
   543  					Expect(buildID).To(Equal(olderBuilds[i].ID()))
   544  				}
   545  
   546  				buildID, ok, err = paginatedBuilds.Next(ctx)
   547  				Expect(err).ToNot(HaveOccurred())
   548  				Expect(ok).To(BeFalse())
   549  				Expect(buildID).To(BeZero())
   550  			})
   551  		})
   552  
   553  		Context("with some older builds and some newer builds and some reruns of the cursor", func() {
   554  			var olderBuilds []db.Build
   555  			var cursorBuild db.Build
   556  			var newerBuilds []db.Build
   557  			var rerunBuilds []db.Build
   558  
   559  			BeforeEach(func() {
   560  				olderBuilds = []db.Build{}
   561  				for i := 0; i < pageLimit; i++ {
   562  					build, err := defaultJob.CreateBuild()
   563  					Expect(err).ToNot(HaveOccurred())
   564  
   565  					err = build.Finish(db.BuildStatusSucceeded)
   566  					Expect(err).ToNot(HaveOccurred())
   567  
   568  					olderBuilds = append(olderBuilds, build)
   569  				}
   570  
   571  				var err error
   572  				cursorBuild, err = defaultJob.CreateBuild()
   573  				Expect(err).ToNot(HaveOccurred())
   574  
   575  				err = cursorBuild.Finish(db.BuildStatusSucceeded)
   576  				Expect(err).ToNot(HaveOccurred())
   577  
   578  				lastUsedBuild = db.BuildCursor{
   579  					ID: cursorBuild.ID(),
   580  				}
   581  
   582  				newerBuilds = []db.Build{}
   583  				for i := 0; i < pageLimit; i++ {
   584  					build, err := defaultJob.CreateBuild()
   585  					Expect(err).ToNot(HaveOccurred())
   586  
   587  					err = build.Finish(db.BuildStatusSucceeded)
   588  					Expect(err).ToNot(HaveOccurred())
   589  
   590  					newerBuilds = append(newerBuilds, build)
   591  				}
   592  
   593  				rerunBuilds = []db.Build{}
   594  				for i := 0; i < pageLimit; i++ {
   595  					build, err := defaultJob.RerunBuild(cursorBuild)
   596  					Expect(err).ToNot(HaveOccurred())
   597  
   598  					err = build.Finish(db.BuildStatusSucceeded)
   599  					Expect(err).ToNot(HaveOccurred())
   600  
   601  					rerunBuilds = append(rerunBuilds, build)
   602  				}
   603  			})
   604  
   605  			It("returns the rerun builds, oldest to newest, followed by the newer builds, oldest to newest, followed by the cursor build and older builds, newest to oldest", func() {
   606  				for i := 0; i < len(rerunBuilds); i++ {
   607  					buildID, ok, err := paginatedBuilds.Next(ctx)
   608  					Expect(err).ToNot(HaveOccurred())
   609  					Expect(ok).To(BeTrue())
   610  					Expect(buildID).To(Equal(rerunBuilds[i].ID()))
   611  				}
   612  
   613  				for i := 0; i < len(newerBuilds); i++ {
   614  					buildID, ok, err := paginatedBuilds.Next(ctx)
   615  					Expect(err).ToNot(HaveOccurred())
   616  					Expect(ok).To(BeTrue())
   617  					Expect(buildID).To(Equal(newerBuilds[i].ID()))
   618  				}
   619  
   620  				buildID, ok, err := paginatedBuilds.Next(ctx)
   621  				Expect(err).ToNot(HaveOccurred())
   622  				Expect(ok).To(BeTrue())
   623  				Expect(buildID).To(Equal(cursorBuild.ID()))
   624  
   625  				for i := len(olderBuilds) - 1; i >= 0; i-- {
   626  					buildID, ok, err := paginatedBuilds.Next(ctx)
   627  					Expect(err).ToNot(HaveOccurred())
   628  					Expect(ok).To(BeTrue())
   629  					Expect(buildID).To(Equal(olderBuilds[i].ID()))
   630  				}
   631  
   632  				buildID, ok, err = paginatedBuilds.Next(ctx)
   633  				Expect(err).ToNot(HaveOccurred())
   634  				Expect(ok).To(BeFalse())
   635  				Expect(buildID).To(BeZero())
   636  			})
   637  		})
   638  
   639  		Context("when the last used build was a rerun and there is another rerun before and after it", func() {
   640  			var build1Succeeded db.Build
   641  			var build2Failed db.Build
   642  			var build3Succeeded db.Build
   643  			var build4Rerun2Succeeded db.Build
   644  			var build5Rerun2Succeeded db.Build
   645  			var build6Rerun2Succeeded db.Build
   646  			var build7Succeeded db.Build
   647  
   648  			BeforeEach(func() {
   649  				var err error
   650  				build1Succeeded, err = defaultJob.CreateBuild()
   651  				Expect(err).ToNot(HaveOccurred())
   652  				err = build1Succeeded.Finish(db.BuildStatusSucceeded)
   653  				Expect(err).ToNot(HaveOccurred())
   654  
   655  				build2Failed, err = defaultJob.CreateBuild()
   656  				Expect(err).ToNot(HaveOccurred())
   657  				err = build2Failed.Finish(db.BuildStatusFailed)
   658  				Expect(err).ToNot(HaveOccurred())
   659  
   660  				build3Succeeded, err = defaultJob.CreateBuild()
   661  				Expect(err).ToNot(HaveOccurred())
   662  				err = build3Succeeded.Finish(db.BuildStatusSucceeded)
   663  				Expect(err).ToNot(HaveOccurred())
   664  
   665  				build4Rerun2Succeeded, err = defaultJob.RerunBuild(build2Failed)
   666  				Expect(err).ToNot(HaveOccurred())
   667  				err = build4Rerun2Succeeded.Finish(db.BuildStatusSucceeded)
   668  				Expect(err).ToNot(HaveOccurred())
   669  
   670  				build5Rerun2Succeeded, err = defaultJob.RerunBuild(build2Failed)
   671  				Expect(err).ToNot(HaveOccurred())
   672  				err = build5Rerun2Succeeded.Finish(db.BuildStatusSucceeded)
   673  				Expect(err).ToNot(HaveOccurred())
   674  
   675  				lastUsedBuild = db.BuildCursor{
   676  					ID: build5Rerun2Succeeded.ID(),
   677  					RerunOf: sql.NullInt64{
   678  						Int64: int64(build5Rerun2Succeeded.RerunOf()),
   679  						Valid: true,
   680  					},
   681  				}
   682  
   683  				build6Rerun2Succeeded, err = defaultJob.RerunBuild(build2Failed)
   684  				Expect(err).ToNot(HaveOccurred())
   685  				err = build6Rerun2Succeeded.Finish(db.BuildStatusSucceeded)
   686  				Expect(err).ToNot(HaveOccurred())
   687  
   688  				build7Succeeded, err = defaultJob.CreateBuild()
   689  				Expect(err).ToNot(HaveOccurred())
   690  				err = build7Succeeded.Finish(db.BuildStatusSucceeded)
   691  				Expect(err).ToNot(HaveOccurred())
   692  			})
   693  
   694  			It("returns newer rerun, the newer builds, followed by the given rerun, the older rerun, and the older builds", func() {
   695  				buildID, ok, err := paginatedBuilds.Next(ctx)
   696  				Expect(err).ToNot(HaveOccurred())
   697  				Expect(ok).To(BeTrue())
   698  				Expect(buildID).To(Equal(build6Rerun2Succeeded.ID()))
   699  
   700  				buildID, ok, err = paginatedBuilds.Next(ctx)
   701  				Expect(err).ToNot(HaveOccurred())
   702  				Expect(ok).To(BeTrue())
   703  				Expect(buildID).To(Equal(build3Succeeded.ID()))
   704  
   705  				buildID, ok, err = paginatedBuilds.Next(ctx)
   706  				Expect(err).ToNot(HaveOccurred())
   707  				Expect(ok).To(BeTrue())
   708  				Expect(buildID).To(Equal(build7Succeeded.ID()))
   709  
   710  				buildID, ok, err = paginatedBuilds.Next(ctx)
   711  				Expect(err).ToNot(HaveOccurred())
   712  				Expect(ok).To(BeTrue())
   713  				Expect(buildID).To(Equal(build5Rerun2Succeeded.ID()))
   714  
   715  				buildID, ok, err = paginatedBuilds.Next(ctx)
   716  				Expect(err).ToNot(HaveOccurred())
   717  				Expect(ok).To(BeTrue())
   718  				Expect(buildID).To(Equal(build4Rerun2Succeeded.ID()))
   719  
   720  				buildID, ok, err = paginatedBuilds.Next(ctx)
   721  				Expect(err).ToNot(HaveOccurred())
   722  				Expect(ok).To(BeTrue())
   723  				Expect(buildID).To(Equal(build1Succeeded.ID()))
   724  
   725  				buildID, ok, err = paginatedBuilds.Next(ctx)
   726  				Expect(err).ToNot(HaveOccurred())
   727  				Expect(ok).To(BeFalse())
   728  				Expect(buildID).To(BeZero())
   729  			})
   730  		})
   731  	})
   732  
   733  	Describe("FindVersionOfResource", func() {
   734  		var (
   735  			scenario     *dbtest.Scenario
   736  			queryVersion atc.Version
   737  
   738  			resourceVersion db.ResourceVersion
   739  			found           bool
   740  		)
   741  
   742  		JustBeforeEach(func() {
   743  			var err error
   744  			resourceVersion, found, err = vdb.FindVersionOfResource(
   745  				ctx,
   746  				scenario.Resource("some-resource").ID(),
   747  				queryVersion,
   748  			)
   749  			Expect(err).ToNot(HaveOccurred())
   750  		})
   751  
   752  		Context("when trying to find version by providing a matched partial version", func() {
   753  			var (
   754  				dbVersion atc.Version
   755  			)
   756  
   757  			BeforeEach(func() {
   758  				dbVersion = atc.Version{"tag": "v1", "commit": "v2"}
   759  
   760  				scenario = dbtest.Setup(
   761  					builder.WithResourceVersions("some-resource", dbVersion),
   762  				)
   763  
   764  				queryVersion = atc.Version{"tag": "v1"}
   765  			})
   766  
   767  			It("return the version md5", func() {
   768  				Expect(found).To(BeTrue())
   769  				Expect(string(resourceVersion)).To(Equal(convertToMD5(dbVersion)))
   770  			})
   771  		})
   772  	})
   773  })