testNodes.py 9.54 KB
Newer Older
1
#
2
# Copyright (C) 2009-2019  Nexedi SA
3
#
4 5 6 7
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
8
#
9 10 11 12 13 14
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

17
import shutil
18
import unittest
19
from .mock import Mock
20
from neo.lib.protocol import NodeTypes, NodeStates
21
from neo.lib.node import Node, MasterDB
22
from . import NeoUnitTestBase, getTempDirectory
23
from time import time
24
from os import chmod, mkdir, rmdir
25
from os.path import join, exists
26

27
class NodesTests(NeoUnitTestBase):
28 29

    def setUp(self):
30
        NeoUnitTestBase.setUp(self)
31
        self.nm = Mock()
32

33 34
    def testInit(self):
        """ Check the node initialization """
35
        address = ('127.0.0.1', 10000)
36
        uuid = self.getNewUUID(None)
37
        node = Node(self.nm, address=address, uuid=uuid)
38
        self.assertEqual(node.getState(), NodeStates.DOWN)
39
        self.assertEqual(node.getAddress(), address)
40
        self.assertEqual(node.getUUID(), uuid)
41
        self.assertTrue(time() - 1 < node.getLastStateChange() < time())
42 43 44

    def testState(self):
        """ Check if the last changed time is updated when state is changed """
45
        node = Node(self.nm)
46
        self.assertEqual(node.getState(), NodeStates.DOWN)
47 48
        self.assertTrue(time() - 1 < node.getLastStateChange() < time())
        previous_time = node.getLastStateChange()
49 50
        node.setState(NodeStates.RUNNING)
        self.assertEqual(node.getState(), NodeStates.RUNNING)
51 52 53
        self.assertTrue(previous_time < node.getLastStateChange())
        self.assertTrue(time() - 1 < node.getLastStateChange() < time())

54
class NodeManagerTests(NeoUnitTestBase):
55

56
    def _addStorage(self):
57 58
        self.storage = self.nm.createStorage(
            address=('127.0.0.1', 1000), uuid=self.getStorageUUID())
59 60

    def _addMaster(self):
61 62
        self.master = self.nm.createMaster(
            address=('127.0.0.1', 2000), uuid=self.getMasterUUID())
63 64

    def _addClient(self):
65
        self.client = self.nm.createClient(uuid=self.getClientUUID())
66 67

    def _addAdmin(self):
68 69
        self.admin = self.nm.createAdmin(
            address=('127.0.0.1', 4000), uuid=self.getAdminUUID())
70 71

    def checkNodes(self, node_list):
72
        self.assertEqual(sorted(self.nm.getList()), sorted(node_list))
73 74

    def checkMasters(self, master_list):
75
        self.assertEqual(self.nm.getMasterList(), master_list)
76 77

    def checkStorages(self, storage_list):
78
        self.assertEqual(self.nm.getStorageList(), storage_list)
79 80

    def checkClients(self, client_list):
81
        self.assertEqual(self.nm.getClientList(), client_list)
82 83

    def checkByServer(self, node):
84
        self.assertEqual(node, self.nm.getByAddress(node.getAddress()))
85

86
    def checkByUUID(self, node):
87
        self.assertEqual(node, self.nm.getByUUID(node.getUUID()))
88

89 90
    def testInit(self):
        """ Check the manager is empty when started """
91
        manager = self.nm
92 93 94 95
        self.checkNodes([])
        self.checkMasters([])
        self.checkStorages([])
        self.checkClients([])
96 97
        address = ('127.0.0.1', 10000)
        self.assertEqual(manager.getByAddress(address), None)
98
        self.assertEqual(manager.getByAddress(None), None)
99
        uuid = self.getNewUUID(None)
100 101
        self.assertEqual(manager.getByUUID(uuid), None)
        self.assertEqual(manager.getByUUID(None), None)
102 103 104

    def testAdd(self):
        """ Check if new nodes are registered in the manager """
105
        manager = self.nm
106 107
        self.checkNodes([])
        # storage
108
        self._addStorage()
109 110 111 112 113 114 115
        self.checkNodes([self.storage])
        self.checkStorages([self.storage])
        self.checkMasters([])
        self.checkClients([])
        self.checkByServer(self.storage)
        self.checkByUUID(self.storage)
        # master
116
        self._addMaster()
117 118 119 120 121 122 123
        self.checkNodes([self.storage, self.master])
        self.checkStorages([self.storage])
        self.checkMasters([self.master])
        self.checkClients([])
        self.checkByServer(self.master)
        self.checkByUUID(self.master)
        # client
124
        self._addClient()
125 126 127 128
        self.checkNodes([self.storage, self.master, self.client])
        self.checkStorages([self.storage])
        self.checkMasters([self.master])
        self.checkClients([self.client])
129 130
        # client node has no address
        self.assertEqual(manager.getByAddress(self.client.getAddress()), None)
131 132
        self.checkByUUID(self.client)
        # admin
133
        self._addAdmin()
134 135 136 137 138 139 140 141 142 143
        self.checkNodes([self.storage, self.master, self.client, self.admin])
        self.checkStorages([self.storage])
        self.checkMasters([self.master])
        self.checkClients([self.client])
        self.checkByServer(self.admin)
        self.checkByUUID(self.admin)

    def testUpdate(self):
        """ Check manager content update """
        # set up four nodes
144
        manager = self.nm
145 146 147 148
        self._addMaster()
        self._addStorage()
        self._addClient()
        self._addAdmin()
149 150 151 152 153
        self.checkNodes([self.master, self.storage, self.client, self.admin])
        self.checkMasters([self.master])
        self.checkStorages([self.storage])
        self.checkClients([self.client])
        # build changes
154
        old_address = self.master.getAddress()
155
        new_address = ('127.0.0.1', 2001)
156
        old_uuid = self.storage.getUUID()
157
        new_uuid = self.getStorageUUID()
158
        node_list = (
159
            (NodeTypes.CLIENT, None, self.client.getUUID(), NodeStates.UNKNOWN, None),
160
            (NodeTypes.MASTER, new_address, self.master.getUUID(), NodeStates.RUNNING, None),
161
            (NodeTypes.STORAGE, self.storage.getAddress(), new_uuid,
162
                NodeStates.RUNNING, None),
163
            (NodeTypes.ADMIN, self.admin.getAddress(), self.admin.getUUID(),
164
                NodeStates.DOWN, None),
165
        )
166
        app = Mock()
167
        app.pt = Mock({'dropNode': True})
168
        # update manager content
169
        manager.update(app, time(), node_list)
170 171 172 173
        # - the client gets down
        self.checkClients([])
        # - master change it's address
        self.checkMasters([self.master])
174
        self.assertEqual(manager.getByAddress(old_address), None)
175
        self.master.setAddress(new_address)
176
        self.checkByServer(self.master)
177
        # - storage change it's UUID
178 179 180 181
        storage_list = manager.getStorageList()
        self.assertTrue(len(storage_list), 1)
        new_storage = storage_list[0]
        self.assertNotEqual(new_storage.getUUID(), old_uuid)
182
        self.assertEqual(new_storage.getState(), NodeStates.RUNNING)
183
        # admin is still here but in DOWN state
184
        self.checkNodes([self.master, self.admin, new_storage])
185
        self.assertEqual(self.admin.getState(), NodeStates.DOWN)
186

187 188 189 190
class MasterDBTests(NeoUnitTestBase):

    def testInitialAccessRights(self):
        """
191
        Verify MasterDB raises immediately on instantiation if it cannot
192 193 194 195 196 197
        create a non-existing database. This does not guarantee any later
        open will succeed, but makes the simple error case obvious.
        """
        temp_dir = getTempDirectory()
        directory = join(temp_dir, 'read_only')
        db_file = join(directory, 'not_created')
198
        mkdir(directory, 0500)
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
        try:
            self.assertRaises(IOError, MasterDB, db_file)
        finally:
            rmdir(directory)

    def testLaterAccessRights(self):
        """
        Verify MasterDB does not raise when modifying database.
        """
        temp_dir = getTempDirectory()
        directory = join(temp_dir, 'read_write')
        db_file = join(directory, 'db')
        mkdir(directory)
        try:
            db = MasterDB(db_file)
            self.assertTrue(exists(db_file), db_file)
215
            chmod(directory, 0500)
216 217
            address = ('example.com', 1024)
            # Must not raise
218
            db.addremove(None, address)
219
            # Value is stored
220
            self.assertIn(address, db)
221 222
            # But not visible to a new db instance (write access restored so
            # it can be created)
223
            chmod(directory, 0700)
224
            db2 = MasterDB(db_file)
225
            self.assertNotIn(address, db2)
226
        finally:
227
            shutil.rmtree(directory)
228 229 230 231 232 233 234 235 236 237

    def testPersistence(self):
        temp_dir = getTempDirectory()
        directory = join(temp_dir, 'read_write')
        db_file = join(directory, 'db')
        mkdir(directory)
        try:
            db = MasterDB(db_file)
            self.assertTrue(exists(db_file), db_file)
            address = ('example.com', 1024)
238
            db.addremove(None, address)
239
            address2 = ('example.org', 1024)
240
            db.addremove(None, address2)
241 242
            # Values are visible to a new db instance
            db2 = MasterDB(db_file)
243 244 245
            self.assertIn(address, db2)
            self.assertIn(address2, db2)
            db.addremove(address, None)
246
            # Create yet another instance (file is not supposed to be shared)
247 248 249 250 251 252
            db2 = MasterDB(db_file)
            self.assertNotIn(address, db2)
            self.assertIn(address2, db2)
            db.remove(address2)
            # and again, to test remove()
            self.assertNotIn(address2, MasterDB(db_file))
253
        finally:
254
            shutil.rmtree(directory)
255

256 257 258
if __name__ == '__main__':
    unittest.main()