def test_it_calls_hugo_as_expected(self, monkeypatch, patch_working_dir): def mock_download(ctx): pass monkeypatch.setattr(tasks.build, 'download_hugo', mock_download) hugo_path = patch_working_dir / HUGO_BIN hugo_call = (f'{hugo_path} --source /work/site_repo ' f'--destination /work/site_repo/_site') ctx = MockContext(run={ f'{hugo_path} version': Result(), hugo_call: Result(), }) with requests_mock.Mocker() as m: m.get('https://github.com/gohugoio/hugo/releases/download' '/v0.48/hugo_0.48_Linux-64bit.tar.gz') kwargs = dict(branch='branch', owner='owner', repository='repo', site_prefix='site/prefix') tasks.build_hugo(ctx, **kwargs) # and with base_url specified kwargs['base_url'] = '/test_base' hugo_call += f' --baseUrl /test_base' ctx = MockContext(run={ f'{hugo_path} version': Result(), hugo_call: Result(), }) tasks.build_hugo(ctx, **kwargs)
def test_it_is_callable(self): ctx = MockContext(run=[ Result('node version result'), Result('npm version result'), Result('npm install result'), ]) setup_node(ctx)
def test_can_provision_instances_according_to_sct_configuration(params, test_config, azure_service, fake_remoter): """Integration test for provisioning sct resources according to SCT configuration.""" fake_remoter.result_map = {r"sudo cloud-init status --wait": Result(stdout="..... \n status: done", stderr="nic", exited=0), r"ls /tmp/cloud-init": Result(stdout="done", exited=0)} tags = TestConfig.common_tags() provision_sct_resources(params=params, test_config=test_config, azure_service=azure_service) provisioner_eastus = provisioner_factory.create_provisioner( backend="azure", test_id=params.get("test_id"), region="eastus", azure_service=azure_service) eastus_instances = provisioner_eastus.list_instances() db_nodes = [node for node in eastus_instances if node.tags['NodeType'] == "scylla-db"] loader_nodes = [node for node in eastus_instances if node.tags['NodeType'] == "loader"] monitor_nodes = [node for node in eastus_instances if node.tags['NodeType'] == "monitor"] assert len(db_nodes) == 3 assert len(loader_nodes) == 2 assert len(monitor_nodes) == 1 db_node = db_nodes[0] assert db_node.region == "eastus" assert list(db_node.tags.keys()) == list(tags.keys()) + ["NodeType", "keep_action", "NodeIndex"] assert db_node.pricing_model == PricingModel.SPOT provisioner_easteu = provisioner_factory.create_provisioner(backend="azure", test_id=params.get("test_id"), region="easteu", azure_service=azure_service) easteu_instances = provisioner_easteu.list_instances() db_nodes = [node for node in easteu_instances if node.tags['NodeType'] == "scylla-db"] loader_nodes = [node for node in easteu_instances if node.tags['NodeType'] == "loader"] monitor_nodes = [node for node in easteu_instances if node.tags['NodeType'] == "monitor"] assert len(db_nodes) == 1 assert len(loader_nodes) == 0 assert len(monitor_nodes) == 0 db_node = db_nodes[0] assert db_node.region == "easteu" assert list(db_node.tags.keys()) == list(tags.keys()) + ["NodeType", "keep_action", "NodeIndex"] assert db_node.pricing_model == PricingModel.SPOT
def test_installs_production_deps(self, patch_clone_dir): create_file(patch_clone_dir / PACKAGE_JSON) ctx = MockContext( run={ 'node --version': Result(), 'npm --version': Result(), 'npm install --production': Result(), }) tasks.setup_node(ctx)
def test_it_is_callable(self): ctx = MockContext(run=[ Result('tar result'), Result('chmod result'), ]) with requests_mock.Mocker() as m: m.get('https://github.com/gohugoio/hugo/releases/download' '/v0.23/hugo_0.23_Linux-64bit.tar.gz') download_hugo(ctx)
def test_it_accepts_other_versions(self): ctx = MockContext(run=[ Result('tar result'), Result('chmod result'), ]) with requests_mock.Mocker() as m: m.get('https://github.com/gohugoio/hugo/releases/download' '/v0.25/hugo_0.25_Linux-64bit.tar.gz') download_hugo(ctx, version='0.25')
def test_it_uses_bundler_version_if_it_exists(self, patch_clone_dir): ctx = MockContext(run={ 'gem install bundler --version "<2"': Result(), }) tasks.setup_bundler(ctx) create_file(patch_clone_dir / BUNDLER_VERSION, '2.0.1') ctx = MockContext(run={ 'gem install bundler --version "2.0.1"': Result(), }) tasks.setup_bundler(ctx)
def test_it_is_callable(self): os.environ['GITHUB_TOKEN'] = 'fake_token' ctx = MockContext( run=[Result('git remote add result'), Result('git push result')]) push_repo_remote(ctx, owner='owner', repository='repo', branch='branch', remote_name='boop')
def test_it_is_callable(self): ctx = MockContext(run=[ Result('gem install jekyll result'), Result('jekyll version result'), Result('jekyll build result'), ]) build_jekyll(ctx, branch='branch', owner='owner', repository='repo', site_prefix='site/prefix', config='boop: beep', base_url='/site/prefix')
def test_it_uses_ruby_version_if_it_exists(self, patch_clone_dir): create_file(patch_clone_dir / RUBY_VERSION, '2.3') ctx = MockContext(run={ 'rvm install 2.3': Result(), 'ruby -v': Result(), }) tasks.setup_ruby(ctx) # ruby_version should be strippeed and quoted as well create_file(patch_clone_dir / RUBY_VERSION, ' $2.2 ') ctx = MockContext(run={ "rvm install '$2.2'": Result(), 'ruby -v': Result(), }) tasks.setup_ruby(ctx)
def test_it_runs_expected_commands(self, monkeypatch, owner, repo, branch, remote): monkeypatch.setenv('GITHUB_TOKEN', 'fake-token') # expected commands to run add_remote_cmd = (f'git remote add {remote} ' f'https://[email protected]/{owner}/{repo}.git') push_cmd = f'git push {remote} {branch}:master' ctx = MockContext(run={ add_remote_cmd: Result(), push_cmd: Result() }) push_repo_remote(ctx, owner=owner, repository=repo, branch=branch, remote_name=remote)
def test_it_is_callable(self, patch_working_dir, patch_clone_dir): create_file(patch_clone_dir / HUGO_VERSION, '0.44') tar_cmd = (f'tar -xzf {patch_working_dir}/hugo.tar.gz -C ' f'{patch_working_dir}') chmod_cmd = f'chmod +x {patch_working_dir}/hugo' ctx = MockContext(run={ tar_cmd: Result(), chmod_cmd: Result(), }) with requests_mock.Mocker() as m: m.get( 'https://github.com/gohugoio/hugo/releases/download' '/v0.44/hugo_0.44_Linux-64bit.tar.gz', text='fake-data') tasks.download_hugo(ctx)
def test_gemfile_is_used_if_it_exists(self, monkeypatch, patch_clone_dir): monkeypatch.setattr(tasks.build, 'SITE_BUILD_DIR_PATH', '/boop') create_file(patch_clone_dir / GEMFILE, '') ctx = MockContext( run={ 'gem install bundler --version "<2"': Result(), 'bundle install': Result(), 'bundle exec jekyll -v': Result(), f'bundle exec jekyll build --destination /boop': Result(), }) tasks.build_jekyll(ctx, branch='branch', owner='owner', repository='repo', site_prefix='site/prefix')
def test_it_is_callable(self, patch_clone_dir): ctx = MockContext(run=[ Result('gem install jekyll result'), Result('jekyll version result'), Result('jekyll build result'), ]) contents = 'hi: test' create_file(patch_clone_dir / JEKYLL_CONFIG_YML, contents) tasks.build_jekyll(ctx, branch='branch', owner='owner', repository='repo', site_prefix='site/prefix', config='boop: beep', base_url='/site/prefix')
def test_it_runs_expected_commands(self, monkeypatch, owner, repo, branch): monkeypatch.setenv('GITHUB_TOKEN', 'fake-token') clone_cmd = (f'git clone -b {branch} --single-branch ' f'https://[email protected]/{owner}/{repo}.git ' f'{CLONE_DIR_PATH}') ctx = MockContext(run={clone_cmd: Result()}) clone_repo(ctx, owner=owner, repository=repo, branch=branch)
def run(self, command, wenv=None, run_mode=run_mode_local, pty=False, exception=True, **kwargs): """ :return Result, 返回为invoke.Result对象可以使用 ret.stdout ret.exited读取属性。 非字典类型 stdout控制台输出, command执行的命令, exited:0成功其他额为错误码, 因为pty=True错误信息也在stdout中 {'stdout': '/bin/bash: fseo: command not found\r\n', 'stderr': '', 'encoding': 'UTF-8', 'command': 'fseo', 'shell': '/bin/bash', 'env': {}, 'exited': 127, 'pty': True, 'hide': ()} """ # todo: # pty 为True时 celery中执行fabric任务报错 # / invoke / runners.py line 1136, in start fcntl.ioctl(sys.stdout.fileno(), termios.TIOCSWINSZ, winsize) # AttributeError: 'LoggingProxy' object has no attribute 'fileno' pty = False try: if run_mode == self.run_mode_sudo: result = super(SshConnection, self).sudo(command, pty=pty, env=self.custom_global_env, **kwargs) elif run_mode == self.run_mode_local: result = super(SshConnection, self).local(command, pty=pty, warn=True, watchers=[say_yes()], env=self.custom_global_env, **kwargs) else: result = super(SshConnection, self).run(command, pty=pty, warn=True, watchers=[say_yes()], env=self.custom_global_env, **kwargs) return result except Exception as e: traceback.print_exc() if hasattr(e, 'message'): msg = e.message elif hasattr(e, 'result'): msg = e.result else: msg = str(e) result = Result(exited=-1, stderr="", stdout=msg) return result
def ctx(): # TODO: make MockContext more usable in a "don't care about results" mode # NOTE: this is ugly but whatever. MockContext.run_command = property(lambda self: self.run.call_args[0][0]) mc = MockContext(run=Result()) mc._set(run=Mock(wraps=mc.run)) yield mc
def shows_UnexpectedExit_str_when_streams_hidden(self, mock_exit): p = Program() oops = UnexpectedExit( Result( command="meh", exited=54, stdout="things!", stderr="ohnoz!", encoding="utf-8", hide=("stdout", "stderr"), )) p.execute = Mock(side_effect=oops) p.run("myapp foo") # Expect repr() of exception prints to stderr # NOTE: this partially duplicates a test in runners.py; whatever. stderr = sys.stderr.getvalue() assert (stderr == """Encountered a bad command exit code! Command: 'meh' Exit code: 54 Stdout: things! Stderr: ohnoz! """) # And exit with expected code (vs e.g. 1 or 0) mock_exit.assert_called_with(54)
def UnexpectedExit_str_encodes_stdout_and_err(self, mock_exit): p = Program() oops = UnexpectedExit( Result( command="meh", exited=54, stdout=u"this is not ascii: \u1234", stderr=u"this is also not ascii: \u4321", encoding="utf-8", hide=("stdout", "stderr"), )) p.execute = Mock(side_effect=oops) p.run("myapp foo") # NOTE: using explicit binary ASCII here, & accessing raw # getvalue() of the faked sys.stderr (spec.trap auto-decodes it # normally) to have a not-quite-tautological test. otherwise we'd # just be comparing unicode to unicode. shrug? expected = b"""Encountered a bad command exit code! Command: 'meh' Exit code: 54 Stdout: this is not ascii: \xe1\x88\xb4 Stderr: this is also not ascii: \xe4\x8c\xa1 """ got = six.BytesIO.getvalue(sys.stderr) assert got == expected
def run(self, command, run_mode=run_mode_remote, write=None, pty=False, exception=True, ws=False, webuser=None, **kwargs): try: if run_mode == self.run_mode_local: result = super(Shell, self).local(command, pty=pty, echo_stdin=True, warn=True, watchers=[say_yes()], env=self.custom_global_env, **kwargs) else: result = super(Shell, self).run(command, pty=pty, echo_stdin=True, warn=True, watchers=[say_yes()], env=self.custom_global_env, **kwargs) exited, stdout, stderr = result.exited, result.stdout, result.stderr if result.failed: message = '[%s@%s]# %s\n[ERROR] %s' % ( self.user, self.host, command, stdout + stderr) error_logger.error(message) else: message = '[%s@%s]# %s\n%s' % (self.user, self.host, command, stdout) if write: with open(write, 'a') as f: f.write(message) elif ws and webuser: message_in = '[%s@%s]# %s' % (self.user, self.host, command) websocket = Tailf() websocket.send_message(webuser, message_in) for m in stdout.split('\n'): websocket.send_message(webuser, m) return result except Exception as e: message = '[%s@%s]%s' % (self.user, self.host, e) error_logger.error(message) message = '[%s@%s]# %s\n[ERROR] %s' % (self.user, self.host, command, str(e)) if write: with open(write, 'a') as f: f.write(message) elif ws and webuser: message_in = '[%s@%s]# %s' % (self.user, self.host, command) message_out = '[ERROR] %s' % (str(e)) Tailf.send_message(webuser, message_in) for m in message_out.split('\n'): Tailf.send_message(webuser, m) result = Result(exited=-1, stderr=message, stdout=message) return result
def test_it_is_callable(self): ctx = MockContext(run=[ Result('tar result'), Result('chmod result'), Result('hugo version result'), Result('hugo build result'), ]) with requests_mock.Mocker() as m: m.get('https://github.com/gohugoio/hugo/releases/download' '/v0.23/hugo_0.23_Linux-64bit.tar.gz') build_hugo(ctx, branch='branch', owner='owner', repository='repo', site_prefix='site/prefix', base_url='/site/prefix', hugo_version='0.23')
def test_with_option_dryrun_on_cmdline(self, capsys): config = Config(DEFAULT_CONFIG) ctx = EchoMockContext(run=Result(), config=config) git_clean(ctx, dry_run=True) captured = capsys.readouterr() expected = "INVOKED: git clean --interactive --dry-run ." assert expected in captured.out
def my_cleanup(ctx): print("CALLED: my_cleanup task (entered)") message = "OOPS: my_cleanup fails" if error_class is Exit: raise Exit(message, code=100) else: raise error_class(Result(message, exited=101)) print("CALLED: my_cleanup task (exited)")
def repeat_True_does_not_consume_results(self): mc = MockContext( repeat=True, run=dict( singleton=True, # will repeat wassup=Result("yo"), # ditto iterable=[Result("tick"), Result("tock")], # will not ), ) assert mc.run("singleton").ok assert mc.run("singleton").ok # not consumed assert mc.run("wassup").ok assert mc.run("wassup").ok # not consumed assert mc.run("iterable").stdout == "tick" assert mc.run("iterable").stdout == "tock" assert mc.run("iterable").stdout == "tick" # not consumed assert mc.run("iterable").stdout == "tock"
def inner(command, *args, **kwargs): # Sanity checking - we always expect that invoke.run is called with # these. assert kwargs.get("hide", None) == "stdout" assert kwargs.get("warn", None) is True # Fake exit exit = 0 if command in success_on else 1 return Result(exited=exit)
def sudo_also_covered(self): c = MockContext(sudo=Result(stderr="super duper")) assert c.sudo("doesn't mattress").stderr == "super duper" try: MockContext().sudo("meh") except NotImplementedError: pass else: assert False, "Did not get a NotImplementedError for sudo!"
def _handle_unexpected_pass(expected_to_fail: bool, result: Result, path: str): if expected_to_fail and not result.failed: result.exited = 1 # force failure cprint( f"\nThis folder was expected to fail but no errors were found.\n\nPlease edit the " f"'{__file__}' file and move '{path}' from `broken_directories` to `fixed_directories`.", "red", attrs=["bold"], )
def test_it_is_callable(self, fs): ctx = MockContext(run=[ Result('gem install jekyll result'), Result('jekyll version result'), Result('jekyll build result'), ]) with Patcher() as patcher: patcher.fs.CreateFile('/tmp/site_repo/_config.yml', contents='hi: test') build_jekyll(ctx, branch='branch', owner='owner', repository='repo', site_prefix='site/prefix', config='boop: beep', base_url='/site/prefix')
def test_with_option_force_on_cmdline(self, capsys): config = Config(DEFAULT_CONFIG) ctx = EchoMockContext(run=Result(), config=config) # ctx.config.git_clean.interactive = False git_clean(ctx, force=True) captured = capsys.readouterr() expected = "INVOKED: git clean --interactive --force ." assert expected in captured.out
def test_with_invoke_option_dry_on_cmdline(self, capsys): config = Config(DEFAULT_CONFIG) ctx = EchoMockContext(run=Result(), config=config) ctx.config.run.dry = True # CMDLINE-EMULATION git_clean(ctx) captured = capsys.readouterr() expected = "INVOKED: git clean --interactive --dry-run ." assert expected in captured.out