def alice_invite(reactor, alice, temp_dir, request): node_dir = join(temp_dir, 'alice') with start_action(action_type=u"integration:alice:magic_folder:create"): # FIXME XXX by the time we see "client running" in the logs, the # storage servers aren't "really" ready to roll yet (uploads fairly # consistently fail if we don't hack in this pause...) import time time.sleep(5) proto = _CollectOutputProtocol() reactor.spawnProcess(proto, sys.executable, [ sys.executable, '-m', 'allmydata.scripts.runner', 'magic-folder', 'create', '--poll-interval', '2', '--basedir', node_dir, 'magik:', 'alice', join(temp_dir, 'magic-alice'), ]) pytest_twisted.blockon(proto.done) with start_action( action_type=u"integration:alice:magic_folder:invite") as a: proto = _CollectOutputProtocol() reactor.spawnProcess(proto, sys.executable, [ sys.executable, '-m', 'allmydata.scripts.runner', 'magic-folder', 'invite', '--basedir', node_dir, 'magik:', 'bob', ]) pytest_twisted.blockon(proto.done) invite = proto.output.getvalue() a.add_success_fields(invite=invite) with start_action(action_type=u"integration:alice:magic_folder:restart"): # before magic-folder works, we have to stop and restart (this is # crappy for the tests -- can we fix it in magic-folder?) try: alice.signalProcess('TERM') pytest_twisted.blockon(alice.exited) except ProcessExitedAlready: pass with start_action( action_type=u"integration:alice:magic_folder:magic-text"): magic_text = 'Completed initial Magic Folder scan successfully' pytest_twisted.blockon( _run_node(reactor, node_dir, request, magic_text)) return invite
def test_daemon_inititialize(request, reactor, temp_dir): """ 'magic-folder init' happy-path works """ node_dir = join(temp_dir, "daemon") tahoe_dir = join(temp_dir, "tahoe") mkdir(tahoe_dir) with open(join(tahoe_dir, "tahoe.cfg"), "w") as f: f.write("# a fake config\n") with open(join(tahoe_dir, "node.url"), "w") as f: f.write('http://localhost:1234/') proto = util._CollectOutputProtocol() util._magic_folder_runner( proto, reactor, request, [ "--config", node_dir, "init", "--listen-endpoint", "tcp:1234", "--node-directory", tahoe_dir, ], ) yield proto.done proto = util._CollectOutputProtocol() util._magic_folder_runner( proto, reactor, request, [ "--config", node_dir, "show-config", ], ) output = yield proto.done config = loads(output) assert config["api_endpoint"] == "tcp:1234" assert config["tahoe_node_directory"] == tahoe_dir assert config["magic_folders"] == dict() # the API token should at least be base64-decodable and result in 32 bytes of entropy assert len(base64.urlsafe_b64decode( config["api_token"].encode("utf8"))) == 32
def alice_invite(reactor, alice, temp_dir, request): node_dir = join(temp_dir, 'alice') with start_action(action_type=u"integration:alice:magic_folder:create"): # FIXME XXX by the time we see "client running" in the logs, the # storage servers aren't "really" ready to roll yet (uploads fairly # consistently fail if we don't hack in this pause...) import time ; time.sleep(5) proto = _CollectOutputProtocol() reactor.spawnProcess( proto, sys.executable, [ sys.executable, '-m', 'allmydata.scripts.runner', 'magic-folder', 'create', '--poll-interval', '2', '--basedir', node_dir, 'magik:', 'alice', join(temp_dir, 'magic-alice'), ] ) pytest_twisted.blockon(proto.done) with start_action(action_type=u"integration:alice:magic_folder:invite") as a: proto = _CollectOutputProtocol() reactor.spawnProcess( proto, sys.executable, [ sys.executable, '-m', 'allmydata.scripts.runner', 'magic-folder', 'invite', '--basedir', node_dir, 'magik:', 'bob', ] ) pytest_twisted.blockon(proto.done) invite = proto.output.getvalue() a.add_success_fields(invite=invite) with start_action(action_type=u"integration:alice:magic_folder:restart"): # before magic-folder works, we have to stop and restart (this is # crappy for the tests -- can we fix it in magic-folder?) try: alice.signalProcess('TERM') pytest_twisted.blockon(alice.exited) except ProcessExitedAlready: pass with start_action(action_type=u"integration:alice:magic_folder:magic-text"): magic_text = 'Completed initial Magic Folder scan successfully' pytest_twisted.blockon(_run_node(reactor, node_dir, request, magic_text)) return invite
def magic_folder(reactor, alice_invite, alice, bob, temp_dir, request): print("pairing magic-folder") bob_dir = join(temp_dir, 'bob') proto = _CollectOutputProtocol() reactor.spawnProcess(proto, sys.executable, [ sys.executable, '-m', 'allmydata.scripts.runner', 'magic-folder', 'join', '--poll-interval', '2', '--basedir', bob_dir, alice_invite, join(temp_dir, 'magic-bob'), ]) pytest_twisted.blockon(proto.done) # before magic-folder works, we have to stop and restart (this is # crappy for the tests -- can we fix it in magic-folder?) try: print("Sending TERM to Bob") bob.signalProcess('TERM') pytest_twisted.blockon(bob.exited) except ProcessExitedAlready: pass magic_text = 'Completed initial Magic Folder scan successfully' pytest_twisted.blockon(_run_node(reactor, bob_dir, request, magic_text)) return (join(temp_dir, 'magic-alice'), join(temp_dir, 'magic-bob'))
def magic_folder(reactor, alice_invite, alice, bob, temp_dir, request): print("pairing magic-folder") bob_dir = join(temp_dir, 'bob') proto = _CollectOutputProtocol() transport = reactor.spawnProcess( proto, sys.executable, [ sys.executable, '-m', 'allmydata.scripts.runner', 'magic-folder', 'join', '--poll-interval', '2', '--basedir', bob_dir, alice_invite, join(temp_dir, 'magic-bob'), ] ) pytest.blockon(proto.done) # before magic-folder works, we have to stop and restart (this is # crappy for the tests -- can we fix it in magic-folder?) try: print("Sending TERM to Bob") bob.signalProcess('TERM') pytest.blockon(bob.exited) except ProcessExitedAlready: pass magic_text = 'Completed initial Magic Folder scan successfully' pytest.blockon(_run_node(reactor, bob_dir, request, magic_text)) return (join(temp_dir, 'magic-alice'), join(temp_dir, 'magic-bob'))
def magic_folder(reactor, alice_invite, alice, bob, temp_dir, request): print("pairing magic-folder") bob_dir = join(temp_dir, 'bob') proto = _CollectOutputProtocol() _tahoe_runner_optional_coverage(proto, reactor, request, [ 'magic-folder', 'join', '--poll-interval', '1', '--basedir', bob_dir, alice_invite, join(temp_dir, 'magic-bob'), ]) pytest_twisted.blockon(proto.done) # before magic-folder works, we have to stop and restart (this is # crappy for the tests -- can we fix it in magic-folder?) try: print("Sending TERM to Bob") bob.transport.signalProcess('TERM') pytest_twisted.blockon(bob.transport.exited) except ProcessExitedAlready: pass magic_text = 'Completed initial Magic Folder scan successfully' pytest_twisted.blockon(_run_node(reactor, bob_dir, request, magic_text)) await_client_ready(bob) return (join(temp_dir, 'magic-alice'), join(temp_dir, 'magic-bob'))
def test_upload_immutable(reactor, temp_dir, introducer_furl, flog_gatherer, storage_nodes, request): edna = yield util._create_node( reactor, request, temp_dir, introducer_furl, flog_gatherer, "edna", web_port="tcp:9983:interface=localhost", storage=False, needed=3, happy=7, total=10, ) util.await_client_ready(edna) node_dir = join(temp_dir, 'edna') # upload a file, which should fail because we have don't have 7 # storage servers (but happiness is set to 7) proto = util._CollectOutputProtocol() reactor.spawnProcess( proto, sys.executable, [ sys.executable, '-m', 'allmydata.scripts.runner', '-d', node_dir, 'put', __file__, ] ) try: yield proto.done assert False, "should raise exception" except Exception as e: assert isinstance(e, ProcessTerminated) output = proto.output.getvalue() assert "shares could be placed on only" in output
def test_onion_service_storage(reactor, request, temp_dir, flog_gatherer, tor_network, tor_introducer_furl): yield _create_anonymous_node(reactor, 'carol', 8008, request, temp_dir, flog_gatherer, tor_network, tor_introducer_furl) yield _create_anonymous_node(reactor, 'dave', 8009, request, temp_dir, flog_gatherer, tor_network, tor_introducer_furl) # ensure both nodes are connected to "a grid" by uploading # something via carol, and retrieve it using dave. gold_path = join(temp_dir, "gold") with open(gold_path, "w") as f: f.write("The object-capability model is a computer security model. A " "capability describes a transferable right to perform one (or " "more) operations on a given object.") # XXX could use treq or similar to POST these to their respective # WUIs instead ... proto = util._CollectOutputProtocol() reactor.spawnProcess(proto, sys.executable, ( sys.executable, '-m', 'allmydata.scripts.runner', '-d', join(temp_dir, 'carol'), 'put', gold_path, )) yield proto.done cap = proto.output.getvalue().strip().split()[-1] print("TEH CAP!", cap) proto = util._CollectOutputProtocol() reactor.spawnProcess(proto, sys.executable, ( sys.executable, '-m', 'allmydata.scripts.runner', '-d', join(temp_dir, 'dave'), 'get', cap, )) yield proto.done dave_got = proto.output.getvalue().strip() assert dave_got == open(gold_path, 'r').read().strip()
def test_onion_service_storage(reactor, request, temp_dir, flog_gatherer, tor_network, tor_introducer_furl): yield _create_anonymous_node(reactor, 'carol', 8008, request, temp_dir, flog_gatherer, tor_network, tor_introducer_furl) yield _create_anonymous_node(reactor, 'dave', 8009, request, temp_dir, flog_gatherer, tor_network, tor_introducer_furl) # ensure both nodes are connected to "a grid" by uploading # something via carol, and retrieve it using dave. gold_path = join(temp_dir, "gold") with open(gold_path, "w") as f: f.write( "The object-capability model is a computer security model. A " "capability describes a transferable right to perform one (or " "more) operations on a given object." ) # XXX could use treq or similar to POST these to their respective # WUIs instead ... proto = util._CollectOutputProtocol() reactor.spawnProcess( proto, sys.executable, ( sys.executable, '-m', 'allmydata.scripts.runner', '-d', join(temp_dir, 'carol'), 'put', gold_path, ) ) yield proto.done cap = proto.output.getvalue().strip().split()[-1] print("TEH CAP!", cap) proto = util._CollectOutputProtocol() reactor.spawnProcess( proto, sys.executable, ( sys.executable, '-m', 'allmydata.scripts.runner', '-d', join(temp_dir, 'dave'), 'get', cap, ) ) yield proto.done dave_got = proto.output.getvalue().strip() assert dave_got == open(gold_path, 'r').read().strip()
def test_add(request, reactor, temp_dir, alice): """ 'magic-folder add' happy-path works """ proto = util._CollectOutputProtocol() util._magic_folder_runner( proto, reactor, request, [ "--config", alice.magic_config_directory, "add", "--name", "test", "--author", "laptop", alice.magic_directory, ], ) yield proto.done proto = util._CollectOutputProtocol() util._magic_folder_runner( proto, reactor, request, [ "--config", alice.magic_config_directory, "show-config", ], ) output = yield proto.done config = loads(output) assert "test" in config["magic_folders"] mf_config = config["magic_folders"]["test"] assert mf_config["name"] == "test" assert mf_config["author_name"] == "laptop" expected_keys = ["stash_path", "author_private_key"] assert all(k in mf_config for k in expected_keys)
def flog_gatherer(reactor, temp_dir, flog_binary, request): out_protocol = _CollectOutputProtocol() gather_dir = join(temp_dir, 'flog_gather') reactor.spawnProcess(out_protocol, flog_binary, ( 'flogtool', 'create-gatherer', '--location', 'tcp:localhost:3117', '--port', '3117', gather_dir, )) pytest_twisted.blockon(out_protocol.done) twistd_protocol = _MagicTextProtocol("Gatherer waiting at") twistd_process = reactor.spawnProcess( twistd_protocol, which('twistd')[0], ( 'twistd', '--nodaemon', '--python', join(gather_dir, 'gatherer.tac'), ), path=gather_dir, ) pytest_twisted.blockon(twistd_protocol.magic_seen) def cleanup(): _cleanup_tahoe_process(twistd_process, twistd_protocol.exited) flog_file = mktemp('.flog_dump') flog_protocol = _DumpOutputProtocol(open(flog_file, 'w')) flog_dir = join(temp_dir, 'flog_gather') flogs = [x for x in listdir(flog_dir) if x.endswith('.flog')] print("Dumping {} flogtool logfiles to '{}'".format( len(flogs), flog_file)) reactor.spawnProcess( flog_protocol, flog_binary, ('flogtool', 'dump', join(temp_dir, 'flog_gather', flogs[0])), ) print("Waiting for flogtool to complete") try: pytest_twisted.blockon(flog_protocol.done) except ProcessTerminated as e: print("flogtool exited unexpectedly: {}".format(str(e))) print("Flogtool completed") request.addfinalizer(cleanup) with open(join(gather_dir, 'log_gatherer.furl'), 'r') as f: furl = f.read().strip() return furl
def flog_gatherer(reactor, temp_dir, flog_binary, request): out_protocol = _CollectOutputProtocol() gather_dir = join(temp_dir, 'flog_gather') reactor.spawnProcess( out_protocol, flog_binary, ( 'flogtool', 'create-gatherer', '--location', 'tcp:localhost:3117', '--port', '3117', gather_dir, ) ) pytest_twisted.blockon(out_protocol.done) twistd_protocol = _MagicTextProtocol("Gatherer waiting at") twistd_process = reactor.spawnProcess( twistd_protocol, which('twistd')[0], ( 'twistd', '--nodaemon', '--python', join(gather_dir, 'gatherer.tac'), ), path=gather_dir, ) pytest_twisted.blockon(twistd_protocol.magic_seen) def cleanup(): _cleanup_twistd_process(twistd_process, twistd_protocol.exited) flog_file = mktemp('.flog_dump') flog_protocol = _DumpOutputProtocol(open(flog_file, 'w')) flog_dir = join(temp_dir, 'flog_gather') flogs = [x for x in listdir(flog_dir) if x.endswith('.flog')] print("Dumping {} flogtool logfiles to '{}'".format(len(flogs), flog_file)) reactor.spawnProcess( flog_protocol, flog_binary, ( 'flogtool', 'dump', join(temp_dir, 'flog_gather', flogs[0]) ), ) print("Waiting for flogtool to complete") try: pytest_twisted.blockon(flog_protocol.done) except ProcessTerminated as e: print("flogtool exited unexpectedly: {}".format(str(e))) print("Flogtool completed") request.addfinalizer(cleanup) with open(join(gather_dir, 'log_gatherer.furl'), 'r') as f: furl = f.read().strip() return furl
def test_daemon_migrate(request, reactor, alice, temp_dir): """ 'magic-folder migrate' happy-path works """ node_dir = join(temp_dir, "test-daemon-migrate") # if we're depending on a "new" tahoe (which we should) then # there's no "tahoe magic-folder" to create "legacy" config for us # to migrate. So, we create an (empty) config. with open(join(alice.node_directory, "private", "magic_folders.yaml"), "w") as f: f.write("magic-folders: {}\n") proto = util._DumpOutputProtocol(None) util._magic_folder_runner( proto, reactor, request, [ "--config", node_dir, "migrate", "--listen-endpoint", "tcp:1234", "--node-directory", alice.node_directory, "--author", "test", ], ) yield proto.done proto = util._CollectOutputProtocol() util._magic_folder_runner( proto, reactor, request, [ "--config", node_dir, "show-config", ], ) output = yield proto.done config = loads(output) assert config["api_endpoint"] == "tcp:1234" assert config["magic_folders"] == dict() # the API token should at least be base64-decodable and result in 32 bytes of entropy assert len(base64.urlsafe_b64decode( config["api_token"].encode("utf8"))) == 32
def cleanup(): print("Tearing down Chutney Tor network") proto = _CollectOutputProtocol() reactor.spawnProcess( proto, sys.executable, ( sys.executable, '-m', 'chutney.TorNet', 'stop', join(chutney_dir, 'networks', 'basic'), ), path=join(chutney_dir), env={"PYTHONPATH": join(chutney_dir, "lib")}, ) pytest.blockon(proto.done)
def cleanup(): print("Tearing down Chutney Tor network") proto = _CollectOutputProtocol() reactor.spawnProcess( proto, sys.executable, ( sys.executable, '-m', 'chutney.TorNet', 'stop', join(chutney_dir, 'networks', 'basic'), ), path=join(chutney_dir), env=env, ) pytest_twisted.blockon(proto.done)
def test_upload_immutable(reactor, temp_dir, introducer_furl, flog_gatherer, storage_nodes, request): # hmm, for some reason this still gets storage enabled ... process = yield util._create_node( reactor, request, temp_dir, introducer_furl, flog_gatherer, "edna", web_port="tcp:9983:interface=localhost", storage=False, needed=3, happy=10, total=10, ) node_dir = join(temp_dir, 'edna') print("waiting 5 seconds unil we're maybe ready") yield task.deferLater(reactor, 5, lambda: None) # upload a file, which should fail because we have don't have 7 # storage servers (but happiness is set to 7) proto = util._CollectOutputProtocol() transport = reactor.spawnProcess(proto, sys.executable, [ sys.executable, '-m', 'allmydata.scripts.runner', '-d', node_dir, 'put', __file__, ]) try: yield proto.done assert False, "should raise exception" except Exception as e: assert isinstance(e, ProcessTerminated) output = proto.output.getvalue() assert "shares could be placed on only" in output
def cleanup(): print("Tearing down Chutney Tor network") proto = _CollectOutputProtocol() reactor.spawnProcess( proto, sys.executable, ( sys.executable, '-m', 'chutney.TorNet', 'stop', join(chutney_dir, 'networks', 'basic'), ), path=join(chutney_dir), env=env, ) try: block_with_timeout(proto.done, reactor) except ProcessTerminated: # If this doesn't exit cleanly, that's fine, that shouldn't fail # the test suite. pass
def test_upload_immutable(reactor, temp_dir, introducer_furl, flog_gatherer, storage_nodes, request): yield util._create_node( reactor, request, temp_dir, introducer_furl, flog_gatherer, "edna", web_port="tcp:9983:interface=localhost", storage=False, needed=3, happy=7, total=10, ) node_dir = join(temp_dir, 'edna') print("waiting 10 seconds unil we're maybe ready") yield task.deferLater(reactor, 10, lambda: None) # upload a file, which should fail because we have don't have 7 # storage servers (but happiness is set to 7) proto = util._CollectOutputProtocol() reactor.spawnProcess( proto, sys.executable, [ sys.executable, '-m', 'allmydata.scripts.runner', '-d', node_dir, 'put', __file__, ] ) try: yield proto.done assert False, "should raise exception" except Exception as e: assert isinstance(e, ProcessTerminated) output = proto.output.getvalue() assert "shares could be placed on only" in output
def test_web_port_required(request, reactor, temp_dir, introducer_furl): """ 'magic-folder run' requires --web-port option """ # enough of a node-dir for "magic-folder" to run .. maybe we # should create a real one? node_dir = join(temp_dir, "webport") mkdir(node_dir) with open(join(node_dir, "tahoe.cfg"), "w") as f: f.write('') with open(join(node_dir, "node.url"), "w") as f: f.write('http://localhost/') # run "magic-folder run" without --web-port which should error proto = util._CollectOutputProtocol() proc = util._magic_folder_runner( proto, reactor, request, [ "--node-directory", node_dir, "run", ], ) try: yield proto.done except ProcessTerminated as e: assert e.exitCode != 0 assert u"Must specify a listening endpoint with --web-port" in proto.output.getvalue( ) return assert False, "Expected an error from magic-folder" print("output: '{}'".format(proto.output.getvalue()))
def tor_network(reactor, temp_dir, chutney, request): # this is the actual "chutney" script at the root of a chutney checkout chutney_dir = chutney chut = join(chutney_dir, 'chutney') # now, as per Chutney's README, we have to create the network # ./chutney configure networks/basic # ./chutney start networks/basic env = environ.copy() env.update({"PYTHONPATH": join(chutney_dir, "lib")}) proto = _DumpOutputProtocol(None) reactor.spawnProcess( proto, sys.executable, ( sys.executable, '-m', 'chutney.TorNet', 'configure', join(chutney_dir, 'networks', 'basic'), ), path=join(chutney_dir), env=env, ) pytest_twisted.blockon(proto.done) proto = _DumpOutputProtocol(None) reactor.spawnProcess( proto, sys.executable, ( sys.executable, '-m', 'chutney.TorNet', 'start', join(chutney_dir, 'networks', 'basic'), ), path=join(chutney_dir), env=env, ) pytest_twisted.blockon(proto.done) # print some useful stuff proto = _CollectOutputProtocol() reactor.spawnProcess( proto, sys.executable, ( sys.executable, '-m', 'chutney.TorNet', 'status', join(chutney_dir, 'networks', 'basic'), ), path=join(chutney_dir), env=env, ) try: pytest_twisted.blockon(proto.done) except ProcessTerminated: print("Chutney.TorNet status failed (continuing):") print(proto.output.getvalue()) def cleanup(): print("Tearing down Chutney Tor network") proto = _CollectOutputProtocol() reactor.spawnProcess( proto, sys.executable, ( sys.executable, '-m', 'chutney.TorNet', 'stop', join(chutney_dir, 'networks', 'basic'), ), path=join(chutney_dir), env=env, ) pytest_twisted.blockon(proto.done) request.addfinalizer(cleanup) return chut
def test_edmond_uploads_then_restarts(reactor, request, temp_dir, introducer_furl, flog_gatherer, storage_nodes): """ ticket 2880: if a magic-folder client uploads something, then re-starts a spurious .backup file should not appear """ edmond_dir = join(temp_dir, 'edmond') edmond = yield util._create_node( reactor, request, temp_dir, introducer_furl, flog_gatherer, "edmond", web_port="tcp:9985:interface=localhost", storage=False, ) magic_folder = join(temp_dir, 'magic-edmond') mkdir(magic_folder) created = False # create a magic-folder # (how can we know that the grid is ready?) for _ in range(10): # try 10 times try: proto = util._CollectOutputProtocol() transport = reactor.spawnProcess( proto, sys.executable, [ sys.executable, '-m', 'allmydata.scripts.runner', 'magic-folder', 'create', '--poll-interval', '2', '--basedir', edmond_dir, 'magik:', 'edmond_magic', magic_folder, ] ) yield proto.done created = True break except Exception as e: print("failed to create magic-folder: {}".format(e)) time.sleep(1) assert created, "Didn't create a magic-folder" # to actually-start the magic-folder we have to re-start edmond.signalProcess('TERM') yield edmond._protocol.exited time.sleep(1) edmond = yield util._run_node(reactor, edmond._node_dir, request, 'Completed initial Magic Folder scan successfully') # add a thing to the magic-folder with open(join(magic_folder, "its_a_file"), "w") as f: f.write("edmond wrote this") # fixme, do status-update attempts in a loop below time.sleep(5) # let it upload; poll the HTTP magic-folder status API until it is # uploaded from allmydata.scripts.magic_folder_cli import _get_json_for_fragment with open(join(edmond_dir, u'private', u'api_auth_token'), 'rb') as f: token = f.read() uploaded = False for _ in range(10): options = { "node-url": open(join(edmond_dir, u'node.url'), 'r').read().strip(), } try: magic_data = _get_json_for_fragment( options, 'magic_folder?t=json', method='POST', post_args=dict( t='json', name='default', token=token, ) ) for mf in magic_data: if mf['status'] == u'success' and mf['path'] == u'its_a_file': uploaded = True break except Exception as e: time.sleep(1) assert uploaded, "expected to upload 'its_a_file'" # re-starting edmond right now would "normally" trigger the 2880 bug # kill edmond edmond.signalProcess('TERM') yield edmond._protocol.exited time.sleep(1) edmond = yield util._run_node(reactor, edmond._node_dir, request, 'Completed initial Magic Folder scan successfully') # XXX how can we say for sure if we've waited long enough? look at # tail of logs for magic-folder ... somethingsomething? print("waiting 20 seconds to see if a .backup appears") for _ in range(20): assert exists(join(magic_folder, "its_a_file")) assert not exists(join(magic_folder, "its_a_file.backup")) time.sleep(1)
def tor_network(reactor, temp_dir, chutney, request): # this is the actual "chutney" script at the root of a chutney checkout chutney_dir = chutney chut = join(chutney_dir, 'chutney') # now, as per Chutney's README, we have to create the network # ./chutney configure networks/basic # ./chutney start networks/basic proto = _DumpOutputProtocol(None) reactor.spawnProcess( proto, sys.executable, ( sys.executable, '-m', 'chutney.TorNet', 'configure', join(chutney_dir, 'networks', 'basic'), ), path=join(chutney_dir), env={"PYTHONPATH": join(chutney_dir, "lib")}, ) pytest.blockon(proto.done) proto = _DumpOutputProtocol(None) reactor.spawnProcess( proto, sys.executable, ( sys.executable, '-m', 'chutney.TorNet', 'start', join(chutney_dir, 'networks', 'basic'), ), path=join(chutney_dir), env={"PYTHONPATH": join(chutney_dir, "lib")}, ) pytest.blockon(proto.done) # print some useful stuff proto = _CollectOutputProtocol() reactor.spawnProcess( proto, sys.executable, ( sys.executable, '-m', 'chutney.TorNet', 'status', join(chutney_dir, 'networks', 'basic'), ), path=join(chutney_dir), env={"PYTHONPATH": join(chutney_dir, "lib")}, ) pytest.blockon(proto.done) def cleanup(): print("Tearing down Chutney Tor network") proto = _CollectOutputProtocol() reactor.spawnProcess( proto, sys.executable, ( sys.executable, '-m', 'chutney.TorNet', 'stop', join(chutney_dir, 'networks', 'basic'), ), path=join(chutney_dir), env={"PYTHONPATH": join(chutney_dir, "lib")}, ) pytest.blockon(proto.done) request.addfinalizer(cleanup) return chut
def test_edmond_uploads_then_restarts(reactor, request, temp_dir, introducer_furl, flog_gatherer, storage_nodes): """ ticket 2880: if a magic-folder client uploads something, then re-starts a spurious .backup file should not appear """ edmond_dir = join(temp_dir, 'edmond') edmond = yield util._create_node( reactor, request, temp_dir, introducer_furl, flog_gatherer, "edmond", web_port="tcp:9985:interface=localhost", storage=False, ) magic_folder = join(temp_dir, 'magic-edmond') mkdir(magic_folder) created = False # create a magic-folder # (how can we know that the grid is ready?) for _ in range(10): # try 10 times try: proto = util._CollectOutputProtocol() transport = reactor.spawnProcess(proto, sys.executable, [ sys.executable, '-m', 'allmydata.scripts.runner', 'magic-folder', 'create', '--poll-interval', '2', '--basedir', edmond_dir, 'magik:', 'edmond_magic', magic_folder, ]) yield proto.done created = True break except Exception as e: print("failed to create magic-folder: {}".format(e)) time.sleep(1) assert created, "Didn't create a magic-folder" # to actually-start the magic-folder we have to re-start edmond.signalProcess('TERM') yield edmond._protocol.exited time.sleep(1) edmond = yield util._run_node( reactor, edmond._node_dir, request, 'Completed initial Magic Folder scan successfully') # add a thing to the magic-folder with open(join(magic_folder, "its_a_file"), "w") as f: f.write("edmond wrote this") # fixme, do status-update attempts in a loop below time.sleep(5) # let it upload; poll the HTTP magic-folder status API until it is # uploaded from allmydata.scripts.magic_folder_cli import _get_json_for_fragment with open(join(edmond_dir, u'private', u'api_auth_token'), 'rb') as f: token = f.read() uploaded = False for _ in range(10): options = { "node-url": open(join(edmond_dir, u'node.url'), 'r').read().strip(), } try: magic_data = _get_json_for_fragment(options, 'magic_folder?t=json', method='POST', post_args=dict( t='json', name='default', token=token, )) for mf in magic_data: if mf['status'] == u'success' and mf['path'] == u'its_a_file': uploaded = True break except Exception as e: time.sleep(1) assert uploaded, "expected to upload 'its_a_file'" # re-starting edmond right now would "normally" trigger the 2880 bug # kill edmond edmond.signalProcess('TERM') yield edmond._protocol.exited time.sleep(1) edmond = yield util._run_node( reactor, edmond._node_dir, request, 'Completed initial Magic Folder scan successfully') # XXX how can we say for sure if we've waited long enough? look at # tail of logs for magic-folder ... somethingsomething? print("waiting 20 seconds to see if a .backup appears") for _ in range(20): assert exists(join(magic_folder, "its_a_file")) assert not exists(join(magic_folder, "its_a_file.backup")) time.sleep(1)
def test_list(request, reactor, temp_dir, introducer_furl, flog_gatherer): """ 'magic-folder list' happy-path works """ with start_action(action_type=u"integration:test_list:zelda", include_args=[], include_result=False): zelda = yield util.MagicFolderEnabledNode.create( reactor, request, temp_dir, introducer_furl, flog_gatherer, name="zelda", tahoe_web_port="tcp:9982:interface=localhost", magic_folder_web_port="tcp:19982:interface=localhost", storage=True, ) proto = util._CollectOutputProtocol() util._magic_folder_runner( proto, reactor, request, [ "--config", zelda.magic_config_directory, "list", ], ) output = yield proto.done assert output.strip() == "No magic-folders" magic_dir = FilePath(temp_dir).child("zelda-magic") magic_dir.makedirs() proto = util._CollectOutputProtocol() util._magic_folder_runner( proto, reactor, request, [ "--config", zelda.magic_config_directory, "add", "--author", "laptop", "--name", "workstuff", magic_dir.path, ], ) output = yield proto.done proto = util._CollectOutputProtocol() util._magic_folder_runner( proto, reactor, request, [ "--config", zelda.magic_config_directory, "list", "--json", ], ) output = yield proto.done data = json.loads(output) assert list(data.keys()) == ["workstuff"] assert data["workstuff"]["name"] == "workstuff" assert int(data["workstuff"]["poll_interval"]) == 60 assert data["workstuff"]["magic_path"] == magic_dir.path assert data["workstuff"]["is_admin"] == True # make sure we didn't reveal secrets assert "signing_key" not in data["workstuff"]["author"] assert "upload_dircap" not in data["workstuff"] assert "collective_dircap" not in data["workstuff"]