def setUp(self): self.cmd = Command() self.maxDiff = None
class TestMeasureCommand(unittest.TestCase): CONF = "ripe.atlas.tools.commands.measure.conf" KINDS = ("ping", "traceroute", "dns", "ssl", "ntp",) def setUp(self): self.cmd = Command() self.maxDiff = None def test_no_arguments(self): with capture_sys_output() as (stdout, stderr): with self.assertRaises(SystemExit): self.cmd.init_args([]) self.cmd.run() self.assertEqual( "ripe-atlas measure: error: too few arguments", stderr.getvalue().split("\n")[-2] ) def test_types_no_arguments(self): for kind in ("ping", "traceroute", "ssl", "ntp",): with capture_sys_output(): with self.assertRaises(RipeAtlasToolsException) as e: self.cmd.init_args([kind]) self.cmd.run() self.assertEqual( str(e.exception), "You must specify a target for that kind of measurement" ) with capture_sys_output(): with self.assertRaises(RipeAtlasToolsException) as e: self.cmd.init_args(["dns"]) self.cmd.run() self.assertEqual( str(e.exception), "At a minimum, DNS measurements require a query argument." ) def test_bad_type_argument(self): with capture_sys_output(): with self.assertRaises(SystemExit): self.cmd.init_args(["not-a-type"]) def test_dry_run(self): with capture_sys_output() as (stdout, stderr): self.cmd.init_args(["ping", "--target", "ripe.net", "--dry-run"]) self.cmd.run() expected = ( "\n" "Definitions:\n" "================================================================================\n" "target ripe.net\n" "packet_interval 1000\n" "description \n" "af 4\n" "packets 3\n" "size 48\n" "\n" "Sources:\n" "================================================================================\n" "requested 50\n" "type area\n" "value WW\n" "tags\n" " include system-ipv4-works\n" " exclude \n" "\n" ) self.assertEqual(stdout.getvalue(), expected) with capture_sys_output() as (stdout, stderr): self.cmd.init_args([ "ping", "--target", "ripe.net", "--af", "6", "--include-tag", "alpha", "--include-tag", "bravo", "--include-tag", "charlie", "--exclude-tag", "delta", "--exclude-tag", "echo", "--exclude-tag", "foxtrot", "--dry-run" ]) self.cmd.run() expected = ( "\n" "Definitions:\n" "================================================================================\n" "target ripe.net\n" "packet_interval 1000\n" "description \n" "af 6\n" "packets 3\n" "size 48\n" "\n" "Sources:\n" "================================================================================\n" "requested 50\n" "type area\n" "value WW\n" "tags\n" " include alpha, bravo, charlie\n" " exclude delta, echo, foxtrot\n" "\n" ) self.assertEqual(stdout.getvalue(), expected) def test_clean_target(self): with capture_sys_output(): self.cmd.init_args(["ping", "--target", "ripe.net"]) self.assertEqual(self.cmd.clean_target(), "ripe.net") with capture_sys_output(): self.cmd.init_args(["dns"]) self.assertEqual(self.cmd.clean_target(), None) @mock.patch("ripe.atlas.tools.commands.measure.conf", Configuration.DEFAULT) def test_clean_protocol(self): spec = Configuration.DEFAULT["specification"]["types"] self.cmd.init_args(["traceroute", "--protocol", "UDP"]) self.assertEqual(self.cmd.clean_protocol(), "UDP") self.assertEqual(self.cmd.arguments.protocol, "UDP") self.cmd.init_args(["traceroute", "--protocol", "TCP"]) self.assertEqual(self.cmd.clean_protocol(), "TCP") self.assertEqual(self.cmd.arguments.protocol, "TCP") self.cmd.init_args(["traceroute", "--protocol", "ICMP"]) self.assertEqual(self.cmd.clean_protocol(), "ICMP") self.assertEqual(self.cmd.arguments.protocol, "ICMP") self.cmd.init_args(["traceroute"]) self.assertEqual( self.cmd.clean_protocol(), spec["traceroute"]["protocol"]) self.assertEqual( self.cmd.arguments.protocol, spec["traceroute"]["protocol"]) self.cmd.init_args(["dns", "--protocol", "UDP"]) self.assertEqual(self.cmd.clean_protocol(), "UDP") self.assertEqual(self.cmd.arguments.protocol, "UDP") self.cmd.init_args(["dns", "--protocol", "TCP"]) self.assertEqual(self.cmd.clean_protocol(), "TCP") self.assertEqual(self.cmd.arguments.protocol, "TCP") self.cmd.init_args(["dns"]) self.assertEqual(self.cmd.clean_protocol(), spec["dns"]["protocol"]) self.assertEqual(self.cmd.arguments.protocol, spec["dns"]["protocol"]) for kind in ("ping", "ssl", "ntp"): with self.assertRaises(RipeAtlasToolsException) as e: self.cmd.init_args([kind]) self.cmd.clean_protocol() self.assertEqual( str(e.exception), "Measurements of type \"{}\" have no use for a " "protocol value.".format(kind) ) @mock.patch("ripe.atlas.tools.commands.measure.conf", Configuration.DEFAULT) def test_clean_shared_option(self): spec = Configuration.DEFAULT["specification"]["types"] for kind in ("ping", "traceroute"): self.cmd.init_args([kind, "--size", "25", "--packets", "6"]) self.assertEqual(self.cmd.clean_shared_option("ping", "size"), 25) self.assertEqual(self.cmd.clean_shared_option("ping", "packets"), 6) self.cmd.init_args([kind]) self.assertEqual( self.cmd.clean_shared_option(kind, "size"), spec[kind]["size"]) self.cmd.init_args(["ping"]) self.assertEqual( self.cmd.clean_shared_option(kind, "packets"), spec[kind]["packets"] ) @mock.patch("ripe.atlas.tools.commands.measure.conf", Configuration.DEFAULT) def test_get_measurement_kwargs_ping(self): spec = Configuration.DEFAULT["specification"]["types"]["ping"] self.cmd.init_args([ "ping", "--target", "ripe.net" ]) self.assertEqual( self.cmd._get_measurement_kwargs(), { "af": Configuration.DEFAULT["specification"]["af"], "description": Configuration.DEFAULT["specification"]["description"], "target": "ripe.net", "packets": spec["packets"], "packet_interval": spec["packet-interval"], "size": spec["size"] } ) self.cmd.init_args([ "ping", "--target", "ripe.net", "--af", "6", "--description", "This is my description", "--packets", "7", "--packet-interval", "200", "--size", "24" ]) self.assertEqual( self.cmd._get_measurement_kwargs(), { "af": 6, "description": "This is my description", "target": "ripe.net", "packets": 7, "packet_interval": 200, "size": 24 } ) @mock.patch("ripe.atlas.tools.commands.measure.conf", Configuration.DEFAULT) def test_get_measurement_kwargs_traceroute(self): spec = Configuration.DEFAULT["specification"]["types"]["traceroute"] self.cmd.init_args([ "traceroute", "--target", "ripe.net" ]) self.assertEqual( self.cmd._get_measurement_kwargs(), { "af": Configuration.DEFAULT["specification"]["af"], "description": Configuration.DEFAULT["specification"]["description"], "target": "ripe.net", "packets": spec["packets"], "size": spec["size"], "destination_option_size": spec["destination-option-size"], "hop_by_hop_option_size": spec["hop-by-hop-option-size"], "dont_fragment": spec["dont-fragment"], "first_hop": spec["first-hop"], "max_hops": spec["max-hops"], "paris": spec["paris"], "port": spec["port"], "protocol": spec["protocol"], "timeout": spec["timeout"] } ) self.cmd.init_args([ "traceroute", "--af", "6", "--description", "This is my description", "--target", "ripe.net", "--packets", "7", "--size", "24", "--destination-option-size", "12", "--hop-by-hop-option-size", "13", "--dont-fragment", "--first-hop", "2", "--max-hops", "5", "--paris", "8", "--port", "123", "--protocol", "TCP", "--timeout", "1500" ]) self.assertEqual( self.cmd._get_measurement_kwargs(), { "af": 6, "description": "This is my description", "target": "ripe.net", "packets": 7, "size": 24, "destination_option_size": 12, "hop_by_hop_option_size": 13, "dont_fragment": True, "first_hop": 2, "max_hops": 5, "paris": 8, "port": 123, "protocol": "TCP", "timeout": 1500 } ) @mock.patch("ripe.atlas.tools.commands.measure.conf", Configuration.DEFAULT) def test_get_measurement_kwargs_dns(self): spec = Configuration.DEFAULT["specification"]["types"]["dns"] self.cmd.init_args([ "dns", "--query-argument", "ripe.net" ]) self.assertEqual( self.cmd._get_measurement_kwargs(), { "af": Configuration.DEFAULT["specification"]["af"], "description": Configuration.DEFAULT["specification"]["description"], "query_class": spec["query-class"], "query_type": spec["query-type"], "query_argument": "ripe.net", "set_cd_bit": spec["set-cd-bit"], "set_do_bit": spec["set-do-bit"], "set_rd_bit": spec["set-rd-bit"], "set_nsid_bit": spec["set-nsid-bit"], "protocol": spec["protocol"], "retry": spec["retry"], "udp_payload_size": spec["udp-payload-size"], "use_probe_resolver": True, } ) self.cmd.init_args([ "dns", "--af", "6", "--description", "This is my description", "--target", "non-existent-dns.ripe.net", "--query-class", "CHAOS", "--query-type", "SOA", "--query-argument", "some arbitrary string", "--set-cd-bit", "--set-do-bit", "--set-rd-bit", "--set-nsid-bit", "--protocol", "TCP", "--retry", "2", "--udp-payload-size", "5" ]) self.assertEqual( self.cmd._get_measurement_kwargs(), { "af": 6, "description": "This is my description", "target": "non-existent-dns.ripe.net", "query_class": "CHAOS", "query_type": "SOA", "query_argument": "some arbitrary string", "set_cd_bit": True, "set_do_bit": True, "set_rd_bit": True, "set_nsid_bit": True, "protocol": "TCP", "retry": 2, "udp_payload_size": 5, "use_probe_resolver": False } ) @mock.patch("ripe.atlas.tools.commands.measure.conf", Configuration.DEFAULT) def test_get_source_kwargs(self): spec = Configuration.DEFAULT["specification"] for kind in self.KINDS: tags = spec["tags"]["ipv{}".format(spec["af"])] includes = tags[kind]["include"] + tags["all"]["include"] excludes = tags[kind]["exclude"] + tags["all"]["exclude"] self.cmd.init_args([kind]) self.assertEqual(self.cmd._get_source_kwargs(), { "requested": spec["source"]["requested"], "type": spec["source"]["type"], "value": spec["source"]["value"], "tags": {"include": includes, "exclude": excludes} }) self.cmd.init_args([ kind, "--probes", "10", "--from-country", "ca" ]) self.assertEqual(self.cmd._get_source_kwargs(), { "requested": 10, "type": "country", "value": "CA", "tags": {"include": includes, "exclude": excludes} }) for area in ("WW", "West", "North-Central", "South-Central", "North-East", "South-East"): self.cmd.init_args([ kind, "--probes", "10", "--from-area", area ]) self.assertEqual(self.cmd._get_source_kwargs(), { "requested": 10, "type": "area", "value": area, "tags": {"include": includes, "exclude": excludes} }) self.cmd.init_args([ kind, "--probes", "10", "--from-prefix", "1.2.3.0/22" ]) self.assertEqual(self.cmd._get_source_kwargs(), { "requested": 10, "type": "prefix", "value": "1.2.3.0/22", "tags": {"include": includes, "exclude": excludes} }) self.cmd.init_args([ kind, "--probes", "10", "--from-asn", "3333" ]) self.assertEqual(self.cmd._get_source_kwargs(), { "requested": 10, "type": "asn", "value": 3333, "tags": {"include": includes, "exclude": excludes} }) # Try 20 permutations of probe lists for __ in range(0, 20): requested = randint(1, 500) selection = [str(randint(0, 5000)) for _ in range(0, 100)] self.cmd.init_args([ kind, "--probes", str(requested), "--from-probes", ",".join(selection) ]) self.assertEqual(self.cmd._get_source_kwargs(), { "requested": requested, "type": "probes", "value": ",".join(selection), "tags": {"include": includes, "exclude": excludes} }) self.cmd.init_args([ kind, "--probes", "10", "--from-measurement", "1001" ]) self.assertEqual(self.cmd._get_source_kwargs(), { "requested": 10, "type": "msm", "value": 1001, "tags": {"include": includes, "exclude": excludes} }) self.cmd.init_args([ kind, "--include-tag", "tag-to-include", "--exclude-tag", "tag-to-exclude" ]) self.assertEqual(self.cmd._get_source_kwargs(), { "requested": spec["source"]["requested"], "type": spec["source"]["type"], "value": spec["source"]["value"], "tags": { "include": ["tag-to-include"], "exclude": ["tag-to-exclude"] } }) def test_get_af(self): conf = copy.deepcopy(Configuration.DEFAULT) conf["specification"]["af"] = 100 with mock.patch(self.CONF, conf): for kind in self.KINDS: for af in (4, 6): self.cmd.init_args([kind, "--af", str(af)]) self.assertEqual(self.cmd._get_af(), af) self.cmd.init_args([kind, "--target", "1.2.3.4"]) self.assertEqual(self.cmd._get_af(), 4) self.cmd.init_args([kind, "--target", "1:2:3:4:5:6:7:8"]) self.assertEqual(self.cmd._get_af(), 6) self.cmd.init_args([kind, "--target", "1.2.3.4.5"]) self.assertEqual( self.cmd._get_af(), conf["specification"]["af"] ) def test_handle_api_error(self): message = ( "There was a problem communicating with the RIPE Atlas " "infrastructure. The message given was:\n\n {}" ) with self.assertRaises(RipeAtlasToolsException) as e: self.cmd._handle_api_error("This is a plain text error") self.assertEqual( str(e.exception), message.format("This is a plain text error") ) with self.assertRaises(RipeAtlasToolsException) as e: self.cmd._handle_api_error({"detail": "This is a formatted error"}) self.assertEqual( str(e.exception), message.format("This is a formatted error") )