~ubuntu-branches/debian/experimental/389-ds-base/experimental

« back to all changes in this revision

Viewing changes to dirsrvtests/tickets/ticket47490_test.py

  • Committer: Package Import Robot
  • Author(s): Timo Aaltonen
  • Date: 2014-07-08 15:50:11 UTC
  • mfrom: (0.2.2)
  • Revision ID: package-import@ubuntu.com-20140708155011-r66lvtioamqwaype
Tags: 1.3.2.19-1
* New upstream release.
* admin_scripts.diff: Updated to fix more bashisms.
* watch: Update the url.
* Install failedbinds.py and logregex.py scripts.
* init: Use status from init-functions.
* control: Update my email.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
'''
 
2
Created on Nov 7, 2013
 
3
 
 
4
@author: tbordaz
 
5
'''
 
6
import os
 
7
import sys
 
8
import time
 
9
import ldap
 
10
import logging
 
11
import socket
 
12
import time
 
13
import logging
 
14
import pytest
 
15
import re
 
16
from lib389 import DirSrv, Entry, tools
 
17
from lib389.tools import DirSrvTools
 
18
from lib389._constants import *
 
19
from lib389.properties import *
 
20
from constants import *
 
21
 
 
22
logging.getLogger(__name__).setLevel(logging.DEBUG)
 
23
log = logging.getLogger(__name__)
 
24
 
 
25
installation_prefix = None
 
26
 
 
27
TEST_REPL_DN = "cn=test_repl, %s" % SUFFIX
 
28
ENTRY_DN = "cn=test_entry, %s" % SUFFIX
 
29
MUST_OLD = "(postalAddress $ preferredLocale)"
 
30
MUST_NEW = "(postalAddress $ preferredLocale $ telexNumber)"
 
31
MAY_OLD  = "(postalCode $ street)"
 
32
MAY_NEW  = "(postalCode $ street $ postOfficeBox)"
 
33
 
 
34
 
 
35
class TopologyMasterConsumer(object):
 
36
    def __init__(self, master, consumer):
 
37
        master.open()
 
38
        self.master = master
 
39
        
 
40
        consumer.open()
 
41
        self.consumer = consumer
 
42
 
 
43
def pattern_errorlog(file, log_pattern):
 
44
    try:
 
45
        pattern_errorlog.last_pos += 1
 
46
    except AttributeError:
 
47
        pattern_errorlog.last_pos = 0
 
48
    
 
49
    found = None
 
50
    log.debug("_pattern_errorlog: start at offset %d" % pattern_errorlog.last_pos)
 
51
    file.seek(pattern_errorlog.last_pos)
 
52
    
 
53
    # Use a while true iteration because 'for line in file: hit a
 
54
    # python bug that break file.tell()
 
55
    while True:
 
56
        line = file.readline()
 
57
        log.debug("_pattern_errorlog: [%d] %s" % (file.tell(), line))
 
58
        found = log_pattern.search(line)
 
59
        if ((line == '') or (found)):
 
60
            break
 
61
        
 
62
    log.debug("_pattern_errorlog: end at offset %d" % file.tell())
 
63
    pattern_errorlog.last_pos = file.tell()
 
64
    return found
 
65
 
 
66
def _oc_definition(oid_ext, name, must=None, may=None):
 
67
    oid  = "1.2.3.4.5.6.7.8.9.10.%d" % oid_ext
 
68
    desc = 'To test ticket 47490'
 
69
    sup  = 'person'
 
70
    if not must:
 
71
        must = MUST_OLD
 
72
    if not may:
 
73
        may = MAY_OLD
 
74
    
 
75
    new_oc = "( %s  NAME '%s' DESC '%s' SUP %s AUXILIARY MUST %s MAY %s )" % (oid, name, desc, sup, must, may)
 
76
    return new_oc
 
77
 
 
78
def add_OC(instance, oid_ext, name):
 
79
    new_oc = _oc_definition(oid_ext, name)
 
80
    instance.schema.add_schema('objectClasses', new_oc)
 
81
 
 
82
def mod_OC(instance, oid_ext, name, old_must=None, old_may=None, new_must=None, new_may=None):
 
83
    old_oc = _oc_definition(oid_ext, name, old_must, old_may)
 
84
    new_oc = _oc_definition(oid_ext, name, new_must, new_may)
 
85
    instance.schema.del_schema('objectClasses', old_oc)
 
86
    instance.schema.add_schema('objectClasses', new_oc)
 
87
    
 
88
def trigger_schema_push(topology):
 
89
    """
 
90
        It triggers an update on the supplier. This will start a replication
 
91
        session and a schema push
 
92
    """
 
93
    try:
 
94
        trigger_schema_push.value += 1
 
95
    except AttributeError:
 
96
        trigger_schema_push.value = 1
 
97
    replace = [(ldap.MOD_REPLACE, 'telephonenumber', str(trigger_schema_push.value))]
 
98
    topology.master.modify_s(ENTRY_DN, replace)
 
99
    
 
100
    # wait 10 seconds that the update is replicated
 
101
    loop = 0
 
102
    while loop <= 10:
 
103
        try:
 
104
            ent = topology.consumer.getEntry(ENTRY_DN, ldap.SCOPE_BASE, "(objectclass=*)", ['telephonenumber'])
 
105
            val = ent.telephonenumber or "0"
 
106
            if int(val) == trigger_schema_push.value:
 
107
                return
 
108
            # the expected value is not yet replicated. try again
 
109
            time.sleep(1)
 
110
            loop += 1
 
111
            log.debug("trigger_schema_push: receive %s (expected %d)" % (val, trigger_schema_push.value))
 
112
        except ldap.NO_SUCH_OBJECT:
 
113
            time.sleep(1)
 
114
            loop += 1
 
115
 
 
116
@pytest.fixture(scope="module")
 
117
def topology(request):
 
118
    '''
 
119
        This fixture is used to create a replicated topology for the 'module'.
 
120
        The replicated topology is MASTER -> Consumer.
 
121
        At the beginning, It may exists a master instance and/or a consumer instance.
 
122
        It may also exists a backup for the master and/or the consumer.
 
123
    
 
124
        Principle:
 
125
            If master instance exists:
 
126
                restart it
 
127
            If consumer instance exists:
 
128
                restart it
 
129
            If backup of master AND backup of consumer exists:
 
130
                create or rebind to consumer
 
131
                create or rebind to master
 
132
 
 
133
                restore master   from backup
 
134
                restore consumer from backup
 
135
            else:
 
136
                Cleanup everything
 
137
                    remove instances
 
138
                    remove backups
 
139
                Create instances
 
140
                Initialize replication
 
141
                Create backups
 
142
    '''
 
143
    global installation_prefix
 
144
 
 
145
    if installation_prefix:
 
146
        args_instance[SER_DEPLOYED_DIR] = installation_prefix
 
147
        
 
148
    master   = DirSrv(verbose=False)
 
149
    consumer = DirSrv(verbose=False)
 
150
    
 
151
    # Args for the master instance
 
152
    args_instance[SER_HOST] = HOST_MASTER
 
153
    args_instance[SER_PORT] = PORT_MASTER
 
154
    args_instance[SER_SERVERID_PROP] = SERVERID_MASTER
 
155
    args_master = args_instance.copy()
 
156
    master.allocate(args_master)
 
157
    
 
158
    # Args for the consumer instance
 
159
    args_instance[SER_HOST] = HOST_CONSUMER
 
160
    args_instance[SER_PORT] = PORT_CONSUMER
 
161
    args_instance[SER_SERVERID_PROP] = SERVERID_CONSUMER
 
162
    args_consumer = args_instance.copy()
 
163
    consumer.allocate(args_consumer)
 
164
 
 
165
    
 
166
    # Get the status of the backups
 
167
    backup_master   = master.checkBackupFS()
 
168
    backup_consumer = consumer.checkBackupFS()
 
169
    
 
170
    # Get the status of the instance and restart it if it exists
 
171
    instance_master   = master.exists()
 
172
    if instance_master:
 
173
        master.stop(timeout=10)
 
174
        master.start(timeout=10)
 
175
        
 
176
    instance_consumer = consumer.exists()
 
177
    if instance_consumer:
 
178
        consumer.stop(timeout=10)
 
179
        consumer.start(timeout=10)
 
180
    
 
181
    if backup_master and backup_consumer:
 
182
        # The backups exist, assuming they are correct 
 
183
        # we just re-init the instances with them
 
184
        if not instance_master:
 
185
            master.create()
 
186
            # Used to retrieve configuration information (dbdir, confdir...)
 
187
            master.open()
 
188
        
 
189
        if not instance_consumer:
 
190
            consumer.create()
 
191
            # Used to retrieve configuration information (dbdir, confdir...)
 
192
            consumer.open()
 
193
        
 
194
        # restore master from backup
 
195
        master.stop(timeout=10)
 
196
        master.restoreFS(backup_master)
 
197
        master.start(timeout=10)
 
198
        
 
199
        # restore consumer from backup
 
200
        consumer.stop(timeout=10)
 
201
        consumer.restoreFS(backup_consumer)
 
202
        consumer.start(timeout=10)
 
203
    else:
 
204
        # We should be here only in two conditions
 
205
        #      - This is the first time a test involve master-consumer
 
206
        #        so we need to create everything
 
207
        #      - Something weird happened (instance/backup destroyed)
 
208
        #        so we discard everything and recreate all
 
209
        
 
210
        # Remove all the backups. So even if we have a specific backup file
 
211
        # (e.g backup_master) we clear all backups that an instance my have created
 
212
        if backup_master:
 
213
            master.clearBackupFS()
 
214
        if backup_consumer:
 
215
            consumer.clearBackupFS()
 
216
        
 
217
        # Remove all the instances
 
218
        if instance_master:
 
219
            master.delete()
 
220
        if instance_consumer:
 
221
            consumer.delete()
 
222
                        
 
223
        # Create the instances
 
224
        master.create()
 
225
        master.open()
 
226
        consumer.create()
 
227
        consumer.open()
 
228
    
 
229
        # 
 
230
        # Now prepare the Master-Consumer topology
 
231
        #
 
232
        # First Enable replication
 
233
        master.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER)
 
234
        consumer.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_CONSUMER)
 
235
        
 
236
        # Initialize the supplier->consumer
 
237
        
 
238
        properties = {RA_NAME:      r'meTo_$host:$port',
 
239
                      RA_BINDDN:    defaultProperties[REPLICATION_BIND_DN],
 
240
                      RA_BINDPW:    defaultProperties[REPLICATION_BIND_PW],
 
241
                      RA_METHOD:    defaultProperties[REPLICATION_BIND_METHOD],
 
242
                      RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
 
243
        repl_agreement = master.agreement.create(suffix=SUFFIX, host=consumer.host, port=consumer.port, properties=properties)
 
244
    
 
245
        if not repl_agreement:
 
246
            log.fatal("Fail to create a replica agreement")
 
247
            sys.exit(1)
 
248
            
 
249
        log.debug("%s created" % repl_agreement)
 
250
        master.agreement.init(SUFFIX, HOST_CONSUMER, PORT_CONSUMER)
 
251
        master.waitForReplInit(repl_agreement)
 
252
        
 
253
        # Check replication is working fine
 
254
        master.add_s(Entry((TEST_REPL_DN, {
 
255
                                                'objectclass': "top person".split(),
 
256
                                                'sn': 'test_repl',
 
257
                                                'cn': 'test_repl'})))
 
258
        loop = 0
 
259
        while loop <= 10:
 
260
            try:
 
261
                ent = consumer.getEntry(TEST_REPL_DN, ldap.SCOPE_BASE, "(objectclass=*)")
 
262
                break
 
263
            except ldap.NO_SUCH_OBJECT:
 
264
                time.sleep(1)
 
265
                loop += 1
 
266
                
 
267
        # Time to create the backups
 
268
        master.stop(timeout=10)
 
269
        master.backupfile = master.backupFS()
 
270
        master.start(timeout=10)
 
271
        
 
272
        consumer.stop(timeout=10)
 
273
        consumer.backupfile = consumer.backupFS()
 
274
        consumer.start(timeout=10)
 
275
    
 
276
    # 
 
277
    # Here we have two instances master and consumer
 
278
    # with replication working. Either coming from a backup recovery
 
279
    # or from a fresh (re)init
 
280
    # Time to return the topology
 
281
    return TopologyMasterConsumer(master, consumer)
 
282
 
 
283
 
 
284
def test_ticket47490_init(topology):
 
285
    """ 
 
286
        Initialize the test environment
 
287
    """
 
288
    log.debug("test_ticket47490_init topology %r (master %r, consumer %r" % (topology, topology.master, topology.consumer))
 
289
    # the test case will check if a warning message is logged in the 
 
290
    # error log of the supplier
 
291
    topology.master.errorlog_file = open(topology.master.errlog, "r")
 
292
    
 
293
    # This entry will be used to trigger attempt of schema push
 
294
    topology.master.add_s(Entry((ENTRY_DN, {
 
295
                                            'objectclass': "top person".split(),
 
296
                                            'sn': 'test_entry',
 
297
                                            'cn': 'test_entry'})))
 
298
    
 
299
def test_ticket47490_one(topology):
 
300
    """
 
301
        Summary: Extra OC Schema is pushed - no error
 
302
        
 
303
        If supplier schema is a superset (one extra OC) of consumer schema, then
 
304
        schema is pushed and there is no message in the error log
 
305
        State at startup:
 
306
            - supplier default schema
 
307
            - consumer default schema
 
308
        Final state
 
309
            - supplier +masterNewOCA
 
310
            - consumer +masterNewOCA
 
311
        
 
312
    """
 
313
    log.debug("test_ticket47490_one topology %r (master %r, consumer %r" % (topology, topology.master, topology.consumer))
 
314
    # update the schema of the supplier so that it is a superset of 
 
315
    # consumer. Schema should be pushed
 
316
    add_OC(topology.master, 2, 'masterNewOCA')
 
317
    
 
318
    trigger_schema_push(topology)
 
319
    master_schema_csn = topology.master.schema.get_schema_csn()
 
320
    consumer_schema_csn = topology.consumer.schema.get_schema_csn()
 
321
    
 
322
    # Check the schemaCSN was updated on the consumer
 
323
    log.debug("test_ticket47490_one master_schema_csn=%s", master_schema_csn)
 
324
    log.debug("ctest_ticket47490_one onsumer_schema_csn=%s", consumer_schema_csn)
 
325
    assert master_schema_csn == consumer_schema_csn
 
326
    
 
327
    # Check the error log of the supplier does not contain an error
 
328
    regex = re.compile("must not be overwritten \(set replication log for additional info\)")
 
329
    res = pattern_errorlog(topology.master.errorlog_file, regex)
 
330
    assert res == None
 
331
    
 
332
def test_ticket47490_two(topology):
 
333
    """
 
334
        Summary: Extra OC Schema is pushed - (ticket 47721 allows to learn missing def)
 
335
        
 
336
        If consumer schema is a superset (one extra OC) of supplier schema, then
 
337
        schema is pushed and there is a message in the error log
 
338
        State at startup 
 
339
            - supplier +masterNewOCA
 
340
            - consumer +masterNewOCA
 
341
        Final state
 
342
            - supplier +masterNewOCA +masterNewOCB
 
343
            - consumer +masterNewOCA               +consumerNewOCA
 
344
        
 
345
    """
 
346
    
 
347
    # add this OC on consumer. Supplier will no push the schema
 
348
    add_OC(topology.consumer, 1, 'consumerNewOCA')
 
349
    
 
350
    # add a new OC on the supplier so that its nsSchemaCSN is larger than the consumer (wait 2s)
 
351
    time.sleep(2)
 
352
    add_OC(topology.master, 3, 'masterNewOCB')
 
353
    
 
354
    # now push the scheam
 
355
    trigger_schema_push(topology)
 
356
    master_schema_csn = topology.master.schema.get_schema_csn()
 
357
    consumer_schema_csn = topology.consumer.schema.get_schema_csn()
 
358
    
 
359
    # Check the schemaCSN was NOT updated on the consumer
 
360
    # with 47721, supplier learns the missing definition
 
361
    log.debug("test_ticket47490_two master_schema_csn=%s", master_schema_csn)
 
362
    log.debug("test_ticket47490_two consumer_schema_csn=%s", consumer_schema_csn)
 
363
    assert master_schema_csn != consumer_schema_csn
 
364
 
 
365
    # Check the error log of the supplier does not contain an error
 
366
    # This message may happen during the learning phase
 
367
    regex = re.compile("must not be overwritten \(set replication log for additional info\)")
 
368
    res = pattern_errorlog(topology.master.errorlog_file, regex)
 
369
 
 
370
 
 
371
def test_ticket47490_three(topology):
 
372
    """
 
373
        Summary: Extra OC Schema is pushed - no error
 
374
        
 
375
        If supplier schema is again a superset (one extra OC), then
 
376
        schema is  pushed and there is no message in the error log
 
377
        State at startup 
 
378
            - supplier +masterNewOCA +masterNewOCB
 
379
            - consumer +masterNewOCA               +consumerNewOCA
 
380
        Final state
 
381
            - supplier +masterNewOCA +masterNewOCB +consumerNewOCA
 
382
            - consumer +masterNewOCA +masterNewOCB +consumerNewOCA
 
383
 
 
384
    """    
 
385
    # Do an upate to trigger the schema push attempt
 
386
    # add this OC on consumer. Supplier will no push the schema
 
387
    add_OC(topology.master, 1, 'consumerNewOCA')
 
388
    
 
389
    # now push the scheam
 
390
    trigger_schema_push(topology)
 
391
    master_schema_csn = topology.master.schema.get_schema_csn()
 
392
    consumer_schema_csn = topology.consumer.schema.get_schema_csn()
 
393
    
 
394
    # Check the schemaCSN was NOT updated on the consumer
 
395
    log.debug("test_ticket47490_three master_schema_csn=%s", master_schema_csn)
 
396
    log.debug("test_ticket47490_three consumer_schema_csn=%s", consumer_schema_csn)
 
397
    assert master_schema_csn == consumer_schema_csn
 
398
 
 
399
    # Check the error log of the supplier does not contain an error
 
400
    regex = re.compile("must not be overwritten \(set replication log for additional info\)")
 
401
    res = pattern_errorlog(topology.master.errorlog_file, regex)
 
402
    assert res == None
 
403
    
 
404
def test_ticket47490_four(topology):
 
405
    """
 
406
        Summary: Same OC - extra MUST: Schema is pushed - no error
 
407
        
 
408
        If supplier schema is again a superset (OC with more MUST), then
 
409
        schema is  pushed and there is no message in the error log
 
410
        State at startup 
 
411
            - supplier +masterNewOCA +masterNewOCB +consumerNewOCA
 
412
            - consumer +masterNewOCA +masterNewOCB +consumerNewOCA
 
413
        Final state
 
414
            - supplier +masterNewOCA     +masterNewOCB     +consumerNewOCA
 
415
                       +must=telexnumber
 
416
            - consumer +masterNewOCA     +masterNewOCB     +consumerNewOCA
 
417
                       +must=telexnumber
 
418
                        
 
419
    """    
 
420
    mod_OC(topology.master, 2, 'masterNewOCA', old_must=MUST_OLD, new_must=MUST_NEW, old_may=MAY_OLD, new_may=MAY_OLD)
 
421
    
 
422
        
 
423
    trigger_schema_push(topology)
 
424
    master_schema_csn = topology.master.schema.get_schema_csn()
 
425
    consumer_schema_csn = topology.consumer.schema.get_schema_csn()
 
426
    
 
427
    # Check the schemaCSN was updated on the consumer
 
428
    log.debug("test_ticket47490_four master_schema_csn=%s", master_schema_csn)
 
429
    log.debug("ctest_ticket47490_four onsumer_schema_csn=%s", consumer_schema_csn)
 
430
    assert master_schema_csn == consumer_schema_csn
 
431
    
 
432
    # Check the error log of the supplier does not contain an error
 
433
    regex = re.compile("must not be overwritten \(set replication log for additional info\)")
 
434
    res = pattern_errorlog(topology.master.errorlog_file, regex)
 
435
    assert res == None
 
436
    
 
437
def test_ticket47490_five(topology):
 
438
    """
 
439
        Summary: Same OC - extra MUST: Schema is pushed - (fix for 47721)
 
440
        
 
441
        If consumer schema is  a superset (OC with more MUST), then
 
442
        schema is  pushed (fix for 47721) and there is a message in the error log
 
443
        State at startup 
 
444
            - supplier +masterNewOCA     +masterNewOCB     +consumerNewOCA
 
445
                       +must=telexnumber
 
446
            - consumer +masterNewOCA     +masterNewOCB     +consumerNewOCA
 
447
                        +must=telexnumber
 
448
        Final state
 
449
            - supplier +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
450
                       +must=telexnumber
 
451
            - consumer +masterNewOCA     +masterNewOCB     +consumerNewOCA
 
452
                       +must=telexnumber                   +must=telexnumber
 
453
                        
 
454
        Note: replication log is enabled to get more details
 
455
    """    
 
456
    # get more detail why it fails
 
457
    topology.master.enableReplLogging()
 
458
    
 
459
    # add telenumber to 'consumerNewOCA' on the consumer
 
460
    mod_OC(topology.consumer, 1, 'consumerNewOCA', old_must=MUST_OLD, new_must=MUST_NEW, old_may=MAY_OLD, new_may=MAY_OLD)
 
461
    # add a new OC on the supplier so that its nsSchemaCSN is larger than the consumer (wait 2s)
 
462
    time.sleep(2)
 
463
    add_OC(topology.master, 4, 'masterNewOCC')
 
464
        
 
465
    trigger_schema_push(topology)
 
466
    master_schema_csn = topology.master.schema.get_schema_csn()
 
467
    consumer_schema_csn = topology.consumer.schema.get_schema_csn()
 
468
    
 
469
    # Check the schemaCSN was NOT updated on the consumer
 
470
    # with 47721, supplier learns the missing definition
 
471
    log.debug("test_ticket47490_five master_schema_csn=%s", master_schema_csn)
 
472
    log.debug("ctest_ticket47490_five onsumer_schema_csn=%s", consumer_schema_csn)
 
473
    assert master_schema_csn != consumer_schema_csn
 
474
    
 
475
    # Check the error log of the supplier does not contain an error
 
476
    # This message may happen during the learning phase
 
477
    regex = re.compile("must not be overwritten \(set replication log for additional info\)")
 
478
    res = pattern_errorlog(topology.master.errorlog_file, regex)
 
479
 
 
480
def test_ticket47490_six(topology):
 
481
    """
 
482
        Summary: Same OC - extra MUST: Schema is pushed - no error
 
483
        
 
484
        If supplier schema is  again a superset (OC with more MUST), then
 
485
        schema is  pushed and there is no message in the error log
 
486
        State at startup 
 
487
            - supplier +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
488
                       +must=telexnumber
 
489
            - consumer +masterNewOCA     +masterNewOCB     +consumerNewOCA
 
490
                       +must=telexnumber                   +must=telexnumber
 
491
        Final state
 
492
                       
 
493
            - supplier +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
494
                       +must=telexnumber                   +must=telexnumber
 
495
            - consumer +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
496
                       +must=telexnumber                   +must=telexnumber
 
497
                        
 
498
        Note: replication log is enabled to get more details
 
499
    """    
 
500
 
 
501
    
 
502
    # add telenumber to 'consumerNewOCA' on the consumer
 
503
    mod_OC(topology.master, 1, 'consumerNewOCA', old_must=MUST_OLD, new_must=MUST_NEW, old_may=MAY_OLD, new_may=MAY_OLD)
 
504
        
 
505
    trigger_schema_push(topology)
 
506
    master_schema_csn = topology.master.schema.get_schema_csn()
 
507
    consumer_schema_csn = topology.consumer.schema.get_schema_csn()
 
508
    
 
509
    # Check the schemaCSN was NOT updated on the consumer
 
510
    log.debug("test_ticket47490_six master_schema_csn=%s", master_schema_csn)
 
511
    log.debug("ctest_ticket47490_six onsumer_schema_csn=%s", consumer_schema_csn)
 
512
    assert master_schema_csn == consumer_schema_csn
 
513
    
 
514
    # Check the error log of the supplier does not contain an error
 
515
    # This message may happen during the learning phase
 
516
    regex = re.compile("must not be overwritten \(set replication log for additional info\)")
 
517
    res = pattern_errorlog(topology.master.errorlog_file, regex)
 
518
    assert res == None
 
519
 
 
520
 
 
521
 
 
522
 
 
523
def test_ticket47490_seven(topology):
 
524
    """
 
525
        Summary: Same OC - extra MAY: Schema is pushed - no error
 
526
        
 
527
        If supplier schema is again a superset (OC with more MAY), then
 
528
        schema is  pushed and there is no message in the error log
 
529
        State at startup
 
530
            - supplier +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
531
                       +must=telexnumber                   +must=telexnumber
 
532
            - consumer +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
533
                       +must=telexnumber                   +must=telexnumber
 
534
        Final stat
 
535
            - supplier +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
536
                       +must=telexnumber                   +must=telexnumber
 
537
                       +may=postOfficeBox
 
538
            - consumer +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
539
                       +must=telexnumber                   +must=telexnumber
 
540
                       +may=postOfficeBox                          
 
541
    """    
 
542
    mod_OC(topology.master, 2, 'masterNewOCA', old_must=MUST_NEW, new_must=MUST_NEW, old_may=MAY_OLD, new_may=MAY_NEW)
 
543
    
 
544
        
 
545
    trigger_schema_push(topology)
 
546
    master_schema_csn = topology.master.schema.get_schema_csn()
 
547
    consumer_schema_csn = topology.consumer.schema.get_schema_csn()
 
548
    
 
549
    # Check the schemaCSN was updated on the consumer
 
550
    log.debug("test_ticket47490_seven master_schema_csn=%s", master_schema_csn)
 
551
    log.debug("ctest_ticket47490_seven consumer_schema_csn=%s", consumer_schema_csn)
 
552
    assert master_schema_csn == consumer_schema_csn
 
553
    
 
554
    # Check the error log of the supplier does not contain an error
 
555
    regex = re.compile("must not be overwritten \(set replication log for additional info\)")
 
556
    res = pattern_errorlog(topology.master.errorlog_file, regex)
 
557
    assert res == None
 
558
    
 
559
 
 
560
def test_ticket47490_eight(topology):
 
561
    """
 
562
        Summary: Same OC - extra MAY: Schema is pushed (fix for 47721)
 
563
        
 
564
        If consumer schema is a superset (OC with more MAY), then
 
565
        schema is  pushed (fix for 47721) and there is  message in the error log
 
566
        State at startup
 
567
            - supplier +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
568
                       +must=telexnumber                   +must=telexnumber
 
569
                       +may=postOfficeBox
 
570
            - consumer +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
571
                       +must=telexnumber                   +must=telexnumber
 
572
                       +may=postOfficeBox
 
573
        Final state
 
574
            - supplier +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
575
                       +must=telexnumber                   +must=telexnumber
 
576
                       +may=postOfficeBox                                     +may=postOfficeBox
 
577
            - consumer +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
578
                       +must=telexnumber                   +must=telexnumber
 
579
                       +may=postOfficeBox                  +may=postOfficeBox    
 
580
    """    
 
581
    mod_OC(topology.consumer, 1, 'consumerNewOCA', old_must=MUST_NEW, new_must=MUST_NEW, old_may=MAY_OLD, new_may=MAY_NEW)
 
582
 
 
583
    # modify OC on the supplier so that its nsSchemaCSN is larger than the consumer (wait 2s)
 
584
    time.sleep(2)
 
585
    mod_OC(topology.master, 4, 'masterNewOCC', old_must=MUST_OLD, new_must=MUST_OLD, old_may=MAY_OLD, new_may=MAY_NEW)
 
586
        
 
587
    trigger_schema_push(topology)
 
588
    master_schema_csn = topology.master.schema.get_schema_csn()
 
589
    consumer_schema_csn = topology.consumer.schema.get_schema_csn()
 
590
    
 
591
    # Check the schemaCSN was not updated on the consumer
 
592
    # with 47721, supplier learns the missing definition
 
593
    log.debug("test_ticket47490_eight master_schema_csn=%s", master_schema_csn)
 
594
    log.debug("ctest_ticket47490_eight onsumer_schema_csn=%s", consumer_schema_csn)
 
595
    assert master_schema_csn != consumer_schema_csn
 
596
    
 
597
    # Check the error log of the supplier does not contain an error
 
598
    # This message may happen during the learning phase
 
599
    regex = re.compile("must not be overwritten \(set replication log for additional info\)")
 
600
    res = pattern_errorlog(topology.master.errorlog_file, regex)
 
601
    
 
602
    
 
603
def test_ticket47490_nine(topology):
 
604
    """
 
605
        Summary: Same OC - extra MAY: Schema is pushed - no error
 
606
        
 
607
        If consumer schema is a superset (OC with more MAY), then
 
608
        schema is  not pushed and there is  message in the error log
 
609
        State at startup
 
610
            - supplier +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
611
                       +must=telexnumber                   +must=telexnumber
 
612
                       +may=postOfficeBox                                     +may=postOfficeBox
 
613
            - consumer +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
614
                       +must=telexnumber                   +must=telexnumber
 
615
                       +may=postOfficeBox                  +may=postOfficeBox 
 
616
 
 
617
        Final state
 
618
   
 
619
            - supplier +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
620
                       +must=telexnumber                   +must=telexnumber
 
621
                       +may=postOfficeBox                  +may=postOfficeBox +may=postOfficeBox
 
622
            - consumer +masterNewOCA     +masterNewOCB     +consumerNewOCA    +masterNewOCC
 
623
                       +must=telexnumber                   +must=telexnumber
 
624
                       +may=postOfficeBox                  +may=postOfficeBox +may=postOfficeBox
 
625
    """    
 
626
    mod_OC(topology.master, 1, 'consumerNewOCA', old_must=MUST_NEW, new_must=MUST_NEW, old_may=MAY_OLD, new_may=MAY_NEW)
 
627
        
 
628
    trigger_schema_push(topology)
 
629
    master_schema_csn = topology.master.schema.get_schema_csn()
 
630
    consumer_schema_csn = topology.consumer.schema.get_schema_csn()
 
631
    
 
632
    # Check the schemaCSN was updated on the consumer
 
633
    log.debug("test_ticket47490_nine master_schema_csn=%s", master_schema_csn)
 
634
    log.debug("ctest_ticket47490_nine onsumer_schema_csn=%s", consumer_schema_csn)
 
635
    assert master_schema_csn == consumer_schema_csn
 
636
    
 
637
    # Check the error log of the supplier does not contain an error
 
638
    regex = re.compile("must not be overwritten \(set replication log for additional info\)")
 
639
    res = pattern_errorlog(topology.master.errorlog_file, regex)
 
640
    assert res == None
 
641
    
 
642
def test_ticket47490_final(topology):
 
643
    topology.master.stop(timeout=10)
 
644
    topology.consumer.stop(timeout=10)
 
645
 
 
646
def run_isolated():
 
647
    '''
 
648
        run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
 
649
        To run isolated without py.test, you need to 
 
650
            - edit this file and comment '@pytest.fixture' line before 'topology' function.
 
651
            - set the installation prefix
 
652
            - run this program
 
653
    '''
 
654
    global installation_prefix
 
655
    installation_prefix =  None
 
656
        
 
657
    topo = topology(True)
 
658
    test_ticket47490_init(topo)
 
659
    test_ticket47490_one(topo)
 
660
    test_ticket47490_two(topo)
 
661
    test_ticket47490_three(topo)
 
662
    test_ticket47490_four(topo)
 
663
    test_ticket47490_five(topo)
 
664
    test_ticket47490_six(topo)
 
665
    test_ticket47490_seven(topo)
 
666
    test_ticket47490_eight(topo)
 
667
    test_ticket47490_nine(topo)
 
668
    
 
669
    test_ticket47490_final(topo)
 
670
 
 
671
 
 
672
if __name__ == '__main__':
 
673
    run_isolated()
 
674