From 7224534c8988f46c197c020a607348741c7438b2 Mon Sep 17 00:00:00 2001 From: Adam Williamson Date: Mar 17 2016 04:27:50 +0000 Subject: add a test suite for the consumer This is a pretty comprehensive test suite which fakes an entire release cycle and ensures the consumer does the right thing in a bunch of different situations. --- diff --git a/test_relvalconsumer.py b/test_relvalconsumer.py new file mode 100644 index 0000000..12db4bc --- /dev/null +++ b/test_relvalconsumer.py @@ -0,0 +1,354 @@ +# Copyright (C) 2016 Red Hat +# +# This file is part of relvalconsumer. +# +# relvalconsumer 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 3 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, see . +# +# Author: Adam Williamson + +import time + +import mock +import pytest +import relvalconsumer +import wikitcms.event + +# The test approach here is that we just recreate an entire release +# cycle with mocks, and ensure the consumer does the right thing for +# each compose that shows up. + +def _fakepginit(self, site, name, info=None, extra_properties=None): + """Stub init for mwclient Page, just make sure name and site are + set. + """ + self.site = site + self.name = name + +def _fakemsg(cid, status='FINISHED_INCOMPLETE'): + return { + 'body': { + 'msg': { + 'compose_id': cid, + 'status': status + } + } + } + +def _fakegetsame(self, packages): + """This is a fake 'get_current_packages' which always returns the + same dict, so when *this* is used as the mock, the consumer will + consider both composes to have the same packages. + """ + return {'key': 'value'} + +def _fakegetdifferent(self, packages): + """This is a fake 'get_current_packages' which returns a dict with + time.clock() as the value. This should mean that when *this* is + used as the mock, the consumer will consider both composes to have + different packages, and the 'new' compose (whose package list is + checked second) will have 'newer' packages. + """ + return {'key': str(time.clock())} + +def _fakegetcurr1(branched=False): + """A faked get_current_release which just returns static values. + This one is for pre-branch-point, when 24 is always the result. + """ + return 24 + +def _fakegetcurr2(branched=False): + """A faked get_current_release which just returns static values. + This one is for post-branch-point, when 25 is the current Branched + but 24 is the current stable. + """ + if branched: + return 25 + else: + return 24 + +# a bunch of patches we need throughout the tests +# we have to stub this as we are skipping FedmsgConsumer __init__ +mock.patch('relvalconsumer.RelvalConsumer._log').start() +# page init requires wiki trip +mock.patch('mwclient.page.Page.__init__', _fakepginit).start() +# testtypes are read from wiki +mock.patch('wikitcms.wiki.Wiki.testtypes', ['Installation', 'Desktop', 'Server', 'Cloud', 'Base']).start() +# login hits the wiki, obviously +mock.patch('wikitcms.wiki.Wiki.login').start() +# so does site init +mock.patch('mwclient.client.Site.site_init').start() + +# this we need to switch at Branch point, so name it. It hits the +# 'collections' API. +fakecurrpatcher = mock.patch('fedfind.helpers.get_current_release', _fakegetcurr1) +fakecurrpatcher.start() + +# proper consumer init requires a fedmsg hub instance, we don't have +# one and don't want to faff around faking one. +CONSUMER = None +with mock.patch('fedmsg.consumers.FedmsgConsumer.__init__', return_value=None): + CONSUMER = relvalconsumer.RelvalProductionConsumer(None) + +# These are all fake IDs for various composes, in the order we'll test them. +RAWHIDE1 = 'Fedora-Rawhide-20160601.n.0' +RAWHIDE2 = 'Fedora-Rawhide-20160601.n.1' +RAWHIDE3 = 'Fedora-Rawhide-20160605.n.0' +RAWHIDE4 = 'Fedora-Rawhide-20160620.n.0' +BRANCHED1 = 'Fedora-25-20160621.n.0' +BRANCHED2 = 'Fedora-25-20160629.n.0' +ALPHA1 = 'Fedora-25-20160629.0' +ALPHA2 = 'Fedora-25-20160629.1' +BRANCHED3 = 'Fedora-25-20160630.n.0' +BRANCHED4 = 'Fedora-25-20160705.n.0' +ALPHA3 = 'Fedora-25-20160706.0' +BRANCHED5 = 'Fedora-25-20160710.n.0' +RAWHIDE5 = 'Fedora-Rawhide-20160714.n.0' +BETA1 = 'Fedora-25-20160714.0' +FINAL1 = 'Fedora-25-20160721.1' + +# obviously we don't really want to create the event. we mock this +# separately for each test, instead of just once, to make the call +# asserts simple. +@mock.patch('wikitcms.event.ValidationEvent.create') +# ditto sending emails. +@mock.patch('smtplib.SMTP') +# this obviously hits mirrors; we have a couple of functions for faking +# 'same' and 'different' package sets, for different tests +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetsame) +# this needs mocking when the current event is a ComposeEvent; it's +# used to figure out how many days it's been since 'current' event. +# For nightly events this doesn't need a remote trip, but for +# candidate events it does +@mock.patch('wikitcms.event.ComposeEvent.creation_date', '20160530') +# this always needs mocking, as whatever the 'current' event ought +# to be in our fake release series. +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.ComposeEvent(None, '24', 'Final', '1.4')) +def test_rawhide1(fakesmtp, fakecreate): + """Creating first Rawhide nightly for next release.""" + CONSUMER.consume(_fakemsg(RAWHIDE1)) + fakecreate.assert_called_with(cid=RAWHIDE1, check=True) + +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetdifferent) +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.NightlyEvent(None, '25', 'Rawhide', '20160601.n.0')) +def test_rawhide2(fakesmtp, fakecreate): + """Another Rawhide nightly one day later should not produce an + event, even if there are package differences. + """ + CONSUMER.consume(_fakemsg(RAWHIDE2)) + assert fakecreate.call_count == 0 + assert fakesmtp.call_count == 0 + +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetsame) +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.NightlyEvent(None, '25', 'Rawhide', '20160601.n.0')) +def test_rawhide3_same(fakesmtp, fakecreate): + """Another Rawhide nightly four days later should not produce an + event if the packages are the same... + """ + CONSUMER.consume(_fakemsg(RAWHIDE3)) + assert fakecreate.call_count == 0 + assert fakesmtp.call_count == 0 + +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetdifferent) +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.NightlyEvent(None, '25', 'Rawhide', '20160601.n.0')) +def test_rawhide3_different(fakesmtp, fakecreate): + """...but the same four days later nightly should produce an + event if the packages are different. + """ + CONSUMER.consume(_fakemsg(RAWHIDE3)) + fakecreate.assert_called_with(cid=RAWHIDE3, check=True) + +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetsame) +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.NightlyEvent(None, '25', 'Rawhide', '20160605.n.0')) +def test_rawhide4(fakesmtp, fakecreate): + """Another Rawhide nightly 15 days later should produce an event + even if the packages are the same. + """ + CONSUMER.consume(_fakemsg(RAWHIDE4)) + fakecreate.assert_called_with(cid=RAWHIDE4, check=True) + +# BRANCH POINT + +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetsame) +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.NightlyEvent(None, '25', 'Rawhide', '20160620.n.0')) +def test_branched1(fakesmtp, fakecreate): + """First Branched nightly shouldn't produce an event as it's only + one day after the Rawhide nightly. + """ + # switch the get_current_release mock to Branched mode + fakecurrpatcher.stop() + mock.patch('fedfind.helpers.get_current_release', _fakegetcurr2).start() + CONSUMER.consume(_fakemsg(BRANCHED1)) + assert fakecreate.call_count == 0 + assert fakesmtp.call_count == 0 + +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetdifferent) +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.NightlyEvent(None, '25', 'Rawhide', '20160620.n.0')) +def test_branched2(fakesmtp, fakecreate): + """Second branched compose some days later should create an event. + """ + CONSUMER.consume(_fakemsg(BRANCHED2)) + fakecreate.assert_called_with(cid=BRANCHED2, check=True) + +# this has to be mocked when the 'new' event is a production one; +# to find the correct event from the compose ID, wikitcms gets a +# Production instance from fedfind and checks its label property, +# then parses that +@mock.patch('fedfind.release.Production.label', 'Alpha-1.1') +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetsame) +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.NightlyEvent(None, '25', 'Branched', '20160629.n.0')) +def test_alpha1(fakesmtp, fakecreate): + """First Alpha candidate should produce an event even though it's + for the same date and package set as BRANCHED2. + """ + CONSUMER.consume(_fakemsg(ALPHA1)) + fakecreate.assert_called_with(cid=ALPHA1, check=True) + +# this has to be mocked whenever the current event is a production; +# wikitcms asks fedfind for the compose for the current event, fedfind +# has to do a label->cid conversion to find the compose. +@mock.patch('fedfind.helpers.cid_from_label', return_value=ALPHA2) +@mock.patch('fedfind.release.Production.label', 'Alpha-1.2') +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetsame) +@mock.patch('wikitcms.event.ComposeEvent.creation_date', '20160629') +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.ComposeEvent(None, '25', 'Alpha', '1.1')) +def test_alpha2(fakesmtp, fakecreate, fakecidfrmlab): + """Second Alpha candidate should produce an event even though it's + for the same date and package set as ALPHA1 (somewhat unrealistic, + but it's what ought to happen). + """ + CONSUMER.consume(_fakemsg(ALPHA2)) + fakecreate.assert_called_with(cid=ALPHA2, check=True) + +@mock.patch('fedfind.helpers.cid_from_label', return_value=ALPHA2) +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetdifferent) +@mock.patch('wikitcms.event.ComposeEvent.creation_date', '20160629') +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.ComposeEvent(None, '25', 'Alpha', '1.2')) +def test_branched3(fakesmtp, fakecreate, fakecidfrmlab): + """Branched nightly shortly after candidate compose should not + create event even if package set is different. + """ + CONSUMER.consume(_fakemsg(BRANCHED3)) + assert fakecreate.call_count == 0 + assert fakesmtp.call_count == 0 + +@mock.patch('fedfind.helpers.cid_from_label', return_value=ALPHA2) +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetsame) +@mock.patch('wikitcms.event.ComposeEvent.creation_date', '20160629') +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.ComposeEvent(None, '25', 'Alpha', '1.2')) +def test_branched4_same(fakesmtp, fakecreate, fakecidfrmlab): + """Branched nightly a few days later with same package set should + not create event... + """ + CONSUMER.consume(_fakemsg(BRANCHED4)) + assert fakecreate.call_count == 0 + assert fakesmtp.call_count == 0 + +@mock.patch('fedfind.helpers.cid_from_label', return_value=ALPHA2) +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetdifferent) +@mock.patch('wikitcms.event.ComposeEvent.creation_date', '20160629') +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.ComposeEvent(None, '25', 'Alpha', '1.2')) +def test_branched4_different(fakesmtp, fakecreate, fakecidfrmlab): + """...but same few-days-later Branched nightly with different + packages should create event. + """ + CONSUMER.consume(_fakemsg(BRANCHED4)) + fakecreate.assert_called_with(cid=BRANCHED4, check=True) + +@mock.patch('fedfind.release.Production.label', 'Alpha-1.3') +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetdifferent) +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.NightlyEvent(None, '25', 'Branched', '20160705.n.0')) +def test_alpha3(fakesmtp, fakecreate): + """Another Alpha candidate came along! Event should be created + even though it's only been one day. + """ + CONSUMER.consume(_fakemsg(ALPHA3)) + fakecreate.assert_called_with(cid=ALPHA3, check=True) + +@mock.patch('fedfind.helpers.cid_from_label', return_value=ALPHA3) +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetdifferent) +@mock.patch('wikitcms.event.ComposeEvent.creation_date', '20160706') +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.ComposeEvent(None, '25', 'Alpha', '1.3')) +def test_branched5(fakesmtp, fakecreate, fakecidfrmlab): + """OK, say Alpha 1.3 went out as Alpha. Now another Branched + comes along. This isn't testing anything new but I wanna go + from Branched to Beta then Beta to Final. We should get an event + here. + """ + CONSUMER.consume(_fakemsg(BRANCHED5)) + fakecreate.assert_called_with(cid=BRANCHED5, check=True) + +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetdifferent) +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.NightlyEvent(None, '25', 'Branched', '20160710.n.0')) +def test_rawhide5(fakesmtp, fakecreate): + """Meanwhile, a Rawhide compose shows up (this is a thing that + happens all the time). We should NOT create any event for it - + we never create events for the release after the next (i.e. for + Rawhide when there is a Branched). + """ + CONSUMER.consume(_fakemsg(RAWHIDE5)) + assert fakecreate.call_count == 0 + assert fakesmtp.call_count == 0 + +@mock.patch('fedfind.release.Production.label', 'Beta-1.1') +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetdifferent) +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.NightlyEvent(None, '25', 'Branched', '20160710.n.0')) +def test_beta1(fakesmtp, fakecreate): + """OK, here comes Beta. We should get an event, of course.""" + CONSUMER.consume(_fakemsg(BETA1)) + fakecreate.assert_called_with(cid=BETA1, check=True) + +@mock.patch('fedfind.release.Production.label', 'Final-1.1') +@mock.patch('fedfind.helpers.cid_from_label', return_value=BETA1) +@mock.patch('wikitcms.event.ValidationEvent.create') +@mock.patch('smtplib.SMTP') +@mock.patch('fedfind.release.Release.get_package_versions', _fakegetdifferent) +@mock.patch('wikitcms.event.ComposeEvent.creation_date', '20160714') +@mock.patch('wikitcms.wiki.Wiki.current_event', wikitcms.event.ComposeEvent(None, '25', 'Beta', '1.1')) +def test_final1(fakesmtp, fakecreate, fakecidfrmlab): + """Finally, here comes Final! Testing going straight from one + candidate compose to another milestone candidate compose, though + this is unlikely ever to happen. We should get an event. + """ + CONSUMER.consume(_fakemsg(FINAL1)) + fakecreate.assert_called_with(cid=FINAL1, check=True)