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 }