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')
46 if not exists(data_base):
47 print("Creating", data_base)
50 if not exists(tahoe_bin):
51 raise RuntimeError("Can't find 'tahoe' binary at %r" % (tahoe_bin,))
53 if 'kill' in sys.argv:
54 print("Killing the grid")
55 for d in listdir(data_base):
59 tahoe_bin, 'stop', join(data_base, d),
64 if not exists(join(data_base, 'introducer')):
65 subprocess.check_call(
67 tahoe_bin, 'create-introducer', join(data_base, 'introducer'),
70 with open(join(data_base, 'introducer', 'tahoe.cfg'), 'w') as f:
73 nickname = introducer0
77 subprocess.check_call(
79 tahoe_bin, 'start', join(data_base, 'introducer'),
83 furl_fname = join(data_base, 'introducer', 'private', 'introducer.furl')
84 while not exists(furl_fname):
86 furl = open(furl_fname, 'r').read()
90 data_dir = join(data_base, 'node%d' % x)
91 if not exists(data_dir):
92 subprocess.check_call(
94 tahoe_bin, 'create-node',
95 '--nickname', 'node%d' % (x,),
100 with open(join(data_dir, 'tahoe.cfg'), 'w') as f:
103 nickname = node%(node_id)s
105 web.static = public_html
106 tub.location = localhost:%(tub_port)d
109 # Which services should this client connect to?
110 introducer.furl = %(furl)s
114 ''' % {'node_id':x, 'furl':furl, 'tub_port':(9900 + x)})
115 subprocess.check_call(
117 tahoe_bin, 'start', data_dir,
123 # alice and bob clients
126 for name in ['alice', 'bob']:
127 data_dir = join(data_base, name)
128 magic_dir = join(data_base, '%s-magic' % (name,))
130 if not exists(data_dir):
132 subprocess.check_call(
134 tahoe_bin, 'create-node',
137 '--introducer', furl,
141 with open(join(data_dir, 'tahoe.cfg'), 'w') as f:
145 web.port = tcp:998%(node_id)d:interface=localhost
146 web.static = public_html
149 # Which services should this client connect to?
150 introducer.furl = %(furl)s
154 ''' % {'name':name, 'node_id':node_id, 'furl':furl})
155 subprocess.check_call(
157 tahoe_bin, 'start', data_dir,
162 # okay, now we have alice + bob (alice, bob)
163 # now we have alice create a magic-folder, and invite bob to it
166 data_dir = join(data_base, 'alice')
167 # alice creates her folder, invites bob
168 print("Alice creates a magic-folder")
169 subprocess.check_call(
171 tahoe_bin, 'magic-folder', 'create', '--basedir', data_dir, 'magik:', 'alice',
172 join(data_base, 'alice-magic'),
175 print("Alice invites Bob")
176 invite = subprocess.check_output(
178 tahoe_bin, 'magic-folder', 'invite', '--basedir', data_dir, 'magik:', 'bob',
181 print(" invite:", invite)
183 # now we let "bob"/bob join
184 print("Bob joins Alice's magic folder")
185 data_dir = join(data_base, 'bob')
186 subprocess.check_call(
188 tahoe_bin, 'magic-folder', 'join', '--basedir', data_dir, invite,
189 join(data_base, 'bob-magic'),
192 print("Bob has joined.")
194 print("Restarting alice + bob clients")
195 subprocess.check_call(
197 tahoe_bin, 'restart', '--basedir', join(data_base, 'alice'),
200 subprocess.check_call(
202 tahoe_bin, 'restart', '--basedir', join(data_base, 'bob'),
207 for name in ['alice', 'bob']:
208 with open(join(data_base, name, 'private', 'magic_folder_dircap'), 'r') as f:
209 print("dircap %s: %s" % (name, f.read().strip()))
211 # give storage nodes a chance to connect properly? I'm not entirely
212 # sure what's up here, but I get "UnrecoverableFileError" on the
213 # first_file upload from Alice "very often" otherwise
214 print("waiting 3 seconds")
218 # alice writes a file; bob should get it
219 alice_foo = join(data_base, 'alice-magic', 'first_file')
220 bob_foo = join(data_base, 'bob-magic', 'first_file')
221 with open(alice_foo, 'w') as f:
222 f.write("line one\n")
224 print("Waiting for:", bob_foo)
227 print(" found", bob_foo)
228 with open(bob_foo, 'r') as f:
229 if f.read() == "line one\n":
231 print(" file contents still mismatched")
235 # bob writes a file; alice should get it
236 alice_bar = join(data_base, 'alice-magic', 'second_file')
237 bob_bar = join(data_base, 'bob-magic', 'second_file')
238 with open(bob_bar, 'w') as f:
239 f.write("line one\n")
241 print("Waiting for:", alice_bar)
244 print(" found", bob_bar)
245 with open(bob_bar, 'r') as f:
246 if f.read() == "line one\n":
248 print(" file contents still mismatched")
252 # alice deletes 'first_file'
253 alice_foo = join(data_base, 'alice-magic', 'first_file')
254 bob_foo = join(data_base, 'bob-magic', 'first_file')
257 print("Waiting for '%s' to disappear" % (bob_foo,))
259 if not exists(bob_foo):
260 print(" disappeared", bob_foo)
264 bob_tmp = bob_foo + '.backup'
265 print("Waiting for '%s' to appear" % (bob_tmp,))
268 print(" appeared", bob_tmp)
273 # bob writes new content to 'second_file'; alice should get it
275 alice_foo = join(data_base, 'alice-magic', 'second_file')
276 bob_foo = join(data_base, 'bob-magic', 'second_file')
277 gold_content = "line one\nsecond line\n"
279 with open(bob_foo, 'w') as f:
280 f.write(gold_content)
282 print("Waiting for:", alice_foo)
284 if exists(alice_foo):
285 print(" found", alice_foo)
286 with open(alice_foo, 'r') as f:
288 if content == gold_content:
290 print(" file contents still mismatched:\n")
295 # bob creates a sub-directory and adds a file to it
296 alice_dir = join(data_base, 'alice-magic', 'subdir')
297 bob_dir = join(data_base, 'alice-magic', 'subdir')
298 gold_content = 'a file in a subdirectory\n'
301 with open(join(bob_dir, 'subfile'), 'w') as f:
302 f.write(gold_content)
304 print("Waiting for Bob's subdir '%s' to appear" % (bob_dir,))
307 print(" found subdir")
308 if exists(join(bob_dir, 'subfile')):
310 with open(join(bob_dir, 'subfile'), 'r') as f:
311 if f.read() == gold_content:
312 print(" contents match")
317 # bob deletes the whole subdir
318 alice_dir = join(data_base, 'alice-magic', 'subdir')
319 bob_dir = join(data_base, 'alice-magic', 'subdir')
320 shutil.rmtree(bob_dir)
322 print("Waiting for Alice's subdir '%s' to disappear" % (alice_dir,))
324 if not exists(alice_dir):
329 # XXX restore the file not working (but, unit-tests work; what's wrong with them?)
330 # NOTE: only not-works if it's alice restoring the file!
332 # restore 'first_file' but with different contents
333 print("re-writing 'first_file'")
334 assert not exists(join(data_base, 'bob-magic', 'first_file'))
335 assert not exists(join(data_base, 'alice-magic', 'first_file'))
336 alice_foo = join(data_base, 'alice-magic', 'first_file')
337 bob_foo = join(data_base, 'bob-magic', 'first_file')
339 # if we don't swap around, it works fine
340 alice_foo, bob_foo = bob_foo, alice_foo
341 gold_content = "see it again for the first time\n"
343 with open(bob_foo, 'w') as f:
344 f.write(gold_content)
346 print("Waiting for:", alice_foo)
348 if exists(alice_foo):
349 print(" found", alice_foo)
350 with open(alice_foo, 'r') as f:
352 if content == gold_content:
354 print(" file contents still mismatched: %d bytes:\n" % (len(content),))
357 print(" %r not there yet" % (alice_foo,))
360 # XXX test .backup (delete a file)
362 # port david's clock.advance stuff
363 # fix clock.advance()