Autocloud was retired years ago, we don't need any of this any more. Simplifies things quite a bit. Yay. Signed-off-by: Adam Williamson <awilliam@redhat.com>
290 lines
12 KiB
Python
290 lines
12 KiB
Python
# Copyright Red Hat
|
|
#
|
|
# This file is part of fedora_nightlies.
|
|
#
|
|
# fedora_nightlies 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 <http://www.gnu.org/licenses/>.
|
|
#
|
|
# Author: Adam Williamson <awilliam@redhat.com>
|
|
|
|
"""Tests for the Fedora nightly image finder."""
|
|
|
|
from __future__ import unicode_literals
|
|
from __future__ import print_function
|
|
|
|
import collections
|
|
import itertools
|
|
import mock
|
|
import pytest
|
|
import fedora_nightlies
|
|
import openqa_client.const as oqc
|
|
|
|
def _fake_get_current(branched=False):
|
|
"""Fake fedfind.helpers.get_current_release for case when there is
|
|
a Branched. Return 24 if branched is true, otherwise 23.
|
|
"""
|
|
if branched:
|
|
return 24
|
|
return 23
|
|
|
|
|
|
class FakeElement(object):
|
|
"""Mock 'Element' class which just stores the args it was called
|
|
with.
|
|
"""
|
|
def __init__(self, name, contents='', cssclass='', **kwargs):
|
|
self.name = name
|
|
self.contents = contents
|
|
self.cssclass = cssclass
|
|
self.kwargs = kwargs
|
|
|
|
|
|
@mock.patch('fedfind.helpers.get_current_release', _fake_get_current)
|
|
def test_current_releases_branched():
|
|
"""If we have a Branched (simulated by _fake_get_current), we
|
|
should get it and Rawhide, as strings.
|
|
"""
|
|
# clear the cache
|
|
fedora_nightlies.CURRENT_RELEASES = []
|
|
assert fedora_nightlies.current_releases() == ['24', 'Rawhide']
|
|
|
|
@mock.patch('fedfind.helpers.get_current_release', return_value=24)
|
|
def test_current_releases_no_branched(fakecurr):
|
|
"""If we have no Branched (simulated by get_current_release always
|
|
returning the same value), we should get a single-item list with
|
|
only Rawhide.
|
|
"""
|
|
# clear the cache
|
|
fedora_nightlies.CURRENT_RELEASES = []
|
|
assert fedora_nightlies.current_releases() == ['Rawhide']
|
|
|
|
# we're not testing the behaviour of Element here, so use FakeElement
|
|
@mock.patch('fedora_nightlies.Element', FakeElement)
|
|
def test_get_cell_pass():
|
|
"""Check the properties of the HTML table cell for an image that
|
|
passed tests. Checks that the FakeElement instances created have
|
|
the expected properties. The Image dict in this test must return
|
|
True for its testspass property, if it doesn't the test should
|
|
fail. We could just mock Image, but mehh.
|
|
"""
|
|
compose = "Fedora-Rawhide-20160418.n.0"
|
|
url = "https://kojipkgs.fedoraproject.org/compose/rawhide/Fedora-Rawhide-20160418.n.0/compose/CloudImages/x86_64/images/Fedora-Cloud-Base-Rawhide-20160418.n.0.x86_64.qcow2"
|
|
image = fedora_nightlies.Image({
|
|
'openqa': [{'result': "passed"}],
|
|
'compose': compose,
|
|
'url': url
|
|
})
|
|
cell = fedora_nightlies.get_cell(image)
|
|
assert cell.name == 'td'
|
|
# cell's contents is itself an element:
|
|
link = cell.contents
|
|
assert link.name == 'a'
|
|
assert link.contents == compose
|
|
assert link.kwargs['href'] == url
|
|
assert link.cssclass == 'passedlink'
|
|
|
|
@mock.patch('fedora_nightlies.Element', FakeElement)
|
|
def test_get_cell_untested():
|
|
"""Ditto the cell for an 'untested' image."""
|
|
compose = "Fedora-Rawhide-20160418.n.0"
|
|
url = "https://kojipkgs.fedoraproject.org/compose/rawhide/Fedora-Rawhide-20160418.n.0/compose/CloudImages/x86_64/images/Fedora-Cloud-Base-Rawhide-20160418.n.0.x86_64.raw.xz"
|
|
image = fedora_nightlies.Image({
|
|
'compose': compose,
|
|
'url': url
|
|
})
|
|
cell = fedora_nightlies.get_cell(image)
|
|
assert cell.name == 'td'
|
|
# cell's contents is itself an element:
|
|
link = cell.contents
|
|
assert link.name == 'a'
|
|
assert link.contents == compose
|
|
assert link.kwargs['href'] == url
|
|
assert link.cssclass == ''
|
|
|
|
@mock.patch('fedora_nightlies.Element', FakeElement)
|
|
def test_get_cell_failed():
|
|
"""Ditto the cell for a 'failed' image. This cell is pretty complex
|
|
and has a ton of nested elements, we extract each and check it.
|
|
"""
|
|
compose = "Fedora-Rawhide-20160418.n.0"
|
|
url = "https://kojipkgs.fedoraproject.org/compose/rawhide/Fedora-Rawhide-20160418.n.0/compose/Server/x86_64/iso/Fedora-Server-dvd-x86_64-Rawhide-20160418.n.0.iso"
|
|
job = 13335
|
|
test = 'base_services_start'
|
|
image = fedora_nightlies.Image({
|
|
'compose': compose,
|
|
'url': url,
|
|
'openqa': [{'result': 'failed', 'id': job, 'test': test}]
|
|
})
|
|
cell = fedora_nightlies.get_cell(image)
|
|
assert cell.name == 'td'
|
|
# cell's contents is itself a div element:
|
|
div = cell.contents
|
|
assert div.name == 'div'
|
|
assert div.cssclass == 'failcell'
|
|
# div's contents is a list of elements:
|
|
(imglink, faillinksdiv) = div.contents
|
|
assert imglink.name == 'a'
|
|
assert imglink.contents == compose
|
|
assert imglink.kwargs['href'] == url
|
|
assert imglink.cssclass == 'failedlink'
|
|
assert faillinksdiv.name == 'div'
|
|
assert faillinksdiv.cssclass == 'faillinks'
|
|
# this div's contents is a list containing a title and links: just one here
|
|
assert len(faillinksdiv.contents) == 2
|
|
faillink = faillinksdiv.contents[1]
|
|
assert faillink.name == 'a'
|
|
assert faillink.contents == 'openQA: {0} ({1})'.format(job, test)
|
|
|
|
def test_element_short_link():
|
|
"""Given a simple link element with short link text and a CSS
|
|
class, we should get the correct syntax all on a single line.
|
|
"""
|
|
elem = fedora_nightlies.Element('a', 'link target', cssclass='test', href='http://www.example.org/link')
|
|
assert str(elem) == '<a class="test" href="http://www.example.org/link">link target</a>'
|
|
assert elem.contents == ['link target']
|
|
|
|
def test_element_single_nest():
|
|
"""An Element with a single other Element as its contents. Outer
|
|
contents should be a single-item list containing inner element.
|
|
Text should be correct syntax on a single line.
|
|
"""
|
|
th = fedora_nightlies.Element('th', 'Title')
|
|
tr = fedora_nightlies.Element('tr', th)
|
|
assert tr.contents == [th]
|
|
assert str(tr) == '<tr><th>Title</th></tr>'
|
|
|
|
def test_element_short_list():
|
|
"""An element with a mixed list of strings and other elements as
|
|
its contents; should still come out on a single line so long as
|
|
the total length of contents is < 80.
|
|
"""
|
|
text = "some text "
|
|
link = fedora_nightlies.Element('a', 'foo', href='http://www.foo.com')
|
|
para = fedora_nightlies.Element('p', "some more text")
|
|
contents = [text, link, para]
|
|
div = fedora_nightlies.Element('div', contents)
|
|
assert div.contents == contents
|
|
assert str(div) == '<div>some text <a href="http://www.foo.com">foo</a><p>some more text</p></div>'
|
|
|
|
def test_element_long_string():
|
|
"""An element whose contents is a long string should have the
|
|
tags and content on separate lines.
|
|
"""
|
|
text = ("Lorem ipsum dolor who the hell remembers how the rest of "
|
|
"this goes anyway? Not me. Oh well, that's enough.")
|
|
elem = fedora_nightlies.Element('p', text)
|
|
assert str(elem) == '<p>\n{0}\n</p>'.format(text)
|
|
|
|
def test_element_long_list():
|
|
"""An element whose contents is a list of items whose combined
|
|
string representations total more than 80 characters should get
|
|
the tags and each item on separate lines.
|
|
"""
|
|
text1 = "Some text goes here, we love text."
|
|
link1 = fedora_nightlies.Element('a', 'link target', href='http://www.link.com')
|
|
text2 = "Some more text! Boy, isn't text great."
|
|
head = fedora_nightlies.Element('h1', "This is a big important heading!")
|
|
elem = fedora_nightlies.Element('div', [text1, link1, text2, head])
|
|
assert str(elem) == '<div>\n{0}\n{1}\n{2}\n{3}\n</div>'.format(
|
|
text1, str(link1), text2, str(head))
|
|
|
|
@mock.patch('fedora_nightlies.get_cell', return_value=fedora_nightlies.Element('td', 'fake cell'))
|
|
def test_release_table(fakegetcell):
|
|
"""Typical release table case. We mock get_cell, so we don't need
|
|
any real contents in any of the image dicts, we just need the
|
|
shape of the group dicts."""
|
|
wslive = {'x86_64': [{}, {}], 'i386': [{}]}
|
|
svboot = {'x86_64': [{}], 'i386': []}
|
|
# no images, should be skipped
|
|
atomic = {'x86_64': [], 'i386': []}
|
|
groups = {'Workstation live': wslive, 'Server boot': svboot, 'Atomic': atomic}
|
|
table = fedora_nightlies.ReleaseTable('24', groups)
|
|
# should try to get a cell for each image
|
|
assert fakegetcell.call_count == 4
|
|
# table should be, well, a table
|
|
assert table.name == 'table'
|
|
# table contents should be a list of table rows:
|
|
# the release header, two group headers, two column title headers,
|
|
# two arch rows for workstation and one arch row for server
|
|
# the contents should all be table rows
|
|
assert all(elem.name == 'tr' for elem in table.contents)
|
|
# we should have two group headers (not three)
|
|
grphds = [elem for elem in table.contents if
|
|
elem.contents[0].attributes.get('class') == 'groupheader']
|
|
assert len(grphds) == 2
|
|
# we should have three actual image rows, two for workstation
|
|
# (both arches), one for server (x86_64 only)
|
|
arches = [elem for elem in table.contents if len(elem.contents) == 3 and
|
|
all(cell.name == 'td' for cell in elem.contents)]
|
|
assert len(arches) == 3
|
|
# we should have two empty 'padding' cells, workstation i386 and
|
|
# server x86_64
|
|
cells = list(itertools.chain.from_iterable(arch.contents for arch in arches))
|
|
empty = [cell for cell in cells if cell.contents == ['']]
|
|
assert len(empty) == 2
|
|
|
|
def test_image():
|
|
"""Some tests for the Image class."""
|
|
img = fedora_nightlies.Image({
|
|
"arch": "x86_64",
|
|
"bootable": True,
|
|
"compose": "Fedora-29-20181028.n.0",
|
|
"disc_count": 1,
|
|
"disc_number": 1,
|
|
"format": "iso",
|
|
"implant_md5": "e0b57a312b61fdc526e521c4de1b59a6",
|
|
"mtime": 1540728857,
|
|
"path": "AtomicHost/x86_64/iso/Fedora-AtomicHost-ostree-x86_64-29-20181028.n.0.iso",
|
|
"size": 1102053376,
|
|
"subvariant": "AtomicHost",
|
|
"type": "dvd-ostree",
|
|
"url": "https://kojipkgs.fedoraproject.org/compose/branched/Fedora-29-20181028.n.0/compose/AtomicHost/x86_64/iso/Fedora-AtomicHost-ostree-x86_64-29-20181028.n.0.iso",
|
|
"volume_id": "Fedora-AH-ostree-x86_64-29"
|
|
})
|
|
assert img.release == "29"
|
|
# newly-instantiated image must always have these attributes
|
|
assert img['openqa'] == []
|
|
assert img.group == "AtomicHost dvd-ostree"
|
|
assert img.openqa_flavor == "AtomicHost-dvd_ostree-iso"
|
|
|
|
# test passed/failed/None test combinations work correctly
|
|
# None
|
|
assert img.testspass is None
|
|
# Pass
|
|
img['openqa'] = [{'result': oqc.JOB_RESULT_PASSED}]
|
|
assert img.testspass is True
|
|
# Fail
|
|
img['openqa'] = [{'result': oqc.JOB_RESULT_FAILED}]
|
|
assert img.testspass is False
|
|
# Softfail
|
|
img['openqa'] = [{'result': oqc.JOB_RESULT_SOFTFAILED}]
|
|
assert img.testspass is True
|
|
|
|
# clone image to test matches
|
|
img2 = fedora_nightlies.Image(img)
|
|
img2['openqa'] = []
|
|
# same image with different test results should match
|
|
assert img.matches(img2)
|
|
|
|
# check Rawhide release
|
|
img2['compose'] = 'Fedora-Rawhide-20181028.n.0'
|
|
assert img2.release == 'Rawhide'
|
|
|
|
# check sorting
|
|
img2['compose'] = 'Fedora-29-20181028.n.1'
|
|
img3 = fedora_nightlies.Image(img2)
|
|
img3['compose'] = 'Fedora-29-20181029.n.0'
|
|
img4 = fedora_nightlies.Image(img3)
|
|
img4['compose'] = 'Fedora-29-20181101.n.0'
|
|
imgs = sorted([img2, img, img4, img3], key=lambda x:x.sortid)
|
|
assert imgs == [img, img2, img3, img4]
|