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

     1  package gc_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	sq "github.com/Masterminds/squirrel"
     8  	"github.com/pf-qiu/concourse/v6/atc"
     9  	"github.com/pf-qiu/concourse/v6/atc/db"
    10  	"github.com/pf-qiu/concourse/v6/atc/db/dbtest"
    11  	"github.com/pf-qiu/concourse/v6/atc/gc"
    12  
    13  	. "github.com/onsi/ginkgo"
    14  	. "github.com/onsi/gomega"
    15  )
    16  
    17  var _ = Describe("ResourceCacheCollector", func() {
    18  	var collector GcCollector
    19  	var buildCollector GcCollector
    20  
    21  	BeforeEach(func() {
    22  		collector = gc.NewResourceCacheCollector(resourceCacheLifecycle)
    23  		buildCollector = gc.NewBuildCollector(buildFactory)
    24  	})
    25  
    26  	Describe("Run", func() {
    27  		Describe("resource caches", func() {
    28  			var resourceCacheUseCollector GcCollector
    29  
    30  			var oneOffBuild db.Build
    31  			var jobBuild db.Build
    32  
    33  			var oneOffCache db.UsedResourceCache
    34  			var jobCache db.UsedResourceCache
    35  
    36  			var scenario *dbtest.Scenario
    37  
    38  			BeforeEach(func() {
    39  				resourceCacheUseCollector = gc.NewResourceCacheUseCollector(resourceCacheLifecycle)
    40  
    41  				scenario = dbtest.Setup(
    42  					builder.WithPipeline(atc.Config{
    43  						Resources: atc.ResourceConfigs{
    44  							{
    45  								Name:   "some-resource",
    46  								Type:   "some-base-type",
    47  								Source: atc.Source{"some": "source"},
    48  							},
    49  						},
    50  						Jobs: atc.JobConfigs{
    51  							{
    52  								Name: "some-job",
    53  							},
    54  							{
    55  								Name: "some-other-job",
    56  							},
    57  						},
    58  					}),
    59  					builder.WithResourceVersions("some-resource"),
    60  				)
    61  
    62  				oneOffBuild, err = scenario.Team.CreateOneOffBuild()
    63  				Expect(err).ToNot(HaveOccurred())
    64  
    65  				oneOffCache, err = resourceCacheFactory.FindOrCreateResourceCache(
    66  					db.ForBuild(oneOffBuild.ID()),
    67  					"some-base-type",
    68  					atc.Version{"some": "version"},
    69  					atc.Source{
    70  						"some": "source",
    71  					},
    72  					nil,
    73  					atc.VersionedResourceTypes{},
    74  				)
    75  				Expect(err).NotTo(HaveOccurred())
    76  
    77  				jobBuild, err = scenario.Job("some-job").CreateBuild()
    78  				Expect(err).ToNot(HaveOccurred())
    79  
    80  				jobCache, err = resourceCacheFactory.FindOrCreateResourceCache(
    81  					db.ForBuild(jobBuild.ID()),
    82  					"some-base-type",
    83  					atc.Version{"some": "version"},
    84  					atc.Source{
    85  						"some": "source",
    86  					},
    87  					nil,
    88  					atc.VersionedResourceTypes{},
    89  				)
    90  				Expect(err).NotTo(HaveOccurred())
    91  			})
    92  
    93  			resourceCacheExists := func(resourceCache db.UsedResourceCache) bool {
    94  				var count int
    95  				err = psql.Select("COUNT(*)").
    96  					From("resource_caches").
    97  					Where(sq.Eq{"id": resourceCache.ID()}).
    98  					RunWith(dbConn).
    99  					QueryRow().
   100  					Scan(&count)
   101  				Expect(err).NotTo(HaveOccurred())
   102  				return count == 1
   103  			}
   104  
   105  			JustBeforeEach(func() {
   106  				Expect(buildCollector.Run(context.TODO())).To(Succeed())
   107  				Expect(resourceCacheUseCollector.Run(context.TODO())).To(Succeed())
   108  				Expect(collector.Run(context.TODO())).To(Succeed())
   109  			})
   110  
   111  			Context("when the resource cache is still in use", func() {
   112  				It("does not delete the cache", func() {
   113  					Expect(collector.Run(context.TODO())).To(Succeed())
   114  					Expect(resourceCacheExists(oneOffCache)).To(BeTrue())
   115  					Expect(resourceCacheExists(jobCache)).To(BeTrue())
   116  				})
   117  			})
   118  
   119  			Context("when the cache is no longer in use", func() {
   120  				BeforeEach(func() {
   121  					Expect(oneOffBuild.Finish(db.BuildStatusSucceeded)).To(Succeed())
   122  					Expect(jobBuild.Finish(db.BuildStatusSucceeded)).To(Succeed())
   123  				})
   124  
   125  				Context("when the cache is an input to a job", func() {
   126  					BeforeEach(func() {
   127  						var versionMD5 string
   128  						version := `{"some":"version"}`
   129  						err = psql.Insert("resource_config_versions").
   130  							Columns("version", "version_md5", "metadata", "resource_config_scope_id").
   131  							Values(version, sq.Expr(fmt.Sprintf("md5('%s')", version)), `null`, jobCache.ResourceConfig().ID()).
   132  							Suffix("RETURNING version_md5").
   133  							RunWith(dbConn).QueryRow().Scan(&versionMD5)
   134  						Expect(err).NotTo(HaveOccurred())
   135  
   136  						Expect(scenario.Job("some-job").SaveNextInputMapping(db.InputMapping{
   137  							"whatever": db.InputResult{
   138  								Input: &db.AlgorithmInput{
   139  									AlgorithmVersion: db.AlgorithmVersion{
   140  										Version:    db.ResourceVersion(versionMD5),
   141  										ResourceID: scenario.Resource("some-resource").ID(),
   142  									},
   143  								},
   144  							},
   145  						}, true)).To(Succeed())
   146  					})
   147  
   148  					Context("when pipeline is paused", func() {
   149  						BeforeEach(func() {
   150  							err := scenario.Pipeline.Pause()
   151  							Expect(err).NotTo(HaveOccurred())
   152  						})
   153  
   154  						It("removes the cache", func() {
   155  							Expect(resourceCacheExists(jobCache)).To(BeFalse())
   156  						})
   157  					})
   158  
   159  					Context("when pipeline is not paused", func() {
   160  						It("leaves it alone", func() {
   161  							Expect(resourceCacheExists(jobCache)).To(BeTrue())
   162  						})
   163  					})
   164  				})
   165  
   166  				Context("when the cache is an image resource version for a job build", func() {
   167  					BeforeEach(func() {
   168  						err := jobBuild.SaveImageResourceVersion(jobCache)
   169  						Expect(err).NotTo(HaveOccurred())
   170  					})
   171  
   172  					It("leaves it alone", func() {
   173  						Expect(resourceCacheExists(jobCache)).To(BeTrue())
   174  					})
   175  
   176  					Context("when another build of the same job exists with a different image cache", func() {
   177  						var secondJobBuild db.Build
   178  						var secondJobCache db.UsedResourceCache
   179  
   180  						BeforeEach(func() {
   181  							secondJobBuild, err = scenario.Job("some-job").CreateBuild()
   182  							Expect(err).ToNot(HaveOccurred())
   183  
   184  							secondJobCache, err = resourceCacheFactory.FindOrCreateResourceCache(
   185  								db.ForBuild(secondJobBuild.ID()),
   186  								"some-base-type",
   187  								atc.Version{"some": "new-version"},
   188  								atc.Source{
   189  									"some": "source",
   190  								},
   191  								nil,
   192  								atc.VersionedResourceTypes{},
   193  							)
   194  							Expect(err).NotTo(HaveOccurred())
   195  
   196  							Expect(secondJobBuild.SaveImageResourceVersion(secondJobCache)).To(Succeed())
   197  						})
   198  
   199  						Context("when the second build succeeds", func() {
   200  							BeforeEach(func() {
   201  								Expect(secondJobBuild.Finish(db.BuildStatusSucceeded)).To(Succeed())
   202  							})
   203  
   204  							It("keeps the new cache and removes the old one", func() {
   205  								Expect(resourceCacheExists(jobCache)).To(BeFalse())
   206  								Expect(resourceCacheExists(secondJobCache)).To(BeTrue())
   207  							})
   208  						})
   209  
   210  						Context("when the second build fails", func() {
   211  							BeforeEach(func() {
   212  								Expect(secondJobBuild.Finish(db.BuildStatusFailed)).To(Succeed())
   213  							})
   214  
   215  							It("keeps the new cache and the old one", func() {
   216  								Expect(resourceCacheExists(jobCache)).To(BeTrue())
   217  								Expect(resourceCacheExists(secondJobCache)).To(BeTrue())
   218  							})
   219  						})
   220  					})
   221  
   222  					Context("when another build of a different job exists with a different image cache", func() {
   223  						var secondJobBuild db.Build
   224  						var secondJobCache db.UsedResourceCache
   225  
   226  						BeforeEach(func() {
   227  							secondJobBuild, err = scenario.Job("some-other-job").CreateBuild()
   228  							Expect(err).ToNot(HaveOccurred())
   229  
   230  							secondJobCache, err = resourceCacheFactory.FindOrCreateResourceCache(
   231  								db.ForBuild(secondJobBuild.ID()),
   232  								"some-base-type",
   233  								atc.Version{"some": "new-version"},
   234  								atc.Source{
   235  									"some": "source",
   236  								},
   237  								nil,
   238  								atc.VersionedResourceTypes{},
   239  							)
   240  							Expect(err).NotTo(HaveOccurred())
   241  
   242  							Expect(secondJobBuild.SaveImageResourceVersion(secondJobCache)).To(Succeed())
   243  						})
   244  
   245  						Context("when the second build succeeds", func() {
   246  							BeforeEach(func() {
   247  								Expect(secondJobBuild.Finish(db.BuildStatusSucceeded)).To(Succeed())
   248  							})
   249  
   250  							It("keeps the new cache and the old one", func() {
   251  								Expect(resourceCacheExists(jobCache)).To(BeTrue())
   252  								Expect(resourceCacheExists(secondJobCache)).To(BeTrue())
   253  							})
   254  						})
   255  
   256  						Context("when the second build fails", func() {
   257  							BeforeEach(func() {
   258  								Expect(secondJobBuild.Finish(db.BuildStatusFailed)).To(Succeed())
   259  							})
   260  
   261  							It("keeps the new cache and the old one", func() {
   262  								Expect(resourceCacheExists(jobCache)).To(BeTrue())
   263  								Expect(resourceCacheExists(secondJobCache)).To(BeTrue())
   264  							})
   265  						})
   266  					})
   267  				})
   268  
   269  				Context("when the cache is an image resource version for a one-off build", func() {
   270  					BeforeEach(func() {
   271  						err := oneOffBuild.SaveImageResourceVersion(oneOffCache)
   272  						Expect(err).NotTo(HaveOccurred())
   273  					})
   274  
   275  					Context("when the build finished recently", func() {
   276  						It("leaves it alone", func() {
   277  							Expect(resourceCacheExists(oneOffCache)).To(BeTrue())
   278  						})
   279  					})
   280  
   281  					Context("when the build finished a day ago", func() {
   282  						BeforeEach(func() {
   283  							_, err := psql.Update("builds").
   284  								Set("end_time", sq.Expr("NOW() - '25 hours'::interval")).
   285  								Where(sq.Eq{"id": oneOffBuild.ID()}).
   286  								RunWith(dbConn).
   287  								Exec()
   288  							Expect(err).ToNot(HaveOccurred())
   289  						})
   290  
   291  						It("removes the cache", func() {
   292  							Expect(resourceCacheExists(oneOffCache)).To(BeFalse())
   293  						})
   294  					})
   295  				})
   296  			})
   297  		})
   298  	})
   299  })