3 # this is a smoke-test using "./bin/tahoe" to:
5 # 1. create an introducer
6 # 2. create 5 storage nodes
7 # 3. create 2 client nodes (alice, bob)
8 # 4. Alice creates a magic-folder ("magik:")
12 # After that, some basic tests are performed; see the "if True:"
13 # blocks to turn some on or off. Could benefit from some cleanups
14 # etc. but this seems useful out of the gate for quick testing.
17 # from top-level of your checkout (we use "./bin/tahoe"):
18 # python src/allmydata/test/check_magicfolder_smoke.py
20 # This will create "./smoke_magicfolder" (which is disposable) and
21 # contains all the Tahoe basedirs for the introducer, storage nodes,
22 # clients, and the clients' magic-folders. NOTE that if these
23 # directories already exist they will NOT be re-created. So kill the
24 # grid and then "rm -rf smoke_magicfolder" if you want to re-run the
27 # Run the script with a single arg, "kill" to run "tahoe stop" on all
30 # This will have "tahoe start" -ed all the nodes, so you can continue
31 # to play around after the script exits.
33 from __future__ import print_function
39 from os.path import join, abspath, curdir, exists
40 from os import mkdir, listdir, unlink
42 tahoe_base = abspath(curdir)
43 data_base = join(tahoe_base, 'smoke_magicfolder')
44 tahoe_bin = join(tahoe_base, 'bin', 'tahoe')
45 python = sys.executable
47 if not exists(data_base):
48 print("Creating", data_base)
51 if not exists(tahoe_bin):
52 raise RuntimeError("Can't find 'tahoe' binary at %r" % (tahoe_bin,))
54 if 'kill' in sys.argv:
55 print("Killing the grid")
56 for d in listdir(data_base):
60 python, tahoe_bin, 'stop', join(data_base, d),
65 if not exists(join(data_base, 'introducer')):
66 subprocess.check_call(
68 python, tahoe_bin, 'create-introducer', join(data_base, 'introducer'),
71 with open(join(data_base, 'introducer', 'tahoe.cfg'), 'w') as f:
74 nickname = introducer0
78 subprocess.check_call(
80 python, tahoe_bin, 'start', join(data_base, 'introducer'),
84 furl_fname = join(data_base, 'introducer', 'private', 'introducer.furl')
85 while not exists(furl_fname):
87 furl = open(furl_fname, 'r').read()
91 data_dir = join(data_base, 'node%d' % x)
92 if not exists(data_dir):
93 subprocess.check_call(
95 python, tahoe_bin, 'create-node',
96 '--nickname', 'node%d' % (x,),
101 with open(join(data_dir, 'tahoe.cfg'), 'w') as f:
104 nickname = node%(node_id)s
106 web.static = public_html
107 tub.location = localhost:%(tub_port)d
110 # Which services should this client connect to?
111 introducer.furl = %(furl)s
115 ''' % {'node_id':x, 'furl':furl, 'tub_port':(9900 + x)})
116 subprocess.check_call(
118 python, tahoe_bin, 'start', data_dir,
124 # alice and bob clients
127 for name in ['alice', 'bob']:
128 data_dir = join(data_base, name)
129 magic_dir = join(data_base, '%s-magic' % (name,))
131 if not exists(data_dir):
133 subprocess.check_call(
135 python, tahoe_bin, 'create-node',
138 '--introducer', furl,
142 with open(join(data_dir, 'tahoe.cfg'), 'w') as f:
146 web.port = tcp:998%(node_id)d:interface=localhost
147 web.static = public_html
150 # Which services should this client connect to?
151 introducer.furl = %(furl)s
155 ''' % {'name':name, 'node_id':node_id, 'furl':furl})
156 subprocess.check_call(
158 python, tahoe_bin, 'start', data_dir,
163 # okay, now we have alice + bob (alice, bob)
164 # now we have alice create a magic-folder, and invite bob to it
167 data_dir = join(data_base, 'alice')
168 # alice creates her folder, invites bob
169 print("Alice creates a magic-folder")
170 subprocess.check_call(
172 python, tahoe_bin, 'magic-folder', 'create', '--basedir', data_dir, 'magik:', 'alice',
173 join(data_base, 'alice-magic'),
176 print("Alice invites Bob")
177 invite = subprocess.check_output(
179 python, tahoe_bin, 'magic-folder', 'invite', '--basedir', data_dir, 'magik:', 'bob',
182 print(" invite:", invite)
184 # now we let "bob"/bob join
185 print("Bob joins Alice's magic folder")
186 data_dir = join(data_base, 'bob')
187 subprocess.check_call(
189 python, tahoe_bin, 'magic-folder', 'join', '--basedir', data_dir, invite,
190 join(data_base, 'bob-magic'),
193 print("Bob has joined.")
195 print("Restarting alice + bob clients")
196 subprocess.check_call(
198 python, tahoe_bin, 'restart', '--basedir', join(data_base, 'alice'),
201 subprocess.check_call(
203 python, tahoe_bin, 'restart', '--basedir', join(data_base, 'bob'),
208 for name in ['alice', 'bob']:
209 with open(join(data_base, name, 'private', 'magic_folder_dircap'), 'r') as f:
210 print("dircap %s: %s" % (name, f.read().strip()))
212 # give storage nodes a chance to connect properly? I'm not entirely
213 # sure what's up here, but I get "UnrecoverableFileError" on the
214 # first_file upload from Alice "very often" otherwise
215 print("waiting 3 seconds")
219 # alice writes a file; bob should get it
220 alice_foo = join(data_base, 'alice-magic', 'first_file')
221 bob_foo = join(data_base, 'bob-magic', 'first_file')
222 with open(alice_foo, 'w') as f:
223 f.write("line one\n")
225 print("Waiting for:", bob_foo)
228 print(" found", bob_foo)
229 with open(bob_foo, 'r') as f:
230 if f.read() == "line one\n":
232 print(" file contents still mismatched")
236 # bob writes a file; alice should get it
237 alice_bar = join(data_base, 'alice-magic', 'second_file')
238 bob_bar = join(data_base, 'bob-magic', 'second_file')
239 with open(bob_bar, 'w') as f:
240 f.write("line one\n")
242 print("Waiting for:", alice_bar)
245 print(" found", bob_bar)
246 with open(bob_bar, 'r') as f:
247 if f.read() == "line one\n":
249 print(" file contents still mismatched")
253 # alice deletes 'first_file'
254 alice_foo = join(data_base, 'alice-magic', 'first_file')
255 bob_foo = join(data_base, 'bob-magic', 'first_file')
258 print("Waiting for '%s' to disappear" % (bob_foo,))
260 if not exists(bob_foo):
261 print(" disappeared", bob_foo)
265 bob_tmp = bob_foo + '.backup'
266 print("Waiting for '%s' to appear" % (bob_tmp,))
269 print(" appeared", bob_tmp)
274 # bob writes new content to 'second_file'; alice should get it
276 alice_foo = join(data_base, 'alice-magic', 'second_file')
277 bob_foo = join(data_base, 'bob-magic', 'second_file')
278 gold_content = "line one\nsecond line\n"
280 with open(bob_foo, 'w') as f:
281 f.write(gold_content)
283 print("Waiting for:", alice_foo)
285 if exists(alice_foo):
286 print(" found", alice_foo)
287 with open(alice_foo, 'r') as f:
289 if content == gold_content:
291 print(" file contents still mismatched:\n")
296 # bob creates a sub-directory and adds a file to it
297 alice_dir = join(data_base, 'alice-magic', 'subdir')
298 bob_dir = join(data_base, 'alice-magic', 'subdir')
299 gold_content = 'a file in a subdirectory\n'
302 with open(join(bob_dir, 'subfile'), 'w') as f:
303 f.write(gold_content)
305 print("Waiting for Bob's subdir '%s' to appear" % (bob_dir,))
308 print(" found subdir")
309 if exists(join(bob_dir, 'subfile')):
311 with open(join(bob_dir, 'subfile'), 'r') as f:
312 if f.read() == gold_content:
313 print(" contents match")
318 # bob deletes the whole subdir
319 alice_dir = join(data_base, 'alice-magic', 'subdir')
320 bob_dir = join(data_base, 'alice-magic', 'subdir')
321 shutil.rmtree(bob_dir)
323 print("Waiting for Alice's subdir '%s' to disappear" % (alice_dir,))
325 if not exists(alice_dir):
330 # XXX restore the file not working (but, unit-tests work; what's wrong with them?)
331 # NOTE: only not-works if it's alice restoring the file!
333 # restore 'first_file' but with different contents
334 print("re-writing 'first_file'")
335 assert not exists(join(data_base, 'bob-magic', 'first_file'))
336 assert not exists(join(data_base, 'alice-magic', 'first_file'))
337 alice_foo = join(data_base, 'alice-magic', 'first_file')
338 bob_foo = join(data_base, 'bob-magic', 'first_file')
340 # if we don't swap around, it works fine
341 alice_foo, bob_foo = bob_foo, alice_foo
342 gold_content = "see it again for the first time\n"
344 with open(bob_foo, 'w') as f:
345 f.write(gold_content)
347 print("Waiting for:", alice_foo)
349 if exists(alice_foo):
350 print(" found", alice_foo)
351 with open(alice_foo, 'r') as f:
353 if content == gold_content:
355 print(" file contents still mismatched: %d bytes:\n" % (len(content),))
358 print(" %r not there yet" % (alice_foo,))
364 data_dir = join(data_base, 'bob')
365 subprocess.check_call(
367 python, tahoe_bin, 'magic-folder', 'leave', '--basedir', data_dir,
372 # XXX test .backup (delete a file)
374 # port david's clock.advance stuff
375 # fix clock.advance()