tahoe-lafs/src/allmydata/test/check_magicfolder_smoke.py
Daira Hopwood d1eb64c01b bin\tahoe can't be run directly on Windows.
Signed-off-by: Daira Hopwood <daira@jacaranda.org>
2016-07-21 12:35:59 -07:00

368 lines
11 KiB
Python

#!/usr/bin/env python
# this is a smoke-test using "./bin/tahoe" to:
#
# 1. create an introducer
# 2. create 5 storage nodes
# 3. create 2 client nodes (alice, bob)
# 4. Alice creates a magic-folder ("magik:")
# 5. Alice invites Bob
# 6. Bob joins
#
# After that, some basic tests are performed; see the "if True:"
# blocks to turn some on or off. Could benefit from some cleanups
# etc. but this seems useful out of the gate for quick testing.
#
# TO RUN:
# from top-level of your checkout (we use "./bin/tahoe"):
# python src/allmydata/test/check_magicfolder_smoke.py
#
# This will create "./smoke_magicfolder" (which is disposable) and
# contains all the Tahoe basedirs for the introducer, storage nodes,
# clients, and the clients' magic-folders. NOTE that if these
# directories already exist they will NOT be re-created. So kill the
# grid and then "rm -rf smoke_magicfolder" if you want to re-run the
# tests cleanly.
#
# Run the script with a single arg, "kill" to run "tahoe stop" on all
# the nodes.
#
# This will have "tahoe start" -ed all the nodes, so you can continue
# to play around after the script exits.
from __future__ import print_function
import sys
import time
import shutil
import subprocess
from os.path import join, abspath, curdir, exists
from os import mkdir, listdir, unlink
tahoe_base = abspath(curdir)
data_base = join(tahoe_base, 'smoke_magicfolder')
tahoe_bin = join(tahoe_base, 'bin', 'tahoe')
python = sys.executable
if not exists(data_base):
print("Creating", data_base)
mkdir(data_base)
if not exists(tahoe_bin):
raise RuntimeError("Can't find 'tahoe' binary at %r" % (tahoe_bin,))
if 'kill' in sys.argv:
print("Killing the grid")
for d in listdir(data_base):
print("killing", d)
subprocess.call(
[
python, tahoe_bin, 'stop', join(data_base, d),
]
)
sys.exit(0)
if not exists(join(data_base, 'introducer')):
subprocess.check_call(
[
python, tahoe_bin, 'create-introducer', join(data_base, 'introducer'),
]
)
with open(join(data_base, 'introducer', 'tahoe.cfg'), 'w') as f:
f.write('''
[node]
nickname = introducer0
web.port = 4560
''')
subprocess.check_call(
[
python, tahoe_bin, 'start', join(data_base, 'introducer'),
]
)
furl_fname = join(data_base, 'introducer', 'private', 'introducer.furl')
while not exists(furl_fname):
time.sleep(1)
furl = open(furl_fname, 'r').read()
print("FURL", furl)
for x in range(5):
data_dir = join(data_base, 'node%d' % x)
if not exists(data_dir):
subprocess.check_call(
[
python, tahoe_bin, 'create-node',
'--nickname', 'node%d' % (x,),
'--introducer', furl,
data_dir,
]
)
with open(join(data_dir, 'tahoe.cfg'), 'w') as f:
f.write('''
[node]
nickname = node%(node_id)s
web.port =
web.static = public_html
tub.location = localhost:%(tub_port)d
[client]
# Which services should this client connect to?
introducer.furl = %(furl)s
shares.needed = 2
shares.happy = 3
shares.total = 4
''' % {'node_id':x, 'furl':furl, 'tub_port':(9900 + x)})
subprocess.check_call(
[
python, tahoe_bin, 'start', data_dir,
]
)
# alice and bob clients
do_invites = False
node_id = 0
for name in ['alice', 'bob']:
data_dir = join(data_base, name)
magic_dir = join(data_base, '%s-magic' % (name,))
mkdir(magic_dir)
if not exists(data_dir):
do_invites = True
subprocess.check_call(
[
python, tahoe_bin, 'create-node',
'--no-storage',
'--nickname', name,
'--introducer', furl,
data_dir,
]
)
with open(join(data_dir, 'tahoe.cfg'), 'w') as f:
f.write('''
[node]
nickname = %(name)s
web.port = tcp:998%(node_id)d:interface=localhost
web.static = public_html
[client]
# Which services should this client connect to?
introducer.furl = %(furl)s
shares.needed = 2
shares.happy = 3
shares.total = 4
''' % {'name':name, 'node_id':node_id, 'furl':furl})
subprocess.check_call(
[
python, tahoe_bin, 'start', data_dir,
]
)
node_id += 1
# okay, now we have alice + bob (alice, bob)
# now we have alice create a magic-folder, and invite bob to it
if do_invites:
data_dir = join(data_base, 'alice')
# alice creates her folder, invites bob
print("Alice creates a magic-folder")
subprocess.check_call(
[
python, tahoe_bin, 'magic-folder', 'create', '--basedir', data_dir, 'magik:', 'alice',
join(data_base, 'alice-magic'),
]
)
print("Alice invites Bob")
invite = subprocess.check_output(
[
python, tahoe_bin, 'magic-folder', 'invite', '--basedir', data_dir, 'magik:', 'bob',
]
)
print(" invite:", invite)
# now we let "bob"/bob join
print("Bob joins Alice's magic folder")
data_dir = join(data_base, 'bob')
subprocess.check_call(
[
python, tahoe_bin, 'magic-folder', 'join', '--basedir', data_dir, invite,
join(data_base, 'bob-magic'),
]
)
print("Bob has joined.")
print("Restarting alice + bob clients")
subprocess.check_call(
[
python, tahoe_bin, 'restart', '--basedir', join(data_base, 'alice'),
]
)
subprocess.check_call(
[
python, tahoe_bin, 'restart', '--basedir', join(data_base, 'bob'),
]
)
if True:
for name in ['alice', 'bob']:
with open(join(data_base, name, 'private', 'magic_folder_dircap'), 'r') as f:
print("dircap %s: %s" % (name, f.read().strip()))
# give storage nodes a chance to connect properly? I'm not entirely
# sure what's up here, but I get "UnrecoverableFileError" on the
# first_file upload from Alice "very often" otherwise
print("waiting 3 seconds")
time.sleep(3)
if True:
# alice writes a file; bob should get it
alice_foo = join(data_base, 'alice-magic', 'first_file')
bob_foo = join(data_base, 'bob-magic', 'first_file')
with open(alice_foo, 'w') as f:
f.write("line one\n")
print("Waiting for:", bob_foo)
while True:
if exists(bob_foo):
print(" found", bob_foo)
with open(bob_foo, 'r') as f:
if f.read() == "line one\n":
break
print(" file contents still mismatched")
time.sleep(1)
if True:
# bob writes a file; alice should get it
alice_bar = join(data_base, 'alice-magic', 'second_file')
bob_bar = join(data_base, 'bob-magic', 'second_file')
with open(bob_bar, 'w') as f:
f.write("line one\n")
print("Waiting for:", alice_bar)
while True:
if exists(bob_bar):
print(" found", bob_bar)
with open(bob_bar, 'r') as f:
if f.read() == "line one\n":
break
print(" file contents still mismatched")
time.sleep(1)
if True:
# alice deletes 'first_file'
alice_foo = join(data_base, 'alice-magic', 'first_file')
bob_foo = join(data_base, 'bob-magic', 'first_file')
unlink(alice_foo)
print("Waiting for '%s' to disappear" % (bob_foo,))
while True:
if not exists(bob_foo):
print(" disappeared", bob_foo)
break
time.sleep(1)
bob_tmp = bob_foo + '.backup'
print("Waiting for '%s' to appear" % (bob_tmp,))
while True:
if exists(bob_tmp):
print(" appeared", bob_tmp)
break
time.sleep(1)
if True:
# bob writes new content to 'second_file'; alice should get it
# get it.
alice_foo = join(data_base, 'alice-magic', 'second_file')
bob_foo = join(data_base, 'bob-magic', 'second_file')
gold_content = "line one\nsecond line\n"
with open(bob_foo, 'w') as f:
f.write(gold_content)
print("Waiting for:", alice_foo)
while True:
if exists(alice_foo):
print(" found", alice_foo)
with open(alice_foo, 'r') as f:
content = f.read()
if content == gold_content:
break
print(" file contents still mismatched:\n")
print(content)
time.sleep(1)
if True:
# bob creates a sub-directory and adds a file to it
alice_dir = join(data_base, 'alice-magic', 'subdir')
bob_dir = join(data_base, 'alice-magic', 'subdir')
gold_content = 'a file in a subdirectory\n'
mkdir(bob_dir)
with open(join(bob_dir, 'subfile'), 'w') as f:
f.write(gold_content)
print("Waiting for Bob's subdir '%s' to appear" % (bob_dir,))
while True:
if exists(bob_dir):
print(" found subdir")
if exists(join(bob_dir, 'subfile')):
print(" found file")
with open(join(bob_dir, 'subfile'), 'r') as f:
if f.read() == gold_content:
print(" contents match")
break
time.sleep(0.1)
if True:
# bob deletes the whole subdir
alice_dir = join(data_base, 'alice-magic', 'subdir')
bob_dir = join(data_base, 'alice-magic', 'subdir')
shutil.rmtree(bob_dir)
print("Waiting for Alice's subdir '%s' to disappear" % (alice_dir,))
while True:
if not exists(alice_dir):
print(" it's gone")
break
time.sleep(0.1)
# XXX restore the file not working (but, unit-tests work; what's wrong with them?)
# NOTE: only not-works if it's alice restoring the file!
if True:
# restore 'first_file' but with different contents
print("re-writing 'first_file'")
assert not exists(join(data_base, 'bob-magic', 'first_file'))
assert not exists(join(data_base, 'alice-magic', 'first_file'))
alice_foo = join(data_base, 'alice-magic', 'first_file')
bob_foo = join(data_base, 'bob-magic', 'first_file')
if True:
# if we don't swap around, it works fine
alice_foo, bob_foo = bob_foo, alice_foo
gold_content = "see it again for the first time\n"
with open(bob_foo, 'w') as f:
f.write(gold_content)
print("Waiting for:", alice_foo)
while True:
if exists(alice_foo):
print(" found", alice_foo)
with open(alice_foo, 'r') as f:
content = f.read()
if content == gold_content:
break
print(" file contents still mismatched: %d bytes:\n" % (len(content),))
print(content)
else:
print(" %r not there yet" % (alice_foo,))
time.sleep(1)
# XXX test .backup (delete a file)
# port david's clock.advance stuff
# fix clock.advance()
# subdirectory
# file deletes
# conflicts