async def test_watch_timeout_with_resource_version(self):
        fake_resp = CoroutineMock()
        fake_resp.content.readline = CoroutineMock()
        fake_resp.release = Mock()

        fake_resp.content.readline.side_effect = [asyncio.TimeoutError(), b""]

        fake_api = Mock()
        fake_api.get_namespaces = CoroutineMock(return_value=fake_resp)
        fake_api.get_namespaces.__doc__ = ':return: V1NamespaceList'

        watch = kubernetes_asyncio.watch.Watch()
        async with watch.stream(fake_api.get_namespaces,
                                resource_version='10') as stream:
            async for e in stream:  # noqa
                pass

        # all calls use the passed resource version
        fake_api.get_namespaces.assert_has_calls([
            call(_preload_content=False, watch=True, resource_version='10'),
            call(_preload_content=False, watch=True, resource_version='10')
        ])

        fake_resp.release.assert_called_once_with()
        self.assertEqual(watch.resource_version, '10')
Exemple #2
0
    async def test_watch_timeout(self):
        fake_resp = CoroutineMock()
        fake_resp.content.readline = CoroutineMock()

        mock_event = {
            "type": "ADDED",
            "object": {
                "metadata": {
                    "name": "test1555",
                    "resourceVersion": "1555"
                },
                "spec": {},
                "status": {}
            }
        }

        fake_resp.content.readline.side_effect = [
            json.dumps(mock_event).encode('utf8'),
            asyncio.TimeoutError(), b""
        ]

        fake_api = Mock()
        fake_api.get_namespaces = CoroutineMock(return_value=fake_resp)
        fake_api.get_namespaces.__doc__ = ':return: V1NamespaceList'

        watch = kubernetes_asyncio.watch.Watch()
        async for e in watch.stream(fake_api.get_namespaces):  # noqa
            pass

        fake_api.get_namespaces.assert_has_calls([
            call(_preload_content=False, watch=True),
            call(_preload_content=False, watch=True, resource_version='1555')
        ])
    async def test_watch_with_exception(self):
        fake_resp = CoroutineMock()
        fake_resp.content.readline = CoroutineMock()
        fake_resp.content.readline.side_effect = KeyError("expected")
        fake_api = Mock()
        fake_api.get_namespaces = CoroutineMock(return_value=fake_resp)
        fake_api.get_namespaces.__doc__ = ':return: V1NamespaceList'

        with self.assertRaises(KeyError):
            watch = kubernetes_asyncio.watch.Watch()
            async for e in watch.stream(fake_api.get_namespaces,
                                        timeout_seconds=10):  # noqa
                pass
    async def test_watch_with_decode(self):
        fake_resp = CoroutineMock()
        fake_resp.content.readline = CoroutineMock()
        fake_resp.release = Mock()
        side_effects = [{
            "type": "ADDED",
            "object": {
                "metadata": {
                    "name": "test{}".format(uid),
                    "resourceVersion": str(uid)
                },
                "spec": {},
                "status": {}
            }
        } for uid in range(3)]
        side_effects = [json.dumps(_).encode('utf8') for _ in side_effects]
        side_effects.extend([AssertionError('Should not have been called')])
        fake_resp.content.readline.side_effect = side_effects

        fake_api = Mock()
        fake_api.get_namespaces = CoroutineMock(return_value=fake_resp)
        fake_api.get_namespaces.__doc__ = ':return: V1NamespaceList'

        watch = kubernetes_asyncio.watch.Watch()
        count = 0
        async with watch:
            async for e in watch.stream(fake_api.get_namespaces,
                                        resource_version='123'):
                self.assertEqual("ADDED", e['type'])
                # make sure decoder worked and we got a model with the right name
                self.assertEqual("test%d" % count, e['object'].metadata.name)
                # make sure decoder worked and updated Watch.resource_version
                self.assertEqual(e['object'].metadata.resource_version,
                                 str(count))
                self.assertEqual(watch.resource_version, str(count))

                # Stop the watch. This must not return the next event which would
                # be an AssertionError exception.
                count += 1
                if count == len(side_effects) - 1:
                    watch.stop()

        fake_api.get_namespaces.assert_called_once_with(_preload_content=False,
                                                        watch=True,
                                                        resource_version='123')
        fake_resp.release.assert_called_once_with()

        # last resource_version has to be stored in the object
        self.assertEqual(watch.resource_version, '2')
Exemple #5
0
    async def test_watch_with_exception(self):
        fake_resp = CoroutineMock()
        fake_resp.content.readline = CoroutineMock(
            side_effect=KeyError("expected"))

        fake_api = Mock()
        fake_api.get_namespaces = CoroutineMock(
            return_value=ApiResponse(http=fake_resp, obj=None))
        fake_api.get_namespaces.__doc__ = ':return: V1NamespaceList'
        fake_api.get_namespaces.__self__ = fake_api

        with self.assertRaises(KeyError):
            watch = k8s.watch.Watch(fake_api.get_namespaces,
                                    timeout_seconds=10)
            [_ async for _ in watch]
Exemple #6
0
    async def test_watch_k8s_empty_response(self):
        """Stop the iterator when the response is empty.

        This typically happens when the user supplied timeout expires.

        """
        # Mock the readline return value to first return a valid response
        # followed by an empty response.
        fake_resp = CoroutineMock()
        fake_resp.content.readline = CoroutineMock()
        side_effects = [
            {
                "type": "ADDED",
                "object": {
                    "metadata": {
                        "name": "test0"
                    },
                    "spec": {},
                    "status": {}
                }
            },
            {
                "type": "ADDED",
                "object": {
                    "metadata": {
                        "name": "test1"
                    },
                    "spec": {},
                    "status": {}
                }
            },
        ]
        side_effects = [json.dumps(_).encode('utf8') for _ in side_effects]
        fake_resp.content.readline.side_effect = side_effects + [b'']

        # Fake the K8s resource object to watch.
        fake_api = Mock()
        fake_api.get_namespaces = CoroutineMock(
            return_value=ApiResponse(http=fake_resp, obj=None))
        fake_api.get_namespaces.__doc__ = ':return: V1NamespaceList'
        fake_api.get_namespaces.__self__ = fake_api

        # Iteration must cease after all valid responses were received.
        watch = k8s.watch.Watch(fake_api.get_namespaces)
        cnt = len([_ async for _ in watch])
        self.assertEqual(cnt, len(side_effects))
Exemple #7
0
    async def test_watch_with_decode(self):
        fake_resp = CoroutineMock()
        fake_resp.content.readline = CoroutineMock()
        side_effects = [{
            "type": "ADDED",
            "object": {
                "metadata": {
                    "name": "test{}".format(uid)
                },
                "spec": {},
                "status": {}
            }
        } for uid in range(3)]
        side_effects = [json.dumps(_).encode('utf8') for _ in side_effects]
        side_effects.extend([AssertionError('Should not have been called')])
        fake_resp.content.readline.side_effect = side_effects

        fake_api = Mock()
        fake_api.get_namespaces = CoroutineMock(
            return_value=ApiResponse(http=fake_resp, obj=None))
        fake_api.get_namespaces.__doc__ = ':return: V1NamespaceList'
        fake_api.get_namespaces.__self__ = SimpleNamespace(
            api_client=self.api_client)

        watch = k8s.watch.Watch(fake_api.get_namespaces,
                                resource_version='123')
        count = 0
        async for e in watch:
            self.assertEqual("ADDED", e.name)
            # make sure decoder worked and we got a model with the right name
            self.assertEqual("test%d" % count, e.obj.metadata.name)

            # Stop the watch. This must not return the next event which would
            # be an AssertionError exception.
            count += 1
            if count == len(side_effects) - 1:
                watch.stop()

        fake_api.get_namespaces.assert_called_once_with(_preload_content=False,
                                                        watch=True,
                                                        resource_version='123')