testStorageOperation.py 44.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#
# Copyright (C) 2009  Nexedi SA
# 
# 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.
# 
# 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
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

import os
import unittest
import logging
import MySQLdb
from tempfile import mkstemp
23
from struct import pack, unpack
24 25 26 27 28 29 30
from mock import Mock
from collections import deque
from neo.master.app import MasterNode
from neo.storage.app import Application, StorageNode
from neo.storage.operation import TransactionInformation, OperationEventHandler
from neo.exception import PrimaryFailure, OperationFailure
from neo.pt import PartitionTable
31
from neo import protocol
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
from neo.protocol import *

SQL_ADMIN_USER = 'root'
SQL_ADMIN_PASSWORD = None
NEO_SQL_USER = 'test'
NEO_SQL_DATABASE = 'test_neo1'

class StorageOperationTests(unittest.TestCase):

    def getNewUUID(self):
        uuid = INVALID_UUID
        while uuid == INVALID_UUID:
            uuid = os.urandom(16)
        self.uuid = uuid
        return uuid

    def getTwoIDs(self):
        # generate two ptid, first is lower
        ptids = self.getNewUUID(), self.getNewUUID()
        return min(ptids), max(ptids)
        ptid = min(ptids)

54 55 56 57
    def checkProtocolErrorRaised(self, method, *args, **kwargs):
        """ Check if the ProtocolError exception was raised """
        self.assertRaises(protocol.ProtocolError, method, *args, **kwargs)

58 59
    def checkUnexpectedPacketRaised(self, method, *args, **kwargs):
        """ Check if the UnexpectedPacketError exception wxas raised """
60
        self.assertRaises(protocol.UnexpectedPacketError, method, *args, **kwargs)
61 62 63 64 65

    def checkIdenficationRequired(self, method, *args, **kwargs):
        """ Check is the identification_required decorator is applied """
        self.checkUnexpectedPacketRaised(method, *args, **kwargs)

66 67 68 69
    def checkBrokenNotDisallowedErrorRaised(self, method, *args, **kwargs):
        """ Check if the BrokenNotDisallowedError exception wxas raised """
        self.assertRaises(protocol.BrokenNotDisallowedError, method, *args, **kwargs)

70 71 72 73
    def checkNotReadyErrorRaised(self, method, *args, **kwargs):
        """ Check if the NotReadyError exception wxas raised """
        self.assertRaises(protocol.NotReadyError, method, *args, **kwargs)

74 75
    def checkCalledAbort(self, conn, packet_number=0):
        """Check the abort method has been called and an error packet has been sent"""
76
        # sometimes we answer an error, sometimes we just send it
77
        notify_calls_len = len(conn.mockGetNamedCalls("notify"))
78
        answer_calls_len = len(conn.mockGetNamedCalls('answer'))
79
        self.assertEquals(notify_calls_len + answer_calls_len, 1)
80 81
        self.assertEquals(len(conn.mockGetNamedCalls("abort")), 1)
        self.assertEquals(len(conn.mockGetNamedCalls("expectMessage")), 0)
82 83
        if notify_calls_len == 1:
            call = conn.mockGetNamedCalls("notify")[packet_number]
84 85
        else:
            call = conn.mockGetNamedCalls("answer")[packet_number]
86 87 88 89 90
        packet = call.getParam(0)
        self.assertTrue(isinstance(packet, Packet))
        self.assertEquals(packet.getType(), ERROR)

    def checkPacket(self, conn, packet_type=ERROR):
91 92
        self.assertEquals(len(conn.mockGetNamedCalls("answer")), 1)
        call = conn.mockGetNamedCalls("answer")[0]
93 94 95 96 97 98 99
        packet = call.getParam(0)
        self.assertTrue(isinstance(packet, Packet))
        self.assertEquals(packet.getType(), packet_type)

    def checkHandleUnexpectedPacket(self, _call, _msg_type, _listening=True, **kwargs):
        conn = Mock({ 
            "getAddress" : ("127.0.0.1", self.master_port), 
100
            "isServerConnection": _listening,    
101
        })
102
        packet = Packet(msg_type=_msg_type)
103 104
        # hook
        self.operation.peerBroken = lambda c: c.peerBrokendCalled()
105
        self.checkUnexpectedPacketRaised(_call, conn=conn, packet=packet, **kwargs)
106

107 108 109 110
    def checkNoPacketSent(self, conn):
        # no packet should be sent
        self.assertEquals(len(conn.mockGetNamedCalls('addPacket')), 0)

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
    def setUp(self):
        logging.basicConfig(level = logging.ERROR)
        # create an application object
        config_file_text = """# Default parameters.
[DEFAULT]
# The list of master nodes.
master_nodes: 127.0.0.1:10010 
# The number of replicas.
replicas: 2
# The number of partitions.
partitions: 1009
# The name of this cluster.
name: main
# The user name for the database.
user: %(user)s
connector : SocketConnector
# The first master.
[mastertest]
server: 127.0.0.1:10010

[storagetest]
database: %(database)s
server: 127.0.0.1:10020
""" % {
    'database': NEO_SQL_DATABASE,
    'user': NEO_SQL_USER,
}
        # SQL connection
        connect_arg_dict = {'user': SQL_ADMIN_USER}
        if SQL_ADMIN_PASSWORD is not None:
            connect_arg_dict['passwd'] = SQL_ADMIN_PASSWORD
        sql_connection = MySQLdb.Connect(**connect_arg_dict)
        cursor = sql_connection.cursor()
        # new database
        cursor.execute('DROP DATABASE IF EXISTS %s' % (NEO_SQL_DATABASE, ))
        cursor.execute('CREATE DATABASE %s' % (NEO_SQL_DATABASE, ))
147 148
        cursor.execute('GRANT ALL ON %s.* TO "%s"@"localhost" IDENTIFIED BY ""' % 
                (NEO_SQL_DATABASE, NEO_SQL_USER))
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
        # config file
        tmp_id, self.tmp_path = mkstemp()
        tmp_file = os.fdopen(tmp_id, "w+b")
        tmp_file.write(config_file_text)
        tmp_file.close()
        # main application
        self.app = Application(self.tmp_path, "storagetest")        
        self.app.num_partitions = 1
        self.app.num_replicas = 1
        self.app.transaction_dict = {}
        self.app.store_lock_dict = {}
        self.app.load_lock_dict = {}
        self.app.event_queue = deque()
        for server in self.app.master_node_list:
            master = MasterNode(server = server)
            self.app.nm.add(master)
        # handler
        self.operation = OperationEventHandler(self.app)
        # set pmn
        self.master_uuid = self.getNewUUID()
        pmn = self.app.nm.getMasterNodeList()[0]
        pmn.setUUID(self.master_uuid)
        self.app.primary_master_node = pmn
        self.master_port = 10010

    def tearDown(self):
175
        os.remove(self.tmp_path)
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196

    def test_01_TransactionInformation(self):
        uuid = self.getNewUUID()
        transaction = TransactionInformation(uuid)
        # uuid
        self.assertEquals(transaction._uuid, uuid)
        self.assertEquals(transaction.getUUID(), uuid)
        # objects
        self.assertEquals(transaction._object_dict, {})
        object = (self.getNewUUID(), 1, 2, 3, )
        transaction.addObject(*object)
        objects = transaction.getObjectList()
        self.assertEquals(len(objects), 1)
        self.assertEquals(objects[0], object)
        # transactions
        self.assertEquals(transaction._transaction, None)
        t = ((1, 2, 3), 'user', 'desc', '')
        transaction.addTransaction(*t)
        self.assertEquals(transaction.getTransaction(), t)

    def test_02_connectionCompleted(self):
197
        # not (yet) implemented
198 199 200 201 202
        conn = Mock()
        self.assertRaises(NotImplementedError, 
                self.operation.connectionCompleted, conn)

    def test_03_connectionFailed(self):
203
        # not (yet) implemented
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
        conn = Mock()
        self.assertRaises(NotImplementedError, 
                self.operation.connectionFailed, conn)

    def test_04_connectionAccepted(self):
        uuid = self.getNewUUID()
        event_manager = Mock({'register': None})
        conn = Mock({"getUUID" : uuid,
                     "getAddress" : ("127.0.0.1", self.master_port),
                     "getHandler" : self.operation,
                     "getEventManager": event_manager,
        })
        connector = Mock({ })
        addr = ("127.0.0.1", self.master_port)
        self.operation.connectionAccepted(conn, connector, addr)
        # check call to subclass
        self.assertEquals(len(conn.mockGetNamedCalls("getHandler")), 1)
        self.assertEquals(len(conn.mockGetNamedCalls("getEventManager")), 1)
222
        self.checkNoPacketSent(conn)
223 224

    def test_05_dealWithClientFailure(self):
225
        # check if client's transaction are cleaned
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
        uuid = self.getNewUUID()
        from neo.node import ClientNode
        client = ClientNode(('127.0.0.1', 10010))
        client.setUUID(uuid)
        self.app.nm.add(client)
        self.app.store_lock_dict[0] = object()
        transaction = Mock({
            'getUUID': uuid,
            'getObjectList': ((0, ), ),
        })
        self.app.transaction_dict[0] = transaction
        self.assertTrue(1 not in self.app.store_lock_dict)
        self.assertTrue(1 not in self.app.transaction_dict)
        self.operation.dealWithClientFailure(uuid)
        # objects and transaction removed
        self.assertTrue(0 not in self.app.store_lock_dict)
        self.assertTrue(0 not in self.app.transaction_dict)

    def test_06_timeoutExpired(self):
        # server connection
        conn = Mock({
247
            "isServerConnection": True, 
248 249 250
            "getAddress" : ("127.0.0.1", self.master_port),
        })
        self.operation.timeoutExpired(conn)
251
        self.assertEquals(len(conn.mockGetNamedCalls('isServerConnection')), 1)
252
        self.assertEquals(len(conn.mockGetNamedCalls('getUUID')), 1)
253
        self.checkNoPacketSent(conn)
254 255 256
        # client connection
        conn = Mock({
            "getUUID": self.master_uuid,
257
            "isServerConnection": False, 
258 259 260
            "getAddress" : ("127.0.0.1", self.master_port),
        })
        self.assertRaises(PrimaryFailure, self.operation.timeoutExpired, conn)
261
        self.assertEquals(len(conn.mockGetNamedCalls('isServerConnection')), 1)
262
        self.assertEquals(len(conn.mockGetNamedCalls('getUUID')), 1)
263
        self.checkNoPacketSent(conn)
264 265 266
        # connection with another storage node
        conn = Mock({
            "getUUID": self.getNewUUID(),
267
            "isServerConnection": False, 
268 269 270
            "getAddress" : ("127.0.0.1", self.master_port),
        })
        self.assertRaises(NotImplementedError, self.operation.timeoutExpired, conn)
271
        self.assertEquals(len(conn.mockGetNamedCalls('isServerConnection')), 1)
272
        self.assertEquals(len(conn.mockGetNamedCalls('getUUID')), 1)
273
        self.checkNoPacketSent(conn)
274 275 276 277

    def test_07_connectionClosed1(self):
        # server connection
        conn = Mock({
278
            "isServerConnection": True, 
279 280 281
            "getAddress" : ("127.0.0.1", self.master_port),
        })
        self.operation.connectionClosed(conn)
282
        self.assertEquals(len(conn.mockGetNamedCalls('isServerConnection')), 1)
283
        self.assertEquals(len(conn.mockGetNamedCalls('getUUID')), 1)
284
        self.checkNoPacketSent(conn)
285 286

    def test_07_connectionClosed2(self):
287
        # primary has closed the connection
288 289
        conn = Mock({
            "getUUID": self.master_uuid,
290
            "isServerConnection": False, 
291 292 293 294
            "getAddress" : ("127.0.0.1", self.master_port),
        })
        self.assertRaises(PrimaryFailure,
                self.operation.connectionClosed, conn)
295
        self.assertEquals(len(conn.mockGetNamedCalls('isServerConnection')), 1)
296
        self.assertEquals(len(conn.mockGetNamedCalls('getUUID')), 1)
297
        self.checkNoPacketSent(conn)
298 299

    def test_07_connectionClosed3(self):
300
        # listening connection with a storage node
301 302
        conn = Mock({
            "getUUID": self.getNewUUID(),
303
            "isServerConnection": False, 
304 305 306
            "getAddress" : ("127.0.0.1", self.master_port),
        })
        self.assertRaises(NotImplementedError, self.operation.connectionClosed, conn)
307
        self.assertEquals(len(conn.mockGetNamedCalls('isServerConnection')), 1)
308
        self.assertEquals(len(conn.mockGetNamedCalls('getUUID')), 1)
309
        self.checkNoPacketSent(conn)
310 311 312 313

    def test_08_peerBroken(self):
        # server connection
        conn = Mock({
314
            "isServerConnection": True, 
315 316 317
            "getAddress" : ("127.0.0.1", self.master_port),
        })
        self.operation.peerBroken(conn)
318
        self.assertEquals(len(conn.mockGetNamedCalls('isServerConnection')), 1)
319
        self.assertEquals(len(conn.mockGetNamedCalls('getUUID')), 1)
320
        self.checkNoPacketSent(conn)
321 322 323
        # client connection
        conn = Mock({
            "getUUID": self.master_uuid,
324
            "isServerConnection": False, 
325 326 327 328
            "getAddress" : ("127.0.0.1", self.master_port),
        })
        self.assertRaises(PrimaryFailure,
                self.operation.peerBroken, conn)
329
        self.assertEquals(len(conn.mockGetNamedCalls('isServerConnection')), 1)
330
        self.assertEquals(len(conn.mockGetNamedCalls('getUUID')), 1)
331
        self.checkNoPacketSent(conn)
332 333 334
        # connection with another storage node
        conn = Mock({
            "getUUID": self.getNewUUID(),
335
            "isServerConnection": False, 
336 337 338
            "getAddress" : ("127.0.0.1", self.master_port),
        })
        self.assertRaises(NotImplementedError, self.operation.peerBroken, conn)
339
        self.assertEquals(len(conn.mockGetNamedCalls('isServerConnection')), 1)
340
        self.assertEquals(len(conn.mockGetNamedCalls('getUUID')), 1)
341
        self.checkNoPacketSent(conn)
342 343 344

    def test_09_handleRequestNodeIdentification1(self):
        # reject client connection
345
        count = len(self.app.nm.getNodeList())
346 347 348 349 350 351 352 353 354
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleRequestNodeIdentification, 
            _listening=False,
            _msg_type=REQUEST_NODE_IDENTIFICATION,
            node_type=MASTER_NODE_TYPE,
            uuid=self.getNewUUID(),
            ip_address='127.0.0.1',
            port=self.master_port,
            name=self.app.name)
355
        self.assertEquals(len(self.app.nm.getNodeList()), count)
356 357 358 359

    def test_09_handleRequestNodeIdentification2(self):
        # bad app name
        uuid = self.getNewUUID()
360
        packet = Packet(msg_type=REQUEST_NODE_IDENTIFICATION)
361 362
        conn = Mock({
            "getUUID": uuid,
363
            "isServerConnection": True, 
364 365
            "getAddress" : ("127.0.0.1", self.master_port),
        })
366
        count = len(self.app.nm.getNodeList())
367 368
        self.checkProtocolErrorRaised(
            self.operation.handleRequestNodeIdentification,
369 370 371 372 373 374 375
            conn=conn,
            packet=packet, 
            node_type=MASTER_NODE_TYPE, 
            uuid=uuid,
            ip_address='127.0.0.1',
            port=self.master_port, 
            name='INVALID_NAME')
376
        self.assertEquals(len(self.app.nm.getNodeList()), count)
377 378 379 380 381

    def test_09_handleRequestNodeIdentification3(self):
        # broken node
        uuid = self.getNewUUID()
        self.app.primary_master_node.setState(BROKEN_STATE)
382
        packet = Packet(msg_type=REQUEST_NODE_IDENTIFICATION)
383 384
        conn = Mock({
            "getUUID": uuid,
385
            "isServerConnection": True, 
386 387
            "getAddress" : ("127.0.0.1", self.master_port),
        })
388
        count = len(self.app.nm.getNodeList())
389 390
        self.checkBrokenNotDisallowedErrorRaised(
            self.operation.handleRequestNodeIdentification,
391 392 393 394 395 396 397
            conn=conn,
            packet=packet, 
            node_type=MASTER_NODE_TYPE, 
            uuid=self.master_uuid,
            ip_address='127.0.0.1',
            port=self.master_port, 
            name=self.app.name)
398
        self.assertEquals(len(self.app.nm.getNodeList()), count)
399 400 401

    def test_09_handleRequestNodeIdentification4(self):
        # new non-master, rejected
402
        packet = Packet(msg_type=REQUEST_NODE_IDENTIFICATION)
403
        conn = Mock({
404
            "isServerConnection": True,
405 406
            "getAddress" : ("127.0.0.1", self.master_port), 
        })
407
        count = len(self.app.nm.getNodeList())
408 409
        self.checkNotReadyErrorRaised(
            self.operation.handleRequestNodeIdentification,
410 411 412 413 414 415 416
            conn=conn,
            uuid=self.getNewUUID(),
            packet=packet, 
            port=self.master_port,
            node_type=STORAGE_NODE_TYPE,
            ip_address='192.168.1.1',
            name=self.app.name,)
417
        self.assertEquals(len(self.app.nm.getNodeList()), count)
418 419 420 421

    def test_09_handleRequestNodeIdentification5(self):
        # new master, accepted
        uuid = self.getNewUUID()
422
        packet = Packet(msg_type=REQUEST_NODE_IDENTIFICATION)
423
        conn = Mock({
424
            "isServerConnection": True,
425 426 427 428 429 430 431 432 433 434 435 436 437
            "getAddress" : ("127.0.0.1", self.master_port), 
        })
        count = len(self.app.nm.getNodeList())
        self.operation.handleRequestNodeIdentification(
            conn=conn,
            uuid=uuid,
            packet=packet, 
            port=self.master_port,
            node_type=MASTER_NODE_TYPE,
            ip_address='192.168.1.1',
            name=self.app.name,)
        # node added
        self.assertEquals(len(self.app.nm.getNodeList()), count + 1)
438 439 440
        n = self.app.nm.getNodeByServer(('192.168.1.1', self.master_port))
        self.assertNotEquals(n, None)
        self.assertEquals(n.getUUID(), uuid)
441 442 443 444 445 446 447 448 449 450
        self.checkPacket(conn, packet_type=ACCEPT_NODE_IDENTIFICATION)
        # uuid
        self.assertEquals(len(conn.mockGetNamedCalls("setUUID")), 1)
        call = conn.mockGetNamedCalls("setUUID")[0]
        self.assertEquals(call.getParam(0), uuid)
        # abort
        self.assertEquals(len(conn.mockGetNamedCalls('abort')), 1)

    def test_09_handleRequestNodeIdentification6(self):
        # not new & accepted
451
        packet = Packet(msg_type=REQUEST_NODE_IDENTIFICATION)
452
        conn = Mock({
453
            "isServerConnection": True,
454 455
            "getAddress" : ("127.0.0.1", self.master_port), 
        })
456 457 458
        mn = self.app.nm.getNodeByServer(('127.0.0.1', self.master_port))
        uuid = self.getNewUUID()
        mn.setUUID(uuid)
459 460 461
        count = len(self.app.nm.getNodeList())
        self.operation.handleRequestNodeIdentification(
            conn=conn,
462
            uuid=self.uuid,
463 464 465 466 467 468 469 470 471 472 473
            packet=packet, 
            port=self.master_port,
            node_type=STORAGE_NODE_TYPE,
            ip_address='127.0.0.1',
            name=self.app.name,)
        # no new node
        self.assertEquals(len(self.app.nm.getNodeList()), count)
        self.checkPacket(conn, packet_type=ACCEPT_NODE_IDENTIFICATION)
        # uuid
        self.assertEquals(len(conn.mockGetNamedCalls("setUUID")), 1)
        call = conn.mockGetNamedCalls("setUUID")[0]
474 475
        self.assertEquals(call.getParam(0), self.uuid)
        self.assertEquals(mn.getUUID(), self.uuid)
476 477 478 479 480 481
        # abort
        self.assertEquals(len(conn.mockGetNamedCalls('abort')), 0)

    def test_10_handleAcceptNodeIdentification1(self):
        # client connection not implemented
        conn = Mock({
482
            "isServerConnection": False,
483 484
            "getAddress" : ("127.0.0.1", self.master_port), 
        })
485
        packet = Packet(msg_type=ACCEPT_NODE_IDENTIFICATION)
486 487 488 489 490 491 492 493 494
        self.assertRaises(NotImplementedError,
            self.operation.handleAcceptNodeIdentification,
            conn=conn,
            packet=packet,
            node_type=MASTER_NODE_TYPE,
            uuid=self.getNewUUID(),
            ip_address='127.0.0.1',
            port=self.master_port,
            num_partitions=self.app.num_partitions,
495 496 497
            num_replicas=self.app.num_replicas,
            your_uuid=INVALID_UUID,
        )
498 499 500 501 502 503 504 505 506 507 508 509

    def test_10_handleAcceptNodeIdentification2(self):
        # server connection rejected
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleAcceptNodeIdentification,
            _msg_type=ACCEPT_NODE_IDENTIFICATION,
            _listening=True, 
            node_type=MASTER_NODE_TYPE,
            uuid=self.getNewUUID(),
            ip_address='127.0.0.1',
            port=self.master_port,
            num_partitions=self.app.num_partitions,
510 511
            num_replicas=self.app.num_replicas,
            your_uuid=INVALID_UUID,
512 513 514
        )

    def test_11_handleAnswerPrimaryMaster(self):
515
        # unexpected packet
516 517 518 519 520 521 522 523
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleAnswerPrimaryMaster,
            _msg_type=ANSWER_PRIMARY_MASTER,
            primary_uuid=self.getNewUUID(),
            known_master_list=()
        )

    def test_11_handleAskLastIDs(self):
524
        # unexpected packet
525 526 527 528 529 530
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleAskLastIDs,
            _msg_type=ASK_LAST_IDS,
        )

    def test_12_handleAskPartitionTable(self):
531
        # unexpected packet
532 533 534 535 536 537 538
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleAskPartitionTable,
            _msg_type=ASK_PARTITION_TABLE,
            offset_list=()
        )

    def test_13_handleSendPartitionTable(self):
539
        # unexpected packet
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleSendPartitionTable,
            _msg_type=SEND_PARTITION_TABLE,
            ptid=0,
            row_list=()
        )

    def test_14_handleNotifyPartitionChanges1(self):
        # reject server connection 
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleNotifyPartitionChanges,
            _msg_type=NOTIFY_PARTITION_CHANGES,
            ptid=0,
            cell_list=()
        )
555 556
        # old partition change -> do nothing
        app = self.app
557
        conn = Mock({
558
            "isServerConnection": False,
559 560
            "getAddress" : ("127.0.0.1", self.master_port), 
        })
561
        app.replicator = Mock({})
562
        packet = Packet(msg_type=NOTIFY_PARTITION_CHANGES)
563
        self.app.ptid = 1
564
        count = len(self.app.nm.getNodeList())
565 566
        self.operation.handleNotifyPartitionChanges(conn, packet, 0, ())
        self.assertEquals(self.app.ptid, 1)
567
        self.assertEquals(len(self.app.nm.getNodeList()), count)
568
        calls = self.app.replicator.mockGetNamedCalls('removePartition')
569
        self.assertEquals(len(calls), 0)
570 571 572
        calls = self.app.replicator.mockGetNamedCalls('addPartition')
        self.assertEquals(len(calls), 0)

573 574 575 576 577 578 579 580 581
    def test_14_handleNotifyPartitionChanges2(self):
        # cases :
        uuid = self.getNewUUID()
        cells = (
            (0, uuid, UP_TO_DATE_STATE),
            (1, self.app.uuid, DISCARDED_STATE),
            (2, self.app.uuid, OUT_OF_DATE_STATE),
        )
        # context
582
        conn = Mock({
583
            "isServerConnection": False,
584 585
            "getAddress" : ("127.0.0.1", self.master_port), 
        })
586
        packet = Packet(msg_type=NOTIFY_PARTITION_CHANGES)
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
        app = self.app
        ptid1, ptid2 = self.getTwoIDs()
        self.assertNotEquals(ptid1, ptid2)
        app.ptid = ptid1
        app.pt = PartitionTable(3, 1)
        app.pt = Mock({ })
        app.dm = Mock({ })
        app.replicator = Mock({})
        count = len(app.nm.getNodeList())
        self.operation.handleNotifyPartitionChanges(conn, packet, ptid2, cells)
        # ptid set
        self.assertEquals(app.ptid, ptid2)
        # two nodes added 
        self.assertEquals(len(app.nm.getNodeList()), count + 2)
        # uuid != app.uuid -> TEMPORARILY_DOWN_STATE
        self.assertEquals(app.nm.getNodeByUUID(uuid).getState(), TEMPORARILY_DOWN_STATE)
        # pt calls
        calls = self.app.pt.mockGetNamedCalls('setCell')
        self.assertEquals(len(calls), 3)
606
        self.assertEquals(calls[0].getParam(0), 0)
607 608 609 610 611 612 613 614 615
        self.assertEquals(calls[1].getParam(0), 1)
        self.assertEquals(calls[2].getParam(0), 2)
        self.assertEquals(calls[0].getParam(1), app.nm.getNodeByUUID(uuid))
        self.assertEquals(calls[1].getParam(1), app.nm.getNodeByUUID(app.uuid))
        self.assertEquals(calls[2].getParam(1), app.nm.getNodeByUUID(app.uuid))
        self.assertEquals(calls[0].getParam(2), UP_TO_DATE_STATE)
        self.assertEquals(calls[1].getParam(2), DISCARDED_STATE)
        self.assertEquals(calls[2].getParam(2), OUT_OF_DATE_STATE)
        # replicator calls
616
        calls = self.app.replicator.mockGetNamedCalls('removePartition')
617 618 619 620 621 622 623 624 625
        self.assertEquals(len(calls), 1)
        self.assertEquals(calls[0].getParam(0), 1)
        calls = self.app.replicator.mockGetNamedCalls('addPartition')
        # dm call
        calls = self.app.dm.mockGetNamedCalls('changePartitionTable')
        self.assertEquals(len(calls), 1)
        self.assertEquals(calls[0].getParam(0), ptid2)
        self.assertEquals(calls[0].getParam(1), cells)
        self.assertEquals(len(calls), 1)
626 627

    def test_15_handleStartOperation(self):
628
        # unexpected packet
629 630 631 632 633 634 635
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleStartOperation,
            _msg_type=START_OPERATION,
        )

    def test_16_handleStopOperation1(self):
        # OperationFailure
636
        conn = Mock({ 'isServerConnection': False })
637
        packet = Packet(msg_type=STOP_OPERATION)
638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
        self.assertRaises(OperationFailure, self.operation.handleStopOperation, conn, packet)

    def test_16_handleStopOperation2(self):
        # server connection rejected
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleStopOperation,
            _msg_type=STOP_OPERATION,
            _listening=True,
        )

    def test_17_handleAskUnfinishedTransaction(self):
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleAskUnfinishedTransactions,
            _msg_type=ASK_UNFINISHED_TRANSACTIONS,
        )

    def test_18_handleAskTransactionInformation1(self):
        # transaction does not exists
        conn = Mock({ })
657
        packet = Packet(msg_type=ASK_TRANSACTION_INFORMATION)
658 659 660 661 662 663
        self.operation.handleAskTransactionInformation(conn, packet, INVALID_TID)
        self.checkPacket(conn, packet_type=ERROR)

    def test_18_handleAskTransactionInformation2(self):
        # answer
        conn = Mock({ })
664
        packet = Packet(msg_type=ASK_TRANSACTION_INFORMATION)
665 666 667 668 669 670
        dm = Mock({ "getTransaction": (INVALID_TID, 'user', 'desc', '', ), })
        self.app.dm = dm
        self.operation.handleAskTransactionInformation(conn, packet, INVALID_TID)
        self.checkPacket(conn, packet_type=ANSWER_TRANSACTION_INFORMATION)

    def test_19_handleAskObjectPresent(self):
671
        # unexpected packet
672 673 674 675 676 677 678 679
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleAskObjectPresent,
            _msg_type=ASK_OBJECT_PRESENT,
            oid=self.getNewUUID(),
            tid=INVALID_TID,
        )

    def test_20_handleDeleteTransaction(self):
680
        # unexpected packet
681 682 683 684 685 686 687
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleDeleteTransaction,
            _msg_type=DELETE_TRANSACTION,
            tid=INVALID_TID,
        )

    def test_21_handleCommitTransaction(self):
688
        # unexpected packet
689 690 691 692 693 694 695 696
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleCommitTransaction,
            _msg_type=COMMIT_TRANSACTION,
            tid=INVALID_TID,
        )

    def test_22_handleLockInformation1(self):
        # reject server connection 
697
        self.app.dm = Mock()
698 699 700 701 702 703
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleLockInformation,
            _msg_type=LOCK_INFORMATION,
            _listening=True,
            tid=INVALID_TID,
        )
704
        self.assertEquals(len(self.app.dm.mockGetNamedCalls('storeTransaction')), 0)
705 706

    def test_22_handleLockInformation2(self):
707
        # load transaction informations
708
        conn = Mock({ 'isServerConnection': False, })
709
        self.app.dm = Mock({ })
710
        packet = Packet(msg_type=LOCK_INFORMATION)
711 712 713 714 715 716 717
        transaction = Mock({ 'getObjectList': ((0, ), ), })
        self.app.transaction_dict[INVALID_TID] = transaction
        self.operation.handleLockInformation(conn, packet, INVALID_TID)
        self.assertEquals(self.app.load_lock_dict[0], INVALID_TID)
        calls = self.app.dm.mockGetNamedCalls('storeTransaction')
        self.assertEquals(len(calls), 1)
        self.checkPacket(conn, packet_type=NOTIFY_INFORMATION_LOCKED)
718 719
        # transaction not in transaction_dict -> KeyError
        transaction = Mock({ 'getObjectList': ((0, ), ), })
720
        conn = Mock({ 'isServerConnection': False, })
721 722
        self.operation.handleLockInformation(conn, packet, '\x01' * 8)
        self.checkPacket(conn, packet_type=NOTIFY_INFORMATION_LOCKED)
723 724 725

    def test_23_handleUnlockInformation1(self):
        # reject server connection
726
        self.app.dm = Mock()
727 728 729 730 731 732
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleUnlockInformation,
            _msg_type=UNLOCK_INFORMATION,
            _listening=True,
            tid=INVALID_TID,
        )
733
        self.assertEquals(len(self.app.dm.mockGetNamedCalls('storeTransaction')), 0)
734 735

    def test_23_handleUnlockInformation2(self):
736
        # delete transaction informations
737
        conn = Mock({ 'isServerConnection': False, })
738
        self.app.dm = Mock({ })
739
        packet = Packet(msg_type=LOCK_INFORMATION)
740 741 742 743 744 745 746 747 748 749 750
        transaction = Mock({ 'getObjectList': ((0, ), ), })
        self.app.transaction_dict[INVALID_TID] = transaction
        self.app.load_lock_dict[0] = transaction
        self.app.store_lock_dict[0] = transaction
        self.operation.handleUnlockInformation(conn, packet, INVALID_TID)
        self.assertEquals(len(self.app.load_lock_dict), 0)
        self.assertEquals(len(self.app.store_lock_dict), 0)
        self.assertEquals(len(self.app.store_lock_dict), 0)
        calls = self.app.dm.mockGetNamedCalls('finishTransaction')
        self.assertEquals(len(calls), 1)
        self.assertEquals(calls[0].getParam(0), INVALID_TID)
751 752
        # transaction not in transaction_dict -> KeyError
        transaction = Mock({ 'getObjectList': ((0, ), ), })
753
        conn = Mock({ 'isServerConnection': False, })
754 755
        self.operation.handleLockInformation(conn, packet, '\x01' * 8)
        self.checkPacket(conn, packet_type=NOTIFY_INFORMATION_LOCKED)
756 757 758 759

    def test_24_handleAskObject1(self):
        # delayed response
        conn = Mock({})
760
        self.app.dm = Mock()
761
        packet = Packet(msg_type=ASK_OBJECT)
762 763 764 765 766 767 768
        self.app.load_lock_dict[INVALID_OID] = object()
        self.assertEquals(len(self.app.event_queue), 0)
        self.operation.handleAskObject(conn, packet, 
            oid=INVALID_OID, 
            serial=INVALID_SERIAL, 
            tid=INVALID_TID)
        self.assertEquals(len(self.app.event_queue), 1)
769 770
        self.assertEquals(len(conn.mockGetNamedCalls('addPacket')), 0)
        self.assertEquals(len(self.app.dm.mockGetNamedCalls('getObject')), 0)
771

772
    def test_24_handleAskObject2(self):
773 774 775
        # invalid serial / tid / packet not found
        self.app.dm = Mock({'getObject': None})
        conn = Mock({})
776
        packet = Packet(msg_type=ASK_OBJECT)
777
        self.assertEquals(len(self.app.event_queue), 0)
778 779 780 781 782
        self.operation.handleAskObject(conn, packet, 
            oid=INVALID_OID, 
            serial=INVALID_SERIAL, 
            tid=INVALID_TID)
        calls = self.app.dm.mockGetNamedCalls('getObject')
783
        self.assertEquals(len(self.app.event_queue), 0)
784 785 786 787 788 789
        self.assertEquals(len(calls), 1)
        self.assertEquals(calls[0].getParam(0), INVALID_OID)
        self.assertEquals(calls[0].getParam(1), None)
        self.assertEquals(calls[0].getParam(2), None)
        self.checkPacket(conn, packet_type=ERROR)

790
    def test_24_handleAskObject3(self):
791
        # object found => answer
792 793
        self.app.dm = Mock({'getObject': ('', '', 0, 0, '', )})
        conn = Mock({})
794
        packet = Packet(msg_type=ASK_OBJECT)
795
        self.assertEquals(len(self.app.event_queue), 0)
796 797 798 799
        self.operation.handleAskObject(conn, packet, 
            oid=INVALID_OID, 
            serial=INVALID_SERIAL, 
            tid=INVALID_TID)
800
        self.assertEquals(len(self.app.event_queue), 0)
801 802 803
        self.checkPacket(conn, packet_type=ANSWER_OBJECT)

    def test_25_handleAskTIDs1(self):
804
        # invalid offsets => error
805 806 807
        app = self.app
        app.pt = Mock()
        app.dm = Mock()
808
        conn = Mock({})
809
        packet = Packet(msg_type=ASK_TIDS)
810
        self.checkProtocolErrorRaised(self.operation.handleAskTIDs, conn, packet, 1, 1, None)
811 812
        self.assertEquals(len(app.pt.mockGetNamedCalls('getCellList')), 0)
        self.assertEquals(len(app.dm.mockGetNamedCalls('getTIDList')), 0)
813 814

    def test_25_handleAskTIDs2(self):
815
        # well case => answer
816
        conn = Mock({})
817
        packet = Packet(msg_type=ASK_TIDS)
818 819 820 821 822 823 824 825 826 827 828 829
        self.app.num_partitions = 1
        self.app.dm = Mock({'getTIDList': (INVALID_TID, )})
        self.operation.handleAskTIDs(conn, packet, 1, 2, 1)
        calls = self.app.dm.mockGetNamedCalls('getTIDList')
        self.assertEquals(len(calls), 1)
        self.assertEquals(calls[0].getParam(0), 1)
        self.assertEquals(calls[0].getParam(1), 1)
        self.assertEquals(calls[0].getParam(2), 1)
        self.assertEquals(calls[0].getParam(3), [1, ])
        self.checkPacket(conn, packet_type=ANSWER_TIDS)

    def test_25_handleAskTIDs3(self):
830
        # invalid partition => answer usable partitions
831
        conn = Mock({})
832
        packet = Packet(msg_type=ASK_TIDS)
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
        self.app.num_partitions = 1
        cell = Mock({'getUUID':self.app.uuid})
        self.app.dm = Mock({'getTIDList': (INVALID_TID, )})
        self.app.pt = Mock({'getCellList': (cell, )})
        self.operation.handleAskTIDs(conn, packet, 1, 2, INVALID_PARTITION)
        self.assertEquals(len(self.app.pt.mockGetNamedCalls('getCellList')), 1)
        calls = self.app.dm.mockGetNamedCalls('getTIDList')
        self.assertEquals(len(calls), 1)
        self.assertEquals(calls[0].getParam(0), 1)
        self.assertEquals(calls[0].getParam(1), 1)
        self.assertEquals(calls[0].getParam(2), 1)
        self.assertEquals(calls[0].getParam(3), [0, ])
        self.checkPacket(conn, packet_type=ANSWER_TIDS)

    def test_26_handleAskObjectHistory1(self):
848
        # invalid offsets => error
849 850
        app = self.app
        app.dm = Mock()
851
        conn = Mock({})
852
        packet = Packet(msg_type=ASK_OBJECT_HISTORY)
853
        self.checkProtocolErrorRaised(self.operation.handleAskObjectHistory, conn, packet, 1, 1, None)
854
        self.assertEquals(len(app.dm.mockGetNamedCalls('getObjectHistory')), 0)
855 856 857

    def test_26_handleAskObjectHistory2(self):
        # first case: empty history
858
        packet = Packet(msg_type=ASK_OBJECT_HISTORY)
859 860 861 862 863 864 865 866 867 868 869
        conn = Mock({})
        self.app.dm = Mock({'getObjectHistory': None})
        self.operation.handleAskObjectHistory(conn, packet, INVALID_OID, 1, 2)
        self.checkPacket(conn, packet_type=ANSWER_OBJECT_HISTORY)
        # second case: not empty history
        conn = Mock({})
        self.app.dm = Mock({'getObjectHistory': [('', 0, ), ]})
        self.operation.handleAskObjectHistory(conn, packet, INVALID_OID, 1, 2)
        self.checkPacket(conn, packet_type=ANSWER_OBJECT_HISTORY)

    def test_27_handleAskStoreTransaction1(self):
870
        # no uuid => abort
871
        before = self.app.transaction_dict.items()[:]
872 873 874 875 876 877 878 879 880
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleAskStoreTransaction,
            _msg_type=ASK_STORE_TRANSACTION,
            tid=INVALID_TID, 
            user='', 
            desc='', 
            ext='', 
            oid_list=()
        )
881 882
        after = self.app.transaction_dict.items()
        self.assertEquals(before, after)
883 884

    def test_27_handleAskStoreTransaction2(self):
885
        # add transaction entry
886
        packet = Packet(msg_type=ASK_STORE_TRANSACTION)
887 888 889 890 891 892 893 894 895 896
        conn = Mock({'getUUID': self.getNewUUID()})
        self.operation.handleAskStoreTransaction(conn, packet,
            INVALID_TID, '', '', '', ())
        t = self.app.transaction_dict.get(INVALID_TID, None)
        self.assertNotEquals(t, None)
        self.assertTrue(isinstance(t, TransactionInformation))
        self.assertEquals(t.getTransaction(), ((), '', '', ''))
        self.checkPacket(conn, packet_type=ANSWER_STORE_TRANSACTION)

    def test_28_handleAskStoreObject1(self):
897
        # no uuid => abort
898 899 900 901 902 903
        app = self.app
        oid = '\x01' * 8
        app.dm = Mock()
        l_before = len(app.event_queue)
        t_before = self.app.transaction_dict.items()[:]
        self.assertTrue(oid not in app.store_lock_dict)
904 905 906
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleAskStoreObject,
            _msg_type=ASK_STORE_OBJECT,
907
            oid=oid,
908 909 910 911 912 913
            serial=INVALID_SERIAL,
            compression=0,
            checksum='',
            data='',
            tid=INVALID_TID
        )
914 915 916 917 918 919
        l_after = len(app.event_queue)
        self.assertEquals(l_before, l_after)
        self.assertEquals(len(app.dm.mockGetNamedCalls('getObjectHistory')), 0)
        t_after = self.app.transaction_dict.items()
        self.assertEquals(t_before, t_after)
        self.assertTrue(oid not in app.store_lock_dict)
920 921 922

    def test_28_handleAskStoreObject2(self):
        # locked => delayed response
923
        packet = Packet(msg_type=ASK_STORE_OBJECT)
924
        conn = Mock({'getUUID': self.app.uuid})
925
        oid = '\x02' * 8
926
        tid1, tid2 = self.getTwoIDs()
927 928 929 930
        self.app.store_lock_dict[oid] = tid1
        self.assertTrue(oid in self.app.store_lock_dict)
        t_before = self.app.transaction_dict.items()[:]
        self.operation.handleAskStoreObject(conn, packet, oid, 
931 932
            INVALID_SERIAL, 0, 0, '', tid2)
        self.assertEquals(len(self.app.event_queue), 1)
933 934 935 936
        t_after = self.app.transaction_dict.items()[:]
        self.assertEquals(t_before, t_after)
        self.assertEquals(len(conn.mockGetNamedCalls('addPacket')), 0)
        self.assertTrue(oid in self.app.store_lock_dict)
937 938

    def test_28_handleAskStoreObject3(self):
939
        # locked => unresolvable conflict => answer
940
        packet = Packet(msg_type=ASK_STORE_OBJECT)
941 942 943 944 945 946
        conn = Mock({'getUUID': self.app.uuid})
        tid1, tid2 = self.getTwoIDs()
        self.app.store_lock_dict[INVALID_OID] = tid2
        self.operation.handleAskStoreObject(conn, packet, INVALID_OID, 
            INVALID_SERIAL, 0, 0, '', tid1)
        self.checkPacket(conn, packet_type=ANSWER_STORE_OBJECT)
947 948
        self.assertEquals(self.app.store_lock_dict[INVALID_OID], tid2)
        # conflicting
949
        packet = conn.mockGetNamedCalls('answer')[0].getParam(0)
950
        self.assertTrue(unpack('!B8s8s', packet._body)[0])
951 952
    
    def test_28_handleAskStoreObject4(self):
953
        # resolvable conflict => answer
954
        packet = Packet(msg_type=ASK_STORE_OBJECT)
955 956
        conn = Mock({'getUUID': self.app.uuid})
        self.app.dm = Mock({'getObjectHistory':((self.getNewUUID(), ), )})
957
        self.assertEquals(self.app.store_lock_dict.get(INVALID_OID, None), None)
958 959 960
        self.operation.handleAskStoreObject(conn, packet, INVALID_OID, 
            INVALID_SERIAL, 0, 0, '', INVALID_TID)
        self.checkPacket(conn, packet_type=ANSWER_STORE_OBJECT)
961 962
        self.assertEquals(self.app.store_lock_dict.get(INVALID_OID, None), None)
        # conflicting
963
        packet = conn.mockGetNamedCalls('answer')[0].getParam(0)
964
        self.assertTrue(unpack('!B8s8s', packet._body)[0])
965 966
        
    def test_28_handleAskStoreObject5(self):
967
        # no conflict => answer
968
        packet = Packet(msg_type=ASK_STORE_OBJECT)
969 970 971 972 973 974 975 976 977
        conn = Mock({'getUUID': self.app.uuid})
        self.operation.handleAskStoreObject(conn, packet, INVALID_OID, 
            INVALID_SERIAL, 0, 0, '', INVALID_TID)
        t = self.app.transaction_dict.get(INVALID_TID, None)
        self.assertNotEquals(t, None)
        self.assertEquals(len(t.getObjectList()), 1)
        object = t.getObjectList()[0]
        self.assertEquals(object, (INVALID_OID, 0, 0, ''))
        self.checkPacket(conn, packet_type=ANSWER_STORE_OBJECT)
978
        # no conflict
979
        packet = conn.mockGetNamedCalls('answer')[0].getParam(0)
980
        self.assertFalse(unpack('!B8s8s', packet._body)[0])
981

982
    def test_29_handleAbortTransaction(self):
983
        # no uuid => abort
984
        before = self.app.transaction_dict.items()[:]
985 986 987 988 989
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleAbortTransaction,
            _msg_type=ABORT_TRANSACTION,
            tid=INVALID_TID
        )
990 991
        after = self.app.transaction_dict.items()
        self.assertEquals(before, after)
992
        # remove transaction
993
        packet = Packet(msg_type=ABORT_TRANSACTION)
994 995
        conn = Mock({'getUUID': self.app.uuid})
        transaction = Mock({ 'getObjectList': ((0, ), ), })
996 997 998 999
        self.called = False
        def called():
            self.called = True
        self.app.executeQueuedEvents = called
1000 1001 1002 1003
        self.app.load_lock_dict[0] = object()
        self.app.store_lock_dict[0] = object()
        self.app.transaction_dict[INVALID_TID] = transaction
        self.operation.handleAbortTransaction(conn, packet, INVALID_TID)
1004
        self.assertTrue(self.called)
1005 1006 1007 1008
        self.assertEquals(len(self.app.load_lock_dict), 0)
        self.assertEquals(len(self.app.store_lock_dict), 0)
        self.assertEquals(len(self.app.store_lock_dict), 0)

1009
    def test_30_handleAnswerLastIDs(self):
1010
        # listening connection => unexpected packet
1011 1012 1013 1014 1015 1016 1017 1018
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleAnswerLastIDs,
            _msg_type=ANSWER_LAST_IDS,
            _listening=True,
            loid=INVALID_OID,
            ltid=INVALID_TID,
            lptid=INVALID_TID,
        )
1019
        # set critical TID on replicator
1020
        conn = Mock()
1021
        packet = Packet(msg_type=ANSWER_LAST_IDS)
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
        self.app.replicator = Mock()
        self.operation.handleAnswerLastIDs(
            conn=conn,
            packet=packet,
            loid=INVALID_OID,
            ltid=INVALID_TID,
            lptid=INVALID_TID,
        )
        calls = self.app.replicator.mockGetNamedCalls('setCriticalTID')
        self.assertEquals(len(calls), 1)
        self.assertEquals(calls[0].getParam(0), packet)
        self.assertEquals(calls[0].getParam(1), INVALID_TID)

1035
    def test_31_handleAnswerUnfinishedTransactions(self):
1036
        # unexpected packet
1037 1038 1039 1040 1041 1042
        self.checkHandleUnexpectedPacket(
            _call=self.operation.handleAnswerUnfinishedTransactions,
            _msg_type=ANSWER_UNFINISHED_TRANSACTIONS,
            _listening=True,
            tid_list=(INVALID_TID, ),
        )
1043
        # set unfinished TID on replicator
1044
        conn = Mock()
1045
        packet = Packet(msg_type=ANSWER_UNFINISHED_TRANSACTIONS)
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
        self.app.replicator = Mock()
        self.operation.handleAnswerUnfinishedTransactions(
            conn=conn,
            packet=packet,
            tid_list=(INVALID_TID, ),
        )
        calls = self.app.replicator.mockGetNamedCalls('setUnfinishedTIDList')
        self.assertEquals(len(calls), 1)
        self.assertEquals(calls[0].getParam(0), (INVALID_TID, ))

    def test_25_handleAskOIDs1(self):
1057
        # invalid offsets => error
1058 1059 1060
        app = self.app
        app.pt = Mock()
        app.dm = Mock()
1061
        conn = Mock({})
1062
        packet = Packet(msg_type=ASK_OIDS)
1063
        self.checkProtocolErrorRaised(self.operation.handleAskOIDs, conn, packet, 1, 1, None)
1064 1065
        self.assertEquals(len(app.pt.mockGetNamedCalls('getCellList')), 0)
        self.assertEquals(len(app.dm.mockGetNamedCalls('getOIDList')), 0)
1066 1067

    def test_25_handleAskOIDs2(self):
1068
        # well case > answer OIDs
1069
        conn = Mock({})
1070
        packet = Packet(msg_type=ASK_OIDS)
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
        self.app.num_partitions = 1
        self.app.dm = Mock({'getOIDList': (INVALID_OID, )})
        self.operation.handleAskOIDs(conn, packet, 1, 2, 1)
        calls = self.app.dm.mockGetNamedCalls('getOIDList')
        self.assertEquals(len(calls), 1)
        self.assertEquals(calls[0].getParam(0), 1)
        self.assertEquals(calls[0].getParam(1), 1)
        self.assertEquals(calls[0].getParam(2), 1)
        self.assertEquals(calls[0].getParam(3), [1, ])
        self.checkPacket(conn, packet_type=ANSWER_OIDS)

    def test_25_handleAskOIDs3(self):
1083
        # invalid partition => answer usable partitions
1084
        conn = Mock({})
1085
        packet = Packet(msg_type=ASK_OIDS)
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102
        self.app.num_partitions = 1
        cell = Mock({'getUUID':self.app.uuid})
        self.app.dm = Mock({'getOIDList': (INVALID_OID, )})
        self.app.pt = Mock({'getCellList': (cell, )})
        self.operation.handleAskOIDs(conn, packet, 1, 2, INVALID_PARTITION)
        self.assertEquals(len(self.app.pt.mockGetNamedCalls('getCellList')), 1)
        calls = self.app.dm.mockGetNamedCalls('getOIDList')
        self.assertEquals(len(calls), 1)
        self.assertEquals(calls[0].getParam(0), 1)
        self.assertEquals(calls[0].getParam(1), 1)
        self.assertEquals(calls[0].getParam(2), 1)
        self.assertEquals(calls[0].getParam(3), [0, ])
        self.checkPacket(conn, packet_type=ANSWER_OIDS)


if __name__ == "__main__":
    unittest.main()