# Copyright 2015 Rackspace # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import json from xml.etree import ElementTree import six import testtools from syntribos.clients.http.models import RequestObject import syntribos.tests.fuzz.datagen as fuzz_datagen action_field = "ACTION_FIELD:" test_dict = {"a": {"b": "c", "ACTION_FIELD:d": "e"}} test_dict_w_list = {"a": ["val", "val2", "val3"], "b": "c"} test_json_str = '{"a": {"b": "c", "ACTION_FIELD:d": "e"}}' test_params_obj = {"key": "val", "otherkey": "val2"} endpoint = "http://test.com" test_headers = { "Content-Type": "application/json", "Accept": "application/json" } test_params = {"var1": "val1", "var2": "val2"} def get_url(path): """Helper method to append endpoint and slash if necessary.""" return "{endpoint}{sep}{path}".format( endpoint=endpoint, sep="/" if not path.startswith("/") else "", path=path) def req(method, path, *args, **kwargs): """Helper method to create a RequestObject.""" if not kwargs.get("headers"): kwargs["headers"] = test_headers if not kwargs.get("action_field"): kwargs["action_field"] = action_field return RequestObject(method, get_url(path), *args, **kwargs) def get_req(path, *args, **kwargs): """Helper method to create a GET request.""" return req("GET", path, *args, **kwargs) def post_req(path, *args, **kwargs): """Helper method to create a POST request.""" return req("POST", path, *args, **kwargs) class FuzzDatagenUnittest(testtools.TestCase): def test_fuzz_data_dict(self): """Test _fuzz_data with a dict.""" strings = ["test"] for i, d in enumerate( fuzz_datagen._fuzz_data(strings, test_dict, action_field, "unittest"), 1): name, model, stri, param_path = d self.assertEqual("unitteststr1_model{0}".format(i), name) self.assertEqual("e", model.get("a").get("ACTION_FIELD:d")) self.assertEqual("test", model.get("a").get("b")) self.assertEqual("test", stri) self.assertEqual("a/b", param_path) def test_fuzz_data_dict_with_list(self): """Test _fuzz_data with a dict containing a list.""" strings = ["test"] expected = [ { "a": ["test", "val2", "val3"], "b": "c" }, { "a": ["val", "test", "val3"], "b": "c" }, { "a": ["val", "val2", "test"], "b": "c" }, { "a": ["val", "val2", "val3"], "b": "test" } ] i = 0 for i, result in enumerate( fuzz_datagen._fuzz_data(strings, test_dict_w_list, action_field, "unittest"), 1): name, model, string, param_path = result self.assertIn(model, expected) self.assertEqual("unitteststr1_model{0}".format(i), name) self.assertEqual(4, i) def test_fuzz_data_xml(self): """Test _fuzz_data_ with an XML element.""" data = ElementTree.Element("a") sub_ele = ElementTree.Element("b") sub_ele.text = "c" sub_ele.attrib = {"name": "val"} sub_ele2 = ElementTree.Element("ACTION_FIELD:d") sub_ele2.text = "e" data.append(sub_ele) data.append(sub_ele2) strings = ["test"] contents = [] expected_contents = [ 'teste', 'ce' ] for i, d in enumerate( fuzz_datagen._fuzz_data(strings, data, "ACTION_FIELD:", "unittest"), 1): name, model, stri, param_path = d self.assertEqual("unitteststr1_model{0}".format(i), name) self.assertEqual("test", stri) if six.PY2: contents.append(ElementTree.tostring(model)) else: contents.append(ElementTree.tostring(model).decode("utf-8")) self.assertEqual(expected_contents, contents) def test_fuzz_data_string(self): """Test _fuzz_data with a string like a URL.""" data = "TEST_STRING/{ST}" strings = ["test"] for i, d in enumerate( fuzz_datagen._fuzz_data(strings, data, action_field, "unittest"), 1): name, model, stri, param_path = d self.assertEqual("unitteststr1_model{0}".format(i), name) self.assertEqual("TEST_STRING/test", model) self.assertEqual("test", stri) self.assertEqual("ST", param_path) def test_invalid_type(self): """Test _fuzz_data with a list (invalid type).""" data = set(["list", "of", "strings"]) strings = ["test"] self.assertRaises( TypeError, fuzz_datagen._fuzz_data(strings, data, action_field, "unittest")) def test_str_combos_with_name(self): """Test building string combinations with 1 named URL variable.""" data = "/api/v1/{key:val}" results = [ d for d in fuzz_datagen._build_str_combinations("test", data) ] self.assertIn(("/api/v1/test", "key"), results) self.assertEqual(1, len(results)) def test_fuzz_data_with_multiple_string_names(self): """Test _fuzz_data with 2 named URL variables.""" strings = ["test", "test2"] data = "/api/v1/{key:val}/path/{otherkey:val2}" expected_results = [ ("unitteststr1_model1", "/api/v1/test/path/{otherkey:val2}", "test", "key"), ("unitteststr1_model2", "/api/v1/{key:val}/path/test", "test", "otherkey"), ("unitteststr2_model1", "/api/v1/test2/path/{otherkey:val2}", "test2", "key"), ("unitteststr2_model2", "/api/v1/{key:val}/path/test2", "test2", "otherkey") ] results = [ d for d in fuzz_datagen._fuzz_data(strings, data, action_field, "unittest") ] self.assertEqual(expected_results, results) def test_fuzz_data_with_one_named_one_unnamed(self): """Test _fuzz_data with 1 named, 1 unnamed URL variables.""" strings = ["test", "test2"] data = "/api/v1/{key:val}/path/{otherkey}" expected_results = [ ("unitteststr1_model1", "/api/v1/test/path/{otherkey}", "test", "key"), ("unitteststr1_model2", "/api/v1/{key:val}/path/test", "test", "otherkey"), ("unitteststr2_model1", "/api/v1/test2/path/{otherkey}", "test2", "key"), ("unitteststr2_model2", "/api/v1/{key:val}/path/test2", "test2", "otherkey") ] results = [ d for d in fuzz_datagen._fuzz_data(strings, data, action_field, "unittest") ] self.assertEqual(expected_results, results) def test_post_fuzz_req_url_vars(self): """Test fuzz_request with 2 named URL params.""" req = post_req("/api/v1/{key:val}/path/{otherkey:val2}") strings = ["test"] results = [ d for d in fuzz_datagen.fuzz_request(req, strings, "url", "ut") ] req_objs = [r[1] for r in results] urls = [o.url for o in req_objs] self.assertIn(get_url("/api/v1/test/path/val2"), urls) self.assertIn(get_url("/api/v1/val/path/test"), urls) self.assertEqual(2, len(results)) def test_post_fuzz_req_json_vars(self): """Test fuzz_request with a JSON-like dict.""" req = post_req( "/api/v1/{key:val}/path/{otherkey:val2}", data=test_dict) strings = ["test"] results = [ d for d in fuzz_datagen.fuzz_request(req, strings, "data", "ut") ] req_objs = [r[1] for r in results] for d in [o.data for o in req_objs]: _dict = json.loads(d) self.assertEqual("test", _dict.get("a").get("b")) self.assertEqual("e", _dict.get("a").get("d")) for url in [o.url for o in req_objs]: self.assertEqual(get_url("/api/v1/val/path/val2"), url) self.assertEqual(1, len(results)) def test_get_fuzz_req_params(self): """Test fuzz_request against request with params.""" req = get_req("/api/v1/endpoint", params=test_params_obj) strings = ["test", "test2"] expected_param_objs = [ { "otherkey": "test", "key": "val" }, { "otherkey": "val2", "key": "test" }, { "otherkey": "test2", "key": "val" }, { "otherkey": "val2", "key": "test2" } ] i = 0 for i, d in enumerate( fuzz_datagen.fuzz_request(req, strings, "params", "ut"), 1): name, req, fuzz_string, name = d self.assertIn(req.params, expected_param_objs) self.assertEqual(i, 4)