672 lines
28 KiB
Python
672 lines
28 KiB
Python
# Copyright 2021-2023 Acme Gating, LLC
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import difflib
|
|
import os
|
|
import re
|
|
import subprocess
|
|
|
|
from zuul.driver.sql import SQLDriver
|
|
from zuul.zk import ZooKeeperClient
|
|
from tests.base import (
|
|
BaseTestCase, MySQLSchemaFixture, PostgresqlSchemaFixture
|
|
)
|
|
|
|
import sqlalchemy
|
|
import testtools
|
|
|
|
|
|
class DBBaseTestCase(BaseTestCase):
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.setupZK()
|
|
|
|
self.zk_client = ZooKeeperClient(
|
|
self.zk_chroot_fixture.zk_hosts,
|
|
tls_cert=self.zk_chroot_fixture.zookeeper_cert,
|
|
tls_key=self.zk_chroot_fixture.zookeeper_key,
|
|
tls_ca=self.zk_chroot_fixture.zookeeper_ca
|
|
)
|
|
self.addCleanup(self.zk_client.disconnect)
|
|
self.zk_client.connect()
|
|
|
|
|
|
class TestMysqlDatabase(DBBaseTestCase):
|
|
def setUp(self):
|
|
super().setUp()
|
|
|
|
f = MySQLSchemaFixture()
|
|
self.useFixture(f)
|
|
|
|
config = dict(dburi=f.dburi)
|
|
driver = SQLDriver()
|
|
self.connection = driver.getConnection('database', config)
|
|
self.connection.onLoad(self.zk_client)
|
|
self.addCleanup(self._cleanup)
|
|
|
|
def _cleanup(self):
|
|
self.connection.onStop()
|
|
|
|
def compareMysql(self, alembic_text, sqlalchemy_text):
|
|
alembic_lines = alembic_text.split('\n')
|
|
sqlalchemy_lines = sqlalchemy_text.split('\n')
|
|
self.assertEqual(len(alembic_lines), len(sqlalchemy_lines))
|
|
alembic_constraints = []
|
|
sqlalchemy_constraints = []
|
|
for i in range(len(alembic_lines)):
|
|
if alembic_lines[i].startswith(" `"):
|
|
# Column
|
|
self.assertEqual(alembic_lines[i], sqlalchemy_lines[i])
|
|
elif alembic_lines[i].startswith(" "):
|
|
# Constraints can be unordered
|
|
# strip trailing commas since the last line omits it
|
|
alembic_constraints.append(
|
|
re.sub(',$', '', alembic_lines[i]))
|
|
sqlalchemy_constraints.append(
|
|
re.sub(',$', '', sqlalchemy_lines[i]))
|
|
else:
|
|
self.assertEqual(alembic_lines[i], sqlalchemy_lines[i])
|
|
alembic_constraints.sort()
|
|
sqlalchemy_constraints.sort()
|
|
self.assertEqual(alembic_constraints, sqlalchemy_constraints)
|
|
|
|
def test_migration(self):
|
|
# Test that SQLAlchemy create_all produces the same output as
|
|
# a full migration run.
|
|
sqlalchemy_tables = {}
|
|
with self.connection.engine.begin() as connection:
|
|
connection.exec_driver_sql("set foreign_key_checks=0")
|
|
for table in connection.exec_driver_sql("show tables"):
|
|
table = table[0]
|
|
sqlalchemy_tables[table] = connection.exec_driver_sql(
|
|
f"show create table {table}").one()[1]
|
|
connection.exec_driver_sql(f"drop table {table}")
|
|
connection.exec_driver_sql("set foreign_key_checks=1")
|
|
|
|
self.connection.force_migrations = True
|
|
self.connection.onLoad(self.zk_client)
|
|
with self.connection.engine.begin() as connection:
|
|
for table in connection.exec_driver_sql("show tables"):
|
|
table = table[0]
|
|
create = connection.exec_driver_sql(
|
|
f"show create table {table}").one()[1]
|
|
self.compareMysql(create, sqlalchemy_tables[table])
|
|
|
|
def test_migration_4647def24b32(self):
|
|
with self.connection.engine.begin() as connection:
|
|
connection.exec_driver_sql("set foreign_key_checks=0")
|
|
for table in connection.exec_driver_sql("show tables"):
|
|
table = table[0]
|
|
connection.exec_driver_sql(f"drop table {table}")
|
|
connection.exec_driver_sql("set foreign_key_checks=1")
|
|
|
|
self.connection.force_migrations = True
|
|
self.connection._migrate('c57e9e76b812')
|
|
with self.connection.engine.begin() as connection:
|
|
connection.exec_driver_sql(
|
|
"insert into zuul_buildset (project, result) "
|
|
"values ('org/project', 'SUCCESS')")
|
|
connection.exec_driver_sql(
|
|
"insert into zuul_buildset (project, result) "
|
|
"values ('org/project', 'MERGER_FAILURE')")
|
|
results = [r[0] for r in connection.exec_driver_sql(
|
|
"select result from zuul_buildset")]
|
|
self.assertEqual(results, ['SUCCESS', 'MERGER_FAILURE'])
|
|
|
|
self.connection._migrate()
|
|
with self.connection.engine.begin() as connection:
|
|
results = [r[0] for r in connection.exec_driver_sql(
|
|
"select result from zuul_buildset")]
|
|
self.assertEqual(results, ['SUCCESS', 'MERGE_CONFLICT'])
|
|
|
|
def test_migration_c7467b642498(self):
|
|
with self.connection.engine.begin() as connection:
|
|
connection.exec_driver_sql("set foreign_key_checks=0")
|
|
for table in connection.exec_driver_sql("show tables"):
|
|
table = table[0]
|
|
connection.exec_driver_sql(f"drop table {table}")
|
|
connection.exec_driver_sql("set foreign_key_checks=1")
|
|
|
|
self.connection.force_migrations = True
|
|
self.connection._migrate('4647def24b32')
|
|
with self.connection.engine.begin() as connection:
|
|
connection.exec_driver_sql(
|
|
"insert into zuul_buildset (project, result) "
|
|
"values ('org/project', 'SUCCESS')")
|
|
connection.exec_driver_sql(
|
|
"insert into zuul_buildset "
|
|
"(project, result, first_build_start_time) "
|
|
"values ('org/project', 'SUCCESS', '2022-05-01 12:34:56')")
|
|
connection.exec_driver_sql(
|
|
"insert into zuul_buildset "
|
|
"(project, result, last_build_end_time) "
|
|
"values ('org/project', 'SUCCESS', '2022-05-02 12:34:56')")
|
|
connection.exec_driver_sql(
|
|
"insert into zuul_buildset "
|
|
"(project, result, event_timestamp) "
|
|
"values ('org/project', 'SUCCESS', '2022-05-03 12:34:56')")
|
|
connection.exec_driver_sql(
|
|
"insert into zuul_buildset (project, result, "
|
|
"first_build_start_time, "
|
|
"last_build_end_time, "
|
|
"event_timestamp)"
|
|
"values ('org/project', 'SUCCESS', "
|
|
"'2022-05-11 12:34:56', "
|
|
"'2022-05-12 12:34:56', "
|
|
"'2022-05-13 12:34:56')")
|
|
|
|
self.connection._migrate()
|
|
with self.connection.engine.begin() as connection:
|
|
results = [str(r[0]) for r in connection.exec_driver_sql(
|
|
"select updated from zuul_buildset")]
|
|
self.assertEqual(results,
|
|
['1970-01-01 00:00:00',
|
|
'2022-05-01 12:34:56',
|
|
'2022-05-02 12:34:56',
|
|
'2022-05-03 12:34:56',
|
|
'2022-05-13 12:34:56'])
|
|
|
|
def test_migration_f7843ddf1552(self):
|
|
with self.connection.engine.begin() as connection:
|
|
connection.exec_driver_sql("set foreign_key_checks=0")
|
|
for table in connection.exec_driver_sql("show tables"):
|
|
table = table[0]
|
|
connection.exec_driver_sql(f"drop table {table}")
|
|
connection.exec_driver_sql("set foreign_key_checks=1")
|
|
|
|
self.connection.force_migrations = True
|
|
self.connection._migrate('151893067f91')
|
|
with self.connection.engine.begin() as connection:
|
|
connection.exec_driver_sql("""
|
|
insert into zuul_buildset
|
|
(id, uuid, zuul_ref, project, `change`, patchset, ref,
|
|
ref_url, oldrev, newrev, branch)
|
|
values
|
|
(1, "bsuuid1", "Z1", "project1",
|
|
1, "1",
|
|
"refs/changes/1",
|
|
"http://project1/1",
|
|
"2d48fe5afe0bc7785294b28e9e96a6c622945b9d",
|
|
"8a938aff20d691d1b9a9f461c6375f0c45acd305",
|
|
"master"),
|
|
(2, "bsuuid2", "Z2", "project1",
|
|
2, "ee743613ce5b3aee11d12e91e932d7876bc0b40c",
|
|
"refs/changes/2",
|
|
"http://project1/2",
|
|
"bd11c4ff79245ae555418e19840ce4752e48ea38",
|
|
"d1ffc204e4b4955f2a47e7e37618fcf13bb1b9fd",
|
|
"stable"),
|
|
(3, "bsuuid3", "Z3", "project2", NULL, NULL, "refs/tags/foo",
|
|
"http://project3",
|
|
"a6cf0e07e9e2964a810196f764fc4ac766742568",
|
|
"1a226acbd022968914574fdeb467b78bc5bfcc77",
|
|
NULL)
|
|
""")
|
|
connection.exec_driver_sql("""
|
|
insert into zuul_build
|
|
(id, buildset_id, uuid, job_name, result)
|
|
values
|
|
(1, 1, "builduuid1", "job1", "RESULT1"),
|
|
(2, 1, "builduuid2", "job2", "RESULT2"),
|
|
(3, 2, "builduuid3", "job1", "RESULT3"),
|
|
(4, 2, "builduuid4", "job2", "RESULT4"),
|
|
(5, 3, "builduuid5", "job3", "RESULT5"),
|
|
(6, 3, "builduuid6", "job4", "RESULT6")
|
|
""")
|
|
|
|
self.connection._migrate()
|
|
with self.connection.engine.begin() as connection:
|
|
results = [r for r in connection.exec_driver_sql(
|
|
"select b.id, r.ref from zuul_build b join zuul_ref r "
|
|
"on b.ref_id=r.id order by b.id")]
|
|
self.assertEqual(results, [
|
|
(1, 'refs/changes/1'),
|
|
(2, 'refs/changes/1'),
|
|
(3, 'refs/changes/2'),
|
|
(4, 'refs/changes/2'),
|
|
(5, 'refs/tags/foo'),
|
|
(6, 'refs/tags/foo'),
|
|
])
|
|
results = [r for r in connection.exec_driver_sql(
|
|
"select bs.uuid, r.ref "
|
|
"from zuul_buildset bs, zuul_buildset_ref t, zuul_ref r "
|
|
"where bs.id = t.buildset_id and r.id = t.ref_id "
|
|
"order by bs.uuid")]
|
|
self.assertEqual(results, [
|
|
('bsuuid1', 'refs/changes/1'),
|
|
('bsuuid2', 'refs/changes/2'),
|
|
('bsuuid3', 'refs/tags/foo'),
|
|
])
|
|
|
|
def test_migration_f7843ddf1552_failure(self):
|
|
with self.connection.engine.begin() as connection:
|
|
connection.exec_driver_sql("set foreign_key_checks=0")
|
|
for table in connection.exec_driver_sql("show tables"):
|
|
table = table[0]
|
|
connection.exec_driver_sql(f"drop table {table}")
|
|
connection.exec_driver_sql("set foreign_key_checks=1")
|
|
|
|
self.connection.force_migrations = True
|
|
self.connection._migrate('151893067f91')
|
|
# This test is identical to the one above, except the patchset
|
|
# sha for the first buildset row is too long to fit in the
|
|
# column (it's lengith is double). The insert here is fine,
|
|
# but that will cause the migration to fail.
|
|
with self.connection.engine.begin() as connection:
|
|
connection.exec_driver_sql("""
|
|
insert into zuul_buildset
|
|
(id, uuid, zuul_ref, project, `change`, patchset, ref,
|
|
ref_url, oldrev, newrev, branch)
|
|
values
|
|
(1, "bsuuid1", "Z1", "project1",
|
|
1, "1",
|
|
"refs/changes/1",
|
|
"http://project1/1",
|
|
"2d48fe5afe0bc7785294b28e9e96a6c622945b9d"
|
|
"2d48fe5afe0bc7785294b28e9e96a6c622945b9d",
|
|
"8a938aff20d691d1b9a9f461c6375f0c45acd305",
|
|
"master"),
|
|
(2, "bsuuid2", "Z2", "project1",
|
|
2, "ee743613ce5b3aee11d12e91e932d7876bc0b40c",
|
|
"refs/changes/2",
|
|
"http://project1/2",
|
|
"bd11c4ff79245ae555418e19840ce4752e48ea38",
|
|
"d1ffc204e4b4955f2a47e7e37618fcf13bb1b9fd",
|
|
"stable"),
|
|
(3, "bsuuid3", "Z3", "project2", NULL, NULL, "refs/tags/foo",
|
|
"http://project3",
|
|
"a6cf0e07e9e2964a810196f764fc4ac766742568",
|
|
"1a226acbd022968914574fdeb467b78bc5bfcc77",
|
|
NULL)
|
|
""")
|
|
connection.exec_driver_sql("""
|
|
insert into zuul_build
|
|
(id, buildset_id, uuid, job_name, result)
|
|
values
|
|
(1, 1, "builduuid1", "job1", "RESULT1"),
|
|
(2, 1, "builduuid2", "job2", "RESULT2"),
|
|
(3, 2, "builduuid3", "job1", "RESULT3"),
|
|
(4, 2, "builduuid4", "job2", "RESULT4"),
|
|
(5, 3, "builduuid5", "job3", "RESULT5"),
|
|
(6, 3, "builduuid6", "job4", "RESULT6")
|
|
""")
|
|
|
|
with testtools.ExpectedException(sqlalchemy.exc.DataError):
|
|
self.connection._migrate()
|
|
|
|
with self.connection.engine.begin() as connection:
|
|
tables = [r[0] for r in connection.exec_driver_sql(
|
|
"show tables")]
|
|
# Make sure we rolled back the buildset_new table creation
|
|
self.assertNotIn('zuul_buildset_new', tables)
|
|
self.assertIn('zuul_buildset', tables)
|
|
|
|
def test_migration_d0a269345a22(self):
|
|
with self.connection.engine.begin() as connection:
|
|
connection.exec_driver_sql("set foreign_key_checks=0")
|
|
for table in connection.exec_driver_sql("show tables"):
|
|
table = table[0]
|
|
connection.exec_driver_sql(f"drop table {table}")
|
|
connection.exec_driver_sql("set foreign_key_checks=1")
|
|
|
|
self.connection.force_migrations = True
|
|
self.connection._migrate('f7843ddf1552')
|
|
with self.connection.engine.begin() as connection:
|
|
connection.exec_driver_sql("""
|
|
insert into zuul_ref
|
|
(id, project, ref, ref_url, `change`,
|
|
patchset, oldrev, newrev, branch)
|
|
values
|
|
(473951, 'openstack/neutron', 'refs/heads/master',
|
|
'https://git.openstack.org/cgit/openstack/neutron/commit/?id=None',
|
|
0, '', '', '', ''),
|
|
(473958, 'openstack/neutron', 'refs/heads/master',
|
|
'https://git.openstack.org/cgit/openstack/neutron/commit/'
|
|
'?id=fd024ac468456561918e02d32f55eabada102fd3',
|
|
0, '',
|
|
'0017b625ddb64cb3f383e1a4b7f20b7a62153705',
|
|
'fd024ac468456561918e02d32f55eabada102fd3',
|
|
''),
|
|
(481941, 'openstack/neutron', 'refs/heads/stable/zed',
|
|
'https://opendev.org/openstack/neutron/commit/'
|
|
'd6ee668cc32725cb7d15d2e08fdb50a761f91fe4',
|
|
0, '',
|
|
'fdba20b27a1b97459db1e83f9b235149fe7fd1f7',
|
|
'd6ee668cc32725cb7d15d2e08fdb50a761f91fe4',
|
|
'stable/zed');
|
|
""")
|
|
self.connection._migrate()
|
|
with self.connection.engine.begin() as connection:
|
|
results = [r for r in connection.exec_driver_sql(
|
|
"select id, ref, branch from zuul_ref order by id")]
|
|
self.assertEqual(results, [
|
|
(473951, 'refs/heads/master', 'master'),
|
|
(473958, 'refs/heads/master', 'master'),
|
|
(481941, 'refs/heads/stable/zed', 'stable/zed'),
|
|
])
|
|
|
|
def test_buildsets(self):
|
|
tenant = 'tenant1',
|
|
buildset_uuid = 'deadbeef'
|
|
change = 1234
|
|
|
|
# Create the buildset entry (driver-internal interface)
|
|
with self.connection.getSession() as db:
|
|
bs = db.createBuildSet(
|
|
uuid=buildset_uuid,
|
|
tenant=tenant,
|
|
pipeline='check',
|
|
event_id='eventid',
|
|
)
|
|
ref = db.getOrCreateRef(
|
|
project='project',
|
|
change=change,
|
|
patchset='1',
|
|
ref='',
|
|
oldrev='',
|
|
newrev='',
|
|
branch='master',
|
|
ref_url='http://example.com/1234',
|
|
)
|
|
bs.refs.append(ref)
|
|
|
|
# Verify that worked using the driver-external interface
|
|
self.assertEqual(len(self.connection.getBuildsets()), 1)
|
|
self.assertEqual(self.connection.getBuildsets()[0].uuid, buildset_uuid)
|
|
|
|
# Update the buildset using the internal interface
|
|
with self.connection.getSession() as db:
|
|
db_buildset = db.getBuildset(tenant=tenant, uuid=buildset_uuid)
|
|
self.assertEqual(db_buildset.refs[0].change, change)
|
|
db_buildset.result = 'SUCCESS'
|
|
|
|
# Verify that worked
|
|
db_buildset = self.connection.getBuildset(
|
|
tenant=tenant, uuid=buildset_uuid)
|
|
self.assertEqual(db_buildset.result, 'SUCCESS')
|
|
|
|
def test_sanitize_subtring_query(self):
|
|
session = self.connection.getSession()
|
|
self.assertEqual(None, session._sanitizeSubstringQuery(None))
|
|
self.assertEqual(
|
|
"job-name", session._sanitizeSubstringQuery("job-name"))
|
|
self.assertEqual(
|
|
"$%job-$%name$%", session._sanitizeSubstringQuery("%job-%name%"))
|
|
self.assertEqual(
|
|
"job$_-$%name$%", session._sanitizeSubstringQuery("job_-%name%"))
|
|
self.assertEqual(
|
|
"job$_-$%name$%", session._sanitizeSubstringQuery("job_-%name%"))
|
|
self.assertEqual(
|
|
"$$$%job$_-$%name$%",
|
|
session._sanitizeSubstringQuery("$%job_-%name%"))
|
|
|
|
def test_fuzzy_filter_op(self):
|
|
col = sqlalchemy.Column("job_name")
|
|
session = self.connection.getSession()
|
|
|
|
filter = session._getFuzzyFilterOp(col, "job-name")
|
|
self.assertEqual(type(col == "foo"), type(filter))
|
|
self.assertEqual("job-name", filter.right.value)
|
|
|
|
filter = session._getFuzzyFilterOp(col, "*job*name*")
|
|
self.assertEqual(type(col.like("foo")), type(filter))
|
|
self.assertEqual("$", filter.modifiers["escape"])
|
|
self.assertEqual("%job%name%", filter.right.value)
|
|
|
|
filter = session._getFuzzyFilterOp(col, None)
|
|
self.assertEqual(type(col.__eq__(None)), type(filter))
|
|
self.assertEqual(sqlalchemy.sql.elements.Null, type(filter.right))
|
|
|
|
|
|
class TestPostgresqlDatabase(DBBaseTestCase):
|
|
def setUp(self):
|
|
super().setUp()
|
|
|
|
f = PostgresqlSchemaFixture()
|
|
self.useFixture(f)
|
|
self.db = f
|
|
|
|
config = dict(dburi=f.dburi)
|
|
driver = SQLDriver()
|
|
self.connection = driver.getConnection('database', config)
|
|
self.connection.onLoad(self.zk_client)
|
|
self.addCleanup(self._cleanup)
|
|
|
|
def _cleanup(self):
|
|
self.connection.onStop()
|
|
|
|
def test_migration(self):
|
|
# Test that SQLAlchemy create_all produces the same output as
|
|
# a full migration run.
|
|
pg_dump = os.environ.get("ZUUL_TEST_PG_DUMP", "pg_dump")
|
|
sqlalchemy_out = subprocess.check_output(
|
|
f"{pg_dump} -h {self.db.host} -U {self.db.name} -s {self.db.name}",
|
|
shell=True,
|
|
env={'PGPASSWORD': self.db.passwd}
|
|
)
|
|
|
|
with self.connection.engine.begin() as connection:
|
|
tables = [x[0] for x in connection.exec_driver_sql(
|
|
"select tablename from pg_catalog.pg_tables "
|
|
"where schemaname='public'"
|
|
).all()]
|
|
|
|
self.assertTrue(len(tables) > 0)
|
|
for table in tables:
|
|
connection.exec_driver_sql(f"drop table {table} cascade")
|
|
|
|
self.connection.force_migrations = True
|
|
self.connection.onLoad(self.zk_client)
|
|
|
|
alembic_out = subprocess.check_output(
|
|
f"{pg_dump} -h {self.db.host} -U {self.db.name} -s {self.db.name}",
|
|
shell=True,
|
|
env={'PGPASSWORD': self.db.passwd}
|
|
)
|
|
try:
|
|
self.assertEqual(alembic_out, sqlalchemy_out)
|
|
except Exception:
|
|
differ = difflib.Differ()
|
|
alembic_out = alembic_out.decode('utf8').splitlines()
|
|
sqlalchemy_out = sqlalchemy_out.decode('utf8').splitlines()
|
|
diff = '\n'.join(list(differ.compare(alembic_out, sqlalchemy_out)))
|
|
self.log.debug("Diff:\n%s", diff)
|
|
raise
|
|
|
|
def test_migration_f7843ddf1552(self):
|
|
with self.connection.engine.begin() as connection:
|
|
tables = [x[0] for x in connection.exec_driver_sql(
|
|
"select tablename from pg_catalog.pg_tables "
|
|
"where schemaname='public'"
|
|
).all()]
|
|
|
|
self.assertTrue(len(tables) > 0)
|
|
for table in tables:
|
|
connection.exec_driver_sql(f"drop table {table} cascade")
|
|
|
|
self.connection.force_migrations = True
|
|
self.connection._migrate('151893067f91')
|
|
with self.connection.engine.begin() as connection:
|
|
connection.exec_driver_sql("""
|
|
insert into zuul_buildset
|
|
(id, uuid, zuul_ref, project, change, patchset, ref,
|
|
ref_url, oldrev, newrev, branch)
|
|
values
|
|
(1, 'bsuuid1', 'Z1', 'project1',
|
|
1, '1',
|
|
'refs/changes/1',
|
|
'http://project1/1',
|
|
'2d48fe5afe0bc7785294b28e9e96a6c622945b9d',
|
|
'8a938aff20d691d1b9a9f461c6375f0c45acd305',
|
|
'master'),
|
|
(2, 'bsuuid2', 'Z2', 'project1',
|
|
2, 'ee743613ce5b3aee11d12e91e932d7876bc0b40c',
|
|
'refs/changes/2',
|
|
'http://project1/2',
|
|
'bd11c4ff79245ae555418e19840ce4752e48ea38',
|
|
'd1ffc204e4b4955f2a47e7e37618fcf13bb1b9fd',
|
|
'stable'),
|
|
(3, 'bsuuid3', 'Z3', 'project2', NULL, NULL, 'refs/tags/foo',
|
|
'http://project3',
|
|
'a6cf0e07e9e2964a810196f764fc4ac766742568',
|
|
'1a226acbd022968914574fdeb467b78bc5bfcc77',
|
|
NULL)
|
|
""")
|
|
connection.exec_driver_sql("""
|
|
insert into zuul_build
|
|
(id, buildset_id, uuid, job_name, result)
|
|
values
|
|
(1, 1, 'builduuid1', 'job1', 'RESULT1'),
|
|
(2, 1, 'builduuid2', 'job2', 'RESULT2'),
|
|
(3, 2, 'builduuid3', 'job1', 'RESULT3'),
|
|
(4, 2, 'builduuid4', 'job2', 'RESULT4'),
|
|
(5, 3, 'builduuid5', 'job3', 'RESULT5'),
|
|
(6, 3, 'builduuid6', 'job4', 'RESULT6')
|
|
""")
|
|
|
|
self.connection._migrate()
|
|
with self.connection.engine.begin() as connection:
|
|
results = [r for r in connection.exec_driver_sql(
|
|
"select b.id, r.ref from zuul_build b join zuul_ref r "
|
|
"on b.ref_id=r.id order by b.id")]
|
|
self.assertEqual(results, [
|
|
(1, 'refs/changes/1'),
|
|
(2, 'refs/changes/1'),
|
|
(3, 'refs/changes/2'),
|
|
(4, 'refs/changes/2'),
|
|
(5, 'refs/tags/foo'),
|
|
(6, 'refs/tags/foo'),
|
|
])
|
|
results = [r for r in connection.exec_driver_sql(
|
|
"select bs.uuid, r.ref "
|
|
"from zuul_buildset bs, zuul_buildset_ref t, zuul_ref r "
|
|
"where bs.id = t.buildset_id and r.id = t.ref_id "
|
|
"order by bs.uuid")]
|
|
self.assertEqual(results, [
|
|
('bsuuid1', 'refs/changes/1'),
|
|
('bsuuid2', 'refs/changes/2'),
|
|
('bsuuid3', 'refs/tags/foo'),
|
|
])
|
|
|
|
def test_migration_f7843ddf1552_failure(self):
|
|
with self.connection.engine.begin() as connection:
|
|
tables = [x[0] for x in connection.exec_driver_sql(
|
|
"select tablename from pg_catalog.pg_tables "
|
|
"where schemaname='public'"
|
|
).all()]
|
|
|
|
self.assertTrue(len(tables) > 0)
|
|
for table in tables:
|
|
connection.exec_driver_sql(f"drop table {table} cascade")
|
|
|
|
self.connection.force_migrations = True
|
|
self.connection._migrate('151893067f91')
|
|
with self.connection.engine.begin() as connection:
|
|
connection.exec_driver_sql("""
|
|
insert into zuul_buildset
|
|
(id, uuid, zuul_ref, project, change, patchset, ref,
|
|
ref_url, oldrev, newrev, branch)
|
|
values
|
|
(1, 'bsuuid1', 'Z1', 'project1',
|
|
1, '1',
|
|
'refs/changes/1',
|
|
'http://project1/1',
|
|
'2d48fe5afe0bc7785294b28e9e96a6c622945b9d'
|
|
'2d48fe5afe0bc7785294b28e9e96a6c622945b9d',
|
|
'8a938aff20d691d1b9a9f461c6375f0c45acd305',
|
|
'master'),
|
|
(2, 'bsuuid2', 'Z2', 'project1',
|
|
2, 'ee743613ce5b3aee11d12e91e932d7876bc0b40c',
|
|
'refs/changes/2',
|
|
'http://project1/2',
|
|
'bd11c4ff79245ae555418e19840ce4752e48ea38',
|
|
'd1ffc204e4b4955f2a47e7e37618fcf13bb1b9fd',
|
|
'stable'),
|
|
(3, 'bsuuid3', 'Z3', 'project2', NULL, NULL, 'refs/tags/foo',
|
|
'http://project3',
|
|
'a6cf0e07e9e2964a810196f764fc4ac766742568',
|
|
'1a226acbd022968914574fdeb467b78bc5bfcc77',
|
|
NULL)
|
|
""")
|
|
connection.exec_driver_sql("""
|
|
insert into zuul_build
|
|
(id, buildset_id, uuid, job_name, result)
|
|
values
|
|
(1, 1, 'builduuid1', 'job1', 'RESULT1'),
|
|
(2, 1, 'builduuid2', 'job2', 'RESULT2'),
|
|
(3, 2, 'builduuid3', 'job1', 'RESULT3'),
|
|
(4, 2, 'builduuid4', 'job2', 'RESULT4'),
|
|
(5, 3, 'builduuid5', 'job3', 'RESULT5'),
|
|
(6, 3, 'builduuid6', 'job4', 'RESULT6')
|
|
""")
|
|
|
|
with testtools.ExpectedException(sqlalchemy.exc.DataError):
|
|
self.connection._migrate()
|
|
|
|
with self.connection.engine.begin() as connection:
|
|
tables = [x[0] for x in connection.exec_driver_sql(
|
|
"select tablename from pg_catalog.pg_tables "
|
|
"where schemaname='public'"
|
|
).all()]
|
|
# Make sure we rolled back the buildset_new table creation
|
|
self.assertNotIn('zuul_buildset_new', tables)
|
|
self.assertIn('zuul_buildset', tables)
|
|
|
|
def test_migration_d0a269345a22(self):
|
|
with self.connection.engine.begin() as connection:
|
|
tables = [x[0] for x in connection.exec_driver_sql(
|
|
"select tablename from pg_catalog.pg_tables "
|
|
"where schemaname='public'"
|
|
).all()]
|
|
|
|
self.assertTrue(len(tables) > 0)
|
|
for table in tables:
|
|
connection.exec_driver_sql(f"drop table {table} cascade")
|
|
|
|
self.connection.force_migrations = True
|
|
self.connection._migrate('f7843ddf1552')
|
|
with self.connection.engine.begin() as connection:
|
|
connection.exec_driver_sql("""
|
|
insert into zuul_ref
|
|
(id, project, ref, ref_url, change,
|
|
patchset, oldrev, newrev, branch)
|
|
values
|
|
(473951, 'openstack/neutron', 'refs/heads/master',
|
|
'https://git.openstack.org/cgit/openstack/neutron/commit/?id=None',
|
|
0, '', '', '', ''),
|
|
(473958, 'openstack/neutron', 'refs/heads/master',
|
|
'https://git.openstack.org/cgit/openstack/neutron/commit/'
|
|
'?id=fd024ac468456561918e02d32f55eabada102fd3',
|
|
0, '',
|
|
'0017b625ddb64cb3f383e1a4b7f20b7a62153705',
|
|
'fd024ac468456561918e02d32f55eabada102fd3',
|
|
''),
|
|
(481941, 'openstack/neutron', 'refs/heads/stable/zed',
|
|
'https://opendev.org/openstack/neutron/commit/'
|
|
'd6ee668cc32725cb7d15d2e08fdb50a761f91fe4',
|
|
0, '',
|
|
'fdba20b27a1b97459db1e83f9b235149fe7fd1f7',
|
|
'd6ee668cc32725cb7d15d2e08fdb50a761f91fe4',
|
|
'stable/zed');
|
|
""")
|
|
self.connection._migrate()
|
|
with self.connection.engine.begin() as connection:
|
|
results = [r for r in connection.exec_driver_sql(
|
|
"select id, ref, branch from zuul_ref order by id")]
|
|
self.assertEqual(results, [
|
|
(473951, 'refs/heads/master', 'master'),
|
|
(473958, 'refs/heads/master', 'master'),
|
|
(481941, 'refs/heads/stable/zed', 'stable/zed'),
|
|
])
|