1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: Apache-2.0
5 from __future__ import print_function
6 from __future__ import division
7 from builtins import str
8 from builtins import range
29 MY_DIRNAME = os.path.dirname(os.path.realpath(__file__))
30 if __name__ == '__main__' and os.path.exists(
31 os.path.join(MY_DIRNAME, '..', 'arvados', '__init__.py')):
32 # We're being launched to support another test suite.
33 # Add the Python SDK source to the library path.
34 sys.path.insert(1, os.path.dirname(MY_DIRNAME))
39 ARVADOS_DIR = os.path.realpath(os.path.join(MY_DIRNAME, '../../..'))
40 SERVICES_SRC_DIR = os.path.join(ARVADOS_DIR, 'services')
41 if 'GOPATH' in os.environ:
42 # Add all GOPATH bin dirs to PATH -- but insert them after the
43 # ruby gems bin dir, to ensure "bundle" runs the Ruby bundler
44 # command, not the golang.org/x/tools/cmd/bundle command.
45 gopaths = os.environ['GOPATH'].split(':')
46 addbins = [os.path.join(path, 'bin') for path in gopaths]
48 for path in os.environ['PATH'].split(':'):
50 if os.path.exists(os.path.join(path, 'bundle')):
54 os.environ['PATH'] = ':'.join(newbins)
56 TEST_TMPDIR = os.path.join(ARVADOS_DIR, 'tmp')
57 if not os.path.exists(TEST_TMPDIR):
62 _cached_db_config = {}
64 def find_server_pid(PID_PATH, wait=10):
68 while (not good_pid) and (now <= timeout):
71 with open(PID_PATH, 'r') as f:
72 server_pid = int(f.read())
73 good_pid = (os.kill(server_pid, 0) is None)
74 except EnvironmentError:
83 def kill_server_pid(pidfile, wait=10, passenger_root=False):
84 # Must re-import modules in order to work during atexit
95 # First try to shut down nicely
96 restore_cwd = os.getcwd()
97 os.chdir(passenger_root)
99 'bundle', 'exec', 'passenger', 'stop', '--pid-file', pidfile])
100 os.chdir(restore_cwd)
101 # Use up to half of the +wait+ period waiting for "passenger
102 # stop" to work. If the process hasn't exited by then, start
103 # sending TERM signals.
107 while now <= deadline and server_pid is None:
109 with open(pidfile, 'r') as f:
110 server_pid = int(f.read())
112 # No pidfile = nothing to kill.
114 except ValueError as error:
115 # Pidfile exists, but we can't parse it. Perhaps the
116 # server has created the file but hasn't written its PID
118 print("Parse error reading pidfile {}: {}".format(pidfile, error),
123 while now <= deadline:
125 exited, _ = os.waitpid(server_pid, os.WNOHANG)
127 _remove_pidfile(pidfile)
130 # already exited, or isn't our child process
134 os.kill(server_pid, signal.SIGTERM)
135 print("Sent SIGTERM to {} ({})".format(server_pid, pidfile),
137 except OSError as error:
138 if error.errno == errno.ESRCH:
139 # Thrown by os.getpgid() or os.kill() if the process
140 # does not exist, i.e., our work here is done.
141 _remove_pidfile(pidfile)
147 print("Server PID {} ({}) did not exit, giving up after {}s".
148 format(server_pid, pidfile, wait),
151 def _remove_pidfile(pidfile):
155 if os.path.lexists(pidfile):
158 def find_available_port():
159 """Return an IPv4 port number that is not in use right now.
161 We assume whoever needs to use the returned port is able to reuse
162 a recently used port without waiting for TIME_WAIT (see
163 SO_REUSEADDR / SO_REUSEPORT).
165 Some opportunity for races here, but it's better than choosing
166 something at random and not checking at all. If all of our servers
167 (hey Passenger) knew that listening on port 0 was a thing, the OS
168 would take care of the races, and this wouldn't be needed at all.
171 sock = socket.socket()
172 sock.bind(('0.0.0.0', 0))
173 port = sock.getsockname()[1]
177 def _wait_until_port_listens(port, timeout=10):
178 """Wait for a process to start listening on the given port.
180 If nothing listens on the port within the specified timeout (given
181 in seconds), print a warning on stderr before returning.
184 subprocess.check_output(['which', 'lsof'])
185 except subprocess.CalledProcessError:
186 print("WARNING: No `lsof` -- cannot wait for port to listen. "+
187 "Sleeping 0.5 and hoping for the best.",
191 deadline = time.time() + timeout
192 while time.time() < deadline:
194 subprocess.check_output(
195 ['lsof', '-t', '-i', 'tcp:'+str(port)])
196 except subprocess.CalledProcessError:
201 "WARNING: Nothing is listening on port {} (waited {} seconds).".
202 format(port, timeout),
205 def _fifo2stderr(label):
206 """Create a fifo, and copy it to stderr, prepending label to each line.
208 Return value is the path to the new FIFO.
210 +label+ should contain only alphanumerics: it is also used as part
211 of the FIFO filename.
213 fifo = os.path.join(TEST_TMPDIR, label+'.fifo')
216 except OSError as error:
217 if error.errno != errno.ENOENT:
219 os.mkfifo(fifo, 0o700)
221 ['stdbuf', '-i0', '-oL', '-eL', 'sed', '-e', 's/^/['+label+'] /', fifo],
225 def run(leave_running_atexit=False):
226 """Ensure an API server is running, and ARVADOS_API_* env vars have
227 admin credentials for it.
229 If ARVADOS_TEST_API_HOST is set, a parent process has started a
230 test server for us to use: we just need to reset() it using the
233 If a previous call to run() started a new server process, and it
234 is still running, we just need to reset() it to fixture state and
237 If neither of those options work out, we'll really start a new
242 # Delete cached discovery documents.
244 # This will clear cached docs that belong to other processes (like
245 # concurrent test suites) even if they're still running. They should
246 # be able to tolerate that.
247 for fn in glob.glob(os.path.join(
248 str(arvados.http_cache('discovery')),
249 '*,arvados,v1,rest,*')):
252 pid_file = _pidfile('api')
253 pid_file_ok = find_server_pid(pid_file, 0)
255 existing_api_host = os.environ.get('ARVADOS_TEST_API_HOST', my_api_host)
256 if existing_api_host and pid_file_ok:
257 if existing_api_host == my_api_host:
261 # Fall through to shutdown-and-start case.
264 # Server was provided by parent. Can't recover if it's
268 # Before trying to start up our own server, call stop() to avoid
269 # "Phusion Passenger Standalone is already running on PID 12345".
270 # (If we've gotten this far, ARVADOS_TEST_API_HOST isn't set, so
271 # we know the server is ours to kill.)
274 restore_cwd = os.getcwd()
275 api_src_dir = os.path.join(SERVICES_SRC_DIR, 'api')
276 os.chdir(api_src_dir)
278 # Either we haven't started a server of our own yet, or it has
279 # died, or we have lost our credentials, or something else is
280 # preventing us from calling reset(). Start a new one.
282 if not os.path.exists('tmp'):
285 if not os.path.exists('tmp/api'):
286 os.makedirs('tmp/api')
288 if not os.path.exists('tmp/logs'):
289 os.makedirs('tmp/logs')
291 if not os.path.exists('tmp/self-signed.pem'):
292 # We assume here that either passenger reports its listening
293 # address as https:/0.0.0.0:port/. If it reports "127.0.0.1"
294 # then the certificate won't match the host and reset() will
295 # fail certificate verification. If it reports "localhost",
296 # clients (notably Python SDK's websocket client) might
297 # resolve localhost as ::1 and then fail to connect.
298 subprocess.check_call([
299 'openssl', 'req', '-new', '-x509', '-nodes',
300 '-out', 'tmp/self-signed.pem',
301 '-keyout', 'tmp/self-signed.key',
303 '-subj', '/CN=0.0.0.0'],
306 # Install the git repository fixtures.
307 gitdir = os.path.join(SERVICES_SRC_DIR, 'api', 'tmp', 'git')
308 gittarball = os.path.join(SERVICES_SRC_DIR, 'api', 'test', 'test.git.tar')
309 if not os.path.isdir(gitdir):
311 subprocess.check_output(['tar', '-xC', gitdir, '-f', gittarball])
313 # The nginx proxy isn't listening here yet, but we need to choose
314 # the wss:// port now so we can write the API server config file.
315 wss_port = find_available_port()
316 _setport('wss', wss_port)
318 port = find_available_port()
319 env = os.environ.copy()
320 env['RAILS_ENV'] = 'test'
321 env['ARVADOS_TEST_WSS_PORT'] = str(wss_port)
322 env.pop('ARVADOS_WEBSOCKETS', None)
323 env.pop('ARVADOS_TEST_API_HOST', None)
324 env.pop('ARVADOS_API_HOST', None)
325 env.pop('ARVADOS_API_HOST_INSECURE', None)
326 env.pop('ARVADOS_API_TOKEN', None)
327 start_msg = subprocess.check_output(
329 'passenger', 'start', '-d', '-p{}'.format(port),
330 '--pid-file', pid_file,
331 '--log-file', os.path.join(os.getcwd(), 'log/test.log'),
333 '--ssl-certificate', 'tmp/self-signed.pem',
334 '--ssl-certificate-key', 'tmp/self-signed.key'],
337 if not leave_running_atexit:
338 atexit.register(kill_server_pid, pid_file, passenger_root=api_src_dir)
340 match = re.search(r'Accessible via: https://(.*?)/', start_msg)
343 "Passenger did not report endpoint: {}".format(start_msg))
344 my_api_host = match.group(1)
345 os.environ['ARVADOS_API_HOST'] = my_api_host
347 # Make sure the server has written its pid file and started
348 # listening on its TCP port
349 find_server_pid(pid_file)
350 _wait_until_port_listens(port)
353 os.chdir(restore_cwd)
356 """Reset the test server to fixture state.
358 This resets the ARVADOS_TEST_API_HOST provided by a parent process
359 if any, otherwise the server started by run().
361 It also resets ARVADOS_* environment vars to point to the test
362 server with admin credentials.
364 existing_api_host = os.environ.get('ARVADOS_TEST_API_HOST', my_api_host)
365 token = auth_token('admin')
366 httpclient = httplib2.Http(ca_certs=os.path.join(
367 SERVICES_SRC_DIR, 'api', 'tmp', 'self-signed.pem'))
369 'https://{}/database/reset'.format(existing_api_host),
371 headers={'Authorization': 'OAuth2 {}'.format(token)})
372 os.environ['ARVADOS_API_HOST_INSECURE'] = 'true'
373 os.environ['ARVADOS_API_HOST'] = existing_api_host
374 os.environ['ARVADOS_API_TOKEN'] = token
376 def stop(force=False):
377 """Stop the API server, if one is running.
379 If force==False, kill it only if we started it ourselves. (This
380 supports the use case where a Python test suite calls run(), but
381 run() just uses the ARVADOS_TEST_API_HOST provided by the parent
382 process, and the test suite cleans up after itself by calling
383 stop(). In this case the test server provided by the parent
384 process should be left alone.)
386 If force==True, kill it even if we didn't start it
387 ourselves. (This supports the use case in __main__, where "run"
388 and "stop" happen in different processes.)
391 if force or my_api_host is not None:
392 kill_server_pid(_pidfile('api'))
396 if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
399 port = find_available_port()
400 conf = os.path.join(TEST_TMPDIR, 'ws.yml')
401 with open(conf, 'w') as f:
414 """.format(os.environ['ARVADOS_API_HOST'],
416 ('info' if os.environ.get('ARVADOS_DEBUG', '') in ['','0'] else 'debug'),
418 _dbconfig('database'),
419 _dbconfig('username'),
420 _dbconfig('password')))
421 logf = open(_fifo2stderr('ws'), 'w')
422 ws = subprocess.Popen(
423 ["ws", "-config", conf],
424 stdin=open('/dev/null'), stdout=logf, stderr=logf, close_fds=True)
425 with open(_pidfile('ws'), 'w') as f:
427 _wait_until_port_listens(port)
432 if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
434 kill_server_pid(_pidfile('ws'))
436 def _start_keep(n, keep_args):
437 keep0 = tempfile.mkdtemp()
438 port = find_available_port()
439 keep_cmd = ["keepstore",
440 "-volume={}".format(keep0),
441 "-listen=:{}".format(port),
442 "-pid="+_pidfile('keep{}'.format(n))]
444 for arg, val in keep_args.items():
445 keep_cmd.append("{}={}".format(arg, val))
447 logf = open(_fifo2stderr('keep{}'.format(n)), 'w')
448 kp0 = subprocess.Popen(
449 keep_cmd, stdin=open('/dev/null'), stdout=logf, stderr=logf, close_fds=True)
451 with open(_pidfile('keep{}'.format(n)), 'w') as f:
452 f.write(str(kp0.pid))
454 with open("{}/keep{}.volume".format(TEST_TMPDIR, n), 'w') as f:
457 _wait_until_port_listens(port)
461 def run_keep(blob_signing_key=None, enforce_permissions=False, num_servers=2):
462 stop_keep(num_servers)
465 if not blob_signing_key:
466 blob_signing_key = 'zfhgfenhffzltr9dixws36j1yhksjoll2grmku38mi7yxd66h5j4q9w4jzanezacp8s6q0ro3hxakfye02152hncy6zml2ed0uc'
467 with open(os.path.join(TEST_TMPDIR, "keep.blob_signing_key"), "w") as f:
468 keep_args['-blob-signing-key-file'] = f.name
469 f.write(blob_signing_key)
470 keep_args['-enforce-permissions'] = str(enforce_permissions).lower()
471 with open(os.path.join(TEST_TMPDIR, "keep.data-manager-token-file"), "w") as f:
472 keep_args['-data-manager-token-file'] = f.name
473 f.write(auth_token('data_manager'))
474 keep_args['-never-delete'] = 'false'
478 host=os.environ['ARVADOS_API_HOST'],
479 token=os.environ['ARVADOS_API_TOKEN'],
482 for d in api.keep_services().list(filters=[['service_type','=','disk']]).execute()['items']:
483 api.keep_services().delete(uuid=d['uuid']).execute()
484 for d in api.keep_disks().list().execute()['items']:
485 api.keep_disks().delete(uuid=d['uuid']).execute()
487 for d in range(0, num_servers):
488 port = _start_keep(d, keep_args)
489 svc = api.keep_services().create(body={'keep_service': {
490 'uuid': 'zzzzz-bi6l4-keepdisk{:07d}'.format(d),
491 'service_host': 'localhost',
492 'service_port': port,
493 'service_type': 'disk',
494 'service_ssl_flag': False,
496 api.keep_disks().create(body={
497 'keep_disk': {'keep_service_uuid': svc['uuid'] }
500 # If keepproxy is running, send SIGHUP to make it discover the new
501 # keepstore services.
502 proxypidfile = _pidfile('keepproxy')
503 if os.path.exists(proxypidfile):
505 os.kill(int(open(proxypidfile).read()), signal.SIGHUP)
507 os.remove(proxypidfile)
510 kill_server_pid(_pidfile('keep{}'.format(n)))
511 if os.path.exists("{}/keep{}.volume".format(TEST_TMPDIR, n)):
512 with open("{}/keep{}.volume".format(TEST_TMPDIR, n), 'r') as r:
513 shutil.rmtree(r.read(), True)
514 os.unlink("{}/keep{}.volume".format(TEST_TMPDIR, n))
515 if os.path.exists(os.path.join(TEST_TMPDIR, "keep.blob_signing_key")):
516 os.remove(os.path.join(TEST_TMPDIR, "keep.blob_signing_key"))
518 def stop_keep(num_servers=2):
519 for n in range(0, num_servers):
522 def run_keep_proxy():
523 if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
527 port = find_available_port()
528 env = os.environ.copy()
529 env['ARVADOS_API_TOKEN'] = auth_token('anonymous')
530 logf = open(_fifo2stderr('keepproxy'), 'w')
531 kp = subprocess.Popen(
533 '-pid='+_pidfile('keepproxy'),
534 '-listen=:{}'.format(port)],
535 env=env, stdin=open('/dev/null'), stdout=logf, stderr=logf, close_fds=True)
539 host=os.environ['ARVADOS_API_HOST'],
540 token=auth_token('admin'),
542 for d in api.keep_services().list(
543 filters=[['service_type','=','proxy']]).execute()['items']:
544 api.keep_services().delete(uuid=d['uuid']).execute()
545 api.keep_services().create(body={'keep_service': {
546 'service_host': 'localhost',
547 'service_port': port,
548 'service_type': 'proxy',
549 'service_ssl_flag': False,
551 os.environ["ARVADOS_KEEP_SERVICES"] = "http://localhost:{}".format(port)
552 _setport('keepproxy', port)
553 _wait_until_port_listens(port)
555 def stop_keep_proxy():
556 if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
558 kill_server_pid(_pidfile('keepproxy'))
560 def run_arv_git_httpd():
561 if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
565 gitdir = os.path.join(SERVICES_SRC_DIR, 'api', 'tmp', 'git')
566 gitport = find_available_port()
567 env = os.environ.copy()
568 env.pop('ARVADOS_API_TOKEN', None)
569 logf = open(_fifo2stderr('arv-git-httpd'), 'w')
570 agh = subprocess.Popen(
572 '-repo-root='+gitdir+'/test',
573 '-address=:'+str(gitport)],
574 env=env, stdin=open('/dev/null'), stdout=logf, stderr=logf)
575 with open(_pidfile('arv-git-httpd'), 'w') as f:
576 f.write(str(agh.pid))
577 _setport('arv-git-httpd', gitport)
578 _wait_until_port_listens(gitport)
580 def stop_arv_git_httpd():
581 if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
583 kill_server_pid(_pidfile('arv-git-httpd'))
586 if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
590 keepwebport = find_available_port()
591 env = os.environ.copy()
592 env['ARVADOS_API_TOKEN'] = auth_token('anonymous')
593 logf = open(_fifo2stderr('keep-web'), 'w')
594 keepweb = subprocess.Popen(
597 '-attachment-only-host=download:'+str(keepwebport),
598 '-listen=:'+str(keepwebport)],
599 env=env, stdin=open('/dev/null'), stdout=logf, stderr=logf)
600 with open(_pidfile('keep-web'), 'w') as f:
601 f.write(str(keepweb.pid))
602 _setport('keep-web', keepwebport)
603 _wait_until_port_listens(keepwebport)
606 if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
608 kill_server_pid(_pidfile('keep-web'))
611 if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
615 nginxconf['KEEPWEBPORT'] = _getport('keep-web')
616 nginxconf['KEEPWEBDLSSLPORT'] = find_available_port()
617 nginxconf['KEEPWEBSSLPORT'] = find_available_port()
618 nginxconf['KEEPPROXYPORT'] = _getport('keepproxy')
619 nginxconf['KEEPPROXYSSLPORT'] = find_available_port()
620 nginxconf['GITPORT'] = _getport('arv-git-httpd')
621 nginxconf['GITSSLPORT'] = find_available_port()
622 nginxconf['WSPORT'] = _getport('ws')
623 nginxconf['WSSPORT'] = _getport('wss')
624 nginxconf['SSLCERT'] = os.path.join(SERVICES_SRC_DIR, 'api', 'tmp', 'self-signed.pem')
625 nginxconf['SSLKEY'] = os.path.join(SERVICES_SRC_DIR, 'api', 'tmp', 'self-signed.key')
626 nginxconf['ACCESSLOG'] = _fifo2stderr('nginx_access_log')
628 conftemplatefile = os.path.join(MY_DIRNAME, 'nginx.conf')
629 conffile = os.path.join(TEST_TMPDIR, 'nginx.conf')
630 with open(conffile, 'w') as f:
633 lambda match: str(nginxconf.get(match.group(1))),
634 open(conftemplatefile).read()))
636 env = os.environ.copy()
637 env['PATH'] = env['PATH']+':/sbin:/usr/sbin:/usr/local/sbin'
639 nginx = subprocess.Popen(
641 '-g', 'error_log stderr info;',
642 '-g', 'pid '+_pidfile('nginx')+';',
644 env=env, stdin=open('/dev/null'), stdout=sys.stderr)
645 _setport('keep-web-dl-ssl', nginxconf['KEEPWEBDLSSLPORT'])
646 _setport('keep-web-ssl', nginxconf['KEEPWEBSSLPORT'])
647 _setport('keepproxy-ssl', nginxconf['KEEPPROXYSSLPORT'])
648 _setport('arv-git-httpd-ssl', nginxconf['GITSSLPORT'])
651 if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
653 kill_server_pid(_pidfile('nginx'))
655 def _pidfile(program):
656 return os.path.join(TEST_TMPDIR, program + '.pid')
658 def _portfile(program):
659 return os.path.join(TEST_TMPDIR, program + '.port')
661 def _setport(program, port):
662 with open(_portfile(program), 'w') as f:
665 # Returns 9 if program is not up.
666 def _getport(program):
668 return int(open(_portfile(program)).read())
673 global _cached_db_config
674 if not _cached_db_config:
675 _cached_db_config = yaml.load(open(os.path.join(
676 SERVICES_SRC_DIR, 'api', 'config', 'database.yml')))
677 return _cached_db_config['test'][key]
680 global _cached_config
682 return _cached_config[key]
683 def _load(f, required=True):
684 fullpath = os.path.join(SERVICES_SRC_DIR, 'api', 'config', f)
685 if not required and not os.path.exists(fullpath):
687 return yaml.load(fullpath)
688 cdefault = _load('application.default.yml')
689 csite = _load('application.yml', required=False)
691 for section in [cdefault.get('common',{}), cdefault.get('test',{}),
692 csite.get('common',{}), csite.get('test',{})]:
693 _cached_config.update(section)
694 return _cached_config[key]
697 '''load a fixture yaml file'''
698 with open(os.path.join(SERVICES_SRC_DIR, 'api', "test", "fixtures",
702 trim_index = yaml_file.index("# Test Helper trims the rest of the file")
703 yaml_file = yaml_file[0:trim_index]
706 return yaml.load(yaml_file)
708 def auth_token(token_name):
709 return fixture("api_client_authorizations")[token_name]["api_token"]
711 def authorize_with(token_name):
712 '''token_name is the symbolic name of the token from the api_client_authorizations fixture'''
713 arvados.config.settings()["ARVADOS_API_TOKEN"] = auth_token(token_name)
714 arvados.config.settings()["ARVADOS_API_HOST"] = os.environ.get("ARVADOS_API_HOST")
715 arvados.config.settings()["ARVADOS_API_HOST_INSECURE"] = "true"
717 class TestCaseWithServers(unittest.TestCase):
718 """TestCase to start and stop supporting Arvados servers.
720 Define any of MAIN_SERVER, KEEP_SERVER, and/or KEEP_PROXY_SERVER
721 class variables as a dictionary of keyword arguments. If you do,
722 setUpClass will start the corresponding servers by passing these
723 keyword arguments to the run, run_keep, and/or run_keep_server
724 functions, respectively. It will also set Arvados environment
725 variables to point to these servers appropriately. If you don't
726 run a Keep or Keep proxy server, setUpClass will set up a
727 temporary directory for Keep local storage, and set it as
730 tearDownClass will stop any servers started, and restore the
731 original environment.
736 KEEP_PROXY_SERVER = None
737 KEEP_WEB_SERVER = None
740 def _restore_dict(src, dest):
741 for key in list(dest.keys()):
748 cls._orig_environ = os.environ.copy()
749 cls._orig_config = arvados.config.settings().copy()
750 cls._cleanup_funcs = []
751 os.environ.pop('ARVADOS_KEEP_SERVICES', None)
752 os.environ.pop('ARVADOS_EXTERNAL_CLIENT', None)
753 for server_kwargs, start_func, stop_func in (
754 (cls.MAIN_SERVER, run, reset),
755 (cls.WS_SERVER, run_ws, stop_ws),
756 (cls.KEEP_SERVER, run_keep, stop_keep),
757 (cls.KEEP_PROXY_SERVER, run_keep_proxy, stop_keep_proxy),
758 (cls.KEEP_WEB_SERVER, run_keep_web, stop_keep_web)):
759 if server_kwargs is not None:
760 start_func(**server_kwargs)
761 cls._cleanup_funcs.append(stop_func)
762 if (cls.KEEP_SERVER is None) and (cls.KEEP_PROXY_SERVER is None):
763 cls.local_store = tempfile.mkdtemp()
764 os.environ['KEEP_LOCAL_STORE'] = cls.local_store
765 cls._cleanup_funcs.append(
766 lambda: shutil.rmtree(cls.local_store, ignore_errors=True))
768 os.environ.pop('KEEP_LOCAL_STORE', None)
769 arvados.config.initialize()
772 def tearDownClass(cls):
773 for clean_func in cls._cleanup_funcs:
775 cls._restore_dict(cls._orig_environ, os.environ)
776 cls._restore_dict(cls._orig_config, arvados.config.settings())
779 if __name__ == "__main__":
782 'start_ws', 'stop_ws',
783 'start_keep', 'stop_keep',
784 'start_keep_proxy', 'stop_keep_proxy',
785 'start_keep-web', 'stop_keep-web',
786 'start_arv-git-httpd', 'stop_arv-git-httpd',
787 'start_nginx', 'stop_nginx',
789 parser = argparse.ArgumentParser()
790 parser.add_argument('action', type=str, help="one of {}".format(actions))
791 parser.add_argument('--auth', type=str, metavar='FIXTURE_NAME', help='Print authorization info for given api_client_authorizations fixture')
792 parser.add_argument('--num-keep-servers', metavar='int', type=int, default=2, help="Number of keep servers desired")
793 parser.add_argument('--keep-enforce-permissions', action="store_true", help="Enforce keep permissions")
795 args = parser.parse_args()
797 if args.action not in actions:
798 print("Unrecognized action '{}'. Actions are: {}.".
799 format(args.action, actions),
802 if args.action == 'start':
803 stop(force=('ARVADOS_TEST_API_HOST' not in os.environ))
804 run(leave_running_atexit=True)
805 host = os.environ['ARVADOS_API_HOST']
806 if args.auth is not None:
807 token = auth_token(args.auth)
808 print("export ARVADOS_API_TOKEN={}".format(pipes.quote(token)))
809 print("export ARVADOS_API_HOST={}".format(pipes.quote(host)))
810 print("export ARVADOS_API_HOST_INSECURE=true")
813 elif args.action == 'stop':
814 stop(force=('ARVADOS_TEST_API_HOST' not in os.environ))
815 elif args.action == 'start_ws':
817 elif args.action == 'stop_ws':
819 elif args.action == 'start_keep':
820 run_keep(enforce_permissions=args.keep_enforce_permissions, num_servers=args.num_keep_servers)
821 elif args.action == 'stop_keep':
822 stop_keep(num_servers=args.num_keep_servers)
823 elif args.action == 'start_keep_proxy':
825 elif args.action == 'stop_keep_proxy':
827 elif args.action == 'start_arv-git-httpd':
829 elif args.action == 'stop_arv-git-httpd':
831 elif args.action == 'start_keep-web':
833 elif args.action == 'stop_keep-web':
835 elif args.action == 'start_nginx':
837 elif args.action == 'stop_nginx':
840 raise Exception("action recognized but not implemented!?")