1 | #-*- coding: utf-8 -*- |
---|
2 | # |
---|
3 | # Copyright (C) 2007 Ole Trenner, <ole@jayotee.de> |
---|
4 | # All rights reserved. |
---|
5 | # |
---|
6 | # This software is licensed as described in the file COPYING, which |
---|
7 | # you should have received as part of this distribution. |
---|
8 | |
---|
9 | import unittest |
---|
10 | |
---|
11 | from trac.db import DatabaseManager |
---|
12 | from trac.test import EnvironmentStub, Mock |
---|
13 | from trac.web.session import DetachedSession |
---|
14 | from bitten.model import schema, Build, BuildStep, BuildLog, BuildConfig |
---|
15 | from bitten.notify import BittenNotify, BuildNotifyEmail |
---|
16 | |
---|
17 | |
---|
18 | class BittenNotifyBaseTest(unittest.TestCase): |
---|
19 | |
---|
20 | def setUp(self): |
---|
21 | self.env = EnvironmentStub(enable=['trac.*', 'bitten.notify.*', |
---|
22 | 'bitten.tests.notify.*']) |
---|
23 | |
---|
24 | db = self.env.get_db_cnx() |
---|
25 | cursor = db.cursor() |
---|
26 | connector, _ = DatabaseManager(self.env)._get_connector() |
---|
27 | for table in schema: |
---|
28 | for stmt in connector.to_sql(table): |
---|
29 | cursor.execute(stmt) |
---|
30 | db.commit() |
---|
31 | |
---|
32 | # Hook up a dummy repository |
---|
33 | self.repos = Mock( |
---|
34 | get_changeset=lambda rev: Mock(author='author', rev=rev), |
---|
35 | normalize_rev=lambda rev: rev) |
---|
36 | self.env.get_repository = lambda authname=None: self.repos # 0.11 |
---|
37 | try: # 0.12+ |
---|
38 | from trac.core import Component, implements |
---|
39 | from trac.versioncontrol.api import IRepositoryConnector, \ |
---|
40 | IRepositoryProvider |
---|
41 | class DummyRepos(Component): |
---|
42 | implements(IRepositoryConnector, IRepositoryProvider) |
---|
43 | def get_supported_types(self): |
---|
44 | yield ('dummy', 9) |
---|
45 | def get_repository(this, repos_type, repos_dir, params): |
---|
46 | return self.repos # Note: 'this' vs 'self' usage |
---|
47 | def get_repositories(self): |
---|
48 | yield ('', {'dir': 'dummy_dir', 'type': 'dummy'}) |
---|
49 | self.dummy = DummyRepos |
---|
50 | except ImportError: |
---|
51 | self.dummy = None # not supported, will use get_repository() |
---|
52 | |
---|
53 | def tearDown(self): |
---|
54 | if self.dummy: # remove from components list + interfaces dict |
---|
55 | self.env.__metaclass__._components.remove(self.dummy) |
---|
56 | for key in self.env.__metaclass__._registry.keys(): |
---|
57 | if self.dummy in self.env.__metaclass__._registry[key]: |
---|
58 | self.env.__metaclass__._registry[key].remove(self.dummy) |
---|
59 | |
---|
60 | |
---|
61 | class BittenNotifyTest(BittenNotifyBaseTest): |
---|
62 | """unit tests for BittenNotify dispatcher class""" |
---|
63 | def setUp(self): |
---|
64 | BittenNotifyBaseTest.setUp(self) |
---|
65 | self.dispatcher = BittenNotify(self.env) |
---|
66 | self.failed_build = Build(self.env, status=Build.FAILURE) |
---|
67 | self.successful_build = Build(self.env, status=Build.SUCCESS) |
---|
68 | |
---|
69 | def test_do_notify_on_failed_build(self): |
---|
70 | self.set_option(BittenNotify.notify_on_failure, 'true') |
---|
71 | self.assertTrue(self.dispatcher._should_notify(self.failed_build), |
---|
72 | 'notifier should be called for failed builds.') |
---|
73 | |
---|
74 | def test_do_not_notify_on_failed_build(self): |
---|
75 | self.set_option(BittenNotify.notify_on_failure, 'false') |
---|
76 | self.assertFalse(self.dispatcher._should_notify(self.failed_build), |
---|
77 | 'notifier should not be called for failed build.') |
---|
78 | |
---|
79 | def test_do_notify_on_successful_build(self): |
---|
80 | self.set_option(BittenNotify.notify_on_success, 'true') |
---|
81 | self.assertTrue(self.dispatcher._should_notify(self.successful_build), |
---|
82 | 'notifier should be called for successful builds when configured.') |
---|
83 | |
---|
84 | def test_do_not_notify_on_successful_build(self): |
---|
85 | self.set_option(BittenNotify.notify_on_success, 'false') |
---|
86 | self.assertFalse(self.dispatcher._should_notify(self.successful_build), |
---|
87 | 'notifier should not be called for successful build.') |
---|
88 | |
---|
89 | def set_option(self, option, value): |
---|
90 | self.env.config.set(option.section, option.name, value) |
---|
91 | |
---|
92 | |
---|
93 | class BuildNotifyEmailTest(BittenNotifyBaseTest): |
---|
94 | """unit tests for BittenNotifyEmail class""" |
---|
95 | def setUp(self): |
---|
96 | BittenNotifyBaseTest.setUp(self) |
---|
97 | self.env.config.set('notification','smtp_enabled','true') |
---|
98 | self.notifications_sent_to = [] |
---|
99 | def send(to, cc, hdrs={}): |
---|
100 | self.notifications_sent_to = to |
---|
101 | def noop(*args, **kw): |
---|
102 | pass |
---|
103 | self.email = Mock(BuildNotifyEmail, self.env, |
---|
104 | begin_send=noop, |
---|
105 | finish_send=noop, |
---|
106 | send=send) |
---|
107 | BuildConfig(self.env, name='c', path='trunk').insert() |
---|
108 | self.build = Build(self.env, config='c', status=Build.SUCCESS, rev=123) |
---|
109 | |
---|
110 | def test_notification_is_sent_to_author(self): |
---|
111 | self.email.notify(self.build) |
---|
112 | self.assertTrue('author' in self.notifications_sent_to, |
---|
113 | 'Recipient list should contain the author') |
---|
114 | |
---|
115 | def test_notification_body_render(self): |
---|
116 | self.email.notify(self.build) |
---|
117 | output = self.email.template.generate(**self.email.data).render('text') |
---|
118 | self.assertTrue('Successful build of My Project [123]' in output) |
---|
119 | self.assertTrue('<http://example.org/trac.cgi/changeset/123>' in output) |
---|
120 | |
---|
121 | # TODO functional tests of generated mails |
---|
122 | |
---|
123 | |
---|
124 | def suite(): |
---|
125 | suite = unittest.TestSuite() |
---|
126 | suite.addTest(unittest.makeSuite(BittenNotifyTest, 'test')) |
---|
127 | suite.addTest(unittest.makeSuite(BuildNotifyEmailTest, 'test')) |
---|
128 | return suite |
---|
129 | |
---|
130 | if __name__ == '__main__': |
---|
131 | unittest.main(defaultTest='suite') |
---|