##// END OF EJS Templates
events: use context manager for testing fired events
dan -
r376:ce1a3e78 default
parent child Browse files
Show More
@@ -1,49 +1,51 b''
1 # Copyright (C) 2016-2016 RhodeCode GmbH
1 # Copyright (C) 2016-2016 RhodeCode GmbH
2 #
2 #
3 # This program is free software: you can redistribute it and/or modify
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
5 # (only), as published by the Free Software Foundation.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU Affero General Public License
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
14 #
15 # This program is dual-licensed. If you wish to learn more about the
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 from pyramid.threadlocal import get_current_registry
19 from pyramid.threadlocal import get_current_registry
20
20
21
21
22 class RhodecodeEvent(object):
22 class RhodecodeEvent(object):
23 """
23 """
24 Base event class for all Rhodecode events
24 Base event class for all Rhodecode events
25 """
25 """
26
26
27
27
28 def trigger(event):
28 def trigger(event):
29 """
29 """
30 Helper method to send an event. This wraps the pyramid logic to send an
30 Helper method to send an event. This wraps the pyramid logic to send an
31 event.
31 event.
32 """
32 """
33 # For the first step we are using pyramids thread locals here. If the
33 # For the first step we are using pyramids thread locals here. If the
34 # event mechanism works out as a good solution we should think about
34 # event mechanism works out as a good solution we should think about
35 # passing the registry as an argument to get rid of it.
35 # passing the registry as an argument to get rid of it.
36 registry = get_current_registry()
36 registry = get_current_registry()
37 registry.notify(event)
37 registry.notify(event)
38
38
39
39
40 from rhodecode.events.user import (
40 from rhodecode.events.user import (
41 UserPreCreate, UserPreUpdate, UserRegistered
41 UserPreCreate,
42 UserPreUpdate,
43 UserRegistered
42 )
44 )
43
45
44 from rhodecode.events.repo import (
46 from rhodecode.events.repo import (
45 RepoPreCreateEvent, RepoCreatedEvent,
47 RepoPreCreateEvent, RepoCreatedEvent,
46 RepoPreDeleteEvent, RepoDeletedEvent,
48 RepoPreDeleteEvent, RepoDeletedEvent,
47 RepoPrePushEvent, RepoPushEvent,
49 RepoPrePushEvent, RepoPushEvent,
48 RepoPrePullEvent, RepoPullEvent,
50 RepoPrePullEvent, RepoPullEvent,
49 ) No newline at end of file
51 )
@@ -1,115 +1,113 b''
1 # Copyright (C) 2016-2016 RhodeCode GmbH
1 # Copyright (C) 2016-2016 RhodeCode GmbH
2 #
2 #
3 # This program is free software: you can redistribute it and/or modify
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
5 # (only), as published by the Free Software Foundation.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU Affero General Public License
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
14 #
15 # This program is dual-licensed. If you wish to learn more about the
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 from rhodecode.model.db import Repository, Session
19 from rhodecode.model.db import Repository, Session
20 from rhodecode.events import RhodecodeEvent
20 from rhodecode.events import RhodecodeEvent
21
21
22
22
23 class RepoEvent(RhodecodeEvent):
23 class RepoEvent(RhodecodeEvent):
24 """
24 """
25 Base class for events acting on a repository.
25 Base class for events acting on a repository.
26
26
27 :param repo: a :class:`Repository` instance
27 :param repo: a :class:`Repository` instance
28 """
28 """
29 def __init__(self, repo):
29 def __init__(self, repo):
30 self.repo = repo
30 self.repo = repo
31
31
32
32
33 class RepoPreCreateEvent(RepoEvent):
33 class RepoPreCreateEvent(RepoEvent):
34 """
34 """
35 An instance of this class is emitted as an :term:`event` before a repo is
35 An instance of this class is emitted as an :term:`event` before a repo is
36 created.
36 created.
37
38 :param repo_name: repository name
39 """
37 """
40 name = 'repo-pre-create'
38 name = 'repo-pre-create'
41
39
42
40
43 class RepoCreatedEvent(RepoEvent):
41 class RepoCreatedEvent(RepoEvent):
44 """
42 """
45 An instance of this class is emitted as an :term:`event` whenever a repo is
43 An instance of this class is emitted as an :term:`event` whenever a repo is
46 created.
44 created.
47 """
45 """
48 name = 'repo-created'
46 name = 'repo-created'
49
47
50
48
51 class RepoPreDeleteEvent(RepoEvent):
49 class RepoPreDeleteEvent(RepoEvent):
52 """
50 """
53 An instance of this class is emitted as an :term:`event` whenever a repo is
51 An instance of this class is emitted as an :term:`event` whenever a repo is
54 created.
52 created.
55 """
53 """
56 name = 'repo-pre-delete'
54 name = 'repo-pre-delete'
57
55
58
56
59 class RepoDeletedEvent(RepoEvent):
57 class RepoDeletedEvent(RepoEvent):
60 """
58 """
61 An instance of this class is emitted as an :term:`event` whenever a repo is
59 An instance of this class is emitted as an :term:`event` whenever a repo is
62 created.
60 created.
63 """
61 """
64 name = 'repo-deleted'
62 name = 'repo-deleted'
65
63
66
64
67 class RepoVCSEvent(RepoEvent):
65 class RepoVCSEvent(RepoEvent):
68 """
66 """
69 Base class for events triggered by the VCS
67 Base class for events triggered by the VCS
70 """
68 """
71 def __init__(self, repo_name, extras):
69 def __init__(self, repo_name, extras):
72 self.repo = Repository.get_by_repo_name(repo_name)
70 self.repo = Repository.get_by_repo_name(repo_name)
73 if not self.repo:
71 if not self.repo:
74 raise Exception('repo by this name %s does not exist' % repo_name)
72 raise Exception('repo by this name %s does not exist' % repo_name)
75 self.extras = extras
73 self.extras = extras
76 super(RepoVCSEvent, self).__init__(self.repo)
74 super(RepoVCSEvent, self).__init__(self.repo)
77
75
78
76
79 class RepoPrePullEvent(RepoVCSEvent):
77 class RepoPrePullEvent(RepoVCSEvent):
80 """
78 """
81 An instance of this class is emitted as an :term:`event` before commits
79 An instance of this class is emitted as an :term:`event` before commits
82 are pulled from a repo.
80 are pulled from a repo.
83 """
81 """
84 name = 'repo-pre-pull'
82 name = 'repo-pre-pull'
85
83
86
84
87 class RepoPullEvent(RepoVCSEvent):
85 class RepoPullEvent(RepoVCSEvent):
88 """
86 """
89 An instance of this class is emitted as an :term:`event` after commits
87 An instance of this class is emitted as an :term:`event` after commits
90 are pulled from a repo.
88 are pulled from a repo.
91 """
89 """
92 name = 'repo-pull'
90 name = 'repo-pull'
93
91
94
92
95 class RepoPrePushEvent(RepoVCSEvent):
93 class RepoPrePushEvent(RepoVCSEvent):
96 """
94 """
97 An instance of this class is emitted as an :term:`event` before commits
95 An instance of this class is emitted as an :term:`event` before commits
98 are pushed to a repo.
96 are pushed to a repo.
99 """
97 """
100 name = 'repo-pre-push'
98 name = 'repo-pre-push'
101
99
102
100
103 class RepoPushEvent(RepoVCSEvent):
101 class RepoPushEvent(RepoVCSEvent):
104 """
102 """
105 An instance of this class is emitted as an :term:`event` after commits
103 An instance of this class is emitted as an :term:`event` after commits
106 are pushed to a repo.
104 are pushed to a repo.
107
105
108 :param extras: (optional) dict of data from proxied VCS actions
106 :param extras: (optional) dict of data from proxied VCS actions
109 """
107 """
110 name = 'repo-push'
108 name = 'repo-push'
111
109
112 def __init__(self, repo_name, pushed_commit_ids, extras):
110 def __init__(self, repo_name, pushed_commit_ids, extras):
113 super(RepoPushEvent, self).__init__(repo_name, extras)
111 super(RepoPushEvent, self).__init__(repo_name, extras)
114 self.pushed_commit_ids = pushed_commit_ids
112 self.pushed_commit_ids = pushed_commit_ids
115
113
@@ -1,38 +1,41 b''
1 # Copyright (C) 2016-2016 RhodeCode GmbH
1 # Copyright (C) 2016-2016 RhodeCode GmbH
2 #
2 #
3 # This program is free software: you can redistribute it and/or modify
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
5 # (only), as published by the Free Software Foundation.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU Affero General Public License
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
14 #
15 # This program is dual-licensed. If you wish to learn more about the
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 import mock
19 import mock
20 import decorator
20 import decorator
21
21
22
22
23 def assert_fires_events(*expected_events):
23 class EventCatcher(object):
24 """ Testing decorator to check if the function fires events in order """
24 """ Testing context manager to check if events are fired """
25 def deco(func):
25
26 def wrapper(func, *args, **kwargs):
26 def __init__(self):
27 with mock.patch('rhodecode.events.trigger') as mock_trigger:
27 self.events = [] # the actual events captured
28 result = func(*args, **kwargs)
28 self.event_types = [] # the types of events captured
29
29
30 captured_events = []
30 def __enter__(self):
31 for call in mock_trigger.call_args_list:
31 self.event_trigger_patch = mock.patch('rhodecode.events.trigger')
32 event = call[0][0]
32 self.mocked_event_trigger = self.event_trigger_patch.start()
33 captured_events.append(type(event))
33 return self
34
34
35 assert set(captured_events) == set(expected_events)
35 def __exit__(self, type_, value, traceback):
36 return result
36 self.event_trigger_patch.stop()
37 return decorator.decorator(wrapper, func)
37
38 return deco No newline at end of file
38 for call in self.mocked_event_trigger.call_args_list:
39 event = call[0][0]
40 self.events.append(event)
41 self.event_types.append(type(event))
@@ -1,68 +1,79 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import pytest
21 import pytest
22
22
23 from rhodecode.tests.events.conftest import assert_fires_events
23 from rhodecode.tests.events.conftest import EventCatcher
24
24
25 from rhodecode.lib import hooks_base, utils2
25 from rhodecode.lib import hooks_base, utils2
26 from rhodecode.model.repo import RepoModel
26 from rhodecode.model.repo import RepoModel
27 from rhodecode.events.repo import (
27 from rhodecode.events.repo import (
28 RepoPrePullEvent, RepoPullEvent,
28 RepoPrePullEvent, RepoPullEvent,
29 RepoPrePushEvent, RepoPushEvent,
29 RepoPrePushEvent, RepoPushEvent,
30 RepoPreCreateEvent, RepoCreatedEvent,
30 RepoPreCreateEvent, RepoCreatedEvent,
31 RepoPreDeleteEvent, RepoDeletedEvent,
31 RepoPreDeleteEvent, RepoDeletedEvent,
32 )
32 )
33
33
34
34
35 @pytest.fixture
35 @pytest.fixture
36 def scm_extras(user_regular, repo_stub):
36 def scm_extras(user_regular, repo_stub):
37 extras = utils2.AttributeDict({
37 extras = utils2.AttributeDict({
38 'ip': '127.0.0.1',
38 'ip': '127.0.0.1',
39 'username': user_regular.username,
39 'username': user_regular.username,
40 'action': '',
40 'action': '',
41 'repository': repo_stub.repo_name,
41 'repository': repo_stub.repo_name,
42 'scm': repo_stub.scm_instance().alias,
42 'scm': repo_stub.scm_instance().alias,
43 'config': '',
43 'config': '',
44 'server_url': 'http://example.com',
44 'server_url': 'http://example.com',
45 'make_lock': None,
45 'make_lock': None,
46 'locked_by': [None],
46 'locked_by': [None],
47 'commit_ids': ['a' * 40] * 3,
47 'commit_ids': ['a' * 40] * 3,
48 })
48 })
49 return extras
49 return extras
50
50
51
51
52 @assert_fires_events(
53 RepoPreCreateEvent, RepoCreatedEvent, RepoPreDeleteEvent, RepoDeletedEvent)
54 def test_create_delete_repo_fires_events(backend):
52 def test_create_delete_repo_fires_events(backend):
53 with EventCatcher() as event_catcher:
55 repo = backend.create_repo()
54 repo = backend.create_repo()
55 assert event_catcher.event_types == [RepoPreCreateEvent, RepoCreatedEvent]
56
57 with EventCatcher() as event_catcher:
56 RepoModel().delete(repo)
58 RepoModel().delete(repo)
59 assert event_catcher.event_types == [RepoPreDeleteEvent, RepoDeletedEvent]
57
60
58
61
59 @assert_fires_events(RepoPrePushEvent, RepoPushEvent)
60 def test_pull_fires_events(scm_extras):
62 def test_pull_fires_events(scm_extras):
63 with EventCatcher() as event_catcher:
61 hooks_base.pre_push(scm_extras)
64 hooks_base.pre_push(scm_extras)
65 assert event_catcher.event_types == [RepoPrePushEvent]
66
67 with EventCatcher() as event_catcher:
62 hooks_base.post_push(scm_extras)
68 hooks_base.post_push(scm_extras)
69 assert event_catcher.event_types == [RepoPushEvent]
63
70
64
71
65 @assert_fires_events(RepoPrePullEvent, RepoPullEvent)
66 def test_push_fires_events(scm_extras):
72 def test_push_fires_events(scm_extras):
73 with EventCatcher() as event_catcher:
67 hooks_base.pre_pull(scm_extras)
74 hooks_base.pre_pull(scm_extras)
75 assert event_catcher.event_types == [RepoPrePullEvent]
76
77 with EventCatcher() as event_catcher:
68 hooks_base.post_pull(scm_extras)
78 hooks_base.post_pull(scm_extras)
79 assert event_catcher.event_types == [RepoPullEvent]
General Comments 0
You need to be logged in to leave comments. Login now