def test_run(self): pack = 'dummy_pack_1' # Verify all the resources are there pack_dbs = Pack.query(ref=pack) action_dbs = Action.query(pack=pack) alias_dbs = ActionAlias.query(pack=pack) rule_dbs = Rule.query(pack=pack) sensor_dbs = Sensor.query(pack=pack) trigger_type_dbs = TriggerType.query(pack=pack) policy_dbs = Policy.query(pack=pack) config_schema_dbs = ConfigSchema.query(pack=pack) config_dbs = Config.query(pack=pack) self.assertEqual(len(pack_dbs), 1) self.assertEqual(len(action_dbs), 1) self.assertEqual(len(alias_dbs), 2) self.assertEqual(len(rule_dbs), 1) self.assertEqual(len(sensor_dbs), 3) self.assertEqual(len(trigger_type_dbs), 4) self.assertEqual(len(policy_dbs), 2) self.assertEqual(len(config_schema_dbs), 1) self.assertEqual(len(config_dbs), 1) # Run action action = self.get_action_instance() action.run(packs=[pack]) # Make sure all resources have been removed from the db pack_dbs = Pack.query(ref=pack) action_dbs = Action.query(pack=pack) alias_dbs = ActionAlias.query(pack=pack) rule_dbs = Rule.query(pack=pack) sensor_dbs = Sensor.query(pack=pack) trigger_type_dbs = TriggerType.query(pack=pack) policy_dbs = Policy.query(pack=pack) config_schema_dbs = ConfigSchema.query(pack=pack) config_dbs = Config.query(pack=pack) self.assertEqual(len(pack_dbs), 0) self.assertEqual(len(action_dbs), 0) self.assertEqual(len(alias_dbs), 0) self.assertEqual(len(rule_dbs), 0) self.assertEqual(len(sensor_dbs), 0) self.assertEqual(len(trigger_type_dbs), 0) self.assertEqual(len(policy_dbs), 0) self.assertEqual(len(config_schema_dbs), 0) self.assertEqual(len(config_dbs), 0)
def test_run(self): pack = 'dummy_pack_1' # Verify all the resources are there pack_dbs = Pack.query(ref=pack) action_dbs = Action.query(pack=pack) alias_dbs = ActionAlias.query(pack=pack) rule_dbs = Rule.query(pack=pack) sensor_dbs = Sensor.query(pack=pack) trigger_type_dbs = TriggerType.query(pack=pack) policy_dbs = Policy.query(pack=pack) config_schema_dbs = ConfigSchema.query(pack=pack) config_dbs = Config.query(pack=pack) self.assertEqual(len(pack_dbs), 1) self.assertEqual(len(action_dbs), 1) self.assertEqual(len(alias_dbs), 3) self.assertEqual(len(rule_dbs), 1) self.assertEqual(len(sensor_dbs), 3) self.assertEqual(len(trigger_type_dbs), 4) self.assertEqual(len(policy_dbs), 2) self.assertEqual(len(config_schema_dbs), 1) self.assertEqual(len(config_dbs), 1) # Run action action = self.get_action_instance() action.run(packs=[pack]) # Make sure all resources have been removed from the db pack_dbs = Pack.query(ref=pack) action_dbs = Action.query(pack=pack) alias_dbs = ActionAlias.query(pack=pack) rule_dbs = Rule.query(pack=pack) sensor_dbs = Sensor.query(pack=pack) trigger_type_dbs = TriggerType.query(pack=pack) policy_dbs = Policy.query(pack=pack) config_schema_dbs = ConfigSchema.query(pack=pack) config_dbs = Config.query(pack=pack) self.assertEqual(len(pack_dbs), 0) self.assertEqual(len(action_dbs), 0) self.assertEqual(len(alias_dbs), 0) self.assertEqual(len(rule_dbs), 0) self.assertEqual(len(sensor_dbs), 0) self.assertEqual(len(trigger_type_dbs), 0) self.assertEqual(len(policy_dbs), 0) self.assertEqual(len(config_schema_dbs), 0) self.assertEqual(len(config_dbs), 0)
def _get_action_by_pack_and_name(pack=None, name=None): """ Get Action by name and pack. Query doesn't raise an exception. """ return Action.query(name=name, pack=pack).first()
def _get_referenced_action_model(self, action_ref): """ Return Action object for the action referenced in a rule. :param action_ref: Action reference. :type action_ref: ``str`` :rtype: ``ActionDB`` """ # NOTE: We need to retrieve pack and name since that's needed for the PK action_dbs = Action.query( only_fields=['pack', 'ref', 'name', 'parameters'], ref=action_ref, limit=1) if action_dbs: return action_dbs[0] return None
def _transform_action(spec, action_key, input_key): if action_key not in spec or spec.get(action_key) == 'st2.action': return if spec.get(action_key) == 'st2.callback': raise Exception('st2.callback is deprecated.') # Convert parameters that are inline (i.e. action: some_action var1={$.value1} var2={$.value2}) # and split it to action name and input dict as illustrated below. # # action: some_action # input: # var1: <% $.value1 %> # var2: <% $.value2 %> # # This step to separate the action name and the input parameters is required # to wrap them with the st2.action proxy. # # action: st2.action # input: # ref: some_action # parameters: # var1: <% $.value1 %> # var2: <% $.value2 %> _eval_inline_params(spec, action_key, input_key) action_ref = spec.get(action_key) if action_ref and ResourceReference.is_resource_reference(action_ref): ref = ResourceReference.from_string_reference(ref=action_ref) actions = Action.query(name=ref.name, pack=ref.pack) action = actions.first() if actions else None else: action = None if action: spec[action_key] = 'st2.action' action_input = spec.get(input_key) spec[input_key] = {'ref': action_ref} if action_input: spec[input_key]['parameters'] = action_input
def _transform_action(spec, action_key, input_key): if action_key not in spec or spec.get(action_key) == 'st2.action': return if spec.get(action_key) == 'st2.callback': raise Exception('st2.callback is deprecated.') # Convert parameters that are inline (i.e. action: some_action var1={$.value1} var2={$.value2}) # and split it to action name and input dict as illustrated below. # # action: some_action # input: # var1: $.value1 # var2: $.value2 # # This step to separate the action name and the input parameters is required # to wrap them with the st2.action proxy. # # action: st2.action # input: # ref: some_action # parameters: # var1: $.value1 # var2: $.value2 _eval_inline_params(spec, action_key, input_key) action_ref = spec.get(action_key) if ResourceReference.is_resource_reference(action_ref): ref = ResourceReference.from_string_reference(ref=action_ref) actions = Action.query(name=ref.name, pack=ref.pack) action = actions.first() if actions else None else: action = None if action: spec[action_key] = 'st2.action' spec[input_key] = {'ref': action_ref, 'parameters': spec[input_key]}
def test_packs_register_endpoint(self, mock_get_packs): # Register resources from all packs - make sure the count values are correctly added # together # Note: We only register a couple of packs and not all on disk to speed # things up. Registering all the packs takes a long time. fixtures_base_path = get_fixtures_base_path() packs_base_path = os.path.join(fixtures_base_path, 'packs') pack_names = [ 'dummy_pack_1', 'dummy_pack_2', 'dummy_pack_3', 'dummy_pack_10', ] mock_return_value = {} for pack_name in pack_names: mock_return_value[pack_name] = os.path.join( packs_base_path, pack_name) mock_get_packs.return_value = mock_return_value resp = self.app.post_json('/v1/packs/register', {'fail_on_failure': False}) self.assertEqual(resp.status_int, 200) self.assertTrue('runners' in resp.json) self.assertTrue('actions' in resp.json) self.assertTrue('triggers' in resp.json) self.assertTrue('sensors' in resp.json) self.assertTrue('rules' in resp.json) self.assertTrue('rule_types' in resp.json) self.assertTrue('aliases' in resp.json) self.assertTrue('policy_types' in resp.json) self.assertTrue('policies' in resp.json) self.assertTrue('configs' in resp.json) self.assertTrue(resp.json['actions'] >= 3) self.assertTrue(resp.json['configs'] >= 1) # Register resources from a specific pack resp = self.app.post_json('/v1/packs/register', { 'packs': ['dummy_pack_1'], 'fail_on_failure': False }) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json['actions'] >= 1) self.assertTrue(resp.json['sensors'] >= 1) self.assertTrue(resp.json['configs'] >= 1) # Verify metadata_file attribute is set action_dbs = Action.query(pack='dummy_pack_1') self.assertEqual(action_dbs[0].metadata_file, 'actions/my_action.yaml') # Register 'all' resource types should try include any possible content for the pack resp = self.app.post_json('/v1/packs/register', { 'packs': ['dummy_pack_1'], 'fail_on_failure': False, 'types': ['all'] }) self.assertEqual(resp.status_int, 200) self.assertTrue('runners' in resp.json) self.assertTrue('actions' in resp.json) self.assertTrue('triggers' in resp.json) self.assertTrue('sensors' in resp.json) self.assertTrue('rules' in resp.json) self.assertTrue('rule_types' in resp.json) self.assertTrue('aliases' in resp.json) self.assertTrue('policy_types' in resp.json) self.assertTrue('policies' in resp.json) self.assertTrue('configs' in resp.json) # Registering single resource type should also cause dependent resources # to be registered # * actions -> runners # * rules -> rule types # * policies -> policy types resp = self.app.post_json( '/v1/packs/register', { 'packs': ['dummy_pack_1'], 'fail_on_failure': False, 'types': ['actions'] }) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json['runners'] >= 1) self.assertTrue(resp.json['actions'] >= 1) resp = self.app.post_json( '/v1/packs/register', { 'packs': ['dummy_pack_1'], 'fail_on_failure': False, 'types': ['rules'] }) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json['rule_types'] >= 1) self.assertTrue(resp.json['rules'] >= 1) resp = self.app.post_json( '/v1/packs/register', { 'packs': ['dummy_pack_2'], 'fail_on_failure': False, 'types': ['policies'] }) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json['policy_types'] >= 1) self.assertTrue(resp.json['policies'] >= 0) # Register specific type for all packs resp = self.app.post_json('/v1/packs/register', { 'types': ['sensor'], 'fail_on_failure': False }) self.assertEqual(resp.status_int, 200) self.assertEqual(resp.json, {'sensors': 3}) # Verify that plural name form also works resp = self.app.post_json('/v1/packs/register', { 'types': ['sensors'], 'fail_on_failure': False }) self.assertEqual(resp.status_int, 200) # Register specific type for a single packs resp = self.app.post_json('/v1/packs/register', { 'packs': ['dummy_pack_1'], 'types': ['action'] }) self.assertEqual(resp.status_int, 200) self.assertEqual(resp.json, {'actions': 1, 'runners': 15}) # Verify that plural name form also works resp = self.app.post_json('/v1/packs/register', { 'packs': ['dummy_pack_1'], 'types': ['actions'] }) self.assertEqual(resp.status_int, 200) self.assertEqual(resp.json, {'actions': 1, 'runners': 15}) # Register single resource from a single pack specified multiple times - verify that # resources from the same pack are only registered once resp = self.app.post_json( '/v1/packs/register', { 'packs': ['dummy_pack_1', 'dummy_pack_1', 'dummy_pack_1'], 'types': ['actions'], 'fail_on_failure': False }) self.assertEqual(resp.status_int, 200) self.assertEqual(resp.json, {'actions': 1, 'runners': 15}) # Register resources from a single (non-existent pack) resp = self.app.post_json('/v1/packs/register', {'packs': ['doesntexist']}, expect_errors=True) self.assertEqual(resp.status_int, 400) self.assertTrue('Pack "doesntexist" not found on disk:' in resp.json['faultstring']) # Fail on failure is enabled by default resp = self.app.post_json('/v1/packs/register', expect_errors=True) expected_msg = 'Failed to register pack "dummy_pack_10":' self.assertEqual(resp.status_int, 400) self.assertTrue(expected_msg in resp.json['faultstring']) # Fail on failure (broken pack metadata) resp = self.app.post_json('/v1/packs/register', {'packs': ['dummy_pack_1']}, expect_errors=True) expected_msg = 'Referenced policy_type "action.mock_policy_error" doesnt exist' self.assertEqual(resp.status_int, 400) self.assertTrue(expected_msg in resp.json['faultstring']) # Fail on failure (broken action metadata) resp = self.app.post_json('/v1/packs/register', {'packs': ['dummy_pack_15']}, expect_errors=True) expected_msg = 'Failed to register action' self.assertEqual(resp.status_int, 400) self.assertTrue(expected_msg in resp.json['faultstring']) expected_msg = '\'stringa\' is not valid under any of the given schemas' self.assertEqual(resp.status_int, 400) self.assertTrue(expected_msg in resp.json['faultstring'])
def test_packs_register_endpoint(self, mock_get_packs): # Register resources from all packs - make sure the count values are correctly added # together # Note: We only register a couple of packs and not all on disk to speed # things up. Registering all the packs takes a long time. fixtures_base_path = get_fixtures_base_path() packs_base_path = os.path.join(fixtures_base_path, 'packs') pack_names = [ 'dummy_pack_1', 'dummy_pack_2', 'dummy_pack_3', 'dummy_pack_10', ] mock_return_value = {} for pack_name in pack_names: mock_return_value[pack_name] = os.path.join(packs_base_path, pack_name) mock_get_packs.return_value = mock_return_value resp = self.app.post_json('/v1/packs/register', {'fail_on_failure': False}) self.assertEqual(resp.status_int, 200) self.assertTrue('runners' in resp.json) self.assertTrue('actions' in resp.json) self.assertTrue('triggers' in resp.json) self.assertTrue('sensors' in resp.json) self.assertTrue('rules' in resp.json) self.assertTrue('rule_types' in resp.json) self.assertTrue('aliases' in resp.json) self.assertTrue('policy_types' in resp.json) self.assertTrue('policies' in resp.json) self.assertTrue('configs' in resp.json) self.assertTrue(resp.json['actions'] >= 3) self.assertTrue(resp.json['configs'] >= 1) # Register resources from a specific pack resp = self.app.post_json('/v1/packs/register', {'packs': ['dummy_pack_1'], 'fail_on_failure': False}) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json['actions'] >= 1) self.assertTrue(resp.json['sensors'] >= 1) self.assertTrue(resp.json['configs'] >= 1) # Verify metadata_file attribute is set action_dbs = Action.query(pack='dummy_pack_1') self.assertEqual(action_dbs[0].metadata_file, 'actions/my_action.yaml') # Register 'all' resource types should try include any possible content for the pack resp = self.app.post_json('/v1/packs/register', {'packs': ['dummy_pack_1'], 'fail_on_failure': False, 'types': ['all']}) self.assertEqual(resp.status_int, 200) self.assertTrue('runners' in resp.json) self.assertTrue('actions' in resp.json) self.assertTrue('triggers' in resp.json) self.assertTrue('sensors' in resp.json) self.assertTrue('rules' in resp.json) self.assertTrue('rule_types' in resp.json) self.assertTrue('aliases' in resp.json) self.assertTrue('policy_types' in resp.json) self.assertTrue('policies' in resp.json) self.assertTrue('configs' in resp.json) # Registering single resource type should also cause dependent resources # to be registered # * actions -> runners # * rules -> rule types # * policies -> policy types resp = self.app.post_json('/v1/packs/register', {'packs': ['dummy_pack_1'], 'fail_on_failure': False, 'types': ['actions']}) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json['runners'] >= 1) self.assertTrue(resp.json['actions'] >= 1) resp = self.app.post_json('/v1/packs/register', {'packs': ['dummy_pack_1'], 'fail_on_failure': False, 'types': ['rules']}) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json['rule_types'] >= 1) self.assertTrue(resp.json['rules'] >= 1) resp = self.app.post_json('/v1/packs/register', {'packs': ['dummy_pack_2'], 'fail_on_failure': False, 'types': ['policies']}) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json['policy_types'] >= 1) self.assertTrue(resp.json['policies'] >= 0) # Register specific type for all packs resp = self.app.post_json('/v1/packs/register', {'types': ['sensor'], 'fail_on_failure': False}) self.assertEqual(resp.status_int, 200) self.assertEqual(resp.json, {'sensors': 3}) # Verify that plural name form also works resp = self.app.post_json('/v1/packs/register', {'types': ['sensors'], 'fail_on_failure': False}) self.assertEqual(resp.status_int, 200) # Register specific type for a single packs resp = self.app.post_json('/v1/packs/register', {'packs': ['dummy_pack_1'], 'types': ['action']}) self.assertEqual(resp.status_int, 200) self.assertEqual(resp.json, {'actions': 1, 'runners': 15}) # Verify that plural name form also works resp = self.app.post_json('/v1/packs/register', {'packs': ['dummy_pack_1'], 'types': ['actions']}) self.assertEqual(resp.status_int, 200) self.assertEqual(resp.json, {'actions': 1, 'runners': 15}) # Register single resource from a single pack specified multiple times - verify that # resources from the same pack are only registered once resp = self.app.post_json('/v1/packs/register', {'packs': ['dummy_pack_1', 'dummy_pack_1', 'dummy_pack_1'], 'types': ['actions'], 'fail_on_failure': False}) self.assertEqual(resp.status_int, 200) self.assertEqual(resp.json, {'actions': 1, 'runners': 15}) # Register resources from a single (non-existent pack) resp = self.app.post_json('/v1/packs/register', {'packs': ['doesntexist']}, expect_errors=True) self.assertEqual(resp.status_int, 400) self.assertTrue('Pack "doesntexist" not found on disk:' in resp.json['faultstring']) # Fail on failure is enabled by default resp = self.app.post_json('/v1/packs/register', expect_errors=True) expected_msg = 'Failed to register pack "dummy_pack_10":' self.assertEqual(resp.status_int, 400) self.assertTrue(expected_msg in resp.json['faultstring']) # Fail on failure (broken pack metadata) resp = self.app.post_json('/v1/packs/register', {'packs': ['dummy_pack_1']}, expect_errors=True) expected_msg = 'Referenced policy_type "action.mock_policy_error" doesnt exist' self.assertEqual(resp.status_int, 400) self.assertTrue(expected_msg in resp.json['faultstring']) # Fail on failure (broken action metadata) resp = self.app.post_json('/v1/packs/register', {'packs': ['dummy_pack_15']}, expect_errors=True) expected_msg = 'Failed to register action' self.assertEqual(resp.status_int, 400) self.assertTrue(expected_msg in resp.json['faultstring']) expected_msg = '\'stringa\' is not valid under any of the given schemas' self.assertEqual(resp.status_int, 400) self.assertTrue(expected_msg in resp.json['faultstring'])
def test_packs_register_endpoint(self, mock_get_packs): # Register resources from all packs - make sure the count values are correctly added # together # Note: We only register a couple of packs and not all on disk to speed # things up. Registering all the packs takes a long time. fixtures_base_path = get_fixtures_base_path() packs_base_path = os.path.join(fixtures_base_path, "packs") pack_names = [ "dummy_pack_1", "dummy_pack_10", ] mock_return_value = {} for pack_name in pack_names: mock_return_value[pack_name] = os.path.join( packs_base_path, pack_name) mock_get_packs.return_value = mock_return_value resp = self.app.post_json("/v1/packs/register", {"fail_on_failure": False}) self.assertEqual(resp.status_int, 200) self.assertIn("runners", resp.json) self.assertIn("actions", resp.json) self.assertIn("triggers", resp.json) self.assertIn("sensors", resp.json) self.assertIn("rules", resp.json) self.assertIn("rule_types", resp.json) self.assertIn("aliases", resp.json) self.assertIn("policy_types", resp.json) self.assertIn("policies", resp.json) self.assertIn("configs", resp.json) self.assertTrue(resp.json["actions"] >= 3) self.assertTrue(resp.json["configs"] >= 1) # Register resources from a specific pack resp = self.app.post_json("/v1/packs/register", { "packs": ["dummy_pack_1"], "fail_on_failure": False }) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json["actions"] >= 1) self.assertTrue(resp.json["sensors"] >= 1) self.assertTrue(resp.json["configs"] >= 1) # Verify metadata_file attribute is set action_dbs = Action.query(pack="dummy_pack_1") self.assertEqual(action_dbs[0].metadata_file, "actions/my_action.yaml") # Register 'all' resource types should try include any possible content for the pack resp = self.app.post_json( "/v1/packs/register", { "packs": ["dummy_pack_1"], "fail_on_failure": False, "types": ["all"] }, ) self.assertEqual(resp.status_int, 200) self.assertIn("runners", resp.json) self.assertIn("actions", resp.json) self.assertIn("triggers", resp.json) self.assertIn("sensors", resp.json) self.assertIn("rules", resp.json) self.assertIn("rule_types", resp.json) self.assertIn("aliases", resp.json) self.assertIn("policy_types", resp.json) self.assertIn("policies", resp.json) self.assertIn("configs", resp.json) # Registering single resource type should also cause dependent resources # to be registered # * actions -> runners # * rules -> rule types # * policies -> policy types resp = self.app.post_json( "/v1/packs/register", { "packs": ["dummy_pack_1"], "fail_on_failure": False, "types": ["actions"] }, ) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json["runners"] >= 1) self.assertTrue(resp.json["actions"] >= 1) resp = self.app.post_json( "/v1/packs/register", { "packs": ["dummy_pack_1"], "fail_on_failure": False, "types": ["rules"] }, ) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json["rule_types"] >= 1) self.assertTrue(resp.json["rules"] >= 1) resp = self.app.post_json( "/v1/packs/register", { "packs": ["dummy_pack_2"], "fail_on_failure": False, "types": ["policies"], }, ) self.assertEqual(resp.status_int, 200) self.assertTrue(resp.json["policy_types"] >= 1) self.assertTrue(resp.json["policies"] >= 0) # Register specific type for all packs resp = self.app.post_json("/v1/packs/register", { "types": ["sensor"], "fail_on_failure": False }) self.assertEqual(resp.status_int, 200) self.assertEqual(resp.json, {"sensors": 3}) # Verify that plural name form also works resp = self.app.post_json("/v1/packs/register", { "types": ["sensors"], "fail_on_failure": False }) self.assertEqual(resp.status_int, 200) # Register specific type for a single packs resp = self.app.post_json("/v1/packs/register", { "packs": ["dummy_pack_1"], "types": ["action"] }) self.assertEqual(resp.status_int, 200) # 13 real plus 1 mock runner self.assertEqual(resp.json, {"actions": 3, "runners": 14}) # Verify that plural name form also works resp = self.app.post_json("/v1/packs/register", { "packs": ["dummy_pack_1"], "types": ["actions"] }) self.assertEqual(resp.status_int, 200) # 13 real plus 1 mock runner self.assertEqual(resp.json, {"actions": 3, "runners": 14}) # Register single resource from a single pack specified multiple times - verify that # resources from the same pack are only registered once resp = self.app.post_json( "/v1/packs/register", { "packs": ["dummy_pack_1", "dummy_pack_1", "dummy_pack_1"], "types": ["actions"], "fail_on_failure": False, }, ) self.assertEqual(resp.status_int, 200) # 13 real plus 1 mock runner self.assertEqual(resp.json, {"actions": 3, "runners": 14}) # Register resources from a single (non-existent pack) resp = self.app.post_json("/v1/packs/register", {"packs": ["doesntexist"]}, expect_errors=True) self.assertEqual(resp.status_int, 400) self.assertIn('Pack "doesntexist" not found on disk:', resp.json["faultstring"]) # Fail on failure is enabled by default resp = self.app.post_json("/v1/packs/register", expect_errors=True) expected_msg = 'Failed to register pack "dummy_pack_10":' self.assertEqual(resp.status_int, 400) self.assertIn(expected_msg, resp.json["faultstring"]) # Fail on failure (broken pack metadata) resp = self.app.post_json("/v1/packs/register", {"packs": ["dummy_pack_1"]}, expect_errors=True) expected_msg = 'Referenced policy_type "action.mock_policy_error" doesnt exist' self.assertEqual(resp.status_int, 400) self.assertIn(expected_msg, resp.json["faultstring"]) # Fail on failure (broken action metadata) resp = self.app.post_json("/v1/packs/register", {"packs": ["dummy_pack_15"]}, expect_errors=True) expected_msg = "Failed to register action" self.assertEqual(resp.status_int, 400) self.assertIn(expected_msg, resp.json["faultstring"]) expected_msg = "'stringa' is not valid under any of the given schemas" self.assertEqual(resp.status_int, 400) self.assertIn(expected_msg, resp.json["faultstring"])