def test_cli_destroy_nonexistent_config_file_fails(self, fixture_cli_base): with pytest.raises(SystemCallException): for base in fixture_cli_base: syscall('{} destroy'.format(base), check=True) with pytest.raises(SystemCallException): for base in fixture_cli_base: syscall('{} destroy -v'.format(base), check=True)
def test_cli_commands_nonexistent_config_fails( fixture_cli_base_nonexistent_config_file, fixture_supported_cli_commands): for command in fixture_supported_cli_commands.keys(): with pytest.raises(SystemCallException): syscall('{} {}'.format(fixture_cli_base_nonexistent_config_file, command), check=True)
def fixture_valid_docker_machine(): # type: () -> None if environ.get('FLOOP_LOCAL_HARDWARE_TEST'): pass elif environ.get('FLOOP_CLOUD_TEST'): pass # default to local 1GB Virtualbox machine else: create_local_machine = '''docker-machine create --driver virtualbox --virtualbox-memory 1024 {}'''.format(_TEST_CORE_NAME) syscall(create_local_machine, check=False)
def destroy(core, check=True): # type: (Core, bool) -> None ''' Parallelizable; destroy core by rm'ing Docker machine Args: core (:py:class:`floopcli.iot.core.Core`): initialized target core object check (bool): if True, check that core destroy system calls return non-zero exit codes Raises: :py:class:`floopcli.iot.core.CoreDestroyException`: destroy commands returned non-zero exit code ''' try: rm_core = ('sys', '{} rm -f {}'.format(core.host_docker_machine_bin, core.core)) # order matters commands = [rm_core] for command_ in commands: kind, command = command_ __log(core, 'info', command) if kind == 'sys': out, err = syscall(command=command, check=check) __log(core, 'info', str((out, err))) # TODO: find a case where init succeeds but destroy fails, enforce idempotency except SystemCallException as e: __log(core, 'error', repr(e)) raise CoreDestroyException(repr(e))
def create(core, check=True, timeout=240): # type: (Core, bool, int) -> None ''' Parallelizable; create new docker-machine on target core Args: core (:py:class:`floopcli.core.iot.Core`): initialized target core object check (bool): if True, check core creation succeeded by running 'pwd' via docker-machine SSH on newly created core timeout (int): time in seconds to wait for success before throwing error (docker-machine create timeout is too long) Raises: :py:class:`floopcli.core.iot.CoreCreateException`: core creation failed during docker-machine create or 'pwd' check failed ''' def timeout_handler(signum, frame): #type: ignore raise CoreCreateException('Create core timed out') create_command = '{} create --driver generic --generic-ip-address {} --generic-ssh-port {} --generic-ssh-user {} --generic-ssh-key {} --engine-storage-driver overlay {}'.format( core.host_docker_machine_bin, core.address, core.port, core.user, core.host_key, core.core) __log(core, 'info', create_command) signal.signal(signal.SIGALRM, timeout_handler) signal.alarm(timeout) try: out, err = syscall(create_command, check=False, verbose=verbose()) __log(core, 'info', out) if check: check_command = 'pwd' __log(core, 'info', 'Checking with {}'.format(check_command)) outd = core.run_ssh_command('pwd', check=check) __log(core, 'info', outd) except SystemCallException as e: __log(core, 'error', 'Create timed out') raise CoreCreateException(repr(e))
def run_ssh_command(self, command, check=True, verbose=False): # type: (str, bool, bool) -> str ''' Run docker-machine SSH command on target core Args: command (str): command to run on target core check (bool): if True, check whether command exit code is non-zero Returns: str: stdout output of SSH command Raises: :py:class:`floopcli.util.syscall.SystemCallException`: SSH command exit code was non-zero ''' sys_string = '{} ssh {} {}'.format(self.host_docker_machine_bin, self.core, command) out, _ = syscall(sys_string, check=check, verbose=verbose) return out
def push(core, check=True): # type: (Core, bool) -> None ''' Parallelizable; push files from host to target core Ignores floop.log and floop.json Args: core (:py:class:`floopcli.core.iot.Core`): initialized target core object check (bool): if True, check core creation succeeded by running 'pwd' via docker-machine SSH on newly created core Raises: :py:class:`floopcli.core.iot.CoreCreateException`: core creation failed during docker-machine create or 'pwd' check failed ''' # prevents race condition where source exists at start of floop # call but gets removed before push # TODO: simulate the race condition if not isdir(core.host_source): __log(core, 'error', 'Source not found: {}'.format(core.host_source)) raise CoreSourceNotFound(core.host_source) try: mkdir_string = 'mkdir -p {}'.format(core.target_source) __log(core, 'info', mkdir_string) out = core.run_ssh_command(mkdir_string, check=True) __log(core, 'info', out) sync_string = "rsync -avhz -e '{} ssh' {} {}:'{}' --exclude=floop.log --exclude=floop.json --delete".format( core.host_docker_machine_bin, core.host_source, core.core, core.target_source) __log(core, 'info', sync_string) out, err = syscall(sync_string, check=check) __log(core, 'info', out) except SystemCallException as e: __log(core, 'error', repr(e)) raise CoreCommunicationException(repr(e))
def test_cli_version(): syscall('floop --version', check=True)
def test_cli_test_fail_fails(fixture_valid_config_file, fixture_failing_testfile): with pytest.raises(SystemCallException): syscall('floop -c {} test'.format(fixture_valid_config_file), check=True)
def test_cli_push_nonexistent_src_dir_fails( fixture_nonexistent_source_dir_cli_config_file): with pytest.raises(SystemCallException): syscall('floop -c {} push'.format( fixture_nonexistent_source_dir_cli_config_file), check=True)
def test_cli_bases_fail(fixture_cli_base, fixture_valid_config_file): for base in fixture_cli_base: with pytest.raises(SystemCallException): syscall(base, check=True)
def test_cli_build_fail_fails(fixture_valid_config_file, fixture_failing_buildfile): with pytest.raises(SystemCallException): print( syscall('floop -c {} build'.format(fixture_valid_config_file), check=True))
def test_cli_unknown_commands_fail(fixture_cli_base, fixture_valid_config_file, fixture_unknown_cli_commands): for base in fixture_cli_base: for command in fixture_unknown_cli_commands: with pytest.raises(SystemCallException): syscall('{} {}'.format(base, command), check=True)
def test_cli_destroy_nonexistent_core_is_idempotent( self, fixture_cli_base, fixture_invalid_core_config_file): syscall('floop destroy', check=True) syscall('floop destroy', check=True)
def test_cli_push_nonexistent_config_file_fails(self): with pytest.raises(SystemCallException): syscall('floop push', check=True) with pytest.raises(SystemCallException): syscall('floop push -v', check=True)
def test_cli_run(self, fixture_cli_base, fixture_valid_config_file, fixture_buildfile): for base in fixture_cli_base: syscall('{} run'.format(base), check=True) syscall('{} run -v'.format(base), check=True)
def test_cli_commands_malformed_configs_fails(fixture_malformed_floop_configs, fixture_supported_cli_commands): for config in fixture_malformed_floop_configs: for command in fixture_supported_cli_commands.keys(): with pytest.raises(SystemCallException): syscall('floop -c {} {}'.format(config, command), check=True)
def test_syscall_check_nonzero_exit_fails(): with pytest.raises(SystemCallException): syscall('cp', check=True, verbose=True)
def test_cli_logs(self, fixture_cli_base, fixture_valid_config_file): syscall('floop logs', check=True) syscall('floop logs -m test', check=True) syscall('floop logs -v', check=True) syscall('floop logs -v -m test', check=True)
def test_cli_create(self, fixture_cli_base, fixture_valid_config_file): for base in fixture_cli_base: syscall('{} create --timeout 10'.format(base), check=True)
def test_cli_config_overwrite(fixture_cleanup_config): syscall('floop config', check=True) syscall('floop config', check=True) syscall('floop config --overwrite', check=True)
def test_cli_push_redundant_config_fails(fixture_redundant_config_file): with pytest.raises(SystemCallException): syscall('floop -c {} push'.format(fixture_redundant_config_file), check=True)
def test_cli_test(self, fixture_cli_base, fixture_valid_config_file, fixture_testfile): for base in fixture_cli_base: syscall('{} test'.format(base), check=True) syscall('{} test -v'.format(base), check=True)
def test_cli_logs_incompatible_flags(self): with pytest.raises(SystemCallException): syscall('floop -c floop.json logs', check=True)
def test_incompatible_cli_commands_fail(fixture_incompatible_cli_commands): for command in fixture_incompatible_cli_commands: with pytest.raises(SystemCallException): syscall(command, check=True)
def test_cli_push(self, fixture_cli_base, fixture_valid_config_file): for base in fixture_cli_base: syscall('{} push'.format(base), check=True) syscall('{} push -v'.format(base), check=True)
def test_syscall_pwd(): syscall('pwd', check=True, verbose=True)