Support the stream_version_lte filter in the API

This commit is contained in:
mprahl
2019-04-22 13:49:47 -04:00
parent 1146bb3043
commit d0aea40788
4 changed files with 67 additions and 10 deletions

View File

@@ -532,6 +532,8 @@ parameters include:
parameter can be given multiple times, in which case or-ing will be used.
- ``state_reason``
- ``stream``
- ``stream_version_lte`` - less than or equal to the stream version. This is limited to
the major version. This value only applies to base modules.
- ``submitted_after`` - Zulu ISO 8601 format e.g. ``submitted_after=2016-08-22T09:40:07Z``
- ``submitted_before`` - Zulu ISO 8601 format e.g. ``submitted_before=2016-08-23T09:40:07Z``
- ``version``

View File

@@ -365,6 +365,25 @@ class ModuleBuild(MBSBase):
name=name, stream=stream, version=str(version), scratch=True, **kwargs)\
.filter(ModuleBuild.context.like(context + '%')).all()
@staticmethod
def _add_stream_version_lte_filter(session, query, stream_version):
"""
Adds a less than or equal to filter for stream versions based on x.y.z versioning.
In essence, the filter does `XX0000 <= stream_version <= XXYYZZ`
:param session: a SQLAlchemy session
:param query: a SQLAlchemy query to add the filtering to
:param int stream_version: the stream version to filter on
:return: the query with the added stream version filter
"""
# Compute the minimal stream_version. For example, for `stream_version` 281234,
# the minimal `stream_version` is 280000.
min_stream_version = (stream_version // 10000) * 10000
return query\
.filter(ModuleBuild.stream_version <= stream_version)\
.filter(ModuleBuild.stream_version >= min_stream_version)
@staticmethod
def get_last_builds_in_stream_version_lte(session, name, stream_version):
"""
@@ -378,16 +397,13 @@ class ModuleBuild(MBSBase):
:param str name: Name of the module to search builds for.
:param int stream_version: Maximum stream_version to search builds for.
"""
# Compute the minimal stream_version - for example for `stream_version` 281234,
# the minimal `stream_version` is 280000.
min_stream_version = (stream_version // 10000) * 10000
query = session.query(ModuleBuild)\
.filter(ModuleBuild.name == name)\
.filter(ModuleBuild.state == BUILD_STATES["ready"])\
.filter(ModuleBuild.stream_version <= stream_version)\
.filter(ModuleBuild.stream_version >= min_stream_version)\
.order_by(ModuleBuild.version.desc())
query = ModuleBuild._add_stream_version_lte_filter(session, query, stream_version)
builds = query.all()
# In case there are multiple versions of single name:stream build, we want to return

View File

@@ -32,7 +32,7 @@ from sqlalchemy.sql.sqltypes import Boolean as sqlalchemy_boolean
from sqlalchemy.orm import aliased
import sqlalchemy
from module_build_service import models, api_version, conf
from module_build_service import models, api_version, conf, db
from module_build_service.errors import ValidationError, NotFound
from .general import scm_url_schemes
@@ -206,11 +206,13 @@ def filter_module_builds(flask_request):
:return: flask_sqlalchemy.Pagination
"""
search_query = dict()
special_columns = ['time_submitted', 'time_modified', 'time_completed', 'state']
for key in request.args.keys():
special_columns = set((
'time_submitted', 'time_modified', 'time_completed', 'state', 'stream_version_lte',))
columns = models.ModuleBuild.__table__.columns.keys()
for key in set(request.args.keys()) - special_columns:
# Only filter on valid database columns but skip columns that are treated specially or
# ignored
if key not in special_columns and key in models.ModuleBuild.__table__.columns.keys():
if key in columns:
search_query[key] = flask_request.args[key]
# Multiple states can be supplied => or-ing will take place
@@ -281,6 +283,21 @@ def filter_module_builds(flask_request):
elif context == 'before':
query = query.filter(column <= item_datetime)
stream_version_lte = flask_request.args.get('stream_version_lte')
if stream_version_lte is not None:
invalid_error = ('An invalid value of stream_version_lte was provided. It must be an '
'integer greater than or equal to 10000.')
try:
stream_version_lte = int(stream_version_lte)
except (TypeError, ValueError):
raise ValidationError(invalid_error)
if stream_version_lte < 10000:
raise ValidationError(invalid_error)
query = models.ModuleBuild._add_stream_version_lte_filter(
db.session, query, stream_version_lte)
br_joined = False
module_br_alias = None
for item in ('base_module_br', 'name', 'stream', 'version', 'context', 'stream_version',

View File

@@ -652,6 +652,28 @@ class TestViews:
'provided for the \"modified_after\" parameter')
assert data['status'] == 400
@pytest.mark.parametrize('stream_version_lte', ('280000', '290000', '293000', 'invalid',))
def test_query_builds_filter_stream_version_lte(self, stream_version_lte):
init_data(data_size=1, multiple_stream_versions=True)
url = ('/module-build-service/1/module-builds/?name=platform&verbose=true'
'&stream_version_lte={}'.format(stream_version_lte))
rv = self.client.get(url)
data = json.loads(rv.data)
total = data.get('meta', {}).get('total')
if stream_version_lte == 'invalid':
assert data == {
'error': 'Bad Request',
'message': ('An invalid value of stream_version_lte was provided. It must be an '
'integer greater than or equal to 10000.'),
'status': 400
}
elif stream_version_lte == '280000':
assert total == 2
elif stream_version_lte == '290000':
assert total == 1
elif stream_version_lte == '293000':
assert total == 3
def test_query_builds_order_by(self):
build = db.session.query(module_build_service.models.ModuleBuild).filter_by(id=2).one()
build.name = 'candy'