2015-12-10 14:49:00 +00:00
|
|
|
#!/usr/bin/env python2
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
import mock
|
2016-05-25 11:39:02 +00:00
|
|
|
try:
|
|
|
|
import unittest2 as unittest
|
|
|
|
except ImportError:
|
|
|
|
import unittest
|
2015-12-10 14:49:00 +00:00
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import tempfile
|
|
|
|
import shutil
|
|
|
|
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
|
|
|
|
|
|
from pungi.compose import Compose
|
|
|
|
|
|
|
|
|
2016-03-29 14:07:24 +00:00
|
|
|
class ConfigWrapper(dict):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super(ConfigWrapper, self).__init__(*args, **kwargs)
|
|
|
|
self._open_file = '%s/fixtures/config.conf' % os.path.abspath(os.path.dirname(__file__))
|
|
|
|
|
|
|
|
|
2015-12-10 14:49:00 +00:00
|
|
|
class ComposeTestCase(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
|
|
self.tmp_dir = tempfile.mkdtemp()
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
shutil.rmtree(self.tmp_dir)
|
|
|
|
|
|
|
|
@mock.patch('pungi.compose.ComposeInfo')
|
|
|
|
def test_can_fail(self, ci):
|
|
|
|
conf = {
|
|
|
|
'failable_deliverables': [
|
|
|
|
('^.*$', {
|
|
|
|
'*': ['buildinstall'],
|
|
|
|
'i386': ['buildinstall', 'live', 'iso'],
|
|
|
|
}),
|
|
|
|
]
|
|
|
|
}
|
|
|
|
compose = Compose(conf, self.tmp_dir)
|
|
|
|
variant = mock.Mock(uid='Server')
|
|
|
|
|
|
|
|
self.assertTrue(compose.can_fail(variant, 'x86_64', 'buildinstall'))
|
|
|
|
self.assertFalse(compose.can_fail(variant, 'x86_64', 'live'))
|
|
|
|
self.assertTrue(compose.can_fail(variant, 'i386', 'live'))
|
|
|
|
|
|
|
|
self.assertFalse(compose.can_fail(None, 'x86_64', 'live'))
|
|
|
|
self.assertTrue(compose.can_fail(None, 'i386', 'live'))
|
|
|
|
|
2016-01-11 16:14:51 +00:00
|
|
|
self.assertTrue(compose.can_fail(variant, '*', 'buildinstall'))
|
|
|
|
self.assertFalse(compose.can_fail(variant, '*', 'live'))
|
|
|
|
|
2016-01-06 11:24:01 +00:00
|
|
|
@mock.patch('pungi.compose.ComposeInfo')
|
|
|
|
def test_get_image_name(self, ci):
|
|
|
|
conf = {}
|
|
|
|
variant = mock.Mock(uid='Server', type='variant')
|
|
|
|
ci.return_value.compose.respin = 2
|
|
|
|
ci.return_value.compose.id = 'compose_id'
|
|
|
|
ci.return_value.compose.date = '20160107'
|
|
|
|
ci.return_value.compose.type = 'nightly'
|
|
|
|
ci.return_value.compose.type_suffix = '.n'
|
|
|
|
ci.return_value.compose.label = 'RC-1.0'
|
|
|
|
ci.return_value.compose.label_major_version = '1'
|
|
|
|
|
|
|
|
ci.return_value.release.version = '3.0'
|
|
|
|
ci.return_value.release.short = 'rel_short'
|
|
|
|
|
|
|
|
compose = Compose(conf, self.tmp_dir)
|
|
|
|
|
|
|
|
keys = ['arch', 'compose_id', 'date', 'disc_num', 'disc_type',
|
|
|
|
'label', 'label_major_version', 'release_short', 'respin',
|
|
|
|
'suffix', 'type', 'type_suffix', 'variant', 'version']
|
|
|
|
format = '-'.join(['%(' + k + ')s' for k in keys])
|
|
|
|
name = compose.get_image_name('x86_64', variant, format=format,
|
|
|
|
disc_num=7, disc_type='live', suffix='.iso')
|
|
|
|
|
|
|
|
self.assertEqual(name, '-'.join(['x86_64', 'compose_id', '20160107', '7', 'live',
|
|
|
|
'RC-1.0', '1', 'rel_short', '2', '.iso', 'nightly',
|
|
|
|
'.n', 'Server', '3.0']))
|
|
|
|
|
2016-03-11 07:55:21 +00:00
|
|
|
@mock.patch('pungi.compose.ComposeInfo')
|
|
|
|
def test_get_image_name_type_netinst(self, ci):
|
|
|
|
conf = {}
|
|
|
|
variant = mock.Mock(uid='Server', type='variant')
|
|
|
|
ci.return_value.compose.respin = 2
|
|
|
|
ci.return_value.compose.id = 'compose_id'
|
|
|
|
ci.return_value.compose.date = '20160107'
|
|
|
|
ci.return_value.compose.type = 'nightly'
|
|
|
|
ci.return_value.compose.type_suffix = '.n'
|
|
|
|
ci.return_value.compose.label = 'RC-1.0'
|
|
|
|
ci.return_value.compose.label_major_version = '1'
|
|
|
|
|
|
|
|
ci.return_value.release.version = '3.0'
|
|
|
|
ci.return_value.release.short = 'rel_short'
|
|
|
|
|
|
|
|
compose = Compose(conf, self.tmp_dir)
|
|
|
|
|
|
|
|
keys = ['arch', 'compose_id', 'date', 'disc_num', 'disc_type',
|
|
|
|
'label', 'label_major_version', 'release_short', 'respin',
|
|
|
|
'suffix', 'type', 'type_suffix', 'variant', 'version']
|
|
|
|
format = '-'.join(['%(' + k + ')s' for k in keys])
|
|
|
|
name = compose.get_image_name('x86_64', variant, format=format,
|
|
|
|
disc_num=7, disc_type='netinst', suffix='.iso')
|
|
|
|
|
|
|
|
self.assertEqual(name, '-'.join(['x86_64', 'compose_id', '20160107', '7', 'netinst',
|
|
|
|
'RC-1.0', '1', 'rel_short', '2', '.iso', 'nightly',
|
|
|
|
'.n', 'Server', '3.0']))
|
|
|
|
|
2016-03-22 07:56:51 +00:00
|
|
|
@mock.patch('pungi.compose.ComposeInfo')
|
|
|
|
def test_image_release(self, ci):
|
|
|
|
conf = {}
|
|
|
|
ci.return_value.compose.respin = 2
|
|
|
|
ci.return_value.compose.date = '20160107'
|
|
|
|
ci.return_value.compose.type = 'nightly'
|
|
|
|
ci.return_value.compose.type_suffix = '.n'
|
2016-08-25 13:22:55 +00:00
|
|
|
ci.return_value.compose.label = None
|
2016-03-22 07:56:51 +00:00
|
|
|
|
|
|
|
compose = Compose(conf, self.tmp_dir)
|
|
|
|
|
|
|
|
self.assertEqual(compose.image_release, '20160107.n.2')
|
|
|
|
|
|
|
|
@mock.patch('pungi.compose.ComposeInfo')
|
|
|
|
def test_image_release_production(self, ci):
|
|
|
|
conf = {}
|
|
|
|
ci.return_value.compose.respin = 2
|
|
|
|
ci.return_value.compose.date = '20160107'
|
|
|
|
ci.return_value.compose.type = 'production'
|
2016-08-30 07:51:36 +00:00
|
|
|
ci.return_value.compose.type_suffix = ''
|
2016-08-25 13:22:55 +00:00
|
|
|
ci.return_value.compose.label = None
|
2016-03-22 07:56:51 +00:00
|
|
|
|
|
|
|
compose = Compose(conf, self.tmp_dir)
|
|
|
|
|
2016-08-30 07:51:36 +00:00
|
|
|
self.assertEqual(compose.image_release, '20160107.2')
|
2016-03-22 07:56:51 +00:00
|
|
|
|
2016-08-25 13:22:55 +00:00
|
|
|
@mock.patch('pungi.compose.ComposeInfo')
|
|
|
|
def test_image_release_from_label(self, ci):
|
|
|
|
conf = {}
|
|
|
|
ci.return_value.compose.respin = 2
|
|
|
|
ci.return_value.compose.date = '20160107'
|
|
|
|
ci.return_value.compose.type = 'production'
|
|
|
|
ci.return_value.compose.type_suffix = '.n'
|
|
|
|
ci.return_value.compose.label = 'Alpha-1.2'
|
|
|
|
|
|
|
|
compose = Compose(conf, self.tmp_dir)
|
|
|
|
|
|
|
|
self.assertEqual(compose.image_release, '1.2')
|
|
|
|
|
2016-08-30 07:51:36 +00:00
|
|
|
@mock.patch('pungi.compose.ComposeInfo')
|
|
|
|
def test_image_version_without_label(self, ci):
|
|
|
|
conf = {}
|
|
|
|
ci.return_value.compose.respin = 2
|
|
|
|
ci.return_value.compose.date = '20160107'
|
|
|
|
ci.return_value.compose.type = 'nightly'
|
|
|
|
ci.return_value.compose.type_suffix = '.n'
|
|
|
|
ci.return_value.compose.label = None
|
|
|
|
ci.return_value.release.version = '25'
|
|
|
|
|
|
|
|
compose = Compose(conf, self.tmp_dir)
|
|
|
|
|
|
|
|
self.assertEqual(compose.image_version, '25')
|
|
|
|
|
|
|
|
@mock.patch('pungi.compose.ComposeInfo')
|
|
|
|
def test_image_version_with_label(self, ci):
|
|
|
|
conf = {}
|
|
|
|
ci.return_value.compose.respin = 2
|
|
|
|
ci.return_value.compose.date = '20160107'
|
|
|
|
ci.return_value.compose.type = 'nightly'
|
|
|
|
ci.return_value.compose.type_suffix = '.n'
|
|
|
|
ci.return_value.compose.label = 'Alpha-1.2'
|
|
|
|
ci.return_value.release.version = '25'
|
|
|
|
|
|
|
|
compose = Compose(conf, self.tmp_dir)
|
|
|
|
|
|
|
|
self.assertEqual(compose.image_version, '25_Alpha')
|
|
|
|
|
|
|
|
@mock.patch('pungi.compose.ComposeInfo')
|
|
|
|
def test_image_version_with_label_rc(self, ci):
|
|
|
|
conf = {}
|
|
|
|
ci.return_value.compose.respin = 2
|
|
|
|
ci.return_value.compose.date = '20160107'
|
|
|
|
ci.return_value.compose.type = 'nightly'
|
|
|
|
ci.return_value.compose.type_suffix = '.n'
|
|
|
|
ci.return_value.compose.label = 'RC-1.2'
|
|
|
|
ci.return_value.release.version = '25'
|
|
|
|
|
|
|
|
compose = Compose(conf, self.tmp_dir)
|
|
|
|
|
|
|
|
self.assertEqual(compose.image_version, '25')
|
|
|
|
|
2016-03-29 14:07:24 +00:00
|
|
|
@mock.patch('pungi.compose.ComposeInfo')
|
|
|
|
def test_get_variant_arches_without_filter(self, ci):
|
|
|
|
conf = ConfigWrapper(
|
|
|
|
variants_file={'scm': 'file',
|
|
|
|
'repo': None,
|
|
|
|
'file': 'variants.xml'},
|
|
|
|
release_name='Test',
|
|
|
|
release_version='1.0',
|
|
|
|
release_short='test',
|
2016-08-22 14:08:25 +00:00
|
|
|
release_type='ga',
|
|
|
|
release_is_layered=False,
|
2016-03-29 14:07:24 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
compose = Compose(conf, self.tmp_dir)
|
|
|
|
compose.read_variants()
|
|
|
|
|
|
|
|
self.assertEqual(sorted([v.uid for v in compose.variants.itervalues()]),
|
|
|
|
['Client', 'Crashy', 'Live', 'Server'])
|
|
|
|
self.assertEqual(sorted([v.uid for v in compose.variants['Server'].variants.itervalues()]),
|
|
|
|
['Server-Gluster', 'Server-ResilientStorage', 'Server-optional'])
|
|
|
|
self.assertItemsEqual(compose.variants['Client'].arches,
|
|
|
|
['i386', 'x86_64'])
|
|
|
|
self.assertItemsEqual(compose.variants['Crashy'].arches,
|
|
|
|
['ppc64le'])
|
|
|
|
self.assertItemsEqual(compose.variants['Live'].arches,
|
|
|
|
['x86_64'])
|
|
|
|
self.assertItemsEqual(compose.variants['Server'].arches,
|
|
|
|
['s390x', 'x86_64'])
|
|
|
|
self.assertItemsEqual(compose.variants['Server'].variants['Gluster'].arches,
|
|
|
|
['x86_64'])
|
|
|
|
self.assertItemsEqual(compose.variants['Server'].variants['ResilientStorage'].arches,
|
|
|
|
['x86_64'])
|
|
|
|
self.assertItemsEqual(compose.variants['Server'].variants['optional'].arches,
|
|
|
|
['s390x', 'x86_64'])
|
|
|
|
|
|
|
|
self.assertEqual([v.uid for v in compose.get_variants()],
|
|
|
|
['Client', 'Crashy', 'Live', 'Server', 'Server-Gluster',
|
|
|
|
'Server-ResilientStorage', 'Server-optional'])
|
|
|
|
self.assertEqual(compose.get_arches(), ['i386', 'ppc64le', 's390x', 'x86_64'])
|
|
|
|
|
|
|
|
@mock.patch('pungi.compose.ComposeInfo')
|
|
|
|
def test_get_variant_arches_with_arch_filter(self, ci):
|
|
|
|
conf = ConfigWrapper(
|
|
|
|
variants_file={'scm': 'file',
|
|
|
|
'repo': None,
|
|
|
|
'file': 'variants.xml'},
|
|
|
|
release_name='Test',
|
|
|
|
release_version='1.0',
|
|
|
|
release_short='test',
|
2016-08-22 14:08:25 +00:00
|
|
|
release_type='ga',
|
|
|
|
release_is_layered=False,
|
2016-03-29 14:07:24 +00:00
|
|
|
tree_arches=['x86_64'],
|
|
|
|
)
|
|
|
|
|
|
|
|
compose = Compose(conf, self.tmp_dir)
|
|
|
|
compose.read_variants()
|
|
|
|
|
|
|
|
self.assertEqual(sorted([v.uid for v in compose.variants.itervalues()]),
|
|
|
|
['Client', 'Live', 'Server'])
|
|
|
|
self.assertEqual(sorted([v.uid for v in compose.variants['Server'].variants.itervalues()]),
|
|
|
|
['Server-Gluster', 'Server-ResilientStorage', 'Server-optional'])
|
|
|
|
self.assertItemsEqual(compose.variants['Client'].arches,
|
|
|
|
['x86_64'])
|
|
|
|
self.assertItemsEqual(compose.variants['Live'].arches,
|
|
|
|
['x86_64'])
|
|
|
|
self.assertItemsEqual(compose.variants['Server'].arches,
|
|
|
|
['x86_64'])
|
|
|
|
self.assertItemsEqual(compose.variants['Server'].variants['Gluster'].arches,
|
|
|
|
['x86_64'])
|
|
|
|
self.assertItemsEqual(compose.variants['Server'].variants['ResilientStorage'].arches,
|
|
|
|
['x86_64'])
|
|
|
|
self.assertItemsEqual(compose.variants['Server'].variants['optional'].arches,
|
|
|
|
['x86_64'])
|
|
|
|
|
|
|
|
self.assertEqual(compose.get_arches(), ['x86_64'])
|
|
|
|
self.assertEqual([v.uid for v in compose.get_variants()],
|
|
|
|
['Client', 'Live', 'Server', 'Server-Gluster',
|
|
|
|
'Server-ResilientStorage', 'Server-optional'])
|
|
|
|
|
|
|
|
@mock.patch('pungi.compose.ComposeInfo')
|
|
|
|
def test_get_variant_arches_with_variant_filter(self, ci):
|
|
|
|
ci.return_value.compose.respin = 2
|
|
|
|
ci.return_value.compose.date = '20160107'
|
|
|
|
ci.return_value.compose.type = 'production'
|
|
|
|
ci.return_value.compose.type_suffix = '.n'
|
|
|
|
|
|
|
|
conf = ConfigWrapper(
|
|
|
|
variants_file={'scm': 'file',
|
|
|
|
'repo': None,
|
|
|
|
'file': 'variants.xml'},
|
|
|
|
release_name='Test',
|
|
|
|
release_version='1.0',
|
|
|
|
release_short='test',
|
2016-08-22 14:08:25 +00:00
|
|
|
release_type='ga',
|
|
|
|
release_is_layered=False,
|
2016-03-29 14:07:24 +00:00
|
|
|
tree_variants=['Server', 'Client', 'Server-Gluster'],
|
|
|
|
)
|
|
|
|
|
|
|
|
compose = Compose(conf, self.tmp_dir)
|
|
|
|
compose.read_variants()
|
|
|
|
|
|
|
|
self.assertEqual(sorted([v.uid for v in compose.variants.itervalues()]),
|
|
|
|
['Client', 'Server'])
|
|
|
|
self.assertItemsEqual(compose.variants['Client'].arches,
|
|
|
|
['i386', 'x86_64'])
|
|
|
|
self.assertItemsEqual(compose.variants['Server'].arches,
|
|
|
|
['s390x', 'x86_64'])
|
|
|
|
self.assertItemsEqual(compose.variants['Server'].variants['Gluster'].arches,
|
|
|
|
['x86_64'])
|
|
|
|
|
|
|
|
self.assertEqual(compose.get_arches(), ['i386', 's390x', 'x86_64'])
|
|
|
|
self.assertEqual([v.uid for v in compose.get_variants()],
|
|
|
|
['Client', 'Server', 'Server-Gluster'])
|
|
|
|
|
|
|
|
@mock.patch('pungi.compose.ComposeInfo')
|
|
|
|
def test_get_variant_arches_with_both_filters(self, ci):
|
|
|
|
ci.return_value.compose.respin = 2
|
|
|
|
ci.return_value.compose.date = '20160107'
|
|
|
|
ci.return_value.compose.type = 'production'
|
|
|
|
ci.return_value.compose.type_suffix = '.n'
|
|
|
|
|
|
|
|
logger = mock.Mock()
|
|
|
|
|
|
|
|
conf = ConfigWrapper(
|
|
|
|
variants_file={'scm': 'file',
|
|
|
|
'repo': None,
|
|
|
|
'file': 'variants.xml'},
|
|
|
|
release_name='Test',
|
|
|
|
release_version='1.0',
|
|
|
|
release_short='test',
|
2016-08-22 14:08:25 +00:00
|
|
|
release_type='ga',
|
|
|
|
release_is_layered=False,
|
2016-03-29 14:07:24 +00:00
|
|
|
tree_variants=['Server', 'Client', 'Server-optional'],
|
|
|
|
tree_arches=['x86_64'],
|
|
|
|
)
|
|
|
|
|
|
|
|
compose = Compose(conf, self.tmp_dir, logger=logger)
|
|
|
|
compose.read_variants()
|
|
|
|
|
|
|
|
self.assertEqual(sorted([v.uid for v in compose.variants.itervalues()]),
|
|
|
|
['Client', 'Server'])
|
|
|
|
self.assertItemsEqual(compose.variants['Client'].arches,
|
|
|
|
['x86_64'])
|
|
|
|
self.assertItemsEqual(compose.variants['Server'].arches,
|
|
|
|
['x86_64'])
|
|
|
|
self.assertItemsEqual(compose.variants['Server'].variants['optional'].arches,
|
|
|
|
['x86_64'])
|
|
|
|
|
|
|
|
self.assertEqual(compose.get_arches(), ['x86_64'])
|
|
|
|
self.assertEqual([v.uid for v in compose.get_variants()],
|
|
|
|
['Client', 'Server', 'Server-optional'])
|
|
|
|
|
|
|
|
self.assertItemsEqual(
|
|
|
|
logger.info.call_args_list,
|
|
|
|
[mock.call('Excluding variant Live: filtered by configuration.'),
|
|
|
|
mock.call('Excluding variant Crashy: all its arches are filtered.'),
|
|
|
|
mock.call('Excluding variant Server-ResilientStorage: filtered by configuration.'),
|
|
|
|
mock.call('Excluding variant Server-Gluster: filtered by configuration.')]
|
|
|
|
)
|
|
|
|
|
2015-12-10 14:49:00 +00:00
|
|
|
|
2016-01-12 12:29:14 +00:00
|
|
|
class StatusTest(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
|
|
self.tmp_dir = tempfile.mkdtemp()
|
|
|
|
self.logger = mock.Mock()
|
|
|
|
with mock.patch('pungi.compose.ComposeInfo'):
|
|
|
|
self.compose = Compose({}, self.tmp_dir, logger=self.logger)
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
shutil.rmtree(self.tmp_dir)
|
|
|
|
|
|
|
|
def test_get_status_non_existing(self):
|
|
|
|
status = self.compose.get_status()
|
|
|
|
self.assertIsNone(status)
|
|
|
|
|
|
|
|
def test_get_status_existing(self):
|
|
|
|
with open(os.path.join(self.tmp_dir, 'STATUS'), 'w') as f:
|
|
|
|
f.write('FOOBAR')
|
|
|
|
|
|
|
|
self.assertEqual(self.compose.get_status(), 'FOOBAR')
|
|
|
|
|
|
|
|
def test_get_status_is_dir(self):
|
|
|
|
os.mkdir(os.path.join(self.tmp_dir, 'STATUS'))
|
|
|
|
|
|
|
|
self.assertIsNone(self.compose.get_status())
|
|
|
|
|
|
|
|
def test_write_status(self):
|
|
|
|
self.compose.write_status('DOOMED')
|
|
|
|
|
|
|
|
with open(os.path.join(self.tmp_dir, 'STATUS'), 'r') as f:
|
|
|
|
self.assertEqual(f.read(), 'DOOMED\n')
|
|
|
|
|
|
|
|
def test_write_non_standard_status(self):
|
|
|
|
self.compose.write_status('FOOBAR')
|
|
|
|
|
|
|
|
self.assertEqual(self.logger.log.call_count, 1)
|
|
|
|
with open(os.path.join(self.tmp_dir, 'STATUS'), 'r') as f:
|
|
|
|
self.assertEqual(f.read(), 'FOOBAR\n')
|
|
|
|
|
|
|
|
def test_write_status_on_finished(self):
|
|
|
|
self.compose.write_status('FINISHED')
|
|
|
|
|
|
|
|
with self.assertRaises(RuntimeError):
|
|
|
|
self.compose.write_status('NOT REALLY')
|
|
|
|
|
|
|
|
def test_write_status_with_failed_deliverables(self):
|
|
|
|
self.compose.conf = {
|
|
|
|
'failable_deliverables': [
|
|
|
|
('^.+$', {
|
|
|
|
'*': ['live', 'build-image'],
|
|
|
|
})
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
variant = mock.Mock(uid='Server')
|
2016-04-13 11:44:17 +00:00
|
|
|
self.compose.fail_deliverable(variant, 'x86_64', 'live')
|
|
|
|
self.compose.fail_deliverable(None, '*', 'build-image')
|
2016-01-12 12:29:14 +00:00
|
|
|
|
|
|
|
self.compose.write_status('FINISHED')
|
|
|
|
|
|
|
|
self.logger.log.assert_has_calls(
|
2016-04-13 11:44:17 +00:00
|
|
|
[mock.call(20, 'Failed build-image on variant <>, arch <*>, subvariant <None>.'),
|
|
|
|
mock.call(20, 'Failed live on variant <Server>, arch <x86_64>, subvariant <None>.')],
|
2016-01-12 12:29:14 +00:00
|
|
|
any_order=True)
|
|
|
|
|
|
|
|
with open(os.path.join(self.tmp_dir, 'STATUS'), 'r') as f:
|
|
|
|
self.assertEqual(f.read(), 'FINISHED_INCOMPLETE\n')
|
|
|
|
|
|
|
|
def test_calls_notifier(self):
|
|
|
|
self.compose.notifier = mock.Mock()
|
|
|
|
self.compose.write_status('FINISHED')
|
|
|
|
|
|
|
|
self.assertTrue(self.compose.notifier.send.call_count, 1)
|
|
|
|
|
|
|
|
|
2015-12-10 14:49:00 +00:00
|
|
|
if __name__ == "__main__":
|
|
|
|
unittest.main()
|