]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/test/check_magicfolder_smoke.py
e363938dad275ba4d014f5500e75951f11875b35
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / test / check_magicfolder_smoke.py
1 #!/usr/bin/env python
2
3 # this is a smoke-test using "./bin/tahoe" to:
4 #
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:")
9 # 5. Alice invites Bob
10 # 6. Bob joins
11 #
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.
15 #
16 # TO RUN:
17 # from top-level of your checkout (we use "./bin/tahoe"):
18 # python src/allmydata/test/check_magicfolder_smoke.py
19 #
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
25 # tests cleanly.
26 #
27 # Run the script with a single arg, "kill" to run "tahoe stop" on all
28 # the nodes.
29 #
30 # This will have "tahoe start" -ed all the nodes, so you can continue
31 # to play around after the script exits.
32
33 from __future__ import print_function
34
35 import sys
36 import time
37 import shutil
38 import subprocess
39 from os.path import join, abspath, curdir, exists
40 from os import mkdir, listdir, unlink
41
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
46
47 if not exists(data_base):
48     print("Creating", data_base)
49     mkdir(data_base)
50
51 if not exists(tahoe_bin):
52     raise RuntimeError("Can't find 'tahoe' binary at %r" % (tahoe_bin,))
53
54 if 'kill' in sys.argv:
55     print("Killing the grid")
56     for d in listdir(data_base):
57         print("killing", d)
58         subprocess.call(
59             [
60                 python, tahoe_bin, 'stop', join(data_base, d),
61             ]
62         )
63     sys.exit(0)
64
65 if not exists(join(data_base, 'introducer')):
66     subprocess.check_call(
67         [
68             python, tahoe_bin, 'create-introducer', join(data_base, 'introducer'),
69         ]
70     )
71 with open(join(data_base, 'introducer', 'tahoe.cfg'), 'w') as f:
72     f.write('''
73 [node]
74 nickname = introducer0
75 web.port = 4560
76 ''')
77
78 subprocess.check_call(
79     [
80         python, tahoe_bin, 'start', join(data_base, 'introducer'),
81     ]
82 )
83
84 furl_fname = join(data_base, 'introducer', 'private', 'introducer.furl')
85 while not exists(furl_fname):
86     time.sleep(1)
87 furl = open(furl_fname, 'r').read()
88 print("FURL", furl)
89
90 for x in range(5):
91     data_dir = join(data_base, 'node%d' % x)
92     if not exists(data_dir):
93         subprocess.check_call(
94             [
95                 python, tahoe_bin, 'create-node',
96                 '--nickname', 'node%d' % (x,),
97                 '--introducer', furl,
98                 data_dir,
99             ]
100         )
101         with open(join(data_dir, 'tahoe.cfg'), 'w') as f:
102             f.write('''
103 [node]
104 nickname = node%(node_id)s
105 web.port =
106 web.static = public_html
107 tub.location = localhost:%(tub_port)d
108
109 [client]
110 # Which services should this client connect to?
111 introducer.furl = %(furl)s
112 shares.needed = 2
113 shares.happy = 3
114 shares.total = 4
115 ''' % {'node_id':x, 'furl':furl, 'tub_port':(9900 + x)})
116     subprocess.check_call(
117         [
118             python, tahoe_bin, 'start', data_dir,
119         ]
120     )
121
122
123
124 # alice and bob clients
125 do_invites = False
126 node_id = 0
127 for name in ['alice', 'bob']:
128     data_dir = join(data_base, name)
129     magic_dir = join(data_base, '%s-magic' % (name,))
130     mkdir(magic_dir)
131     if not exists(data_dir):
132         do_invites = True
133         subprocess.check_call(
134             [
135                 python, tahoe_bin, 'create-node',
136                 '--no-storage',
137                 '--nickname', name,
138                 '--introducer', furl,
139                 data_dir,
140             ]
141         )
142         with open(join(data_dir, 'tahoe.cfg'), 'w') as f:
143             f.write('''
144 [node]
145 nickname = %(name)s
146 web.port = tcp:998%(node_id)d:interface=localhost
147 web.static = public_html
148
149 [client]
150 # Which services should this client connect to?
151 introducer.furl = %(furl)s
152 shares.needed = 2
153 shares.happy = 3
154 shares.total = 4
155 ''' % {'name':name, 'node_id':node_id, 'furl':furl})
156     subprocess.check_call(
157         [
158             python, tahoe_bin, 'start', data_dir,
159         ]
160     )
161     node_id += 1
162
163 # okay, now we have alice + bob (alice, bob)
164 # now we have alice create a magic-folder, and invite bob to it
165
166 if do_invites:
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(
171         [
172             python, tahoe_bin, 'magic-folder', 'create', '--basedir', data_dir, 'magik:', 'alice',
173             join(data_base, 'alice-magic'),
174         ]
175     )
176     print("Alice invites Bob")
177     invite = subprocess.check_output(
178         [
179             python, tahoe_bin, 'magic-folder', 'invite', '--basedir', data_dir, 'magik:', 'bob',
180         ]
181     )
182     print("  invite:", invite)
183
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(
188         [
189             python, tahoe_bin, 'magic-folder', 'join', '--basedir', data_dir, invite,
190             join(data_base, 'bob-magic'),
191         ]
192     )
193     print("Bob has joined.")
194
195     print("Restarting alice + bob clients")
196     subprocess.check_call(
197         [
198             python, tahoe_bin, 'restart', '--basedir', join(data_base, 'alice'),
199         ]
200     )
201     subprocess.check_call(
202         [
203             python, tahoe_bin, 'restart', '--basedir', join(data_base, 'bob'),
204         ]
205     )
206
207 if True:
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()))
211
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")
216 time.sleep(3)
217
218 if True:
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")
224
225     print("Waiting for:", bob_foo)
226     while True:
227         if exists(bob_foo):
228             print("  found", bob_foo)
229             with open(bob_foo, 'r') as f:
230                 if f.read() == "line one\n":
231                     break
232                 print("  file contents still mismatched")
233         time.sleep(1)
234
235 if True:
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")
241
242     print("Waiting for:", alice_bar)
243     while True:
244         if exists(bob_bar):
245             print("  found", bob_bar)
246             with open(bob_bar, 'r') as f:
247                 if f.read() == "line one\n":
248                     break
249                 print("  file contents still mismatched")
250         time.sleep(1)
251
252 if True:
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')
256     unlink(alice_foo)
257
258     print("Waiting for '%s' to disappear" % (bob_foo,))
259     while True:
260         if not exists(bob_foo):
261             print("  disappeared", bob_foo)
262             break
263         time.sleep(1)
264
265     bob_tmp = bob_foo + '.backup'
266     print("Waiting for '%s' to appear" % (bob_tmp,))
267     while True:
268         if exists(bob_tmp):
269             print("  appeared", bob_tmp)
270             break
271         time.sleep(1)
272
273 if True:
274     # bob writes new content to 'second_file'; alice should get it
275     # 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"
279
280     with open(bob_foo, 'w') as f:
281         f.write(gold_content)
282
283     print("Waiting for:", alice_foo)
284     while True:
285         if exists(alice_foo):
286             print("  found", alice_foo)
287             with open(alice_foo, 'r') as f:
288                 content = f.read()
289                 if content == gold_content:
290                     break
291                 print("  file contents still mismatched:\n")
292                 print(content)
293         time.sleep(1)
294
295 if True:
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'
300
301     mkdir(bob_dir)
302     with open(join(bob_dir, 'subfile'), 'w') as f:
303         f.write(gold_content)
304
305     print("Waiting for Bob's subdir '%s' to appear" % (bob_dir,))
306     while True:
307         if exists(bob_dir):
308             print("  found subdir")
309             if exists(join(bob_dir, 'subfile')):
310                 print("  found file")
311                 with open(join(bob_dir, 'subfile'), 'r') as f:
312                     if f.read() == gold_content:
313                         print("  contents match")
314                         break
315         time.sleep(0.1)
316
317 if True:
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)
322
323     print("Waiting for Alice's subdir '%s' to disappear" % (alice_dir,))
324     while True:
325         if not exists(alice_dir):
326             print("  it's gone")
327             break
328         time.sleep(0.1)
329
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!
332 if True:
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')
339     if True:
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"
343
344     with open(bob_foo, 'w') as f:
345         f.write(gold_content)
346
347     print("Waiting for:", alice_foo)
348     while True:
349         if exists(alice_foo):
350             print("  found", alice_foo)
351             with open(alice_foo, 'r') as f:
352                 content = f.read()
353                 if content == gold_content:
354                     break
355                 print("  file contents still mismatched: %d bytes:\n" % (len(content),))
356                 print(content)
357         else:
358             print("   %r not there yet" % (alice_foo,))
359         time.sleep(1)
360
361 # XXX test .backup (delete a file)
362
363 # port david's clock.advance stuff
364 # fix clock.advance()
365 # subdirectory
366 # file deletes
367 # conflicts