def main(): test_name = 'GET fuzzed' get_template = Template( name=test_name, fields=[ XmlElement( name='html', element_name='html', content=[ XmlElement( name='head', element_name='head', content='<meta http-equiv="refresh" content="5; url=/">' ), XmlElement(name='body', element_name='body', content='123', fuzz_content=True), ]) ]) fuzzer = ClientFuzzer(name='Example 2 - Browser Fuzzer (Remote)') fuzzer.set_interface(WebInterface(host='0.0.0.0', port=26000)) target = ClientTarget(name='BrowserTarget') # # Note: to avoid opening the process on our X server, we use another display for it # display ':2' that is specified below was started this way: # >> sudo apt-get install xvfb # >> Xvfb :2 -screen 2 1280x1024x8 # env = os.environ.copy() env['DISPLAY'] = ':2' controller = ClientProcessController('BrowserController', '/usr/bin/opera', ['http://localhost:8082/fuzzed'], process_env=env) target.set_controller(controller) target.set_mutation_server_timeout(20) model = GraphModel() model.connect(get_template) fuzzer.set_model(model) fuzzer.set_target(target) # # only fuzz the half of the mutations, just as an example fuzzer.set_range(end_index=model.num_mutations() // 2) fuzzer.set_delay_between_tests(0.1) remote = RpcServer(host='localhost', port=26007, impl=fuzzer) remote.start()
def main(): test_name = 'GET /fuzzed' get_template = Template(name=test_name, fields=[ XmlElement(name='html', element_name='html', content=[ XmlElement(name='head', element_name='head', content='<meta http-equiv="refresh" content="5; url=/">'), XmlElement(name='body', element_name='body', content='123', fuzz_content=True), ]) ]) fuzzer = ClientFuzzer(name='BrowserFuzzer') fuzzer.set_interface(WebInterface(host='0.0.0.0', port=26000)) target = ClientTarget(name='BrowserTarget') # # Note: to avoid opening the process on our X server, we use another display for it # display ':2' that is specified below was started this way: # >> sudo apt-get install xvfb # >> Xvfb :2 -screen 2 1280x1024x8 # env = os.environ.copy() env['DISPLAY'] = ':2' controller = ClientProcessController( 'BrowserController', '/usr/bin/opera', ['http://localhost:8082/fuzzed'], process_env=env ) target.set_controller(controller) target.set_mutation_server_timeout(20) model = GraphModel() model.connect(get_template) fuzzer.set_model(model) fuzzer.set_target(target) # # only fuzz the half of the mutations, just as an example fuzzer.set_range(end_index=model.num_mutations() / 2) fuzzer.set_delay_between_tests(0.1) remote = RpcServer(host='localhost', port=26007, impl=fuzzer) remote.start()
class GraphModelTests(unittest.TestCase): def setUp(self): self.logger = get_test_logger() self.logger.debug('TESTING METHOD: %s', self._testMethodName) self.model = GraphModel() self.templates = self.get_templates() self.todo = [] def get_templates(self): res = [] res.append(Template(name='t1', fields=[String('data1')])) res.append(Template(name='t2', fields=[String('data2'), UInt32(300)])) res.append(Template(name='t3', fields=[UInt32(400)])) return res def _check_sequences(self, expected_sequences): self.logger.debug('check num_mutations()') t_num_mutations = sum(s[-1].num_mutations() for s in expected_sequences) m_num_mutations = self.model.num_mutations() self.assertEqual(t_num_mutations, m_num_mutations) sequences = {} while self.model.mutate(): sequence = tuple(self.model.get_sequence()) if sequence not in sequences: sequences[sequence] = 1 else: sequences[sequence] += 1 self.assertEqual(len(sequences), len(expected_sequences)) self.logger.debug('check that each sequence appears the appropriate number of times') for sequence, count in sequences.items(): seq_templates = [e.dst for e in sequence] self.assertIn(seq_templates, expected_sequences) last = seq_templates[-1] last_num_mutations = last.num_mutations() self.assertEqual(count, last_num_mutations) def test_sequence_single_template(self): t = self.templates[0] self.model.connect(t) expected_sequences = [[t]] self._check_sequences(expected_sequences) def test_sequence_direct_path(self): ''' root -> t1 ''' self.model.connect(self.templates[0]) for i in range(len(self.templates) - 1): self.model.connect(self.templates[i], self.templates[i + 1]) expected_sequences = list(self.templates[:i + 1] for i in range(len(self.templates))) self._check_sequences(expected_sequences) def test_sequence_complex_path(self): ''' root -> t1 root -> t1 -> t2 root -> t1 -> t3 root -> t1 -> t2 -> t3 ''' self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) self.model.connect(self.templates[0], self.templates[2]) self.model.connect(self.templates[1], self.templates[2]) expected_sequences = [ [self.templates[0]], [self.templates[0], self.templates[1]], [self.templates[0], self.templates[2]], [self.templates[0], self.templates[1], self.templates[2]] ] self._check_sequences(expected_sequences) def test_multi_head_path(self): ''' root -> t1 root -> t2 root -> t3 ''' expected_sequences = [] for t in self.templates: expected_sequences.append([t]) self.model.connect(t) self._check_sequences(expected_sequences) def _check_skip(self, to_skip, expected_skipped, expected_mutated): skipped = self.model.skip(to_skip) self.assertEqual(expected_skipped, skipped) mutated = 0 while self.model.mutate(): mutated += 1 self.assertEqual(expected_mutated, mutated) def test_skip_zero_single_template(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = 0 expected_skipped = to_skip expected_mutated = m_num_mutations self._check_skip(to_skip, expected_skipped, expected_mutated) def test_skip_half_single_template(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations / 2 expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def test_skip_exact_single_template(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def test_skip_too_much_single_template(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations + 10 expected_skipped = m_num_mutations expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def test_skip_zero_multi_template(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = 0 expected_skipped = to_skip expected_mutated = m_num_mutations self._check_skip(to_skip, expected_skipped, expected_mutated) def test_skip_half_multi_template(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations / 2 expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def test_skip_exact_multi_template(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def test_skip_too_much_multi_template(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations + 10 expected_skipped = m_num_mutations expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def test_failure_to_to(self): self.assertEqual(len(self.todo), 0) def test_exception_if_loop(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) self.model.connect(self.templates[1], self.templates[0]) with self.assertRaises(KittyException): self.model.num_mutations()
class TestClientFuzzer(unittest.TestCase): def setUp(self): self.logger = get_test_logger() self.logger.debug('TESTING METHOD: %s', self._testMethodName) self._default_stage = 'simple_str_template' self.t_str = Template(name=self._default_stage, fields=[String(name='str1', value='kitty')]) self.t_int = Template(name='simple_int_template', fields=[UInt32(name='int1', value=0x1234)]) self.fuzzer = None self.mutations = {} self.prepare() def tearDown(self): if self.fuzzer: self.fuzzer.stop() def default_callback(self, test, stage, resp): if test not in self.mutations: self.mutations[test] = [] self.mutations[test].append((stage, resp)) def prepare(self): self.start_index = 10 self.end_index = 20 self.delay_duration = 0 self.fuzzer = ClientFuzzer(name="TestServerFuzzer", logger=self.logger) self.interface = EmptyInterface() self.fuzzer.set_interface(self.interface) self.model = GraphModel() self.model.logger = self.logger self.model.connect(self.t_str) self.fuzzer.set_model(self.model) self.default_config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [(self._default_stage, {})] } } } self.target = ClientTargetMock(self.default_config, self.default_callback, logger=self.logger) self.fuzzer.set_target(self.target) self.fuzzer.set_range(self.start_index, self.end_index) self.fuzzer.set_delay_between_tests(self.delay_duration) def testRaisesExceptionWhenStartedWithoutModel(self): self.fuzzer.set_model(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testRaisesExceptionWhenStartedWithoutTarget(self): self.fuzzer.set_target(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testRaisesExceptionWhenStartedWithoutInterface(self): self.fuzzer.set_interface(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testVanilla(self): self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() # reports = self.fuzzer._get_reports_manager() # self.assertEqual(len(reports), 0) self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, None) # self.assertEqual(info.original_start_index, 10) self.assertEqual(info.start_index, self.start_index) self.assertEqual(info.end_index, self.end_index) def testStartingFromStartIndex(self): start_index = self.model.num_mutations() - 2 self.fuzzer.set_range(start_index) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() self.assertEqual(info.current_index, None) self.assertEqual(info.end_index, self.model.last_index()) def testEndingAtEndIndex(self): start_index = 0 end_index = 3 self.fuzzer.set_range(start_index, end_index) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, 3) self.assertEqual(info.current_index, None) def testFullMutationRange(self): self.fuzzer.set_range() self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, self.model.last_index()) self.assertEqual(info.current_index, None) def testTestFailedWhenReportIsFailed(self): config = { '13': { 'report': { 'status': 'failed', 'reason': 'failure reason' } } } config.update(self.default_config) target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual( sorted(reports), sorted([int(x) for x in config.keys() if x != 'always'])) self.assertEqual(info.failure_count, len(config) - 1) def testAllFailedTestsHaveReports(self): config = { '10': { 'report': { 'status': 'failed', 'reason': 'failure reason' } }, '11': { 'report': { 'status': 'failed', 'reason': 'failure reason' } }, '12': { 'report': { 'status': 'failed', 'reason': 'failure reason' } }, '13': { 'report': { 'status': 'failed', 'reason': 'failure reason' } } } config.update(self.default_config) target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual( sorted(reports), sorted([int(x) for x in config.keys() if x != 'always'])) self.assertEqual(info.failure_count, len(config) - 1) def testStoringAllReportsWhenStoreAllReportsIsSetToTrue(self): config = {} config.update(self.default_config) target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_store_all_reports(True) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() expected_mutation_count = self.end_index - self.start_index + 1 expected_failure_count = 0 self.assertEqual(len(reports), expected_mutation_count) self.assertEqual(info.failure_count, expected_failure_count) def testOnlyTestsInSetRangeAreExecuted(self): start_index = self.model.num_mutations() - 5 self.model.connect(self.t_str, self.t_int) expected_end_index = self.model.last_index() self.fuzzer.set_range(start_index) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, None) self.assertEqual(info.start_index, start_index) self.assertEqual(info.end_index, expected_end_index) def testGetMutationForStage(self): self.fuzzer.set_range(0, 1) config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [(self._default_stage, {})] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEqual(self.mutations[0][0][0], self._default_stage) self.assertIsNotNone(self.mutations[0][0][1]) def testGetMutationForStageTwice(self): self.fuzzer.set_range(0, 1) config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [(self._default_stage, {}), (self._default_stage, {})] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEqual(self.mutations[0][0][0], self._default_stage) self.assertIsNotNone(self.mutations[0][0][1]) self.assertEqual(self.mutations[0][1][0], self._default_stage) self.assertIsNotNone(self.mutations[0][1][1]) def testGetMutationWrongStage(self): self.fuzzer.set_range(0, 1) wrong_stage = 'simple_str_template1' config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (wrong_stage, {}), ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEqual(self.mutations[0][0][0], wrong_stage) self.assertIsNone(self.mutations[0][0][1]) def testGetMutationWrongAfterCorrectStage(self): self.fuzzer.set_range(0, 1) wrong_stage = 'simple_str_template1' config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (self._default_stage, {}), (wrong_stage, {}), ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEqual(self.mutations[0][0][0], self._default_stage) self.assertIsNotNone(self.mutations[0][0][1]) self.assertEqual(self.mutations[0][1][0], wrong_stage) self.assertIsNone(self.mutations[0][1][1]) def testGetMutationCorrectAfterWrongStage(self): self.fuzzer.set_range(0, 1) wrong_stage = 'simple_str_template1' config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (wrong_stage, {}), (self._default_stage, {}), ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEqual(self.mutations[0][0][0], wrong_stage) self.assertIsNone(self.mutations[0][0][1]) self.assertEqual(self.mutations[0][1][0], self._default_stage) self.assertIsNotNone(self.mutations[0][1][1]) def testGetMutationWithWildcard(self): self.fuzzer.set_range(0, 1) config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [(ClientFuzzer.STAGE_ANY, {})] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEqual(self.mutations[0][0][0], ClientFuzzer.STAGE_ANY) self.assertIsNotNone(self.mutations[0][0][1])
class TestServerFuzzer(unittest.TestCase): def setUp(self): self.logger = get_test_logger() self.logger.debug('TESTING METHOD: %s', self._testMethodName) self.t_str = Template(name='simple_str_template', fields=[String(name='str1', value='kitty')]) self.t_int = Template(name='simple_int_template', fields=[UInt32(name='int1', value=0x1234)]) self.fuzzer = None self.prepare() def tearDown(self): if self.fuzzer: self.fuzzer.stop() if self.session_file_name: if os.path.exists(self.session_file_name): os.remove(self.session_file_name) def prepare(self): self.start_index = 10 self.end_index = 20 self.delay_duration = 0 self.session_file_name = None self.interface = EmptyInterface() self.model = GraphModel() self.model.logger = self.logger self.model.connect(self.t_str) self.target = ServerTargetMock({}, logger=self.logger) self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_range(self.start_index, self.end_index) self.fuzzer.set_delay_between_tests(self.delay_duration) def testRaisesExceptionWhenStartedWithoutModel(self): self.fuzzer.set_model(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testRaisesExceptionWhenStartedWithoutTarget(self): self.fuzzer.set_target(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testRaisesExceptionWhenStartedWithoutInterface(self): self.fuzzer.set_interface(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testCommandLineArgumentsStart(self): self.start_index = 10 cmd_line = '--start=%d' % self.start_index self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_delay_between_tests(self.delay_duration) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.current_index, self.model.last_index()) self.assertEqual(info.start_index, self.start_index) def testCommandLineArgumentsEnd(self): self.end_index = 10 cmd_line = '--end=%d' % self.end_index self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_delay_between_tests(self.delay_duration) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, self.end_index) self.assertEqual(info.current_index, self.end_index) def testCommandLineArgumentDelay(self): self.delay_duration = 0.1 cmd_line = '--delay=%s' % self.delay_duration self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_range(self.start_index, self.end_index) self.assertEqual(self.delay_duration, self.fuzzer.config.delay_secs) start_time = time.time() self.fuzzer.start() end_time = time.time() expected_runtime = self.delay_duration * (self.end_index - self.start_index + 1) actual_runtime = end_time - start_time self.assertAlmostEqual(int(actual_runtime), int(expected_runtime)) def testCommandLineArgumentSession(self): self.session_file_name = 'mysession.sqlite' cmd_line = '--session=%s' % self.session_file_name self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger, option_line=cmd_line) self.fuzzer.set_interface(self.interface) self.fuzzer.set_model(self.model) self.fuzzer.set_target(self.target) self.fuzzer.set_delay_between_tests(self.delay_duration) self.fuzzer.set_range(self.start_index, self.end_index) self.assertEqual(self.session_file_name, self.fuzzer.config.session_file_name) self.fuzzer.start() def testVanilla(self): self.fuzzer.start() info = self.fuzzer._get_session_info() # reports = self.fuzzer._get_reports_manager() # self.assertEqual(len(reports), 0) self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, self.end_index) # self.assertEqual(info.original_start_index, 10) self.assertEqual(info.start_index, self.start_index) self.assertEqual(info.end_index, self.end_index) mutations_tested = info.current_index - info.start_index self.assertEqual(mutations_tested, self.end_index - self.start_index) def testStartingFromStartIndex(self): start_index = self.model.num_mutations() - 2 self.fuzzer.set_range(start_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.current_index, self.model.last_index()) self.assertEqual(info.end_index, self.model.last_index()) def testEndingAtEndIndex(self): start_index = 0 end_index = 3 self.fuzzer.set_range(start_index, end_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, 3) self.assertEqual(info.current_index, 3) def testFullMutationRange(self): self.fuzzer.set_range() self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, self.model.last_index()) self.assertEqual(info.current_index, self.model.last_index()) def _MOVE_TO_TARGET_TESTS_test_send_failure(self): config = { '12': { 'send': {"raise exception": True} } } send_error_target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_target(send_error_target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer._get_reports_manager() self.assertEqual(len(reports), 1) self.assertTrue(12 in reports) self.assertEqual(info.failure_count, 1) def testTestFailedWhenReportIsFailed(self): config = { '13': { 'report': { 'status': 'failed', 'reason': 'failure reason' } } } target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual(reports, [int(x) for x in config.keys()]) self.assertEqual(info.failure_count, len(config)) def testAllFailedTestsHaveReports(self): config = { '10': {'report': {'status': 'failed', 'reason': 'failure reason'}}, '11': {'report': {'status': 'failed', 'reason': 'failure reason'}}, '12': {'report': {'status': 'failed', 'reason': 'failure reason'}}, '13': {'report': {'status': 'failed', 'reason': 'failure reason'}} } target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual(reports, sorted([int(x) for x in config.keys()])) self.assertEqual(info.failure_count, len(config)) def testStoringAllReportsWhenStoreAllReportsIsSetToTrue(self): config = {} target = ServerTargetMock(config, logger=self.logger) self.fuzzer.set_store_all_reports(True) self.fuzzer.set_target(target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() expected_mutation_count = self.end_index - self.start_index + 1 expected_failure_count = 0 self.assertEqual(len(reports), expected_mutation_count) self.assertEqual(info.failure_count, expected_failure_count) def testOnlyTestsInSetRangeAreExecuted(self): start_index = self.model.num_mutations() - 5 self.model.connect(self.t_str, self.t_int) expected_end_index = self.model.last_index() expected_num_mutations = expected_end_index - start_index self.fuzzer.set_range(start_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, expected_end_index) mutations_tested = info.current_index - info.start_index self.assertEqual(mutations_tested, expected_num_mutations) self.assertEqual(info.start_index, start_index) self.assertEqual(info.end_index, expected_end_index) def testCallbackIsCalledBetweenTwoNodes(self): template1 = Template(name='template1', fields=String('str1')) template2 = Template(name='template2', fields=String('str2')) self.cb_call_count = 0 def t1_t2_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template2) self.cb_call_count += 1 model = GraphModel() model.logger = self.logger model.connect(template1) model.connect(template1, template2, t1_t2_cb) self.model = model self.fuzzer.set_model(model) self.fuzzer.set_range() self.fuzzer.start() self.assertEqual(template2.num_mutations(), self.cb_call_count) def testCorrectCallbackIsCalledForEachEdge(self): template1 = Template(name='template1', fields=String('str1')) template2 = Template(name='template2', fields=String('str2')) template3 = Template(name='template3', fields=String('str3')) self.cb2_call_count = 0 self.cb3_call_count = 0 def t1_t2_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template2) self.cb2_call_count += 1 def t1_t3_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template3) self.cb3_call_count += 1 model = GraphModel() model.logger = self.logger model.connect(template1) model.connect(template1, template2, t1_t2_cb) model.connect(template1, template3, t1_t3_cb) self.model = model self.fuzzer.set_model(model) self.fuzzer.set_range() self.fuzzer.start() self.assertEqual(template2.num_mutations(), self.cb2_call_count) self.assertEqual(template3.num_mutations(), self.cb3_call_count) def testCorrectCallbackIsCalledForAllEdgesInPath(self): template1 = Template(name='template1', fields=String('str1')) template2 = Template(name='template2', fields=String('str2')) template3 = Template(name='template3', fields=String('str3')) self.cb2_call_count = 0 self.cb3_call_count = 0 def t1_t2_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template1) self.assertEqual(edge.dst, template2) self.cb2_call_count += 1 def t2_t3_cb(fuzzer, edge, response): self.assertEqual(fuzzer, self.fuzzer) self.assertEqual(edge.src, template2) self.assertEqual(edge.dst, template3) self.cb3_call_count += 1 model = GraphModel() model.logger = self.logger model.connect(template1) model.connect(template1, template2, t1_t2_cb) model.connect(template2, template3, t2_t3_cb) self.model = model self.fuzzer.set_model(model) self.fuzzer.set_range() self.fuzzer.start() self.assertEqual(template2.num_mutations() + template3.num_mutations(), self.cb2_call_count) self.assertEqual(template3.num_mutations(), self.cb3_call_count)
class TestClientFuzzer(unittest.TestCase): def setUp(self): self.logger = get_test_logger() self.logger.debug('TESTING METHOD: %s', self._testMethodName) self._default_stage = 'simple_str_template' self.t_str = Template(name=self._default_stage, fields=[String(name='str1', value='kitty')]) self.t_int = Template(name='simple_int_template', fields=[UInt32(name='int1', value=0x1234)]) self.fuzzer = None self.mutations = {} self.prepare() def tearDown(self): if self.fuzzer: self.fuzzer.stop() def default_callback(self, test, stage, resp): if test not in self.mutations: self.mutations[test] = [] self.mutations[test].append((stage, resp)) def prepare(self): self.start_index = 10 self.end_index = 20 self.delay_duration = 0 self.fuzzer = ClientFuzzer(name="TestServerFuzzer", logger=self.logger) self.interface = EmptyInterface() self.fuzzer.set_interface(self.interface) self.model = GraphModel() self.model.logger = self.logger self.model.connect(self.t_str) self.fuzzer.set_model(self.model) self.default_config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (self._default_stage, {}) ] } } } self.target = ClientTargetMock(self.default_config, self.default_callback, logger=self.logger) self.fuzzer.set_target(self.target) self.fuzzer.set_range(self.start_index, self.end_index) self.fuzzer.set_delay_between_tests(self.delay_duration) def testRaisesExceptionWhenStartedWithoutModel(self): self.fuzzer.set_model(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testRaisesExceptionWhenStartedWithoutTarget(self): self.fuzzer.set_target(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testRaisesExceptionWhenStartedWithoutInterface(self): self.fuzzer.set_interface(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def testVanilla(self): self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() # reports = self.fuzzer._get_reports_manager() # self.assertEqual(len(reports), 0) self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, None) # self.assertEqual(info.original_start_index, 10) self.assertEqual(info.start_index, self.start_index) self.assertEqual(info.end_index, self.end_index) def testStartingFromStartIndex(self): start_index = self.model.num_mutations() - 2 self.fuzzer.set_range(start_index) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() self.assertEqual(info.current_index, None) self.assertEqual(info.end_index, self.model.last_index()) def testEndingAtEndIndex(self): start_index = 0 end_index = 3 self.fuzzer.set_range(start_index, end_index) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, 3) self.assertEqual(info.current_index, None) def testFullMutationRange(self): self.fuzzer.set_range() self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, self.model.last_index()) self.assertEqual(info.current_index, None) def testTestFailedWhenReportIsFailed(self): config = { '13': { 'report': { 'status': 'failed', 'reason': 'failure reason' } } } config.update(self.default_config) target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual(sorted(reports), sorted([int(x) for x in config.keys() if x != 'always'])) self.assertEqual(info.failure_count, len(config) - 1) def testAllFailedTestsHaveReports(self): config = { '10': {'report': {'status': 'failed', 'reason': 'failure reason'}}, '11': {'report': {'status': 'failed', 'reason': 'failure reason'}}, '12': {'report': {'status': 'failed', 'reason': 'failure reason'}}, '13': {'report': {'status': 'failed', 'reason': 'failure reason'}} } config.update(self.default_config) target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() self.assertEqual(sorted(reports), sorted([int(x) for x in config.keys() if x != 'always'])) self.assertEqual(info.failure_count, len(config) - 1) def testStoringAllReportsWhenStoreAllReportsIsSetToTrue(self): config = {} config.update(self.default_config) target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_store_all_reports(True) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() reports = self.fuzzer.dataman.get_report_test_ids() expected_mutation_count = self.end_index - self.start_index + 1 expected_failure_count = 0 self.assertEqual(len(reports), expected_mutation_count) self.assertEqual(info.failure_count, expected_failure_count) def testOnlyTestsInSetRangeAreExecuted(self): start_index = self.model.num_mutations() - 5 self.model.connect(self.t_str, self.t_int) expected_end_index = self.model.last_index() self.fuzzer.set_range(start_index) self.fuzzer.start() self.fuzzer.wait_until_done() info = self.fuzzer._get_session_info() self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, None) self.assertEqual(info.start_index, start_index) self.assertEqual(info.end_index, expected_end_index) def testGetMutationForStage(self): self.fuzzer.set_range(0, 1) config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (self._default_stage, {}) ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEquals(self.mutations[0][0][0], self._default_stage) self.assertIsNotNone(self.mutations[0][0][1]) def testGetMutationForStageTwice(self): self.fuzzer.set_range(0, 1) config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (self._default_stage, {}), (self._default_stage, {}) ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEquals(self.mutations[0][0][0], self._default_stage) self.assertIsNotNone(self.mutations[0][0][1]) self.assertEquals(self.mutations[0][1][0], self._default_stage) self.assertIsNotNone(self.mutations[0][1][1]) def testGetMutationWrongStage(self): self.fuzzer.set_range(0, 1) wrong_stage = 'simple_str_template1' config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (wrong_stage, {}), ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEquals(self.mutations[0][0][0], wrong_stage) self.assertIsNone(self.mutations[0][0][1]) def testGetMutationWrongAfterCorrectStage(self): self.fuzzer.set_range(0, 1) wrong_stage = 'simple_str_template1' config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (self._default_stage, {}), (wrong_stage, {}), ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEquals(self.mutations[0][0][0], self._default_stage) self.assertIsNotNone(self.mutations[0][0][1]) self.assertEquals(self.mutations[0][1][0], wrong_stage) self.assertIsNone(self.mutations[0][1][1]) def testGetMutationCorrectAfterWrongStage(self): self.fuzzer.set_range(0, 1) wrong_stage = 'simple_str_template1' config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (wrong_stage, {}), (self._default_stage, {}), ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEquals(self.mutations[0][0][0], wrong_stage) self.assertIsNone(self.mutations[0][0][1]) self.assertEquals(self.mutations[0][1][0], self._default_stage) self.assertIsNotNone(self.mutations[0][1][1]) def testGetMutationWithWildcard(self): self.fuzzer.set_range(0, 1) config = { 'always': { 'trigger': { 'fuzzer': self.fuzzer, 'stages': [ (ClientFuzzer.STAGE_ANY, {}) ] } } } target = ClientTargetMock(config, self.default_callback, logger=self.logger) self.fuzzer.set_target(target) self.fuzzer.start() self.fuzzer.wait_until_done() self.assertIn(0, self.mutations) self.assertEquals(self.mutations[0][0][0], ClientFuzzer.STAGE_ANY) self.assertIsNotNone(self.mutations[0][0][1])
class GraphModelTests(unittest.TestCase): def setUp(self): self.logger = get_test_logger() self.logger.debug('TESTING METHOD: %s', self._testMethodName) self.model = GraphModel() self.templates = self.get_templates() self.todo = [] def get_templates(self): res = [] res.append(Template(name='t1', fields=[String('data1')])) res.append(Template(name='t2', fields=[String('data2'), UInt32(300)])) res.append(Template(name='t3', fields=[UInt32(400)])) return res def _check_sequences(self, expected_sequences): self.logger.debug('check num_mutations()') t_num_mutations = sum(s[-1].num_mutations() for s in expected_sequences) m_num_mutations = self.model.num_mutations() self.assertEqual(t_num_mutations, m_num_mutations) sequences = {} while self.model.mutate(): sequence = tuple(self.model.get_sequence()) if sequence not in sequences: sequences[sequence] = 1 else: sequences[sequence] += 1 self.assertEqual(len(sequences), len(expected_sequences)) self.logger.debug( 'check that each sequence appears the appropriate number of times') for sequence, count in sequences.items(): seq_templates = [e.dst for e in sequence] self.assertIn(seq_templates, expected_sequences) last = seq_templates[-1] last_num_mutations = last.num_mutations() self.assertEqual(count, last_num_mutations) def testSequenceSingleTemplate(self): t = self.templates[0] self.model.connect(t) expected_sequences = [[t]] self._check_sequences(expected_sequences) def testSequenceDirectPath(self): ''' root -> t1 ''' self.model.connect(self.templates[0]) for i in range(len(self.templates) - 1): self.model.connect(self.templates[i], self.templates[i + 1]) expected_sequences = list(self.templates[:i + 1] for i in range(len(self.templates))) self._check_sequences(expected_sequences) def testSequenceComplexPath(self): ''' root -> t1 root -> t1 -> t2 root -> t1 -> t3 root -> t1 -> t2 -> t3 ''' self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) self.model.connect(self.templates[0], self.templates[2]) self.model.connect(self.templates[1], self.templates[2]) expected_sequences = [[self.templates[0]], [self.templates[0], self.templates[1]], [self.templates[0], self.templates[2]], [ self.templates[0], self.templates[1], self.templates[2] ]] self._check_sequences(expected_sequences) def testMultiHeadPath(self): ''' root -> t1 root -> t2 root -> t3 ''' expected_sequences = [] for t in self.templates: expected_sequences.append([t]) self.model.connect(t) self._check_sequences(expected_sequences) def _check_skip(self, to_skip, expected_skipped, expected_mutated): skipped = self.model.skip(to_skip) self.assertEqual(expected_skipped, skipped) mutated = 0 while self.model.mutate(): mutated += 1 self.assertEqual(expected_mutated, mutated) def testSkipZeroSingleTemplate(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = 0 expected_skipped = to_skip expected_mutated = m_num_mutations self._check_skip(to_skip, expected_skipped, expected_mutated) def testSkipHalfSingleTemplate(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations // 2 expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def testSkipExactSingleTemplate(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def testSkipTooMuchSingleTemplate(self): self.model.connect(self.templates[0]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations + 10 expected_skipped = m_num_mutations expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def testSkipZeroMultiTemplate(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = 0 expected_skipped = to_skip expected_mutated = m_num_mutations self._check_skip(to_skip, expected_skipped, expected_mutated) def testSkipHalfMultiTemplate(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations // 2 expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def testSkipExactMultiTemplate(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations expected_skipped = to_skip expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def testSkipTooMuchMultiTemplate(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) m_num_mutations = self.model.num_mutations() to_skip = m_num_mutations + 10 expected_skipped = m_num_mutations expected_mutated = m_num_mutations - expected_skipped self._check_skip(to_skip, expected_skipped, expected_mutated) def testFailureToTo(self): self.assertEqual(len(self.todo), 0) def testExceptionIfLoop(self): self.model.connect(self.templates[0]) self.model.connect(self.templates[0], self.templates[1]) self.model.connect(self.templates[1], self.templates[0]) with self.assertRaises(KittyException): self.model.num_mutations()
class TestServerFuzzer(unittest.TestCase): def setUp(self): self.logger = get_test_logger() self.logger.debug('TESTING METHOD: %s', self._testMethodName) self.t_str = Template(name='simple_str_template', fields=[String(name='str1', value='kitty')]) self.t_int = Template(name='simple_int_template', fields=[UInt32(name='int1', value=0x1234)]) self.fuzzer = None self.prepare() def tearDown(self): if self.fuzzer: self.fuzzer.stop() def prepare(self): self.start_index = 10 self.end_index = 20 self.delay_duration = 0 self.fuzzer = ServerFuzzer(name="TestServerFuzzer", logger=self.logger) self.interface = EmptyInterface() self.fuzzer.set_interface(self.interface) self.model = GraphModel() self.model.connect(self.t_str) self.fuzzer.set_model(self.model) self.target = TargetMock({}) self.fuzzer.set_target(self.target) self.fuzzer.set_range(self.start_index, self.end_index) self.fuzzer.set_delay_between_tests(self.delay_duration) def test_start_without_session(self): self.fuzzer.set_model(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def test_start_without_target(self): self.fuzzer.set_target(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def test_start_without_interface(self): self.fuzzer.set_interface(None) self.assertRaises(AssertionError, self.fuzzer.start) self.fuzzer = None def test_vanilla(self): self.fuzzer.start() info = self.fuzzer._get_session_info() # reports = self.fuzzer._get_reports_manager() # self.assertEqual(len(reports), 0) self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, self.end_index) # self.assertEqual(info.original_start_index, 10) self.assertEqual(info.start_index, self.start_index) self.assertEqual(info.end_index, self.end_index) mutations_tested = info.current_index - info.start_index self.assertEqual(mutations_tested, self.end_index - self.start_index) def test_start_index(self): start_index = self.model.num_mutations() - 2 self.fuzzer.set_range(start_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.current_index, self.model.last_index()) self.assertEqual(info.end_index, self.model.last_index()) def test_end_index(self): start_index = 0 end_index = 3 self.fuzzer.set_range(start_index, end_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, 3) self.assertEqual(info.current_index, 3) def test_full_range(self): self.fuzzer.set_range() self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.start_index, 0) self.assertEqual(info.end_index, self.model.last_index()) self.assertEqual(info.current_index, self.model.last_index()) def _MOVE_TO_TARGET_TESTS_test_send_failure(self): config = { '12': { 'send': ["raise exception"] } } send_error_target = TargetMock(config) self.fuzzer.set_target(send_error_target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer._get_reports_manager() self.assertEqual(len(reports), 1) self.assertTrue(12 in reports) self.assertEqual(info.failure_count, 1) def ___test_target_failed_is_true(self): config = { '12': { 'report': { 'failed': False } }, '13': { 'report': { 'failed': True } } } target = TargetMock(config) self.fuzzer.set_target(target) self.fuzzer.start() info = self.fuzzer._get_session_info() reports = self.fuzzer._get_reports_manager() self.assertEqual(len(reports), 1) self.assertTrue(13 in reports) self.assertEqual(info.failure_count, 1) def test_set_range(self): start_index = self.model.num_mutations() - 5 self.model.connect(self.t_str, self.t_int) expected_end_index = self.model.last_index() expected_num_mutations = expected_end_index - start_index self.fuzzer.set_range(start_index) self.fuzzer.start() info = self.fuzzer._get_session_info() self.assertEqual(info.failure_count, 0) self.assertEqual(info.current_index, expected_end_index) mutations_tested = info.current_index - info.start_index self.assertEqual(mutations_tested, expected_num_mutations) self.assertEqual(info.start_index, start_index) self.assertEqual(info.end_index, expected_end_index)