def test_truesendall_after_mocket_session(): Mocket.enable() Mocket.disable() url = "https://httpbin.org/ip" resp = requests.get(url) assert resp.status_code == 200
def test_simple_run_with_close(monkeypatch, mocker): """Test graceful close.""" monkeypatch.setattr('os.urandom', b'\x00'.__mul__) Mocket.register( MocketEntry(('example.com', 80), [(b'HTTP/1.1 101 Switching Protocols\r\n' b'Upgrade: websocket\r\n' b'Connection: Upgrade\r\n' b'Sec-WebSocket-Accept: icx+yqv66kxgm0fcwalwlflwtai=\r\n' b'\r\n' b'\x81\x81\x00\x00\x00\x00A\x88\x80\xba51e')])) session = WebsocketSession(WebSocket('ws://example.com/')) session._selector_cls = FakeSelector session._on_ready() session._regular_orig = session._regular mocker.patch('lomond.websocket.WebSocket._send_close') mocker.patch.object(session.websocket, 'send_ping') session.websocket.state.session = session _events = list(session.run()) assert len(_events) == 7 assert isinstance(_events[0], events.Connecting) assert isinstance(_events[1], events.Connected) assert isinstance(_events[2], events.Ready) assert isinstance(_events[3], events.Poll) assert isinstance(_events[4], events.Text) assert isinstance(_events[5], events.Closing) assert isinstance(_events[6], events.Disconnected) assert _events[6].graceful
async def __aenter__(self): Mocket.enable( namespace=self.namespace, truesocket_recording_dir=self.truesocket_recording_dir, ) if self.instance: self.check_and_call("mocketize_setup")
def test_truesendall_after_mocket_session(): Mocket.enable() Mocket.disable() url = 'https://mockbin.com/ip' resp = requests.get(url) assert resp.status_code == 200
def test_fail_because_entry_not_served(self): url = "http://github.com/fluidicon.png" Entry.single_register(Entry.GET, url) Entry.single_register(Entry.GET, "http://github.com/fluidicon.jpg") requests.get(url) with self.assertRaises(AssertionError): Mocket.assert_fail_if_entries_not_served()
def test_multipart(self): url = "http://httpbin.org/post" data = '--xXXxXXyYYzzz\r\nContent-Disposition: form-data; name="content"\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: 68\r\n\r\nAction: comment\nText: Comment with attach\nAttachment: x1.txt, x2.txt\r\n--xXXxXXyYYzzz\r\nContent-Disposition: form-data; name="attachment_2"; filename="x.txt"\r\nContent-Type: text/plain\r\nContent-Length: 4\r\n\r\nbye\n\r\n--xXXxXXyYYzzz\r\nContent-Disposition: form-data; name="attachment_1"; filename="x.txt"\r\nContent-Type: text/plain\r\nContent-Length: 4\r\n\r\nbye\n\r\n--xXXxXXyYYzzz--\r\n' headers = { "Content-Length": "495", "Content-Type": "multipart/form-data; boundary=xXXxXXyYYzzz", "Accept": "text/plain", "User-Agent": "Mocket", "Accept-encoding": "identity", } Entry.register(Entry.POST, url) response = requests.post(url, data=data, headers=headers) self.assertEqual(response.status_code, 200) last_request = Mocket.last_request() self.assertEqual(last_request.method, "POST") self.assertEqual(last_request.path, "/post") self.assertEqual(last_request.body, data) sent_headers = dict(last_request.headers) self.assertEqualHeaders( sent_headers, { "accept": "text/plain", "accept-encoding": "identity", "content-length": "495", "content-type": "multipart/form-data; boundary=xXXxXXyYYzzz", "host": "httpbin.org", "user-agent": "Mocket", "connection": "keep-alive", }, ) self.assertEqual(len(Mocket.request_list()), 1)
def test_hgetall(self): h = {b"f1": b"one", b"f2": b"two"} Entry.register_response("HGETALL hash", h) self.assertEqual(self.rclient.hgetall("hash"), h) self.assertEqual(len(Mocket.request_list()), 1) self.assertEqual(Mocket.request_list()[0].data, b"*2\r\n$7\r\nHGETALL\r\n$4\r\nhash\r\n")
def test_scanner_google_httpproxy_env_ipv4(mocker): fqdn = "google.com" port = 443 MOCK_JARM = "27d40d40d29d40d1dc42d43d00041d4689ee210389f4f6b4b5b1b93f92252d" family = socket.AF_INET TEST_NAME = "google_com_443_httpproxy_env_ipv4" os.environ["HTTPS_PROXY"] = "http://*****:*****@127.0.0.1:3128" global conn_idx conn_idx = 0 def get_user_agent(): global conn_idx print(f"Called at {conn_idx}") hdr = {"User-Agent": f"pyJARM/UnitTest/{TEST_NAME}/{conn_idx}"} conn_idx += 1 return hdr mocker.patch( "os.urandom", return_value= b"\x17]\x18r\xb2\xe7\x14L\x82\x9anR\xe59{D\xb9\xf8\xb2P\x9cd\xb5\x03g3<\x99)\x176n", ) mocker.patch("random.choice", return_value=b"\x5a\x5a") mocker.patch.object(Proxy, "get_http_headers", side_effect=get_user_agent) Mocket.enable(TEST_NAME, "./tests/data") jarm = asyncio.run( Scanner.scan_async(fqdn, port, address_family=family, concurrency=1)) assert jarm == (MOCK_JARM, fqdn, port)
def test_scanner_google_noproxy_ipv4(mocker): fqdn = "google.com" ip = "142.250.184.174" port = 443 MOCK_JARM = "27d40d40d29d40d1dc42d43d00041d4689ee210389f4f6b4b5b1b93f92252d" family = socket.AF_INET TEST_NAME = "google_com_443_noproxy_ipv4" mocker.patch( "os.urandom", return_value= b"\x17]\x18r\xb2\xe7\x14L\x82\x9anR\xe59{D\xb9\xf8\xb2P\x9cd\xb5\x03g3<\x99)\x176n", ) mocker.patch("random.choice", return_value=b"\x5a\x5a") mocker.patch( "socket.getaddrinfo", return_value=[(family, socket.SOCK_STREAM, socket.IPPROTO_TCP, "", (ip, port))], ) Mocket.enable(TEST_NAME, "./tests/data") jarm = asyncio.run( Scanner.scan_async(fqdn, port, address_family=family, concurrency=1)) assert jarm == (MOCK_JARM, fqdn, port)
def apply_safety_net(fake_getaddrinfo): fake_getaddrinfo.append( ( socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_TCP, "", ("2606:2800:220:1:248:1893:25c8:1946", 80), ) ) # Set up a fake entry to return some data for all of the IP's so mocket # doesn't try to connect if it can't find an entry. mocket_entry = Entry( "http://example.com/info.json", Entry.GET, Entry.response_cls( body=json.dumps({"ip": "2606:2800:220:1:248:1893:25c8:1946"}), status=200, headers=None, ), ) mocket_entry.location = ("2606:2800:220:1:248:1893:25c8:1946", 80) Mocket.register(mocket_entry)
def test_truesendall_after_mocket_session(): Mocket.enable() Mocket.disable() url = 'https://httpbin.org/ip' resp = requests.get(url) assert resp.status_code == 200
def test_does_not_fail_because_all_entries_are_served(self): url = "http://github.com/fluidicon.png" second_url = "http://github.com/fluidicon.jpg" Entry.single_register(Entry.GET, url) Entry.single_register(Entry.GET, second_url) requests.get(url) requests.get(second_url) Mocket.assert_fail_if_entries_not_served()
def test_set(self): Entry.register_response('SET mocket "is awesome!"', OK) self.assertTrue(self.rclient.set("mocket", "is awesome!")) self.assertEqual(len(Mocket.request_list()), 1) self.assertEqual( Mocket.last_request().data, b"*3\r\n$3\r\nSET\r\n$6\r\nmocket\r\n$11\r\nis awesome!\r\n", )
def test_unresponsive(monkeypatch, mocker): """Check ping timeout.""" monkeypatch.setattr( 'os.urandom', b'\x00'.__mul__ ) Mocket.register( MocketEntry( ('example.com', 80), [( b'HTTP/1.1 101 Switching Protocols\r\n' b'Upgrade: websocket\r\n' b'Connection: Upgrade\r\n' b'Sec-WebSocket-Accept: icx+yqv66kxgm0fcwalwlflwtai=\r\n' b'\r\n' b'\x81\x81\x00\x00\x00\x00A' )] ) ) # mocket doesn't support .pending() call which is used when ssl is used session = WebsocketSession(WebSocket('ws://example.com/')) session._selector_cls = FakeSelector session._on_ready() # well, we have to cheat a little. The thing is, inner loop of # run() sets last poll time to time.time and so we would have to # wait for some time to actually hit poll / ping. This is not desirable # so we can do the following: # save original _regular call into _regular_orig # (_regular is a first - well, technically, a second) call inside run # after _poll_start is set which makes it a nice candidate for monkey-patch # location. Here's how we do it: session._regular_orig = session._regular mocker.patch( 'lomond.websocket.WebSocket._send_close') mocker.patch.object(session.websocket, 'send_ping') _events = [] iter_events = iter(session.run(ping_timeout=5)) for event in iter_events: _events.append(event) if event.name == 'text': break with freeze_time("1994-05-01 18:41:00"): for event in iter_events: _events.append(event) assert len(_events) == 8 assert isinstance(_events[0], events.Connecting) assert isinstance(_events[1], events.Connected) assert isinstance(_events[2], events.Ready) assert isinstance(_events[3], events.Poll) assert isinstance(_events[4], events.Text) assert isinstance(_events[5], events.Poll) assert isinstance(_events[6], events.Unresponsive) assert isinstance(_events[7], events.Disconnected)
def test_register(self): entry_1 = MocketEntry(('localhost', 80), True) entry_2 = MocketEntry(('localhost', 80), True) entry_3 = MocketEntry(('localhost', 8080), True) Mocket.register(entry_1, entry_2, entry_3) self.assertEqual(Mocket._entries, { ('localhost', 80): [entry_1, entry_2], ('localhost', 8080): [entry_3], })
def test_socket_fail(session, mocker): def select_that_throws_exception(*args, **kwargs): raise select.error('this is just a test') Mocket.register(MocketEntry(('example.com', 80), [b'some binary data'])) mocker.patch('lomond.session.select.select', select_that_throws_exception) with pytest.raises(WebsocketSession._SocketFail): session._select(session._sock, poll=5)
def test_connect(session, mocker): Mocket.register( MocketEntry( ('example.com', 80), [b'some binary data'] ) ) _socket, _proxy = session._connect() assert isinstance(_socket, socket.socket)
def test_lrange(self): l = [b"one", b"two", b"three"] Entry.register_response("LRANGE list 0 -1", l) self.assertEqual(self.rclient.lrange("list", 0, -1), l) self.assertEqual(len(Mocket.request_list()), 1) self.assertEqual( Mocket.last_request().data, b"*4\r\n$6\r\nLRANGE\r\n$4\r\nlist\r\n$1\r\n0\r\n$2\r\n-1\r\n", )
def can_handle(self, data): try: requestline, _ = data.split(CRLF, 1) method, path, version = self._parse_requestline(requestline) except ValueError: Mocket.remove_last_request() return True uri = urlsplit(path) return uri.path == self.path and parse_qs(uri.query) == parse_qs(self.query)
def test_socket_as_context_manager(self): addr = ("localhost", 80) Mocket.register(MocketEntry(addr, ["Show me.\r\n"])) with Mocketizer(): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as _so: _so.connect(addr) _so.sendall(encode_to_bytes("Whatever...")) data = _so.recv(4096) self.assertEqual(data, encode_to_bytes("Show me.\r\n"))
def test_subsequent_recv_requests_have_correct_length(self): Mocket.register( MocketEntry(('localhost', 80), [b'Long payload', b'Short'])) _so = socket.socket(socket.AF_INET, socket.SOCK_STREAM) _so.connect(('localhost', 80)) _so.sendall(b'first\r\n') assert _so.recv(4096) == b'Long payload' _so.sendall(b'second\r\n') assert _so.recv(4096) == b'Short' _so.close()
def test_send_command(self): Mocket.register( MocketEntry(self.bulb_addr, [b'{"id":1, "result":["ok"]}\r\n'])) with Bulb(*self.bulb_addr, **self.kwargs | { "id": 1, "support": ["set_ct_abx"] }) as b: loop = asyncio.get_event_loop() loop.run_until_complete( b.send_command("set_ct_abx", [3500, "smooth", 500]))
def test_makefile(self): addr = ("localhost", 80) Mocket.register(MocketEntry(addr, ["Show me.\r\n"])) with Mocketizer(): _so = socket.socket(socket.AF_INET, socket.SOCK_STREAM) _so.connect(addr) fp = _so.makefile("rb") _so.sendall(encode_to_bytes("...\r\n")) self.assertEqual(fp.read().strip(), encode_to_bytes("Show me.")) self.assertEqual(len(Mocket.request_list()), 1)
def session_with_socket(monkeypatch): Mocket.register( MocketEntry( ('example.com', 80), [b'some binary data'] ) ) session_obj = session(monkeypatch) return session_obj
def test_subsequent_recv_requests_have_correct_length(self): addr = ("localhost", 80) Mocket.register(MocketEntry(addr, [b"Long payload", b"Short"])) with Mocketizer(): _so = socket.socket(socket.AF_INET, socket.SOCK_STREAM) _so.connect(addr) _so.sendall(b"first\r\n") self.assertEqual(_so.recv(4096), b"Long payload") _so.sendall(b"second\r\n") self.assertEqual(_so.recv(4096), b"Short") _so.close()
def test_err(self): Entry.register_response( "INCRBY counter one", ERROR("ERR value is not an integer or out of range")) self.assertRaises(redis.ResponseError, self.rclient.incr, "counter", "one") self.assertEqual(len(Mocket.request_list()), 1) self.assertEqual( Mocket.last_request().data, b"*3\r\n$6\r\nINCRBY\r\n$7\r\ncounter\r\n$3\r\none\r\n", )
def test_default_connect(data_dir, request): """Test connection to TheSkyX If not running with a real connection then use Mocket """ # Use `--with-hardware thesky` on cli to run without mock if 'theskyx' not in request.config.getoption('--with-hardware'): Mocket.enable('theskyx', data_dir) skyx = TheSkyX() assert skyx.is_connected is True
def test_collect_last_request(self): addr = ("localhost", 80) entry = MocketEntry(addr, True) Mocket.register(entry) with Mocketizer(): _so = socket.socket(socket.AF_INET, socket.SOCK_STREAM) _so.connect(addr) _so.sendall(b"data\r\n") _so.close() self.assertEqual(Mocket.last_request(), b"data\r\n")
def test_truesendall_with_dump_from_recording(self): requests.get('http://httpbin.org/ip', headers={"user-agent": "Fake-User-Agent"}) requests.get('http://httpbin.org/gzip', headers={"user-agent": "Fake-User-Agent"}) dump_filename = os.path.join( Mocket.get_truesocket_recording_dir(), Mocket.get_namespace() + '.json', ) with io.open(dump_filename) as f: responses = json.load(f) self.assertEqual(len(responses['httpbin.org']['80'].keys()), 2)
def test_mockhttp_entry_collect_duplicates(self): Entry.single_register( Entry.POST, "http://testme.org/", status=200, match_querystring=False ) requests.post( "http://testme.org/?foo=bar", data="{'foo': 'bar'}", headers={"content-type": "application/json"}, ) requests.post("http://testme.org/") self.assertEqual(len(Mocket.request_list()), 2) self.assertEqual(Mocket.last_request().path, "/")
def test_truesendall_with_chunk_recording(self): url = "http://httpbin.org/range/70000?chunk_size=65536" requests.get(url) resp = requests.get(url) self.assertEqual(resp.status_code, 200) dump_filename = os.path.join(Mocket.get_truesocket_recording_dir(), Mocket.get_namespace() + ".json") with io.open(dump_filename) as f: responses = json.load(f) assert len(responses["httpbin.org"]["80"].keys()) == 1
def test_default_connect(request): """Test connection to TheSkyX If not running with a real connection then use Mocket """ # Use `--with-hardware thesky` on cli to run without mock if 'theskyx' not in request.config.getoption('--with-hardware'): Mocket.enable( 'theskyx', '{}/panoptes-utils/panoptes/utils/tests/data'.format( os.getenv('PANDIR'))) skyx = TheSkyX() assert skyx.is_connected is True
def test_truesendall_with_chunk_recording(self): url = 'http://httpbin.org/range/70000?chunk_size=65536' requests.get(url) resp = requests.get(url) self.assertEqual(resp.status_code, 200) dump_filename = os.path.join( Mocket.get_truesocket_recording_dir(), Mocket.get_namespace() + '.json', ) with io.open(dump_filename) as f: responses = json.load(f) assert len(responses['httpbin.org']['80'].keys()) == 1
def test_truesendall_with_recording_https(): url = 'https://httpbin.org/ip' requests.get(url) resp = requests.get(url) assert resp.status_code == 200 dump_filename = os.path.join( Mocket.get_truesocket_recording_dir(), Mocket.get_namespace() + '.json', ) with io.open(dump_filename) as f: responses = json.load(f) assert len(responses['httpbin.org']['443'].keys()) == 1
def test_multipart(self): url = 'http://httpbin.org/post' data = '--xXXxXXyYYzzz\r\nContent-Disposition: form-data; name="content"\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: 68\r\n\r\nAction: comment\nText: Comment with attach\nAttachment: x1.txt, x2.txt\r\n--xXXxXXyYYzzz\r\nContent-Disposition: form-data; name="attachment_2"; filename="x.txt"\r\nContent-Type: text/plain\r\nContent-Length: 4\r\n\r\nbye\n\r\n--xXXxXXyYYzzz\r\nContent-Disposition: form-data; name="attachment_1"; filename="x.txt"\r\nContent-Type: text/plain\r\nContent-Length: 4\r\n\r\nbye\n\r\n--xXXxXXyYYzzz--\r\n' headers = { 'Content-Length': '495', 'Content-Type': 'multipart/form-data; boundary=xXXxXXyYYzzz', 'Accept': 'text/plain', 'User-Agent': 'Mocket', 'Accept-encoding': 'identity', } Entry.register(Entry.POST, url) response = requests.post(url, data=data, headers=headers) self.assertEqual(response.status_code, 200) last_request = Mocket.last_request() self.assertEqual(last_request.method, 'POST') self.assertEqual(last_request.path, '/post') self.assertEqual(last_request.body, data) sent_headers = dict(last_request.headers) self.assertEqualHeaders( sent_headers, { 'accept': 'text/plain', 'accept-encoding': 'identity', 'content-length': '495', 'content-type': 'multipart/form-data; boundary=xXXxXXyYYzzz', 'host': 'httpbin.org', 'user-agent': 'Mocket', 'connection': 'keep-alive', } ) self.assertEqual(len(Mocket._requests), 1)
def test_subsequent_recv_requests_have_correct_length(self): Mocket.register( MocketEntry( ('localhost', 80), [ b'Long payload', b'Short' ] ) ) with Mocketizer(): _so = socket.socket(socket.AF_INET, socket.SOCK_STREAM) _so.connect(('localhost', 80)) _so.sendall(b'first\r\n') assert _so.recv(4096) == b'Long payload' _so.sendall(b'second\r\n') assert _so.recv(4096) == b'Short' _so.close()
def test_request_bodies(self): url = 'http://bit.ly/fakeurl/{0}' for e in range(5): u = url.format(e) Entry.single_register(Entry.POST, u, body=str(e)) request_body = urlencode({'key-{0}'.format(e): 'value={0}'.format(e)}) urlopen(u, request_body.encode('utf-8')) last_request = Mocket.last_request() assert last_request.body == request_body
def test_truesendall_with_recording(self): url = 'http://httpbin.org/ip' urlopen(url) requests.get(url) resp = urlopen(url) self.assertEqual(resp.code, 200) resp = requests.get(url) self.assertEqual(resp.status_code, 200) assert 'origin' in resp.json() dump_filename = os.path.join( Mocket.get_truesocket_recording_dir(), Mocket.get_namespace() + '.json', ) with io.open(dump_filename) as f: responses = json.load(f) self.assertEqual(len(responses['httpbin.org']['80'].keys()), 2)
def test_recv_into(self): Mocket.register( MocketEntry( ('localhost', 80), [ b'Long payload', b'Short' ] ) ) buffer = io.BytesIO() with Mocketizer(): _so = socket.socket(socket.AF_INET, socket.SOCK_STREAM) _so.connect(('localhost', 80)) _so.sendall(b'first\r\n') assert _so.recv_into(buffer, 4096) == 12 _so.sendall(b'second\r\n') assert _so.recv_into(buffer, 4096) == 5 _so.close() buffer.seek(0) assert buffer.read() == b'Long payloadShort'
def test_reset(self): Mocket._requests.extend([1, 2, 3]) self.assertEqual(Mocket._requests, [1, 2, 3]) Mocket.reset() self.assertEqual(Mocket._requests, [])
def register(addr, command, *responses): responses = [Entry.response_cls(r) for r in responses] Mocket.register(Entry(addr, command, responses))
def test_has_requests(self): Mocket._requests.extend([1, 2, 3]) self.assertTrue(Mocket.has_requests()) Mocket.reset() self.assertFalse(Mocket.has_requests())
def test_gethostname(self): hostname = socket.gethostname() Mocket.enable() self.assertEqual(socket.gethostname(), 'localhost') Mocket.disable() self.assertEqual(socket.gethostname(), hostname)
def test_gethostbyname(self): host = socket.gethostbyname('localhost') Mocket.enable() self.assertEqual(socket.gethostbyname('localhost'), '127.0.0.1') Mocket.disable() self.assertEqual(socket.gethostbyname('localhost'), host)
def test_collect(self): request = 'GET /get/p/?b=2&a=1 HTTP/1.1\r\nAccept-Encoding: identity\r\nHost: testme.org\r\nConnection: close\r\nUser-Agent: Python-urllib/2.6\r\n\r\n' Mocket.collect(request) self.assertEqual(Mocket.last_request(), request) self.assertEqual(Mocket._requests, [request])
def setUp(self): Mocket.reset()
def test_remove_last_empty(self): Mocket.remove_last_request() self.assertEqual(Mocket._requests, [])
def test_getentry(self): entry = MocketEntry(('localhost', 80), True) Mocket.register(entry) self.assertEqual(Mocket.get_entry('localhost', 80, True), entry)
def mocketize_setup(self): Entry.register_response('FLUSHDB', OK) self.rclient.flushdb() self.assertEqual(len(Mocket._requests), 1) Mocket.reset()
def test_set(self): Entry.register_response('SET mocket "is awesome!"', OK) self.assertTrue(self.rclient.set('mocket', 'is awesome!')) self.assertEqual(len(Mocket._requests), 1) self.assertEqual(Mocket.last_request().data, b'*3\r\n$3\r\nSET\r\n$6\r\nmocket\r\n$11\r\nis awesome!\r\n')
def test_get_unicode(self): Entry.register_response('GET snowman', '\u2603') self.assertEqual(self.rclient.get('snowman'), b'\xe2\x98\x83') self.assertEqual(len(Mocket._requests), 1) self.assertEqual(Mocket.last_request().data, b'*2\r\n$3\r\nGET\r\n$7\r\nsnowman\r\n')
def test_lrange(self): l = [b'one', b'two', b'three'] Entry.register_response('LRANGE list 0 -1', l) self.assertEqual(self.rclient.lrange('list', 0, -1), l) self.assertEqual(len(Mocket._requests), 1) self.assertEqual(Mocket.last_request().data, b'*4\r\n$6\r\nLRANGE\r\n$4\r\nlist\r\n$1\r\n0\r\n$2\r\n-1\r\n')
def test_err(self): Entry.register_response('INCRBY counter one', ERROR('ERR value is not an integer or out of range')) self.assertRaises(redis.ResponseError, self.rclient.incr, 'counter', 'one') self.assertEqual(len(Mocket._requests), 1) self.assertEqual(Mocket.last_request().data, b'*3\r\n$6\r\nINCRBY\r\n$7\r\ncounter\r\n$3\r\none\r\n')
def test_lastrequest(self): self.assertEqual(Mocket.last_request(), None) Mocket._requests.extend([1, 2, 3]) self.assertEqual(Mocket.last_request(), 3)
def test_remove_last(self): Mocket._requests = [1, 2] Mocket.remove_last_request() self.assertEqual(Mocket._requests, [1])
def register(method, uri, *responses): Mocket.register(Entry(uri, method, responses))