Skip to content

Commit

Permalink
Add script and tests for moving a batched request to a stable request
Browse files Browse the repository at this point in the history
  • Loading branch information
crungehottman committed Jul 24, 2017
1 parent 80b6fa5 commit 7c48a9f
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 20 deletions.
6 changes: 3 additions & 3 deletions bodhi/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def _warn_if_url_and_staging_set(ctx, param, value):
click.option('--bugs', help='Comma-separated list of bug numbers', default=''),
click.option('--close-bugs', default=True, is_flag=True, help='Automatically close bugs'),
click.option('--request', help='Requested repository',
type=click.Choice(['testing', 'stable', 'unpush'])),
type=click.Choice(['testing', 'stable', 'unpush', 'batched'])),
click.option('--autokarma', is_flag=True, help='Enable karma automatism'),
click.option('--stable-karma', type=click.INT, help='Stable karma threshold'),
click.option('--unstable-karma', type=click.INT, help='Unstable karma threshold'),
Expand Down Expand Up @@ -274,7 +274,7 @@ def edit(user, password, url, **kwargs):
@click.option('--releases', help='Updates for specific releases')
@click.option('--locked', help='Updates that are in a locked state')
@click.option('--request', help='Updates with a specific request',
type=click.Choice(['testing', 'stable', 'unpush']))
type=click.Choice(['testing', 'stable', 'unpush', 'batched']))
@click.option('--submitted-since',
help='Updates that have been submitted since a certain time')
@click.option('--status', help='Filter by update status',
Expand Down Expand Up @@ -324,7 +324,7 @@ def request(update, state, user, password, url, **kwargs):
UPDATE: The title of the update (e.g. FEDORA-2017-f8e0ef2850)
STATE: The state you wish to change the update\'s request to. Valid options are
testing, stable, obsolete, unpush, and revoke.
testing, stable, obsolete, unpush, batched, and revoke.
"""

# Developer Docs
Expand Down
3 changes: 3 additions & 0 deletions bodhi/server/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,9 @@ class BodhiConfig(dict):
'value': ('%s has been pushed to the %s repository. If problems still persist, please '
'make note of it in this bug report.'),
'validator': unicode},
'stable_from_batched_msg': {
'value': ('This update has been dequeued from batched and is now entering stable.'),
'validator': unicode},
'stacks_enabled': {
'value': False,
'validator': _validate_bool},
Expand Down
21 changes: 13 additions & 8 deletions bodhi/server/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1731,8 +1731,8 @@ def set_request(self, db, action, username):

# If status is testing going to stable request and action is revoke,
# keep the status at testing
elif self.status is UpdateStatus.testing and self.request is UpdateRequest.stable \
and action is UpdateRequest.revoke:
elif self.request in (UpdateRequest.stable, UpdateRequest.batched) and \
self.status is UpdateStatus.testing and action is UpdateRequest.revoke:
self.status = UpdateStatus.testing
self.revoke()
flash_log("%s has been revoked." % self.title)
Expand All @@ -1748,7 +1748,7 @@ def set_request(self, db, action, username):
return

# Disable pushing critical path updates for pending releases directly to stable
if action is UpdateRequest.stable and self.critpath:
if action in (UpdateRequest.stable, UpdateRequest.batched) and self.critpath:
if config.get('critpath.num_admin_approvals') is not None:
if not self.critpath_approved:
stern_note = (
Expand All @@ -1774,7 +1774,7 @@ def set_request(self, db, action, username):

# Ensure this update meets the minimum testing requirements
flash_notes = ''
if action is UpdateRequest.stable and not self.critpath:
if action in (UpdateRequest.stable, UpdateRequest.batched) and not self.critpath:
# Check if we've met the karma requirements
if (self.stable_karma not in (None, 0) and self.karma >=
self.stable_karma) or self.critpath_approved:
Expand Down Expand Up @@ -2373,9 +2373,14 @@ def check_karma_thresholds(self, db, agent):
self.comment(db, text, author=u'bodhi')
elif self.stable_karma and self.karma >= self.stable_karma:
if self.autokarma:
log.info("Automatically marking %s as stable" % self.title)
self.set_request(db, UpdateRequest.stable, agent)
self.request = UpdateRequest.stable
if self.severity is UpdateSeverity.urgent or self.type is UpdateType.security:
log.info("Automatically marking %s as stable" % self.title)
self.set_request(db, UpdateRequest.stable, agent)
else:
log.info("Automatically adding %s to batch of updates that will be pushed to"
" stable at a later date" % self.title)
self.set_request(db, UpdateRequest.batched, agent)

self.date_pushed = None
notifications.publish(
topic='update.karma.threshold.reach',
Expand Down Expand Up @@ -2571,7 +2576,7 @@ def requested_tag(self):
# release to the Release.dist-tag
if self.release.state is ReleaseState.pending:
tag = self.release.dist_tag
elif self.request is UpdateRequest.testing:
elif self.request in (UpdateRequest.testing, UpdateRequest.batched):
tag = self.release.testing_tag
elif self.request is UpdateRequest.obsolete:
tag = self.release.candidate_tag
Expand Down
45 changes: 45 additions & 0 deletions bodhi/server/scripts/dequeue_stable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
# Copyright © 2017 Caleigh Runge-Hottman
#
# This file is part of Bodhi.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""This script is responsible for moving all updates with a batched request to a stable request."""

import sys

import click

from bodhi.server import config, models, Session, initialize_db


@click.command()
@click.version_option(message='%(version)s')
def dequeue_stable():
"""Convert all batched requests to stable requests."""
initialize_db(config.config)
db = Session()

try:
batched = db.query(models.Update).filter_by(request=models.UpdateRequest.batched).all()
for update in batched:
update.set_request(db, models.UpdateRequest.stable, u'bodhi')
db.commit()

except Exception as e:
print(str(e))
db.rollback()
Session.remove()
sys.exit(1)
1 change: 1 addition & 0 deletions bodhi/server/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ def request2html(context, request):
'obsolete': 'default',
'testing': 'warning',
'stable': 'success',
'batched': 'success',
}.get(request)

return "<span class='label label-%s'>%s</span>" % (cls, request)
Expand Down
2 changes: 1 addition & 1 deletion bodhi/tests/server/consumers/test_masher.py
Original file line number Diff line number Diff line change
Expand Up @@ -1053,7 +1053,7 @@ def test_stable_requirements_met_during_push(self, *args):

# Ensure the masher set the autokarma once the push is done
self.assertEquals(up.locked, False)
self.assertEquals(up.request, UpdateRequest.stable)
self.assertEquals(up.request, UpdateRequest.batched)

@mock.patch(**mock_taskotron_results)
@mock.patch('bodhi.server.consumers.masher.MasherThread.update_comps')
Expand Down
65 changes: 65 additions & 0 deletions bodhi/tests/server/scripts/test_dequeue_stable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
# Copyright © 2017 Caleigh Runge-Hottman
#
# This file is part of Bodhi.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
This module contains tests for the bodhi.server.scripts.dequeue_stable module.
"""
from datetime import datetime, timedelta

from click import testing

from bodhi.server import models
from bodhi.server.scripts import dequeue_stable
from bodhi.tests.server.base import BaseTestCase


class TestDequeueStable(BaseTestCase):
"""
This class contains tests for the dequeue_stable() function.
"""
def test_dequeue_stable(self):
"""
Assert that dequeue_stable moves only the batched updates to stable.
"""
runner = testing.CliRunner()

update = self.db.query(models.Update).all()[0]
update.request = models.UpdateRequest.batched
update.locked = False
update.date_testing = datetime.utcnow() - timedelta(days=7)
self.db.commit()

result = runner.invoke(dequeue_stable.dequeue_stable, [])
self.assertEqual(result.exit_code, 0)

update = self.db.query(models.Update).all()[0]
self.assertEqual(update.request, models.UpdateRequest.stable)

def test_dequeue_stable_exception(self):
"""
Assert that a locked update triggers an exception, and doesn't move to stable.
"""
runner = testing.CliRunner()
update = self.db.query(models.Update).all()[0]
update.request = models.UpdateRequest.batched
self.db.commit()

result = runner.invoke(dequeue_stable.dequeue_stable, [])

self.assertEqual(result.exit_code, 1)
self.assertEqual(result.output, u"Can't change the request on a locked update\n")
78 changes: 70 additions & 8 deletions bodhi/tests/server/services/test_updates.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from bodhi.server.models import (
BuildrootOverride, Group, RpmPackage, Release,
ReleaseState, RpmBuild, Update, UpdateRequest, UpdateStatus, UpdateType,
User, CiStatus)
UpdateSeverity, User, CiStatus)
from bodhi.tests.server import base


Expand Down Expand Up @@ -660,7 +660,7 @@ def test_provenpackager_request_privs(self, publish, *args):
update.comment(self.db, u"foo", 1, u'biz')
update = self.db.query(Update).filter_by(title=nvr).one()
self.assertEqual(update.karma, 3)
self.assertEqual(update.request, UpdateRequest.stable)
self.assertEqual(update.request, UpdateRequest.batched)

# Set it back to testing
update.request = UpdateRequest.testing
Expand Down Expand Up @@ -2234,7 +2234,7 @@ def test_pending_update_on_stable_karma_reached_autopush_enabled(self, publish,
up = self.db.query(Update).filter_by(title=nvr).one()

self.assertEquals(up.karma, 2)
self.assertEquals(up.request, UpdateRequest.stable)
self.assertEquals(up.request, UpdateRequest.batched)
self.assertEquals(up.status, UpdateStatus.pending)

@mock.patch(**mock_valid_requirements)
Expand Down Expand Up @@ -3455,7 +3455,7 @@ def test_autopush_critical_update_with_no_negative_karma(self, publish, *args):
self.assertEquals(up.autokarma, True)

up = self.db.query(Update).filter_by(title=resp.json['title']).one()
self.assertEquals(up.request, UpdateRequest.stable)
self.assertEquals(up.request, UpdateRequest.batched)

@mock.patch(**mock_valid_requirements)
@mock.patch('bodhi.server.notifications.publish')
Expand Down Expand Up @@ -3614,7 +3614,7 @@ def test_autopush_non_critical_update_with_no_negative_karma(self, publish, *arg
"""
Make sure autopush doesn't get disabled for Non Critical update if it
does not receive any negative karma. Test update gets automatically
marked as stable.
marked as batched.
"""
user = User(name=u'bob')
self.db.add(user)
Expand Down Expand Up @@ -3644,7 +3644,7 @@ def test_autopush_non_critical_update_with_no_negative_karma(self, publish, *arg
self.assertEquals(up.autokarma, True)

up = self.db.query(Update).filter_by(title=resp.json['title']).one()
self.assertEquals(up.request, UpdateRequest.stable)
self.assertEquals(up.request, UpdateRequest.batched)

@mock.patch(**mock_valid_requirements)
@mock.patch('bodhi.server.notifications.publish')
Expand Down Expand Up @@ -3820,7 +3820,6 @@ def test_edit_testing_update_with_build_from_different_update(self, publish, *ar
self.assertEquals(len(up.builds), 1)
self.assertEquals(up.builds[0].nvr, nvr1)

@mock.patch(**mock_taskotron_results)
@mock.patch(**mock_valid_requirements)
@mock.patch('bodhi.server.notifications.publish')
def test_batched_update(self, publish, *args):
Expand All @@ -3830,11 +3829,74 @@ def test_batched_update(self, publish, *args):
args = self.get_update('bodhi-2.0.0-3.fc17')
resp = self.app.post_json('/updates/', args)
up = self.db.query(Update).filter_by(title=resp.json['title']).one()
up.builds[0].ci_status = CiStatus.passed
up.comment(self.db, u"foo1", 1, u'foo1')
up.comment(self.db, u"foo2", 1, u'foo2')
self.db.commit()

resp = self.app.post_json(
'/updates/%s/request' % args['builds'],
{'request': 'batched', 'csrf_token': self.get_csrf_token()})

self.assertEqual(resp.json['update']['request'], 'batched')
publish.assert_called_with(
topic='update.request.batched', msg=mock.ANY)

@mock.patch(**mock_valid_requirements)
@mock.patch('bodhi.server.notifications.publish')
def test_security_update_bypass_batched(self, publish, *args):
"""
Make sure a security update skips the 'batched' request and immediately enters stable
upon getting the sufficient number of karma.
"""
nvr = u'bodhi-2.0.0-2.fc17'
args = self.get_update(nvr)
args['autokarma'] = True
args['stable_karma'] = 2

resp = self.app.post_json('/updates/', args)
self.assertEquals(resp.json['request'], 'testing')
publish.assert_called_with(topic='update.request.testing', msg=ANY)

up = self.db.query(Update).filter_by(title=resp.json['title']).one()
up.status = UpdateStatus.testing
up.type = UpdateType.security
self.db.commit()

up.comment(self.db, u'cool beans', author=u'mrgroovy', karma=1)
up = self.db.query(Update).filter_by(title=resp.json['title']).one()

up.comment(self.db, u'lgtm', author=u'caleigh', karma=1)
up = self.db.query(Update).filter_by(title=resp.json['title']).one()

up = self.db.query(Update).filter_by(title=resp.json['title']).one()
self.assertEquals(up.request, UpdateRequest.stable)

@mock.patch(**mock_valid_requirements)
@mock.patch('bodhi.server.notifications.publish')
def test_urgent_update_bypass_batched(self, publish, *args):
"""
Make sure an urgent update skips the 'batched' request and immediately enters stable
upon getting the sufficient number of karma.
"""
nvr = u'bodhi-2.0.0-2.fc17'
args = self.get_update(nvr)
args['autokarma'] = True
args['stable_karma'] = 2

resp = self.app.post_json('/updates/', args)
self.assertEquals(resp.json['request'], 'testing')
publish.assert_called_with(topic='update.request.testing', msg=ANY)

up = self.db.query(Update).filter_by(title=resp.json['title']).one()
up.status = UpdateStatus.testing
up.severity = UpdateSeverity.urgent
self.db.commit()

up.comment(self.db, u'cool beans', author=u'mrgroovy', karma=1)
up = self.db.query(Update).filter_by(title=resp.json['title']).one()

up.comment(self.db, u'lgtm', author=u'caleigh', karma=1)
up = self.db.query(Update).filter_by(title=resp.json['title']).one()

up = self.db.query(Update).filter_by(title=resp.json['title']).one()
self.assertEquals(up.request, UpdateRequest.stable)

0 comments on commit 7c48a9f

Please sign in to comment.