async def test_timeout_value_used(self, event_loop, mocker, cluster, ops): optimeout_class = mocker.patch("emcache.autobatching.OpTimeout", AsyncMagicMock()) connection = CoroutineMock() connection.fetch_command = CoroutineMock( return_value=(list(ops.keys()), list(ops.keys()), None, None)) node = Mock() connection_context = AsyncMagicMock() connection_context.__aenter__.return_value = connection node.connection.return_value = connection_context cluster.pick_nodes.return_value = {node: list(ops.keys())} # InflightBatches takes the ownership of the dictionary, we concat # all futures into our own list futures = itertools.chain(*list(ops.values())) _ = _InflightBatches(ops, cluster, Mock(), event_loop, return_flags=False, return_cas=False, timeout=1.0, max_keys=1) for future in futures: await future # Check that the timeout value was properly used optimeout_class.assert_called_with(1.0, ANY)
async def test_delete_use_timeout(self, client, mocker): optimeout_class = mocker.patch("emcache.client.OpTimeout", AsyncMagicMock()) connection = CoroutineMock() connection.delete_command = CoroutineMock(return_value=DELETED) connection_context = AsyncMagicMock() connection_context.__aenter__.return_value = connection node = Mock() node.connection.return_value = connection_context client._cluster.pick_node.return_value = node await client.delete(b"foo") optimeout_class.assert_called()
async def test_incr_decr_use_timeout(self, client, command, mocker): optimeout_class = mocker.patch("emcache.client.OpTimeout", AsyncMagicMock()) connection = CoroutineMock() connection.incr_decr_command = CoroutineMock(return_value=1) connection_context = AsyncMagicMock() connection_context.__aenter__.return_value = connection node = Mock() node.connection.return_value = connection_context client._cluster.pick_node.return_value = node f = getattr(client, command) await f(b"foo", 1) optimeout_class.assert_called()
async def test_futures_are_wake_up_no_side_effect_on_cancellation( self, event_loop, cluster, ops): connection = CoroutineMock() connection.fetch_command = CoroutineMock( return_value=(list(ops.keys()), list(ops.keys()), None, None)) node = Mock() connection_context = AsyncMagicMock() connection_context.__aenter__.return_value = connection node.connection.return_value = connection_context cluster.pick_nodes.return_value = {node: list(ops.keys())} # InflightBatches takes the ownership of the dictionary, we concat # all futures into our own list futures = list(itertools.chain(*list(ops.values()))) # Cancel the first one futures[0].cancel() _ = _InflightBatches(ops, cluster, Mock(), event_loop, return_flags=False, return_cas=False, timeout=1.0, max_keys=1) # Wait for the other ones for future in futures[1:]: await future
async def test_multiple_batches(self, event_loop, mocker, cluster, ops): connection = CoroutineMock() connection.fetch_command = CoroutineMock( return_value=(list(ops.keys()), list(ops.keys()), None, None)) node = Mock() connection_context = AsyncMagicMock() connection_context.__aenter__.return_value = connection node.connection.return_value = connection_context cluster.pick_nodes.return_value = {node: list(ops.keys())} # InflightBatches takes the ownership of the dictionary, we concat # all futures into our own list futures = itertools.chain(*list(ops.values())) # Configure batches of maximum one key per batch _ = _InflightBatches(ops, cluster, Mock(), event_loop, return_flags=False, return_cas=False, timeout=1.0, max_keys=1) for future in futures: await future # Check that two calls to the fetch command were done assert connection.fetch_command.call_count == 2
async def test_signal_termination(self, event_loop, mocker, cluster, ops): on_finish = Mock() connection = CoroutineMock() connection.fetch_command = CoroutineMock( return_value=(list(ops.keys()), list(ops.keys()), None, None)) node = Mock() connection_context = AsyncMagicMock() connection_context.__aenter__.return_value = connection node.connection.return_value = connection_context cluster.pick_nodes.return_value = {node: list(ops.keys())} # InflightBatches takes the ownership of the dictionary, we concat # all futures into our own list futures = itertools.chain(*list(ops.values())) inflight_batches = _InflightBatches(ops, cluster, on_finish, event_loop, return_flags=False, return_cas=False, timeout=1.0, max_keys=1) for future in futures: await future # Check that the timeout value was properly used on_finish.assert_called_with(inflight_batches)
async def test_timeout_futures_are_wake_up_no_side_effect_on_cancellation( self, event_loop, mocker, cluster, ops): # force to trigger the exception at `fetch_command` level, thought is not the # where the exception will be raised is good enough for knowing if the caller # is managing as is expected the exception. connection = CoroutineMock() connection.fetch_command = CoroutineMock( side_effect=asyncio.TimeoutError) node = Mock() connection_context = AsyncMagicMock() connection_context.__aenter__.return_value = connection node.connection.return_value = connection_context cluster.pick_nodes.return_value = {node: list(ops.keys())} # InflightBatches takes the ownership of the dictionary, we concat # all futures into our own list futures = list(itertools.chain(*list(ops.values()))) # Cancel the first one futures[0].cancel() _ = _InflightBatches(ops, cluster, Mock(), event_loop, return_flags=False, return_cas=False, timeout=1.0, max_keys=1) # Wait for the other ones for future in futures[1:]: with pytest.raises(asyncio.TimeoutError): await future
async def test_fetch_many_command_use_timeout(self, client, command, mocker): optimeout_class = mocker.patch("emcache.client.OpTimeout", AsyncMagicMock()) connection = CoroutineMock() connection.fetch_command = CoroutineMock(return_value=([b"foo"], [b"value"], [0], [0])) connection_context = AsyncMagicMock() connection_context.__aenter__.return_value = connection node = Mock() node.connection.return_value = connection_context client._cluster.pick_nodes.return_value = {node: [b"foo"]} f = getattr(client, command) await f([b"foo"]) optimeout_class.assert_called()
async def test_delete_error_not_found(self, client): # patch what is necesary for returnning an error string connection = CoroutineMock() connection.delete_command = CoroutineMock(return_value=NOT_FOUND) connection_context = AsyncMagicMock() connection_context.__aenter__.return_value = connection node = Mock() node.connection.return_value = connection_context client._cluster.pick_node.return_value = node with pytest.raises(NotFoundCommandError): await client.delete(b"foo")
async def test_touch_error_command(self, client): # patch what is necesary for returnning an error string connection = CoroutineMock() connection.touch_command = CoroutineMock(return_value=b"ERROR") connection_context = AsyncMagicMock() connection_context.__aenter__.return_value = connection node = Mock() node.connection.return_value = connection_context client._cluster.pick_node.return_value = node with pytest.raises(CommandError): await client.touch(b"foo", 1)
async def test_timeout_value_used(self, event_loop, mocker, memcached_host_address): mocker.patch("emcache.client.Cluster") optimeout_class = mocker.patch("emcache.client.OpTimeout", AsyncMagicMock()) timeout = 2.0 client = _Client([memcached_host_address], timeout, 1, 1, None, None, None, False, False, 32, False, False, None) connection = CoroutineMock(return_value=b"") connection.storage_command = CoroutineMock(return_value=b"STORED") node = Mock() connection_context = AsyncMagicMock() connection_context.__aenter__.return_value = connection node.connection.return_value = connection_context client._cluster.pick_node.return_value = node await client.set(b"key", b"value") optimeout_class.assert_called_with(timeout, ANY)
async def test_flush_all_error_command(self, client, memcached_host_address): # patch what is necesary for returnning an error string connection = CoroutineMock() connection.flush_all_command = CoroutineMock(return_value=b"ERROR") connection_context = AsyncMagicMock() connection_context.__aenter__.return_value = connection node = Mock() node.connection.return_value = connection_context client._cluster.node.return_value = node with pytest.raises(CommandError): await client.flush_all(memcached_host_address)
async def test_not_stored_error_storage_command(self, client, command): # patch what is necesary for returnning an error string connection = CoroutineMock() connection.storage_command = CoroutineMock(return_value=b"ERROR") connection_context = AsyncMagicMock() connection_context.__aenter__.return_value = connection node = Mock() node.connection.return_value = connection_context client._cluster.pick_node.return_value = node with pytest.raises(StorageCommandError): f = getattr(client, command) await f(b"foo", b"value")
async def test_exptime_flags_disabled(self, client, command): # Some storage commands do not support update the flags and neither # the exptime, in these use cases the values are set to 0. connection = CoroutineMock() connection.storage_command = CoroutineMock(return_value=b"STORED") connection_context = AsyncMagicMock() connection_context.__aenter__.return_value = connection node = Mock() node.connection.return_value = connection_context client._cluster.pick_node.return_value = node f = getattr(client, command) await f(b"key", b"value") connection.storage_command.assert_called_with(ANY, ANY, ANY, 0, 0, ANY, ANY)
async def test_exception_cancels_everything(self, client, command): # patch what is necesary for rasing an exception for the first query and # a "valid" response from the others connection = CoroutineMock() connection.fetch_command.side_effect = CoroutineMock( side_effect=[OSError(), b"Ok", b"Ok"]) connection_context = AsyncMagicMock() connection_context.__aenter__.return_value = connection node1 = Mock() node2 = Mock() node3 = Mock() node1.connection.return_value = connection_context node2.connection.return_value = connection_context node3.connection.return_value = connection_context client._cluster.pick_nodes.return_value = { node1: [b"key1"], node2: [b"key2"], node3: [b"key3"] } with pytest.raises(OSError): f = getattr(client, command) await f([b"key1", b"key2", b"key3"])