Merge branch '2881-node-manager'
[arvados.git] / services / nodemanager / tests / test_clientactor.py
1 #!/usr/bin/env python
2
3 from __future__ import absolute_import, print_function
4
5 import unittest
6
7 import mock
8 import pykka
9
10 import arvnodeman.clientactor as clientactor
11 from . import testutil
12
13 class RemotePollLoopActorTestCase(testutil.RemotePollLoopActorTestMixin,
14                                   unittest.TestCase):
15     class MockClientError(Exception):
16         pass
17
18     class TestActor(clientactor.RemotePollLoopActor):
19         LOGGER_NAME = 'arvnodeman.testpoll'
20
21         def _send_request(self):
22             return self._client()
23     TestActor.CLIENT_ERRORS = (MockClientError,)
24     TEST_CLASS = TestActor
25
26
27     def build_monitor(self, side_effect, *args, **kwargs):
28         super(RemotePollLoopActorTestCase, self).build_monitor(*args, **kwargs)
29         self.client.side_effect = side_effect
30
31     def test_poll_loop_starts_after_subscription(self):
32         self.build_monitor(['test1'])
33         self.monitor.subscribe(self.subscriber)
34         self.wait_for_call(self.subscriber)
35         self.subscriber.assert_called_with('test1')
36         self.wait_for_call(self.timer.schedule)
37
38     def test_poll_loop_continues_after_failure(self):
39         self.build_monitor(self.MockClientError)
40         self.monitor.subscribe(self.subscriber)
41         self.wait_for_call(self.timer.schedule)
42         self.assertTrue(self.monitor.actor_ref.is_alive(),
43                         "poll loop died after error")
44         self.assertFalse(self.subscriber.called,
45                          "poll loop notified subscribers after error")
46
47     def test_late_subscribers_get_responses(self):
48         self.build_monitor(['late_test'])
49         self.monitor.subscribe(lambda response: None)
50         self.monitor.subscribe(self.subscriber)
51         self.monitor.poll()
52         self.wait_for_call(self.subscriber)
53         self.subscriber.assert_called_with('late_test')
54
55     def test_survive_dead_subscriptions(self):
56         self.build_monitor(['survive1', 'survive2'])
57         dead_subscriber = mock.Mock(name='dead_subscriber')
58         dead_subscriber.side_effect = pykka.ActorDeadError
59         self.monitor.subscribe(dead_subscriber)
60         self.wait_for_call(dead_subscriber)
61         self.monitor.subscribe(self.subscriber)
62         self.monitor.poll()
63         self.wait_for_call(self.subscriber)
64         self.subscriber.assert_called_with('survive2')
65         self.assertTrue(self.monitor.actor_ref.is_alive(),
66                         "poll loop died from dead subscriber")
67
68     def test_no_subscriptions_by_key_without_support(self):
69         self.build_monitor([])
70         with self.assertRaises(AttributeError):
71             self.monitor.subscribe_to('key')
72
73
74 class RemotePollLoopActorWithKeysTestCase(testutil.RemotePollLoopActorTestMixin,
75                                           unittest.TestCase):
76     class TestActor(RemotePollLoopActorTestCase.TestActor):
77         def _item_key(self, item):
78             return item['key']
79     TEST_CLASS = TestActor
80
81
82     def build_monitor(self, side_effect, *args, **kwargs):
83         super(RemotePollLoopActorWithKeysTestCase, self).build_monitor(
84             *args, **kwargs)
85         self.client.side_effect = side_effect
86
87     def test_key_subscription(self):
88         self.build_monitor([[{'key': 1}, {'key': 2}]])
89         self.monitor.subscribe_to(2, self.subscriber)
90         self.wait_for_call(self.subscriber)
91         self.subscriber.assert_called_with({'key': 2})
92
93     def test_survive_dead_key_subscriptions(self):
94         item = {'key': 3}
95         self.build_monitor([[item], [item]])
96         dead_subscriber = mock.Mock(name='dead_subscriber')
97         dead_subscriber.side_effect = pykka.ActorDeadError
98         self.monitor.subscribe_to(3, dead_subscriber)
99         self.wait_for_call(dead_subscriber)
100         self.monitor.subscribe_to(3, self.subscriber)
101         self.monitor.poll()
102         self.wait_for_call(self.subscriber)
103         self.subscriber.assert_called_with(item)
104         self.assertTrue(self.monitor.actor_ref.is_alive(),
105                         "poll loop died from dead key subscriber")
106
107     def test_mixed_subscriptions(self):
108         item = {'key': 4}
109         self.build_monitor([[item], [item]])
110         key_subscriber = mock.Mock(name='key_subscriber')
111         self.monitor.subscribe(self.subscriber)
112         self.monitor.subscribe_to(4, key_subscriber)
113         self.monitor.poll()
114         self.wait_for_call(self.subscriber)
115         self.subscriber.assert_called_with([item])
116         key_subscriber.assert_called_with(item)
117
118     def test_subscription_to_missing_key(self):
119         self.build_monitor([[]])
120         self.monitor.subscribe_to('nonesuch', self.subscriber)
121         self.wait_for_call(self.subscriber)
122         self.subscriber.assert_called_with(None)
123
124
125 if __name__ == '__main__':
126     unittest.main()
127