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

     1  package migration_test
     2  
     3  import (
     4  	"database/sql"
     5  	"fmt"
     6  
     7  	. "github.com/onsi/ginkgo"
     8  	. "github.com/onsi/gomega"
     9  )
    10  
    11  var _ = Describe("Add global resource versions", func() {
    12  	const preMigrationVersion = 1537196857
    13  	const postMigrationVersion = 1537546150
    14  
    15  	var (
    16  		db *sql.DB
    17  	)
    18  
    19  	Context("Up", func() {
    20  		It("migrates disabled resource versions to new resource disabled versions table", func() {
    21  			db = postgresRunner.OpenDBAtVersion(preMigrationVersion)
    22  
    23  			setup(db)
    24  			setupResource(db)
    25  			setupVersionedResources(db)
    26  			db.Close()
    27  
    28  			db = postgresRunner.OpenDBAtVersion(postMigrationVersion)
    29  
    30  			for i := 1; i <= 3; i++ {
    31  				_, err := db.Exec("INSERT INTO resource_config_versions(version, version_md5, resource_config_id, check_order) VALUES($1::jsonb, md5($1::text), 1, $2)", fmt.Sprintf(`{"version": "v%d"}`, i), i)
    32  				Expect(err).NotTo(HaveOccurred())
    33  			}
    34  
    35  			rows, err := db.Query(`SELECT d.resource_id, v.version FROM resource_disabled_versions d, resource_config_versions v WHERE d.version_md5 = v.version_md5`)
    36  			Expect(err).NotTo(HaveOccurred())
    37  
    38  			type disabledVersions struct {
    39  				resourceID int
    40  				version    string
    41  			}
    42  
    43  			dvs := []disabledVersions{}
    44  			for rows.Next() {
    45  				dv := disabledVersions{}
    46  
    47  				err := rows.Scan(&dv.resourceID, &dv.version)
    48  				Expect(err).NotTo(HaveOccurred())
    49  
    50  				dvs = append(dvs, dv)
    51  			}
    52  
    53  			_ = db.Close()
    54  
    55  			Expect(dvs).To(HaveLen(2))
    56  			Expect(dvs[0].resourceID).To(Equal(1))
    57  			Expect(dvs[0].version).To(Equal(`{"version": "v3"}`))
    58  		})
    59  
    60  		It("migrates the build inputs into the new build resource config version inputs table", func() {
    61  			db = postgresRunner.OpenDBAtVersion(preMigrationVersion)
    62  
    63  			setup(db)
    64  			setupResource(db)
    65  			setupVersionedResources(db)
    66  			setupBuilds(db)
    67  			db.Close()
    68  
    69  			db = postgresRunner.OpenDBAtVersion(postMigrationVersion)
    70  
    71  			rows, err := db.Query(`SELECT build_id, version_md5, resource_id, name FROM build_resource_config_version_inputs`)
    72  			Expect(err).NotTo(HaveOccurred())
    73  
    74  			type buildInput struct {
    75  				buildID    int
    76  				versionMD5 string
    77  				resourceID int
    78  				name       string
    79  			}
    80  
    81  			buildInputs := []buildInput{}
    82  			for rows.Next() {
    83  				bi := buildInput{}
    84  
    85  				err := rows.Scan(&bi.buildID, &bi.versionMD5, &bi.resourceID, &bi.name)
    86  				Expect(err).NotTo(HaveOccurred())
    87  
    88  				buildInputs = append(buildInputs, bi)
    89  			}
    90  
    91  			rows, err = db.Query(`SELECT id, md5(version) FROM versioned_resources`)
    92  			Expect(err).NotTo(HaveOccurred())
    93  
    94  			versions := map[int]string{}
    95  			for rows.Next() {
    96  				var id int
    97  				var version string
    98  
    99  				err := rows.Scan(&id, &version)
   100  				Expect(err).NotTo(HaveOccurred())
   101  
   102  				versions[id] = version
   103  			}
   104  
   105  			_ = db.Close()
   106  
   107  			actualBuildInputs := []buildInput{
   108  				{
   109  					buildID:    1,
   110  					versionMD5: versions[1],
   111  					resourceID: 1,
   112  					name:       "build_input1",
   113  				},
   114  				{
   115  					buildID:    1,
   116  					versionMD5: versions[2],
   117  					resourceID: 1,
   118  					name:       "build_input2",
   119  				},
   120  				{
   121  					buildID:    2,
   122  					versionMD5: versions[1],
   123  					resourceID: 1,
   124  					name:       "build_input3",
   125  				},
   126  				{
   127  					buildID:    3,
   128  					versionMD5: versions[1],
   129  					resourceID: 1,
   130  					name:       "build_input4",
   131  				},
   132  				{
   133  					buildID:    4,
   134  					versionMD5: versions[4],
   135  					resourceID: 2,
   136  					name:       "build_input5",
   137  				},
   138  			}
   139  
   140  			Expect(buildInputs).To(HaveLen(5))
   141  			Expect(buildInputs).To(ConsistOf(actualBuildInputs))
   142  		})
   143  
   144  		It("migrates the build outputs into the new build resource config version outputs table", func() {
   145  			db = postgresRunner.OpenDBAtVersion(preMigrationVersion)
   146  
   147  			setup(db)
   148  			setupResource(db)
   149  			setupVersionedResources(db)
   150  			setupBuildOutputs(db)
   151  			db.Close()
   152  
   153  			db = postgresRunner.OpenDBAtVersion(postMigrationVersion)
   154  
   155  			rows, err := db.Query(`SELECT build_id, version_md5, resource_id, name FROM build_resource_config_version_outputs`)
   156  			Expect(err).NotTo(HaveOccurred())
   157  
   158  			type buildOutput struct {
   159  				buildID    int
   160  				versionMD5 string
   161  				resourceID int
   162  				name       string
   163  			}
   164  
   165  			buildOutputs := []buildOutput{}
   166  			for rows.Next() {
   167  				bo := buildOutput{}
   168  
   169  				err := rows.Scan(&bo.buildID, &bo.versionMD5, &bo.resourceID, &bo.name)
   170  				Expect(err).NotTo(HaveOccurred())
   171  
   172  				buildOutputs = append(buildOutputs, bo)
   173  			}
   174  
   175  			rows, err = db.Query(`SELECT id, md5(version) FROM versioned_resources`)
   176  			Expect(err).NotTo(HaveOccurred())
   177  
   178  			versions := map[int]string{}
   179  			for rows.Next() {
   180  				var id int
   181  				var version string
   182  
   183  				err := rows.Scan(&id, &version)
   184  				Expect(err).NotTo(HaveOccurred())
   185  
   186  				versions[id] = version
   187  			}
   188  
   189  			_ = db.Close()
   190  
   191  			actualBuildOutputs := []buildOutput{
   192  				{
   193  					buildID:    1,
   194  					versionMD5: versions[2],
   195  					resourceID: 1,
   196  					name:       "some-resource",
   197  				},
   198  				{
   199  					buildID:    2,
   200  					versionMD5: versions[1],
   201  					resourceID: 1,
   202  					name:       "some-resource",
   203  				},
   204  				{
   205  					buildID:    3,
   206  					versionMD5: versions[1],
   207  					resourceID: 1,
   208  					name:       "some-resource",
   209  				},
   210  				{
   211  					buildID:    4,
   212  					versionMD5: versions[4],
   213  					resourceID: 2,
   214  					name:       "some-other-resource",
   215  				},
   216  			}
   217  
   218  			Expect(buildOutputs).To(HaveLen(4))
   219  			Expect(buildOutputs).To(ConsistOf(actualBuildOutputs))
   220  		})
   221  	})
   222  
   223  	Context("Down", func() {
   224  		It("saves all versions (disabled and enabled) into the versioned resources table", func() {
   225  			db = postgresRunner.OpenDBAtVersion(postMigrationVersion)
   226  
   227  			setup(db)
   228  			setupResource(db)
   229  			setupVersionedResources(db)
   230  
   231  			// Insert three versions into resource config versions table
   232  			for i := 1; i <= 3; i++ {
   233  				_, err := db.Exec("INSERT INTO resource_config_versions(version, version_md5, resource_config_id, check_order) VALUES($1::jsonb, md5($1::text), 1, $2)", fmt.Sprintf(`{"version": "v%d"}`, i), i)
   234  				Expect(err).NotTo(HaveOccurred())
   235  			}
   236  
   237  			// Disable the second and third resource version
   238  			_, err := db.Exec("INSERT INTO resource_disabled_versions(version_md5, resource_id) VALUES(md5($1::text), 1)", fmt.Sprintf(`{"version": "v%d"}`, 2))
   239  			Expect(err).NotTo(HaveOccurred())
   240  
   241  			_, err = db.Exec("INSERT INTO resource_disabled_versions(version_md5, resource_id) VALUES(md5($1::text), 1)", fmt.Sprintf(`{"version": "v%d"}`, 3))
   242  			Expect(err).NotTo(HaveOccurred())
   243  
   244  			db.Close()
   245  
   246  			db = postgresRunner.OpenDBAtVersion(preMigrationVersion)
   247  
   248  			rows, err := db.Query(`SELECT v.resource_id, v.version, v.type, v.enabled FROM versioned_resources v`)
   249  			Expect(err).NotTo(HaveOccurred())
   250  
   251  			type versionedResource struct {
   252  				resourceID int
   253  				version    string
   254  				enabled    bool
   255  				type_      string
   256  			}
   257  
   258  			vs := []versionedResource{}
   259  			for rows.Next() {
   260  				v := versionedResource{}
   261  
   262  				err := rows.Scan(&v.resourceID, &v.version, &v.type_, &v.enabled)
   263  				Expect(err).NotTo(HaveOccurred())
   264  
   265  				vs = append(vs, v)
   266  			}
   267  
   268  			db.Close()
   269  
   270  			Expect(vs).To(HaveLen(6))
   271  
   272  			desiredVersionedResources := []versionedResource{
   273  				{
   274  					resourceID: 1,
   275  					version:    `{"version": "v1"}`,
   276  					type_:      "some-type",
   277  					enabled:    true,
   278  				},
   279  				{
   280  					resourceID: 1,
   281  					version:    `{"version": "v2"}`,
   282  					type_:      "some-type",
   283  					enabled:    false,
   284  				},
   285  				{
   286  					resourceID: 1,
   287  					version:    `{"version": "v3"}`,
   288  					type_:      "some-type",
   289  					enabled:    false,
   290  				},
   291  				{
   292  					resourceID: 2,
   293  					version:    `{"version": "v1"}`,
   294  					type_:      "some-type",
   295  					enabled:    true,
   296  				},
   297  				{
   298  					resourceID: 2,
   299  					version:    `{"version": "v2"}`,
   300  					type_:      "some-type",
   301  					enabled:    true,
   302  				},
   303  				{
   304  					resourceID: 2,
   305  					version:    `{"version": "v3"}`,
   306  					type_:      "some-type",
   307  					enabled:    true,
   308  				},
   309  			}
   310  
   311  			Expect(vs).To(ConsistOf(desiredVersionedResources))
   312  		})
   313  	})
   314  })
   315  
   316  func setupResource(db *sql.DB) {
   317  	_, err := db.Exec("INSERT INTO base_resource_types(name) VALUES('some-type')")
   318  	Expect(err).NotTo(HaveOccurred())
   319  
   320  	_, err = db.Exec("INSERT INTO resource_configs(source_hash, base_resource_type_id) VALUES('some-source', 1)")
   321  	Expect(err).NotTo(HaveOccurred())
   322  
   323  	_, err = db.Exec(`INSERT INTO resources(name, pipeline_id, config, active, resource_config_id) VALUES('some-resource', 1, '{"type": "some-type"}', true, 1)`)
   324  	Expect(err).NotTo(HaveOccurred())
   325  
   326  	_, err = db.Exec(`INSERT INTO resources(name, pipeline_id, config, active, resource_config_id) VALUES('some-other-resource', 2, '{"type": "some-type"}', true, 1)`)
   327  	Expect(err).NotTo(HaveOccurred())
   328  }
   329  
   330  func setupVersionedResources(db *sql.DB) {
   331  	// Insert two enabled versions into the versioned resources table
   332  	for i := 1; i <= 2; i++ {
   333  		_, err := db.Exec("INSERT INTO versioned_resources(version, metadata, type, enabled, resource_id, check_order) VALUES($1, 'some-metadata', 'some-type', true, 1, $2)", fmt.Sprintf(`{"version": "v%d"}`, i), i)
   334  		Expect(err).NotTo(HaveOccurred())
   335  	}
   336  
   337  	// Insert a disabled version into the versioned resources table
   338  	_, err := db.Exec(`INSERT INTO versioned_resources(version, metadata, type, enabled, resource_id, check_order) VALUES('{"version": "v3"}', 'some-metadata', 'some-type', false, 1, 3)`)
   339  	Expect(err).NotTo(HaveOccurred())
   340  
   341  	// Insert another version into the versioned resources table for pipeline 2
   342  	_, err = db.Exec(`INSERT INTO versioned_resources(version, metadata, type, enabled, resource_id, check_order) VALUES('{"version": "v1"}', 'some-metadata', 'some-type', false, 2, 1)`)
   343  	Expect(err).NotTo(HaveOccurred())
   344  }
   345  
   346  func setupBuilds(db *sql.DB) {
   347  	_, err := db.Exec(`
   348  				INSERT INTO builds(id, name, status, job_id, team_id, pipeline_id) VALUES
   349  					(1, 'build1', 'succeeded', 1, 1, 1),
   350  					(2, 'build2', 'succeeded', 1, 1, 1),
   351  					(3, 'build3', 'started', 2, 1, 1),
   352  					(4, 'build4', 'pending', 4, 1, 2)
   353  			`)
   354  	Expect(err).NotTo(HaveOccurred())
   355  
   356  	_, err = db.Exec(`
   357  				INSERT INTO build_inputs(build_id, versioned_resource_id, name) VALUES
   358  					(1, 1, 'build_input1'),
   359  					(1, 2, 'build_input2'),
   360  					(2, 1, 'build_input3'),
   361  					(3, 1, 'build_input4'),
   362  					(3, 1, 'build_input4'),
   363  					(4, 4, 'build_input5')
   364  			`)
   365  	Expect(err).NotTo(HaveOccurred())
   366  }
   367  
   368  func setupBuildOutputs(db *sql.DB) {
   369  	_, err := db.Exec(`
   370  				INSERT INTO builds(id, name, status, job_id, team_id, pipeline_id) VALUES
   371  					(1, 'build1', 'succeeded', 1, 1, 1),
   372  					(2, 'build2', 'succeeded', 1, 1, 1),
   373  					(3, 'build3', 'started', 2, 1, 1),
   374  					(4, 'build4', 'pending', 4, 1, 2)
   375  			`)
   376  	Expect(err).NotTo(HaveOccurred())
   377  
   378  	_, err = db.Exec(`
   379  				INSERT INTO build_outputs(build_id, versioned_resource_id) VALUES
   380  					(1, 2),
   381  					(2, 1),
   382  					(3, 1),
   383  					(3, 1),
   384  					(4, 4)
   385  			`)
   386  	Expect(err).NotTo(HaveOccurred())
   387  }