1# Copyright 2015 Intel
2# All Rights Reserved.
3#
4#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5#    not use this file except in compliance with the License. You may obtain
6#    a copy of the License at
7#
8#         http://www.apache.org/licenses/LICENSE-2.0
9#
10#    Unless required by applicable law or agreed to in writing, software
11#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13#    License for the specific language governing permissions and limitations
14#    under the License.
15
16import inspect
17
18import mock
19import tooz.coordination
20import tooz.locking
21
22from cinder import coordination
23from cinder import test
24
25if hasattr(inspect, 'getfullargspec'):
26    getargspec = inspect.getfullargspec
27else:
28    getargspec = inspect.getargspec
29
30
31class Locked(Exception):
32    pass
33
34
35class MockToozLock(tooz.locking.Lock):
36    active_locks = set()
37
38    def acquire(self, blocking=True):
39        if self.name not in self.active_locks:
40            self.active_locks.add(self.name)
41            return True
42        elif not blocking:
43            return False
44        else:
45            raise Locked
46
47    def release(self):
48        self.active_locks.remove(self.name)
49
50
51@mock.patch('tooz.coordination.get_coordinator')
52class CoordinatorTestCase(test.TestCase):
53    MOCK_TOOZ = False
54
55    def test_coordinator_start(self, get_coordinator):
56        crd = get_coordinator.return_value
57
58        agent = coordination.Coordinator()
59        agent.start()
60        self.assertTrue(get_coordinator.called)
61        self.assertTrue(crd.start.called)
62
63    def test_coordinator_stop(self, get_coordinator):
64        crd = get_coordinator.return_value
65
66        agent = coordination.Coordinator()
67        agent.start()
68        self.assertIsNotNone(agent.coordinator)
69        agent.stop()
70        self.assertTrue(crd.stop.called)
71        self.assertIsNone(agent.coordinator)
72
73    def test_coordinator_lock(self, get_coordinator):
74        crd = get_coordinator.return_value
75        crd.get_lock.side_effect = lambda n: MockToozLock(n)
76
77        agent1 = coordination.Coordinator()
78        agent1.start()
79        agent2 = coordination.Coordinator()
80        agent2.start()
81
82        lock_name = 'lock'
83        expected_name = lock_name.encode('ascii')
84
85        self.assertNotIn(expected_name, MockToozLock.active_locks)
86        with agent1.get_lock(lock_name):
87            self.assertIn(expected_name, MockToozLock.active_locks)
88            self.assertRaises(Locked, agent1.get_lock(lock_name).acquire)
89            self.assertRaises(Locked, agent2.get_lock(lock_name).acquire)
90        self.assertNotIn(expected_name, MockToozLock.active_locks)
91
92    def test_coordinator_offline(self, get_coordinator):
93        crd = get_coordinator.return_value
94        crd.start.side_effect = tooz.coordination.ToozConnectionError('err')
95
96        agent = coordination.Coordinator()
97        self.assertRaises(tooz.coordination.ToozError, agent.start)
98        self.assertFalse(agent.started)
99
100
101@mock.patch.object(coordination.COORDINATOR, 'get_lock')
102class CoordinationTestCase(test.TestCase):
103    def test_synchronized(self, get_lock):
104        @coordination.synchronized('lock-{f_name}-{foo.val}-{bar[val]}')
105        def func(foo, bar):
106            pass
107
108        foo = mock.Mock()
109        foo.val = 7
110        bar = mock.MagicMock()
111        bar.__getitem__.return_value = 8
112        func(foo, bar)
113        get_lock.assert_called_with('lock-func-7-8')
114        self.assertEqual(['foo', 'bar'], getargspec(func)[0])
115