Add ModuleBuild methods for getting list of streams, last build in a name:stream and all builds in name:stream:version.

This commit is contained in:
Jan Kaluza
2018-02-28 14:44:14 +01:00
committed by mprahl
parent f0852d9009
commit 1bbe8d69f1
4 changed files with 147 additions and 69 deletions

View File

@@ -38,10 +38,12 @@ from module_build_service import db, log, get_url_for, app, conf
import module_build_service.messaging
from sqlalchemy.orm import lazyload
from sqlalchemy import func, and_
import gi
gi.require_version('Modulemd', '1.0') # noqa
from gi.repository import Modulemd
# Just like koji.BUILD_STATES, except our own codes for modules.
BUILD_STATES = {
# This is (obviously) the first state a module build enters.
@@ -241,6 +243,42 @@ class ModuleBuild(MBSBase):
if component.batch <= self.batch
]
@staticmethod
def get_last_build_in_all_streams(session, name):
"""
Returns list of all last ModuleBuilds in "ready" state for all
streams for given module `name`.
"""
subq = session.query(
func.max(ModuleBuild.id).label('id')
).group_by(ModuleBuild.name, ModuleBuild.stream).filter_by(
name=name, state=BUILD_STATES["ready"]).subquery('t2')
query = session.query(ModuleBuild).join(
subq, and_(ModuleBuild.id == subq.c.id))
return query.all()
@staticmethod
def get_last_build_in_stream(session, name, stream):
"""
Returns the last build in "ready" state for given name:stream.
"""
query = session.query(ModuleBuild)
query = query.filter_by(name=name, stream=stream,
state=BUILD_STATES["ready"])
query = query.order_by(ModuleBuild.id.desc())
return query.first()
@staticmethod
def get_builds_in_version(session, name, stream, version):
"""
Returns list of all module builds in "ready" state for given
name:stream:version - it means all the contexts of this module.
"""
query = session.query(ModuleBuild)
query = query.filter_by(name=name, stream=stream, version=version,
state=BUILD_STATES["ready"])
return query.all()
def mmd(self):
try:
mmd = Modulemd.Module().new_from_string(self.modulemd)

View File

@@ -24,6 +24,7 @@ import os
from datetime import datetime, timedelta
from mock import patch
import time
import hashlib
from traceback import extract_stack
import gi
@@ -92,75 +93,86 @@ def clean_database():
db.create_all()
def init_data(data_size=10):
def init_data(data_size=10, contexts=False):
"""
Creates data_size * 3 modules in database in different states and
with different component builds. See _populate_data for more info.
:param bool contexts: If True, multiple streams and contexts in each stream
are generated for 'nginx' module.
"""
clean_database()
with make_session(conf) as session:
_populate_data(session, data_size)
_populate_data(session, data_size, contexts=contexts)
def _populate_data(session, data_size=10):
def _populate_data(session, data_size=10, contexts=False):
num_contexts = 2 if contexts else 1
for index in range(data_size):
build_one = ModuleBuild()
build_one.name = 'nginx'
build_one.stream = '1'
build_one.version = 2
build_one.state = BUILD_STATES['done']
with open(os.path.join(base_dir, "staged_data", "nginx_mmd.yaml")) as mmd:
build_one.modulemd = mmd.read()
build_one.koji_tag = 'module-nginx-1.2'
build_one.scmurl = ('git://pkgs.domain.local/modules/nginx?'
'#ba95886c7a443b36a9ce31abda1f9bef22f2f8c9')
build_one.batch = 2
# https://www.youtube.com/watch?v=iQGwrK_yDEg
build_one.owner = 'Moe Szyslak'
build_one.time_submitted = \
datetime(2016, 9, 3, 11, 23, 20) + timedelta(minutes=(index * 10))
build_one.time_modified = \
datetime(2016, 9, 3, 11, 25, 32) + timedelta(minutes=(index * 10))
build_one.time_completed = \
datetime(2016, 9, 3, 11, 25, 32) + timedelta(minutes=(index * 10))
build_one.rebuild_strategy = 'changed-and-after'
session.add(build_one)
session.commit()
build_one_component_release = get_rpm_release(build_one)
for context in range(num_contexts):
build_one = ModuleBuild()
build_one.name = 'nginx'
build_one.stream = '1'
build_one.version = 2 + index
build_one.state = BUILD_STATES['ready']
if contexts:
build_one.stream = str(index)
unique_hash = hashlib.sha1("%s:%s:%d:%d" % (
build_one.name, build_one.stream, build_one.version, context)).hexdigest()
build_one.build_context = unique_hash
build_one.runtime_context = unique_hash
with open(os.path.join(base_dir, "staged_data", "nginx_mmd.yaml")) as mmd:
build_one.modulemd = mmd.read()
build_one.koji_tag = 'module-nginx-1.2'
build_one.scmurl = ('git://pkgs.domain.local/modules/nginx?'
'#ba95886c7a443b36a9ce31abda1f9bef22f2f8c9')
build_one.batch = 2
# https://www.youtube.com/watch?v=iQGwrK_yDEg
build_one.owner = 'Moe Szyslak'
build_one.time_submitted = \
datetime(2016, 9, 3, 11, 23, 20) + timedelta(minutes=(index * 10))
build_one.time_modified = \
datetime(2016, 9, 3, 11, 25, 32) + timedelta(minutes=(index * 10))
build_one.time_completed = \
datetime(2016, 9, 3, 11, 25, 32) + timedelta(minutes=(index * 10))
build_one.rebuild_strategy = 'changed-and-after'
session.add(build_one)
session.commit()
build_one_component_release = get_rpm_release(build_one)
component_one_build_one = ComponentBuild()
component_one_build_one.package = 'nginx'
component_one_build_one.scmurl = \
('git://pkgs.domain.local/rpms/nginx?'
'#ga95886c8a443b36a9ce31abda1f9bed22f2f8c3')
component_one_build_one.format = 'rpms'
component_one_build_one.task_id = 12312345 + index
component_one_build_one.state = koji.BUILD_STATES['COMPLETE']
component_one_build_one.nvr = 'nginx-1.10.1-2.{0}'.format(build_one_component_release)
component_one_build_one.batch = 1
component_one_build_one.module_id = 1 + index * 3
component_one_build_one.tagged = True
component_one_build_one.tagged_in_final = True
component_one_build_one = ComponentBuild()
component_one_build_one.package = 'nginx'
component_one_build_one.scmurl = \
('git://pkgs.domain.local/rpms/nginx?'
'#ga95886c8a443b36a9ce31abda1f9bed22f2f8c3')
component_one_build_one.format = 'rpms'
component_one_build_one.task_id = 12312345 + index
component_one_build_one.state = koji.BUILD_STATES['COMPLETE']
component_one_build_one.nvr = 'nginx-1.10.1-2.{0}'.format(build_one_component_release)
component_one_build_one.batch = 1
component_one_build_one.module_id = 1 + index * 3
component_one_build_one.tagged = True
component_one_build_one.tagged_in_final = True
component_two_build_one = ComponentBuild()
component_two_build_one.package = 'module-build-macros'
component_two_build_one.scmurl = \
('/tmp/module_build_service-build-macrosWZUPeK/SRPMS/'
'module-build-macros-0.1-1.module_nginx_1_2.src.rpm')
component_two_build_one.format = 'rpms'
component_two_build_one.task_id = 12312321 + index
component_two_build_one.state = koji.BUILD_STATES['COMPLETE']
component_two_build_one.nvr = \
'module-build-macros-01-1.{0}'.format(build_one_component_release)
component_two_build_one.batch = 2
component_two_build_one.module_id = 1 + index * 3
component_two_build_one.tagged = True
component_two_build_one.tagged_in_final = True
component_two_build_one = ComponentBuild()
component_two_build_one.package = 'module-build-macros'
component_two_build_one.scmurl = \
('/tmp/module_build_service-build-macrosWZUPeK/SRPMS/'
'module-build-macros-0.1-1.module_nginx_1_2.src.rpm')
component_two_build_one.format = 'rpms'
component_two_build_one.task_id = 12312321 + index
component_two_build_one.state = koji.BUILD_STATES['COMPLETE']
component_two_build_one.nvr = \
'module-build-macros-01-1.{0}'.format(build_one_component_release)
component_two_build_one.batch = 2
component_two_build_one.module_id = 1 + index * 3
component_two_build_one.tagged = True
component_two_build_one.tagged_in_final = True
build_two = ModuleBuild()
build_two.name = 'postgressql'
build_two.stream = '1'
build_two.version = 2
build_two.version = 2 + index
build_two.state = BUILD_STATES['done']
build_two.modulemd = '' # Skipping since no tests rely on it
build_two.koji_tag = 'module-postgressql-1.2'
@@ -211,7 +223,7 @@ def _populate_data(session, data_size=10):
build_three = ModuleBuild()
build_three.name = 'testmodule'
build_three.stream = '4.3.43'
build_three.version = 6
build_three.version = 6 + index
build_three.state = BUILD_STATES['wait']
build_three.modulemd = '' # Skipping because no tests rely on it
build_three.koji_tag = None

View File

@@ -27,6 +27,7 @@ gi.require_version('Modulemd', '1.0') # noqa
from gi.repository import Modulemd
from tests.test_models import init_data
from tests import init_data as init_data_contexts
from module_build_service import conf
from module_build_service.models import ComponentBuild, ModuleBuild, make_session
@@ -74,3 +75,30 @@ class TestModels:
assert build.build_context == 'f6e2aeec7576196241b9afa0b6b22acf2b6873d7'
assert build.runtime_context == '1739827b08388842fc90ccc0b6070c59b7d856fc'
assert build.context == 'e7a3d35e'
class TestModelsGetStreamsContexts:
def setup_method(self, test_method):
init_data_contexts(contexts=True)
def test_get_last_build_in_all_streams(self):
with make_session(conf) as session:
builds = ModuleBuild.get_last_build_in_all_streams(
session, "nginx")
builds = ["%s:%s:%s" % (build.name, build.stream, str(build.version))
for build in builds]
assert builds == ["nginx:%d:%d" % (i, i + 2) for i in range(10)]
def test_get_last_build_in_stream(self):
with make_session(conf) as session:
build = ModuleBuild.get_last_build_in_stream(
session, "nginx", "1")
build = "%s:%s:%s" % (build.name, build.stream, str(build.version))
assert build == 'nginx:1:3'
def test_get_builds_in_version(self):
with make_session(conf) as session:
builds = ModuleBuild.get_builds_in_version(
session, "nginx", "1", "3")
builds = ["%s:%s:%s:%s" % (build.name, build.stream, str(build.version),
build.context) for build in builds]
assert builds == ['nginx:1:3:d5a6c0fa', 'nginx:1:3:795e97c1']

View File

@@ -124,7 +124,7 @@ class TestViews:
assert data['name'] == 'nginx'
assert data['owner'] == 'Moe Szyslak'
assert data['stream'] == '1'
assert data['state'] == 3
assert data['state'] == 5
assert data['state_reason'] is None
assert data['tasks'] == {
'rpms': {
@@ -154,8 +154,8 @@ class TestViews:
assert data['id'] == 1
assert data['context'] == '00000000'
assert data['name'] == 'nginx'
assert data['state'] == 3
assert data['state_name'] == 'done'
assert data['state'] == 5
assert data['state_name'] == 'ready'
assert data['stream'] == '1'
assert data['version'] == '2'
@@ -174,8 +174,8 @@ class TestViews:
assert data['owner'] == 'Moe Szyslak'
assert data['scmurl'] == ('git://pkgs.domain.local/modules/nginx'
'?#ba95886c7a443b36a9ce31abda1f9bef22f2f8c9')
assert data['state'] == 3
assert data['state_name'] == 'done'
assert data['state'] == 5
assert data['state_name'] == 'ready'
assert data['state_reason'] is None
# State trace is empty because we directly created these builds and didn't have them
# transition, which creates these entries
@@ -240,18 +240,18 @@ class TestViews:
"state": 1,
"state_reason": None,
"task_id": 47383994,
"nvr": "module-build-macros-01-1.module+6+8d3cee59"
"nvr": "module-build-macros-01-1.module+6+f95651e2"
},
"rubygem-rails": {
"state": 3,
"state_reason": None,
"task_id": 2433434,
"nvr": "postgresql-9.5.3-4.module+6+8d3cee59"
"nvr": "postgresql-9.5.3-4.module+6+f95651e2"
}
}
},
"owner": "some_other_user",
"version": "6",
"version": "7",
"state_reason": None,
"state": 1,
"stream": "4.3.43",
@@ -274,18 +274,18 @@ class TestViews:
"state": 1,
"state_reason": None,
"task_id": 47383994,
"nvr": "module-build-macros-01-1.module+5+0557c87d"
"nvr": "module-build-macros-01-1.module+5+fa947d31"
},
"postgresql": {
"state": 1,
"state_reason": None,
"task_id": 2433434,
"nvr": "postgresql-9.5.3-4.module+5+0557c87d"
"nvr": "postgresql-9.5.3-4.module+5+fa947d31"
}
}
},
"owner": "some_user",
"version": "2",
"version": "3",
"state_reason": None,
"state": 3,
"stream": "1",
@@ -300,6 +300,7 @@ class TestViews:
"koji_tag": "module-postgressql-1.2"
}
]
assert items == expected
def test_query_builds_with_id_error(self):
@@ -439,7 +440,7 @@ class TestViews:
rv = self.client.get(
'/module-build-service/1/module-builds/?state=3')
data = json.loads(rv.data)
assert data['meta']['total'] == 4
assert data['meta']['total'] == 2
def test_query_builds_two_filters(self):
rv = self.client.get('/module-build-service/1/module-builds/?owner=Moe%20Szyslak'
@@ -451,12 +452,11 @@ class TestViews:
rv = self.client.get(
'/module-build-service/1/module-builds/?name=postgressql&stream=1&version=2')
data = json.loads(rv.data)
# TODO: The nsv should really be unique in the test data
for item in data['items']:
assert item['name'] == 'postgressql'
assert item['stream'] == '1'
assert item['version'] == '2'
assert data['meta']['total'] == 2
assert data['meta']['total'] == 1
def test_query_builds_filter_invalid_date(self):
rv = self.client.get(