def setup(self): self.cls = Runner() self.mock_ver_info = Mock(release='1.2.3', url='http://myurl', commit='abcd', tag='mytag', version_str='1.2.3@mytag')
def setup(self): self.cls = Runner() self.mock_ver_info = Mock( release='1.2.3', url='http://myurl', commit='abcd', tag='mytag', version_str='1.2.3@mytag' )
class TestAwsLimitCheckerRunner(object): def setup(self): self.cls = Runner() self.mock_ver_info = Mock( release='1.2.3', url='http://myurl', commit='abcd', tag='mytag', version_str='1.2.3@mytag' ) def test_module_entry_point(self): with patch('%s.Runner' % pb) as mock_runner: console_entry_point() assert mock_runner.mock_calls == [ call(), call().console_entry_point(), ] def test_init(self): assert self.cls.colorize is True assert self.cls.checker is None assert self.cls.skip_ta is False assert self.cls.service_name is None def test_parse_args(self): argv = ['-V'] res = self.cls.parse_args(argv) assert isinstance(res, argparse.Namespace) assert res.version is True def test_parse_args_parser(self): argv = ['-V'] desc = 'Report on AWS service limits and usage via boto, optionally ' \ 'warn about any services with usage nearing or exceeding ' \ 'their limits. For further help, see ' \ '<http://awslimitchecker.readthedocs.org/>' epilog = 'awslimitchecker is AGPLv3-licensed Free Software. Anyone ' \ 'using this program, even remotely over a network, is ' \ 'entitled to a copy of the source code. Use `--version` for '\ 'information on the source code location.' with patch('awslimitchecker.runner.argparse.ArgumentParser', spec_set=argparse.ArgumentParser) as mock_parser: self.cls.parse_args(argv) assert mock_parser.mock_calls == [ call(description=desc, epilog=epilog), call().add_argument('-S', '--service', action='store', default=None, help='perform action for only the specified ' 'service name; see -s|--list-services for ' 'valid names'), call().add_argument('-s', '--list-services', default=False, action='store_true', help='print a list of all AWS service types ' 'that awslimitchecker knows how to check'), call().add_argument('-l', '--list-limits', action='store_true', default=False, help='print all AWS effective limits in ' '"service_name/limit_name" format'), call().add_argument('--list-defaults', action='store_true', default=False, help='print all AWS default limits in ' '"service_name/limit_name" format'), call().add_argument('-L', '--limit', action=StoreKeyValuePair, help='override a single AWS limit, specified in' ' "service_name/limit_name=value" format; can ' 'be specified multiple times.'), call().add_argument('-u', '--show-usage', action='store_true', default=False, help='find and print the current usage of ' 'all AWS services with known limits'), call().add_argument('--iam-policy', action='store_true', default=False, help='output a JSON serialized IAM Policy ' 'listing the required permissions for ' 'awslimitchecker to run correctly.'), call().add_argument('-W', '--warning-threshold', action='store', type=int, default=80, help='default warning threshold (percentage of ' 'limit); default: 80'), call().add_argument('-C', '--critical-threshold', action='store', type=int, default=99, help='default critical threshold (percentage ' 'of limit); default: 99'), call().add_argument('--skip-ta', action='store_true', default=False, help='do not attempt to pull *any* information ' 'on limits from Trusted Advisor'), call().add_argument('--no-color', action='store_true', default=False, help='do not colorize output'), call().add_argument('-v', '--verbose', dest='verbose', action='count', default=0, help='verbose output. specify twice ' 'for debug-level output.'), call().add_argument('-V', '--version', dest='version', action='store_true', default=False, help='print version number and exit.'), call().parse_args(argv), ] def test_entry_version(self, capsys): argv = ['awslimitchecker', '-V'] expected = 'awslimitchecker ver (see <foo> for source code)\n' with patch.object(sys, 'argv', argv): with patch('%s.AwsLimitChecker' % pb, spec_set=AwsLimitChecker) as mock_alc: mock_alc.return_value.get_project_url.return_value = 'foo' mock_alc.return_value.get_version.return_value = 'ver' with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() out, err = capsys.readouterr() assert out == expected assert err == '' assert excinfo.value.code == 0 assert mock_alc.mock_calls == [ call( warning_threshold=80, critical_threshold=99, ), call().get_project_url(), call().get_version() ] def test_entry_list_services(self): argv = ['awslimitchecker', '-s'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.list_services' % pb, autospec=True) as mock_list: with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert mock_list.mock_calls == [ call(self.cls) ] def test_list_services(self, capsys): expected = 'Bar\nFoo\n' mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_service_names.return_value = [ 'Foo', 'Bar' ] self.cls.checker = mock_checker self.cls.list_services() out, err = capsys.readouterr() assert out == expected assert err == '' assert mock_checker.mock_calls == [ call.get_service_names() ] def test_entry_iam_policy(self): argv = ['awslimitchecker', '--iam-policy'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.iam_policy' % pb, autospec=True) as mock_iam: with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert mock_iam.mock_calls == [ call(self.cls) ] def test_iam_policy(self, capsys): expected = {"baz": "blam", "foo": "bar"} mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_required_iam_policy.return_value = { 'foo': 'bar', 'baz': 'blam', } self.cls.checker = mock_checker self.cls.iam_policy() out, err = capsys.readouterr() assert json.loads(out) == expected assert err == '' assert mock_checker.mock_calls == [ call.get_required_iam_policy() ] def test_entry_list_defaults(self): argv = ['awslimitchecker', '--list-defaults'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.list_defaults' % pb, autospec=True) as mock_list: with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert mock_list.mock_calls == [ call(self.cls) ] def test_list_defaults(self, capsys): mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_limits.return_value = sample_limits() self.cls.checker = mock_checker with patch('awslimitchecker.runner.dict2cols', autospec=True) as mock_d2c: mock_d2c.return_value = 'd2cval' self.cls.list_defaults() out, err = capsys.readouterr() assert out == 'd2cval\n' assert err == '' assert mock_checker.mock_calls == [ call.get_limits(service=None) ] assert mock_d2c.mock_calls == [ call({ 'SvcBar/bar limit2': '2', 'SvcBar/barlimit1': '1', 'SvcFoo/foo limit3': '3', }) ] def test_list_defaults_one_service(self, capsys): mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_limits.return_value = { 'SvcFoo': sample_limits()['SvcFoo'], } self.cls.checker = mock_checker self.cls.service_name = 'SvcFoo' with patch('awslimitchecker.runner.dict2cols', autospec=True) as mock_d2c: mock_d2c.return_value = 'd2cval' self.cls.list_defaults() out, err = capsys.readouterr() assert out == 'd2cval\n' assert err == '' assert mock_checker.mock_calls == [ call.get_limits(service='SvcFoo') ] assert mock_d2c.mock_calls == [ call({ 'SvcFoo/foo limit3': '3', }) ] def test_entry_list_limits(self): argv = ['awslimitchecker', '-l'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.list_limits' % pb, autospec=True) as mock_list: with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert mock_list.mock_calls == [ call(self.cls) ] def test_list_limits(self, capsys): mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_limits.return_value = sample_limits() self.cls.checker = mock_checker with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' self.cls.list_limits() out, err = capsys.readouterr() assert out == 'd2cval\n' assert err == '' assert mock_checker.mock_calls == [ call.get_limits(use_ta=True, service=None) ] assert mock_d2c.mock_calls == [ call({ 'SvcBar/bar limit2': '99', 'SvcBar/barlimit1': '1', 'SvcFoo/foo limit3': '10 (TA)', }) ] def test_list_limits_one_service(self, capsys): mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_limits.return_value = { 'SvcFoo': sample_limits()['SvcFoo'], } self.cls.checker = mock_checker self.cls.service_name = 'SvcFoo' with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' self.cls.list_limits() out, err = capsys.readouterr() assert out == 'd2cval\n' assert err == '' assert mock_checker.mock_calls == [ call.get_limits(use_ta=True, service='SvcFoo') ] assert mock_d2c.mock_calls == [ call({ 'SvcFoo/foo limit3': '10 (TA)', }) ] def test_entry_limit(self): argv = ['awslimitchecker', '-L', 'foo=bar'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb) as mock_ct: with patch('%s.Runner.set_limit_overrides' '' % pb, autospec=True) as mock_slo: mock_ct.return_value = 0 with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert mock_slo.mock_calls == [ call(self.cls, {'foo': 'bar'}) ] def test_entry_limit_multi(self): argv = ['awslimitchecker', '--limit=foo=bar', '--limit=baz=blam'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with patch('%s.Runner.set_limit_overrides' '' % pb, autospec=True) as mock_slo: mock_ct.return_value = 0 with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert mock_slo.mock_calls == [ call(self.cls, {'foo': 'bar', 'baz': 'blam'}) ] def test_set_limit_overrides(self): overrides = { 'EC2/Foo bar': "2", 'ElastiCache/Cache cluster subnet groups': "100", } mock_checker = Mock(spec_set=AwsLimitChecker) self.cls.checker = mock_checker self.cls.set_limit_overrides(overrides) assert mock_checker.mock_calls == [ call.set_limit_override('EC2', 'Foo bar', 2), call.set_limit_override( 'ElastiCache', 'Cache cluster subnet groups', 100 ) ] def test_set_limit_overrides_error(self): overrides = { 'EC2': 2, } mock_checker = Mock(spec_set=AwsLimitChecker) self.cls.checker = mock_checker with pytest.raises(ValueError) as excinfo: self.cls.set_limit_overrides(overrides) assert mock_checker.mock_calls == [] if sys.version_info[0] > 2: msg = excinfo.value.args[0] else: msg = excinfo.value.message assert msg == "Limit names must be in " \ "'service/limit' format; EC2 is invalid." def test_entry_show_usage(self): argv = ['awslimitchecker', '-u'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.show_usage' % pb, autospec=True) as mock_show: with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert mock_show.mock_calls == [ call(self.cls) ] def test_show_usage(self, capsys): limits = sample_limits() limits['SvcFoo']['foo limit3']._add_current_usage(33) limits['SvcBar']['bar limit2']._add_current_usage(22) limits['SvcBar']['barlimit1']._add_current_usage(11) mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_limits.return_value = limits self.cls.checker = mock_checker with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' self.cls.show_usage() out, err = capsys.readouterr() assert out == 'd2cval\n' assert err == '' assert mock_checker.mock_calls == [ call.find_usage(service=None), call.get_limits(service=None) ] assert mock_d2c.mock_calls == [ call({ 'SvcBar/bar limit2': '22', 'SvcBar/barlimit1': '11', 'SvcFoo/foo limit3': '33', }) ] def test_show_usage_one_service(self, capsys): limits = { 'SvcFoo': sample_limits()['SvcFoo'], } limits['SvcFoo']['foo limit3']._add_current_usage(33) mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_limits.return_value = limits self.cls.checker = mock_checker self.cls.service_name = 'SvcFoo' with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' self.cls.show_usage() out, err = capsys.readouterr() assert out == 'd2cval\n' assert err == '' assert mock_checker.mock_calls == [ call.find_usage(service='SvcFoo'), call.get_limits(service='SvcFoo') ] assert mock_d2c.mock_calls == [ call({ 'SvcFoo/foo limit3': '33', }) ] def test_entry_skip_ta(self, capsys): argv = ['awslimitchecker', '--skip-ta'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 6 self.cls.console_entry_point() out, err = capsys.readouterr() assert err == '' assert out == '' assert excinfo.value.code == 6 assert self.cls.skip_ta is True def test_entry_service_name(self, capsys): argv = ['awslimitchecker', '-S', 'foo'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 6 self.cls.console_entry_point() out, err = capsys.readouterr() assert err == '' assert out == '' assert excinfo.value.code == 6 assert self.cls.service_name == 'foo' def test_entry_no_service_name(self, capsys): argv = ['awslimitchecker'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 6 self.cls.console_entry_point() out, err = capsys.readouterr() assert err == '' assert out == '' assert excinfo.value.code == 6 assert self.cls.service_name is None def test_entry_verbose(self, capsys): argv = ['awslimitchecker', '-v'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with patch('awslimitchecker.runner.logger.setLevel' '') as mock_set_level: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 6 self.cls.console_entry_point() out, err = capsys.readouterr() assert err == '' assert out == '' assert excinfo.value.code == 6 assert mock_set_level.mock_calls == [call(logging.INFO)] def test_entry_debug(self, capsys): argv = ['awslimitchecker', '-vv'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with patch('awslimitchecker.runner.logger.setLevel' '') as mock_set_level: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 7 self.cls.console_entry_point() out, err = capsys.readouterr() assert err == '' assert out == '' assert excinfo.value.args[0] == 7 assert mock_set_level.mock_calls == [call(logging.DEBUG)] def test_entry_warning(self): argv = ['awslimitchecker', '-W', '50'] with patch.object(sys, 'argv', argv): with patch('%s.AwsLimitChecker' % pb, autospec=True) as mock_alc: with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 8 self.cls.console_entry_point() assert excinfo.value.code == 8 assert mock_alc.mock_calls == [ call(warning_threshold=50, critical_threshold=99) ] def test_entry_critical(self): argv = ['awslimitchecker', '-C', '95'] with patch.object(sys, 'argv', argv): with patch('%s.AwsLimitChecker' % pb, autospec=True) as mock_alc: with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 9 self.cls.console_entry_point() assert excinfo.value.code == 9 assert mock_alc.mock_calls == [ call(warning_threshold=80, critical_threshold=95) ] def test_entry_check_thresholds(self): argv = ['awslimitchecker'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 10 self.cls.console_entry_point() assert excinfo.value.code == 10 assert mock_ct.mock_calls == [ call(self.cls) ] def test_check_thresholds_ok(self, capsys): """no problems, return 0 and print nothing""" mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.check_thresholds.return_value = {} self.cls.checker = mock_checker with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = '' res = self.cls.check_thresholds() out, err = capsys.readouterr() assert out == '\n' assert err == '' assert mock_checker.mock_calls == [ call.check_thresholds(use_ta=True, service=None) ] assert res == 0 def test_check_thresholds_many_problems(self): """lots of problems""" mock_limit1 = Mock(spec_set=AwsLimit) type(mock_limit1).name = 'limit1' mock_w1 = Mock(spec_set=AwsLimitUsage) mock_limit1.get_warnings.return_value = [mock_w1] mock_c1 = Mock(spec_set=AwsLimitUsage) mock_limit1.get_criticals.return_value = [mock_c1] mock_limit2 = Mock(spec_set=AwsLimit) type(mock_limit2).name = 'limit2' mock_w2 = Mock(spec_set=AwsLimitUsage) mock_limit2.get_warnings.return_value = [mock_w2] mock_limit2.get_criticals.return_value = [] mock_limit3 = Mock(spec_set=AwsLimit) type(mock_limit3).name = 'limit3' mock_w3 = Mock(spec_set=AwsLimitUsage) mock_limit3.get_warnings.return_value = [mock_w3] mock_limit3.get_criticals.return_value = [] mock_limit4 = Mock(spec_set=AwsLimit) type(mock_limit4).name = 'limit4' mock_limit4.get_warnings.return_value = [] mock_c2 = Mock(spec_set=AwsLimitUsage) mock_limit4.get_criticals.return_value = [mock_c2] mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.check_thresholds.return_value = { 'svc2': { 'limit3': mock_limit3, 'limit4': mock_limit4, }, 'svc1': { 'limit1': mock_limit1, 'limit2': mock_limit2, }, } def se_print(cls, s, l, c, w): return ('{s}/{l}'.format(s=s, l=l.name), '') self.cls.checker = mock_checker with patch('awslimitchecker.runner.Runner.print_issue', autospec=True) as mock_print: mock_print.side_effect = se_print with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' res = self.cls.check_thresholds() assert mock_checker.mock_calls == [ call.check_thresholds(use_ta=True, service=None) ] assert mock_print.mock_calls == [ call(self.cls, 'svc1', mock_limit1, [mock_c1], [mock_w1]), call(self.cls, 'svc1', mock_limit2, [], [mock_w2]), call(self.cls, 'svc2', mock_limit3, [], [mock_w3]), call(self.cls, 'svc2', mock_limit4, [mock_c2], []), ] assert mock_d2c.mock_calls == [ call({ 'svc1/limit1': '', 'svc1/limit2': '', 'svc2/limit3': '', 'svc2/limit4': '', }) ] assert res == 2 def test_check_thresholds_warn(self): """just warnings""" mock_limit1 = Mock(spec_set=AwsLimit) mock_w1 = Mock(spec_set=AwsLimitUsage) mock_w2 = Mock(spec_set=AwsLimitUsage) mock_limit1.get_warnings.return_value = [mock_w1, mock_w2] mock_limit1.get_criticals.return_value = [] mock_limit2 = Mock(spec_set=AwsLimit) mock_w3 = Mock(spec_set=AwsLimitUsage) mock_limit2.get_warnings.return_value = [mock_w3] mock_limit2.get_criticals.return_value = [] mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.check_thresholds.return_value = { 'svc2': { 'limit2': mock_limit2, }, 'svc1': { 'limit1': mock_limit1, }, } self.cls.checker = mock_checker with patch('awslimitchecker.runner.Runner.print_issue', autospec=True) as mock_print: mock_print.return_value = ('', '') with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' res = self.cls.check_thresholds() assert mock_checker.mock_calls == [ call.check_thresholds(use_ta=True, service=None) ] assert mock_print.mock_calls == [ call(self.cls, 'svc1', mock_limit1, [], [mock_w1, mock_w2]), call(self.cls, 'svc2', mock_limit2, [], [mock_w3]), ] assert res == 1 def test_check_thresholds_warn_one_service(self): """just warnings""" mock_limit1 = Mock(spec_set=AwsLimit) mock_w1 = Mock(spec_set=AwsLimitUsage) mock_w2 = Mock(spec_set=AwsLimitUsage) mock_limit1.get_warnings.return_value = [mock_w1, mock_w2] mock_limit1.get_criticals.return_value = [] mock_limit2 = Mock(spec_set=AwsLimit) mock_w3 = Mock(spec_set=AwsLimitUsage) mock_limit2.get_warnings.return_value = [mock_w3] mock_limit2.get_criticals.return_value = [] mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.check_thresholds.return_value = { 'svc2': { 'limit2': mock_limit2, }, } self.cls.checker = mock_checker self.cls.service_name = 'svc2' with patch('awslimitchecker.runner.Runner.print_issue', autospec=True) as mock_print: mock_print.return_value = ('', '') with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' res = self.cls.check_thresholds() assert mock_checker.mock_calls == [ call.check_thresholds(use_ta=True, service='svc2') ] assert mock_print.mock_calls == [ call(self.cls, 'svc2', mock_limit2, [], [mock_w3]), ] assert res == 1 def test_check_thresholds_crit(self): """only critical""" mock_limit1 = Mock(spec_set=AwsLimit) mock_limit1.get_warnings.return_value = [] mock_c1 = Mock(spec_set=AwsLimitUsage) mock_c2 = Mock(spec_set=AwsLimitUsage) mock_limit1.get_criticals.return_value = [mock_c1, mock_c2] mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.check_thresholds.return_value = { 'svc1': { 'limit1': mock_limit1, }, } self.cls.checker = mock_checker self.cls.skip_ta = True with patch('awslimitchecker.runner.Runner.print_issue', autospec=True) as mock_print: mock_print.return_value = ('', '') with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' res = self.cls.check_thresholds() assert mock_checker.mock_calls == [ call.check_thresholds(use_ta=False, service=None) ] assert mock_print.mock_calls == [ call(self.cls, 'svc1', mock_limit1, [mock_c1, mock_c2], []), ] assert res == 2 def test_print_issue_crit_one(self): mock_limit = Mock(spec_set=AwsLimit) type(mock_limit).name = 'limitname' mock_limit.get_limit.return_value = 12 c1 = AwsLimitUsage(mock_limit, 56) res = self.cls.print_issue( 'svcname', mock_limit, [c1], [] ) assert res == ('svcname/limitname', '(limit 12) ' + red('CRITICAL: 56')) def test_print_issue_crit_multi(self): mock_limit = Mock(spec_set=AwsLimit) type(mock_limit).name = 'limitname' mock_limit.get_limit.return_value = 5 c1 = AwsLimitUsage(mock_limit, 10) c2 = AwsLimitUsage(mock_limit, 12, resource_id='c2id') c3 = AwsLimitUsage(mock_limit, 8) res = self.cls.print_issue( 'svcname', mock_limit, [c1, c2, c3], [] ) assert res == ('svcname/limitname', '(limit 5) ' + red('CRITICAL: 8, 10, c2id=12')) def test_print_issue_warn_one(self): mock_limit = Mock(spec_set=AwsLimit) type(mock_limit).name = 'limitname' mock_limit.get_limit.return_value = 12 w1 = AwsLimitUsage(mock_limit, 11) res = self.cls.print_issue( 'svcname', mock_limit, [], [w1] ) assert res == ('svcname/limitname', '(limit 12) ' + yellow('WARNING: 11')) def test_print_issue_warn_multi(self): mock_limit = Mock(spec_set=AwsLimit) type(mock_limit).name = 'limitname' mock_limit.get_limit.return_value = 12 w1 = AwsLimitUsage(mock_limit, 11) w2 = AwsLimitUsage(mock_limit, 10, resource_id='w2id') w3 = AwsLimitUsage(mock_limit, 10, resource_id='w3id') res = self.cls.print_issue( 'svcname', mock_limit, [], [w1, w2, w3] ) assert res == ('svcname/limitname', '(limit 12) ' + yellow('WARNING: ' 'w2id=10, w3id=10, 11')) def test_print_issue_both_one(self): mock_limit = Mock(spec_set=AwsLimit) type(mock_limit).name = 'limitname' mock_limit.get_limit.return_value = 12 c1 = AwsLimitUsage(mock_limit, 10) w1 = AwsLimitUsage(mock_limit, 10, resource_id='w3id') res = self.cls.print_issue( 'svcname', mock_limit, [c1], [w1] ) assert res == ('svcname/limitname', '(limit 12) ' + red('CRITICAL: 10') + ' ' + yellow('WARNING: w3id=10')) def test_print_issue_both_multi(self): mock_limit = Mock(spec_set=AwsLimit) type(mock_limit).name = 'limitname' mock_limit.get_limit.return_value = 12 c1 = AwsLimitUsage(mock_limit, 10) c2 = AwsLimitUsage(mock_limit, 12, resource_id='c2id') c3 = AwsLimitUsage(mock_limit, 8) w1 = AwsLimitUsage(mock_limit, 11) w2 = AwsLimitUsage(mock_limit, 10, resource_id='w2id') w3 = AwsLimitUsage(mock_limit, 10, resource_id='w3id') res = self.cls.print_issue( 'svcname', mock_limit, [c1, c2, c3], [w1, w2, w3] ) assert res == ('svcname/limitname', '(limit 12) ' + red('CRITICAL: 8, 10, c2id=12') + ' ' + yellow('WARNING: w2id=10, w3id=10, 11')) def test_entry_no_color(self): argv = ['awslimitchecker', '--no-color'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: mock_ct.return_value = 0 with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert self.cls.color_output('foo', 'red') == 'foo' self.cls.colorize = True def test_color_output(self): assert self.cls.color_output('foo', 'yellow') == termcolor.colored( 'foo', 'yellow')
class TestAwsLimitCheckerRunner(object): def setup(self): self.cls = Runner() self.mock_ver_info = Mock(release='1.2.3', url='http://myurl', commit='abcd', tag='mytag', version_str='1.2.3@mytag') def test_module_entry_point(self): with patch('%s.Runner' % pb) as mock_runner: console_entry_point() assert mock_runner.mock_calls == [ call(), call().console_entry_point(), ] def test_init(self): assert self.cls.colorize is True assert self.cls.checker is None assert self.cls.skip_ta is False assert self.cls.service_name is None def test_parse_args(self): argv = ['-V'] res = self.cls.parse_args(argv) assert isinstance(res, argparse.Namespace) assert res.version is True def test_parse_args_parser(self): argv = ['-V'] desc = 'Report on AWS service limits and usage via boto3, optionally ' \ 'warn about any services with usage nearing or exceeding ' \ 'their limits. For further help, see ' \ '<http://awslimitchecker.readthedocs.org/>' epilog = 'awslimitchecker is AGPLv3-licensed Free Software. Anyone ' \ 'using this program, even remotely over a network, is ' \ 'entitled to a copy of the source code. Use `--version` for '\ 'information on the source code location.' with patch('awslimitchecker.runner.argparse.ArgumentParser', spec_set=argparse.ArgumentParser) as mock_parser: self.cls.parse_args(argv) assert mock_parser.mock_calls == [ call(description=desc, epilog=epilog), call().add_argument('-S', '--service', action='store', default=None, help='perform action for only the specified ' 'service name; see -s|--list-services for ' 'valid names'), call().add_argument('-s', '--list-services', default=False, action='store_true', help='print a list of all AWS service types ' 'that awslimitchecker knows how to check'), call().add_argument('-l', '--list-limits', action='store_true', default=False, help='print all AWS effective limits in ' '"service_name/limit_name" format'), call().add_argument('--list-defaults', action='store_true', default=False, help='print all AWS default limits in ' '"service_name/limit_name" format'), call().add_argument( '-L', '--limit', action=StoreKeyValuePair, help='override a single AWS limit, specified in' ' "service_name/limit_name=value" format; can ' 'be specified multiple times.'), call().add_argument('-u', '--show-usage', action='store_true', default=False, help='find and print the current usage of ' 'all AWS services with known limits'), call().add_argument('--iam-policy', action='store_true', default=False, help='output a JSON serialized IAM Policy ' 'listing the required permissions for ' 'awslimitchecker to run correctly.'), call().add_argument( '-W', '--warning-threshold', action='store', type=int, default=80, help='default warning threshold (percentage of ' 'limit); default: 80'), call().add_argument('-C', '--critical-threshold', action='store', type=int, default=99, help='default critical threshold (percentage ' 'of limit); default: 99'), call().add_argument('-A', '--sts-account-id', action='store', type=str, default=None, help='for use with STS, the Account ID of the ' 'destination account (account to assume a role' ' in)'), call().add_argument('-R', '--sts-account-role', action='store', type=str, default=None, help='for use with STS, the name of the IAM ' 'role to assume'), call().add_argument('-E', '--external-id', action='store', type=str, default=None, help='External ID to use when ' 'assuming a role via STS'), call().add_argument('-M', '--mfa-serial-number', action='store', type=str, default=None, help='MFA Serial ' 'Number to use when assuming a role via STS'), call().add_argument('-T', '--mfa-token', action='store', type=str, default=None, help='MFA Token to use when ' 'assuming a role via STS'), call().add_argument('-r', '--region', action='store', type=str, default=None, help='AWS region name to connect to; required ' 'for STS'), call().add_argument( '--skip-ta', action='store_true', default=False, help='do not attempt to pull *any* information ' 'on limits from Trusted Advisor'), call().add_argument('--no-color', action='store_true', default=False, help='do not colorize output'), call().add_argument('-v', '--verbose', dest='verbose', action='count', default=0, help='verbose output. specify twice ' 'for debug-level output.'), call().add_argument('-V', '--version', dest='version', action='store_true', default=False, help='print version number and exit.'), call().parse_args(argv), ] def test_entry_version(self, capsys): argv = ['awslimitchecker', '-V'] expected = 'awslimitchecker ver (see <foo> for source code)\n' with patch.object(sys, 'argv', argv): with patch('%s.AwsLimitChecker' % pb, spec_set=AwsLimitChecker) as mock_alc: mock_alc.return_value.get_project_url.return_value = 'foo' mock_alc.return_value.get_version.return_value = 'ver' with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() out, err = capsys.readouterr() assert out == expected assert excinfo.value.code == 0 assert mock_alc.mock_calls == [ call(warning_threshold=80, critical_threshold=99, account_id=None, account_role=None, region=None, external_id=None, mfa_serial_number=None, mfa_token=None), call().get_project_url(), call().get_version() ] def test_entry_list_services(self): argv = ['awslimitchecker', '-s'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.list_services' % pb, autospec=True) as mock_list: with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert mock_list.mock_calls == [call(self.cls)] def test_list_services(self, capsys): expected = 'Bar\nFoo\n' mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_service_names.return_value = ['Foo', 'Bar'] self.cls.checker = mock_checker self.cls.list_services() out, err = capsys.readouterr() assert out == expected assert mock_checker.mock_calls == [call.get_service_names()] def test_entry_iam_policy(self): argv = ['awslimitchecker', '--iam-policy'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.iam_policy' % pb, autospec=True) as mock_iam: with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert mock_iam.mock_calls == [call(self.cls)] def test_iam_policy(self, capsys): expected = {"baz": "blam", "foo": "bar"} mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_required_iam_policy.return_value = { 'foo': 'bar', 'baz': 'blam', } self.cls.checker = mock_checker self.cls.iam_policy() out, err = capsys.readouterr() assert json.loads(out) == expected assert mock_checker.mock_calls == [call.get_required_iam_policy()] def test_entry_list_defaults(self): argv = ['awslimitchecker', '--list-defaults'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.list_defaults' % pb, autospec=True) as mock_list: with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert mock_list.mock_calls == [call(self.cls)] def test_list_defaults(self, capsys): mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_limits.return_value = sample_limits() self.cls.checker = mock_checker with patch('awslimitchecker.runner.dict2cols', autospec=True) as mock_d2c: mock_d2c.return_value = 'd2cval' self.cls.list_defaults() out, err = capsys.readouterr() assert out == 'd2cval\n' assert mock_checker.mock_calls == [call.get_limits(service=None)] assert mock_d2c.mock_calls == [ call({ 'SvcBar/bar limit2': '2', 'SvcBar/barlimit1': '1', 'SvcFoo/foo limit3': '3', }) ] def test_list_defaults_one_service(self, capsys): mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_limits.return_value = { 'SvcFoo': sample_limits()['SvcFoo'], } self.cls.checker = mock_checker self.cls.service_name = 'SvcFoo' with patch('awslimitchecker.runner.dict2cols', autospec=True) as mock_d2c: mock_d2c.return_value = 'd2cval' self.cls.list_defaults() out, err = capsys.readouterr() assert out == 'd2cval\n' assert mock_checker.mock_calls == [call.get_limits(service='SvcFoo')] assert mock_d2c.mock_calls == [call({ 'SvcFoo/foo limit3': '3', })] def test_entry_list_limits(self): argv = ['awslimitchecker', '-l'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.list_limits' % pb, autospec=True) as mock_list: with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert mock_list.mock_calls == [call(self.cls)] def test_list_limits(self, capsys): mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_limits.return_value = sample_limits_api() self.cls.checker = mock_checker with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' self.cls.list_limits() out, err = capsys.readouterr() assert out == 'd2cval\n' assert mock_checker.mock_calls == [ call.get_limits(use_ta=True, service=None) ] assert mock_d2c.mock_calls == [ call({ 'SvcBar/bar limit2': '99', 'SvcBar/barlimit1': '1', 'SvcFoo/foo limit3': '10 (TA)', 'SvcFoo/zzz limit4': '34 (API)', }) ] def test_list_limits_one_service(self, capsys): mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_limits.return_value = { 'SvcFoo': sample_limits_api()['SvcFoo'], } self.cls.checker = mock_checker self.cls.service_name = 'SvcFoo' with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' self.cls.list_limits() out, err = capsys.readouterr() assert out == 'd2cval\n' assert mock_checker.mock_calls == [ call.get_limits(use_ta=True, service='SvcFoo') ] assert mock_d2c.mock_calls == [ call({ 'SvcFoo/foo limit3': '10 (TA)', 'SvcFoo/zzz limit4': '34 (API)', }) ] def test_entry_limit(self): argv = ['awslimitchecker', '-L', 'foo=bar'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb) as mock_ct: with patch('%s.Runner.set_limit_overrides' '' % pb, autospec=True) as mock_slo: mock_ct.return_value = 0 with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert mock_slo.mock_calls == [call(self.cls, {'foo': 'bar'})] def test_entry_limit_multi(self): argv = ['awslimitchecker', '--limit=foo=bar', '--limit=baz=blam'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with patch('%s.Runner.set_limit_overrides' '' % pb, autospec=True) as mock_slo: mock_ct.return_value = 0 with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert mock_slo.mock_calls == [ call(self.cls, { 'foo': 'bar', 'baz': 'blam' }) ] def test_set_limit_overrides(self): overrides = { 'EC2/Foo bar': "2", 'ElastiCache/Cache cluster subnet groups': "100", } mock_checker = Mock(spec_set=AwsLimitChecker) self.cls.checker = mock_checker self.cls.set_limit_overrides(overrides) assert mock_checker.mock_calls == [ call.set_limit_override('EC2', 'Foo bar', 2), call.set_limit_override('ElastiCache', 'Cache cluster subnet groups', 100) ] def test_set_limit_overrides_error(self): overrides = { 'EC2': 2, } mock_checker = Mock(spec_set=AwsLimitChecker) self.cls.checker = mock_checker with pytest.raises(ValueError) as excinfo: self.cls.set_limit_overrides(overrides) assert mock_checker.mock_calls == [] if sys.version_info[0] > 2: msg = excinfo.value.args[0] else: msg = excinfo.value.message assert msg == "Limit names must be in " \ "'service/limit' format; EC2 is invalid." def test_entry_show_usage(self): argv = ['awslimitchecker', '-u'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.show_usage' % pb, autospec=True) as mock_show: with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert mock_show.mock_calls == [call(self.cls)] def test_show_usage(self, capsys): limits = sample_limits() limits['SvcFoo']['foo limit3']._add_current_usage(33) limits['SvcBar']['bar limit2']._add_current_usage(22) limits['SvcBar']['barlimit1']._add_current_usage(11) mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_limits.return_value = limits self.cls.checker = mock_checker with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' self.cls.show_usage() out, err = capsys.readouterr() assert out == 'd2cval\n' assert mock_checker.mock_calls == [ call.find_usage(service=None), call.get_limits(service=None) ] assert mock_d2c.mock_calls == [ call({ 'SvcBar/bar limit2': '22', 'SvcBar/barlimit1': '11', 'SvcFoo/foo limit3': '33', }) ] def test_show_usage_one_service(self, capsys): limits = { 'SvcFoo': sample_limits()['SvcFoo'], } limits['SvcFoo']['foo limit3']._add_current_usage(33) mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.get_limits.return_value = limits self.cls.checker = mock_checker self.cls.service_name = 'SvcFoo' with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' self.cls.show_usage() out, err = capsys.readouterr() assert out == 'd2cval\n' assert mock_checker.mock_calls == [ call.find_usage(service='SvcFoo'), call.get_limits(service='SvcFoo') ] assert mock_d2c.mock_calls == [call({ 'SvcFoo/foo limit3': '33', })] def test_entry_skip_ta(self, capsys): argv = ['awslimitchecker', '--skip-ta'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 6 self.cls.console_entry_point() out, err = capsys.readouterr() assert out == '' assert excinfo.value.code == 6 assert self.cls.skip_ta is True def test_entry_service_name(self, capsys): argv = ['awslimitchecker', '-S', 'foo'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 6 self.cls.console_entry_point() out, err = capsys.readouterr() assert out == '' assert excinfo.value.code == 6 assert self.cls.service_name == 'foo' def test_entry_no_service_name(self, capsys): argv = ['awslimitchecker'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 6 self.cls.console_entry_point() out, err = capsys.readouterr() assert out == '' assert excinfo.value.code == 6 assert self.cls.service_name is None def test_entry_no_service_name_region(self, capsys): argv = ['awslimitchecker', '-r', 'myregion'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with patch('%s.AwsLimitChecker' % pb, spec_set=AwsLimitChecker) as mock_alc: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 6 self.cls.console_entry_point() out, err = capsys.readouterr() assert out == '' assert excinfo.value.code == 6 assert mock_alc.mock_calls == [ call(warning_threshold=80, critical_threshold=99, account_id=None, account_role=None, region='myregion', external_id=None, mfa_serial_number=None, mfa_token=None) ] assert self.cls.service_name is None def test_entry_no_service_name_sts(self, capsys): argv = [ 'awslimitchecker', '-r', 'myregion', '-A', '098765432109', '-R', 'myrole' ] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with patch('%s.AwsLimitChecker' % pb, spec_set=AwsLimitChecker) as mock_alc: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 6 self.cls.console_entry_point() out, err = capsys.readouterr() assert out == '' assert excinfo.value.code == 6 assert mock_alc.mock_calls == [ call(warning_threshold=80, critical_threshold=99, account_id='098765432109', account_role='myrole', region='myregion', external_id=None, mfa_serial_number=None, mfa_token=None) ] assert self.cls.service_name is None def test_entry_no_service_name_sts_external_id(self, capsys): argv = [ 'awslimitchecker', '-r', 'myregion', '-A', '098765432109', '-R', 'myrole', '-E', 'myextid' ] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with patch('%s.AwsLimitChecker' % pb, spec_set=AwsLimitChecker) as mock_alc: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 6 self.cls.console_entry_point() out, err = capsys.readouterr() assert out == '' assert excinfo.value.code == 6 assert mock_alc.mock_calls == [ call(warning_threshold=80, critical_threshold=99, account_id='098765432109', account_role='myrole', region='myregion', external_id='myextid', mfa_serial_number=None, mfa_token=None) ] assert self.cls.service_name is None def test_entry_verbose(self, capsys): argv = ['awslimitchecker', '-v'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with patch('awslimitchecker.runner.logger.setLevel' '') as mock_set_level: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 6 self.cls.console_entry_point() out, err = capsys.readouterr() assert out == '' assert excinfo.value.code == 6 assert mock_set_level.mock_calls == [call(logging.INFO)] def test_entry_debug(self, capsys): argv = ['awslimitchecker', '-vv'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with patch('awslimitchecker.runner.logger.setLevel' '') as mock_set_level: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 7 self.cls.console_entry_point() out, err = capsys.readouterr() assert out == '' assert excinfo.value.args[0] == 7 assert mock_set_level.mock_calls == [call(logging.DEBUG)] def test_entry_warning(self): argv = ['awslimitchecker', '-W', '50'] with patch.object(sys, 'argv', argv): with patch('%s.AwsLimitChecker' % pb, autospec=True) as mock_alc: with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 8 self.cls.console_entry_point() assert excinfo.value.code == 8 assert mock_alc.mock_calls == [ call(warning_threshold=50, critical_threshold=99, account_id=None, account_role=None, region=None, external_id=None, mfa_serial_number=None, mfa_token=None) ] def test_entry_critical(self): argv = ['awslimitchecker', '-C', '95'] with patch.object(sys, 'argv', argv): with patch('%s.AwsLimitChecker' % pb, autospec=True) as mock_alc: with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 9 self.cls.console_entry_point() assert excinfo.value.code == 9 assert mock_alc.mock_calls == [ call(warning_threshold=80, critical_threshold=95, account_id=None, account_role=None, region=None, external_id=None, mfa_serial_number=None, mfa_token=None) ] def test_entry_check_thresholds(self): argv = ['awslimitchecker'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: with pytest.raises(SystemExit) as excinfo: mock_ct.return_value = 10 self.cls.console_entry_point() assert excinfo.value.code == 10 assert mock_ct.mock_calls == [call(self.cls)] def test_check_thresholds_ok(self, capsys): """no problems, return 0 and print nothing""" mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.check_thresholds.return_value = {} self.cls.checker = mock_checker with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = '' res = self.cls.check_thresholds() out, err = capsys.readouterr() assert out == '\n' assert mock_checker.mock_calls == [ call.check_thresholds(use_ta=True, service=None) ] assert res == 0 def test_check_thresholds_many_problems(self): """lots of problems""" mock_limit1 = Mock(spec_set=AwsLimit) type(mock_limit1).name = 'limit1' mock_w1 = Mock(spec_set=AwsLimitUsage) mock_limit1.get_warnings.return_value = [mock_w1] mock_c1 = Mock(spec_set=AwsLimitUsage) mock_limit1.get_criticals.return_value = [mock_c1] mock_limit2 = Mock(spec_set=AwsLimit) type(mock_limit2).name = 'limit2' mock_w2 = Mock(spec_set=AwsLimitUsage) mock_limit2.get_warnings.return_value = [mock_w2] mock_limit2.get_criticals.return_value = [] mock_limit3 = Mock(spec_set=AwsLimit) type(mock_limit3).name = 'limit3' mock_w3 = Mock(spec_set=AwsLimitUsage) mock_limit3.get_warnings.return_value = [mock_w3] mock_limit3.get_criticals.return_value = [] mock_limit4 = Mock(spec_set=AwsLimit) type(mock_limit4).name = 'limit4' mock_limit4.get_warnings.return_value = [] mock_c2 = Mock(spec_set=AwsLimitUsage) mock_limit4.get_criticals.return_value = [mock_c2] mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.check_thresholds.return_value = { 'svc2': { 'limit3': mock_limit3, 'limit4': mock_limit4, }, 'svc1': { 'limit1': mock_limit1, 'limit2': mock_limit2, }, } def se_print(cls, s, l, c, w): return ('{s}/{l}'.format(s=s, l=l.name), '') self.cls.checker = mock_checker with patch('awslimitchecker.runner.Runner.print_issue', autospec=True) as mock_print: mock_print.side_effect = se_print with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' res = self.cls.check_thresholds() assert mock_checker.mock_calls == [ call.check_thresholds(use_ta=True, service=None) ] assert mock_print.mock_calls == [ call(self.cls, 'svc1', mock_limit1, [mock_c1], [mock_w1]), call(self.cls, 'svc1', mock_limit2, [], [mock_w2]), call(self.cls, 'svc2', mock_limit3, [], [mock_w3]), call(self.cls, 'svc2', mock_limit4, [mock_c2], []), ] assert mock_d2c.mock_calls == [ call({ 'svc1/limit1': '', 'svc1/limit2': '', 'svc2/limit3': '', 'svc2/limit4': '', }) ] assert res == 2 def test_check_thresholds_warn(self): """just warnings""" mock_limit1 = Mock(spec_set=AwsLimit) mock_w1 = Mock(spec_set=AwsLimitUsage) mock_w2 = Mock(spec_set=AwsLimitUsage) mock_limit1.get_warnings.return_value = [mock_w1, mock_w2] mock_limit1.get_criticals.return_value = [] mock_limit2 = Mock(spec_set=AwsLimit) mock_w3 = Mock(spec_set=AwsLimitUsage) mock_limit2.get_warnings.return_value = [mock_w3] mock_limit2.get_criticals.return_value = [] mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.check_thresholds.return_value = { 'svc2': { 'limit2': mock_limit2, }, 'svc1': { 'limit1': mock_limit1, }, } self.cls.checker = mock_checker with patch('awslimitchecker.runner.Runner.print_issue', autospec=True) as mock_print: mock_print.return_value = ('', '') with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' res = self.cls.check_thresholds() assert mock_checker.mock_calls == [ call.check_thresholds(use_ta=True, service=None) ] assert mock_print.mock_calls == [ call(self.cls, 'svc1', mock_limit1, [], [mock_w1, mock_w2]), call(self.cls, 'svc2', mock_limit2, [], [mock_w3]), ] assert res == 1 def test_check_thresholds_warn_one_service(self): """just warnings""" mock_limit1 = Mock(spec_set=AwsLimit) mock_w1 = Mock(spec_set=AwsLimitUsage) mock_w2 = Mock(spec_set=AwsLimitUsage) mock_limit1.get_warnings.return_value = [mock_w1, mock_w2] mock_limit1.get_criticals.return_value = [] mock_limit2 = Mock(spec_set=AwsLimit) mock_w3 = Mock(spec_set=AwsLimitUsage) mock_limit2.get_warnings.return_value = [mock_w3] mock_limit2.get_criticals.return_value = [] mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.check_thresholds.return_value = { 'svc2': { 'limit2': mock_limit2, }, } self.cls.checker = mock_checker self.cls.service_name = 'svc2' with patch('awslimitchecker.runner.Runner.print_issue', autospec=True) as mock_print: mock_print.return_value = ('', '') with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' res = self.cls.check_thresholds() assert mock_checker.mock_calls == [ call.check_thresholds(use_ta=True, service='svc2') ] assert mock_print.mock_calls == [ call(self.cls, 'svc2', mock_limit2, [], [mock_w3]), ] assert res == 1 def test_check_thresholds_crit(self): """only critical""" mock_limit1 = Mock(spec_set=AwsLimit) mock_limit1.get_warnings.return_value = [] mock_c1 = Mock(spec_set=AwsLimitUsage) mock_c2 = Mock(spec_set=AwsLimitUsage) mock_limit1.get_criticals.return_value = [mock_c1, mock_c2] mock_checker = Mock(spec_set=AwsLimitChecker) mock_checker.check_thresholds.return_value = { 'svc1': { 'limit1': mock_limit1, }, } self.cls.checker = mock_checker self.cls.skip_ta = True with patch('awslimitchecker.runner.Runner.print_issue', autospec=True) as mock_print: mock_print.return_value = ('', '') with patch('awslimitchecker.runner.dict2cols') as mock_d2c: mock_d2c.return_value = 'd2cval' res = self.cls.check_thresholds() assert mock_checker.mock_calls == [ call.check_thresholds(use_ta=False, service=None) ] assert mock_print.mock_calls == [ call(self.cls, 'svc1', mock_limit1, [mock_c1, mock_c2], []), ] assert res == 2 def test_print_issue_crit_one(self): mock_limit = Mock(spec_set=AwsLimit) type(mock_limit).name = 'limitname' mock_limit.get_limit.return_value = 12 c1 = AwsLimitUsage(mock_limit, 56) res = self.cls.print_issue('svcname', mock_limit, [c1], []) assert res == ('svcname/limitname', '(limit 12) ' + red('CRITICAL: 56')) def test_print_issue_crit_multi(self): mock_limit = Mock(spec_set=AwsLimit) type(mock_limit).name = 'limitname' mock_limit.get_limit.return_value = 5 c1 = AwsLimitUsage(mock_limit, 10) c2 = AwsLimitUsage(mock_limit, 12, resource_id='c2id') c3 = AwsLimitUsage(mock_limit, 8) res = self.cls.print_issue('svcname', mock_limit, [c1, c2, c3], []) assert res == ('svcname/limitname', '(limit 5) ' + red('CRITICAL: 8, 10, c2id=12')) def test_print_issue_warn_one(self): mock_limit = Mock(spec_set=AwsLimit) type(mock_limit).name = 'limitname' mock_limit.get_limit.return_value = 12 w1 = AwsLimitUsage(mock_limit, 11) res = self.cls.print_issue('svcname', mock_limit, [], [w1]) assert res == ('svcname/limitname', '(limit 12) ' + yellow('WARNING: 11')) def test_print_issue_warn_multi(self): mock_limit = Mock(spec_set=AwsLimit) type(mock_limit).name = 'limitname' mock_limit.get_limit.return_value = 12 w1 = AwsLimitUsage(mock_limit, 11) w2 = AwsLimitUsage(mock_limit, 10, resource_id='w2id') w3 = AwsLimitUsage(mock_limit, 10, resource_id='w3id') res = self.cls.print_issue('svcname', mock_limit, [], [w1, w2, w3]) assert res == ('svcname/limitname', '(limit 12) ' + yellow('WARNING: ' 'w2id=10, w3id=10, 11')) def test_print_issue_both_one(self): mock_limit = Mock(spec_set=AwsLimit) type(mock_limit).name = 'limitname' mock_limit.get_limit.return_value = 12 c1 = AwsLimitUsage(mock_limit, 10) w1 = AwsLimitUsage(mock_limit, 10, resource_id='w3id') res = self.cls.print_issue('svcname', mock_limit, [c1], [w1]) assert res == ('svcname/limitname', '(limit 12) ' + red('CRITICAL: 10') + ' ' + yellow('WARNING: w3id=10')) def test_print_issue_both_multi(self): mock_limit = Mock(spec_set=AwsLimit) type(mock_limit).name = 'limitname' mock_limit.get_limit.return_value = 12 c1 = AwsLimitUsage(mock_limit, 10) c2 = AwsLimitUsage(mock_limit, 12, resource_id='c2id') c3 = AwsLimitUsage(mock_limit, 8) w1 = AwsLimitUsage(mock_limit, 11) w2 = AwsLimitUsage(mock_limit, 10, resource_id='w2id') w3 = AwsLimitUsage(mock_limit, 10, resource_id='w3id') res = self.cls.print_issue('svcname', mock_limit, [c1, c2, c3], [w1, w2, w3]) assert res == ('svcname/limitname', '(limit 12) ' + red('CRITICAL: 8, 10, c2id=12') + ' ' + yellow('WARNING: w2id=10, w3id=10, 11')) def test_entry_no_color(self): argv = ['awslimitchecker', '--no-color'] with patch.object(sys, 'argv', argv): with patch('%s.Runner.check_thresholds' % pb, autospec=True) as mock_ct: mock_ct.return_value = 0 with pytest.raises(SystemExit) as excinfo: self.cls.console_entry_point() assert excinfo.value.code == 0 assert self.cls.color_output('foo', 'red') == 'foo' self.cls.colorize = True def test_color_output(self): assert self.cls.color_output('foo', 'yellow') == termcolor.colored( 'foo', 'yellow')