1 # Tests of Python-specific parts of the xapian bindings.
3 # Copyright (C) 2007,2008 Lemur Consulting Ltd
4 # Copyright (C) 2008,2009 Olly Betts
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License as
8 # published by the Free Software Foundation; either version 2 of the
9 # License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
28 from testsuite
import *
30 def set_master(masterpath
, srcpath
):
31 # Take a copy of the source, to make modifications to.
32 if os
.path
.exists(masterpath
+ "_"):
33 shutil
.rmtree(masterpath
+ "_")
34 shutil
.copytree(srcpath
, masterpath
+ "_")
36 # Set a new uuid on the copy.
37 xapian
.WritableDatabase(masterpath
+ "__", xapian
.DB_CREATE_OR_OVERWRITE
)
38 os
.unlink(os
.path
.join(masterpath
+ "_", "iamchert"))
39 os
.rename(os
.path
.join(masterpath
+ "__", "iamchert"),
40 os
.path
.join(masterpath
+ "_", "iamchert"))
41 shutil
.rmtree(masterpath
+ "__")
43 # Replace the current master with the copy of the source.
44 # Note that this isn't an atomic replace, so we'll sometimes get errors
45 # such as "NetworkError: Unable to fully synchronise: Can't open database:
46 # Cannot open tables at consistent revisions" - the replication protocol
47 # should recover happily from this, though.
48 if os
.path
.exists(masterpath
):
49 os
.rename(masterpath
, masterpath
+ "__")
50 os
.rename(masterpath
+ '_', masterpath
)
51 if os
.path
.exists(masterpath
+ "__"):
52 shutil
.rmtree(masterpath
+ "__")
54 def test_replication_concurrency():
55 """Test concurrent replication and modification
59 builddir
= os
.environ
['abs_builddir']
60 dbsdir
= os
.path
.join(builddir
, 'dbs_replication')
61 if not os
.path
.isdir(dbsdir
):
64 masterpath
= os
.path
.join(dbsdir
, 'master')
65 firstpath
= os
.path
.join(dbsdir
, 'first')
66 secondpath
= os
.path
.join(dbsdir
, 'second')
67 slavepath
= os
.path
.join(dbsdir
, 'slave')
68 if os
.path
.isdir(masterpath
):
69 shutil
.rmtree(masterpath
)
70 if os
.path
.isdir(slavepath
):
71 shutil
.rmtree(slavepath
)
74 expect_exception(xapian
.DatabaseOpeningError
,
75 "Couldn't stat '" + dbsdir
+ "/slave' (No such file or directory)",
76 xapian
.Database
, slavepath
)
79 serverp
= subprocess
.Popen(('../../xapian-core/bin/xapian-replicate-server',
88 starttime
= time
.time()
89 if not os
.path
.isdir(firstpath
):
90 firstdb
= xapian
.WritableDatabase(firstpath
, xapian
.DB_CREATE_OR_OVERWRITE
)
91 # Make an initial, large database
93 print "Building initial database ..."
94 for num
in xrange(1, doccount1
):
98 firstdb
.add_document(doc
)
100 print "%d documents..." % num
101 firstdb
.set_metadata('dbname', '1')
105 # The secondary database gets modified during the test, so needs to be
107 shutil
.rmtree(secondpath
)
108 if not os
.path
.isdir(secondpath
):
109 seconddb
= xapian
.WritableDatabase(secondpath
, xapian
.DB_CREATE_OR_OVERWRITE
)
110 # Make second, small database
112 print "Building secondary database ..."
113 for num
in xrange(1, doccount2
):
114 doc
=xapian
.Document()
116 doc
.add_value(1, val
)
117 seconddb
.add_document(doc
)
118 if num
% 100000 == 0:
119 print "%d documents..." % num
120 seconddb
.set_metadata('dbname', '2')
124 if time
.time() - starttime
< 1:
125 time
.sleep(1) # Give server time to start
128 set_master(masterpath
, firstpath
)
129 clientp
= subprocess
.Popen(('../../xapian-core/bin/xapian-replicate',
132 os
.path
.join(dbsdir
, 'slave'),
138 time
.sleep(1) # Give client time to start
139 expect(xapian
.Database(slavepath
).get_metadata('dbname'), '1')
141 for count
in xrange(10):
142 # Test that swapping between databases doesn't confuse replication.
143 for count2
in xrange(2):
144 set_master(masterpath
, secondpath
)
146 set_master(masterpath
, firstpath
)
149 # Test making changes to the database.
150 set_master(masterpath
, secondpath
)
151 masterdb
= xapian
.WritableDatabase(masterpath
, xapian
.DB_OPEN
)
152 print "making 100 changes"
153 for num
in xrange(100):
154 masterdb
.set_metadata('num%d' % num
, str(num
+ count
))
159 # Allow time for the replication client to catch up with the
162 expect(xapian
.Database(slavepath
).get_metadata('dbname'), '2')
163 expect(xapian
.Database(slavepath
).get_metadata('num99'), str(99 + count
))
166 if clientp
is not None:
167 os
.kill(clientp
.pid
, 9)
169 os
.kill(serverp
.pid
, 9)
171 #shutil.rmtree(dbsdir)
173 # Run all tests (ie, callables with names starting "test_").
174 if not runtests(globals(), sys
.argv
[1:]):
177 # vim:syntax=python:set expandtab: