public async Task WatchNamespacedObjectAsync_CancelsIfNeeded_Async() { var readTaskCompletion = new TaskCompletionSource <int>(); var stream = new Mock <Stream>(MockBehavior.Strict); stream.Setup(s => s.CanSeek).Returns(false); stream.Setup(s => s.CanRead).Returns(true); stream .Setup(s => s.ReadAsync(It.IsAny <Memory <byte> >(), It.IsAny <CancellationToken>())) .Returns <Memory <byte>, CancellationToken>(async(memory, cancellationToken) => await readTaskCompletion.Task); stream .Setup(s => s.Close()) .Callback(() => readTaskCompletion.TrySetException(new ObjectDisposedException("Stream", "Stream is being disposed, and all pending I/O cancelled"))) .Verifiable(); var handler = new DummyHandler(); handler.Responses.Enqueue( new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new WatchHttpContent( new StreamContent(stream.Object)), }); Collection <(WatchEventType, V1Pod)> events = new Collection <(WatchEventType, V1Pod)>(); var protocol = new KubernetesProtocol(handler, this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory); var cts = new CancellationTokenSource(); var watchTask = protocol.WatchNamespacedObjectAsync( new V1Pod() { Metadata = new V1ObjectMeta(name: "pod", namespaceProperty: "default", resourceVersion: "1"), }, protocol.ListNamespacedPodWithHttpMessagesAsync, (eventType, result) => { events.Add((eventType, result)); return(Task.FromResult(WatchResult.Continue)); }, cts.Token); Assert.False(watchTask.IsCompleted); cts.Cancel(); await Task.WhenAny( watchTask, Task.Delay(TimeSpan.FromSeconds(5))).ConfigureAwait(false); Assert.True(watchTask.IsCompletedSuccessfully); stream.Verify(); }
public async Task SendAsync_NonWatchUrl_PassThrough_Async(string method, string url, HttpStatusCode statusCode) { var innerHandler = new DummyHandler(); var expectedResponse = new HttpResponseMessage() { StatusCode = statusCode, Content = new StringContent("test"), }; innerHandler.Responses.Enqueue(expectedResponse); var client = new HttpClient(new WatchHandler(innerHandler)); var response = method == "GET" ? await client.GetAsync(url).ConfigureAwait(false) : await client.PostAsync(url, new StringContent(string.Empty)); Assert.Same(expectedResponse, response); }
public async Task WatchNamespacedObjectAsync_ThrowsExceptionIfNeeded_Async() { var handler = new DummyHandler(); handler.Responses.Enqueue( new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new WatchHttpContent( new StringContent( JsonConvert.SerializeObject( new V1WatchEvent() { Type = nameof(WatchEventType.Error), ObjectProperty = new V1Status() { Kind = "Status", Message = "ErrorMessage", }, }))), }); Collection <(WatchEventType, V1Pod)> events = new Collection <(WatchEventType, V1Pod)>(); var protocol = new KubernetesProtocol(handler, this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory); var cts = new CancellationTokenSource(); var ex = await Assert.ThrowsAsync <KubernetesException>( () => protocol.WatchNamespacedObjectAsync( new V1Pod() { Metadata = new V1ObjectMeta(name: "pod", namespaceProperty: "default", resourceVersion: "1"), }, protocol.ListNamespacedPodWithHttpMessagesAsync, (eventType, result) => { events.Add((eventType, result)); return(Task.FromResult(WatchResult.Continue)); }, cts.Token)).ConfigureAwait(false); Assert.Equal("ErrorMessage", ex.Message); }
public async Task SendAsync_WatchUrl_Intercepts_Async(string url) { var innerHandler = new DummyHandler(); var expectedResponse = new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new StringContent("test"), }; innerHandler.Responses.Enqueue(expectedResponse); var client = new HttpClient(new WatchHandler(innerHandler)); var response = await client.GetAsync(url).ConfigureAwait(false); Assert.Same(expectedResponse, response); var watchContent = Assert.IsType <WatchHttpContent>(response.Content); Assert.IsType <StringContent>(watchContent.OriginalContent); }
public async Task SendAsync_PatchedPodUrl_Async() { var innerHandler = new DummyHandler(); var expectedResponse = new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new StringContent("test"), }; innerHandler.Responses.Enqueue(expectedResponse); var client = new HttpClient(new CoreApiHandler(innerHandler)); client.BaseAddress = new Uri("http://localhost"); var response = await client.GetAsync("/apis/core/v1/").ConfigureAwait(false); Assert.Collection( innerHandler.Requests, r => Assert.Equal(new Uri("http://localhost/api/v1/"), r.RequestUri)); }
public async Task WatchNamespacedObjectAsync_EmptyContent_Completes_Async() { var handler = new DummyHandler(); handler.Responses.Enqueue( new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new WatchHttpContent( new StringContent(string.Empty)), }); Collection <(WatchEventType, V1Pod)> events = new Collection <(WatchEventType, V1Pod)>(); var protocol = new KubernetesProtocol(handler, this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory); var result = await protocol.WatchNamespacedObjectAsync <V1Pod, V1PodList>( new V1Pod() { Metadata = new V1ObjectMeta(name: "pod", namespaceProperty: "default", resourceVersion: "1"), }, protocol.ListNamespacedPodWithHttpMessagesAsync, (eventType, result) => { events.Add((eventType, result)); return(Task.FromResult(WatchResult.Continue)); }, default).ConfigureAwait(false); Assert.Equal(WatchExitReason.ServerDisconnected, result); Assert.Empty(events); Assert.Collection( handler.Requests, r => { Assert.Equal(new Uri("http://localhost/api/v1/namespaces/default/pods?allowWatchBookmarks=true&fieldSelector=metadata.name%3Dpod&resourceVersion=1&watch=true"), r.RequestUri); }); }
public async Task WatchCustomResourceDefinitionAsync_EmptyContent_Completes_Async() { var handler = new DummyHandler(); handler.Responses.Enqueue( new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new WatchHttpContent( new StringContent(string.Empty)), }); Collection <(WatchEventType, V1CustomResourceDefinition)> events = new Collection <(WatchEventType, V1CustomResourceDefinition)>(); var protocol = new KubernetesProtocol(handler, this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory); var result = await protocol.WatchCustomResourceDefinitionAsync( new V1CustomResourceDefinition() { Metadata = new V1ObjectMeta(name: "crd", namespaceProperty: "default", resourceVersion: "1"), }, (eventType, result) => { events.Add((eventType, result)); return(Task.FromResult(WatchResult.Continue)); }, default).ConfigureAwait(false); Assert.Equal(WatchExitReason.ServerDisconnected, result); Assert.Empty(events); Assert.Collection( handler.Requests, r => { Assert.Equal(new Uri("http://localhost/apis/apiextensions.k8s.io/v1/customresourcedefinitions?fieldSelector=metadata.name%3Dcrd&resourceVersion=1&watch=true"), r.RequestUri); }); }
public async Task WatchNamespacedObjectAsync_ClientCanStopLoop_Async() { using (var stream = new SimplexStream()) using (var writer = new StreamWriter(stream)) { var handler = new DummyHandler(); handler.Responses.Enqueue( new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new WatchHttpContent( new StreamContent(stream)), }); Collection <(WatchEventType, V1Pod)> events = new Collection <(WatchEventType, V1Pod)>(); var protocol = new KubernetesProtocol(handler, this.loggerFactory.CreateLogger <KubernetesProtocol>(), this.loggerFactory); var cts = new CancellationTokenSource(); var watchTask = protocol.WatchNamespacedObjectAsync( new V1Pod() { Metadata = new V1ObjectMeta(name: "pod", namespaceProperty: "default", resourceVersion: "1"), }, protocol.ListNamespacedPodWithHttpMessagesAsync, (eventType, result) => { events.Add((eventType, result)); return(Task.FromResult(events.Count == 1 ? WatchResult.Continue : WatchResult.Stop)); }, cts.Token); Assert.True(!watchTask.IsCompleted); await writer.WriteAsync( JsonConvert.SerializeObject( new V1WatchEvent() { Type = nameof(WatchEventType.Deleted), ObjectProperty = new V1Pod() { Metadata = new V1ObjectMeta() { NamespaceProperty = "some-namespace", Name = "some-name", }, }, })); await writer.WriteAsync('\n').ConfigureAwait(false); await writer.FlushAsync().ConfigureAwait(false); Assert.True(!watchTask.IsCompleted); await writer.WriteAsync( JsonConvert.SerializeObject( new V1WatchEvent() { Type = nameof(WatchEventType.Deleted), ObjectProperty = new V1Pod() { Metadata = new V1ObjectMeta() { NamespaceProperty = "some-namespace2", Name = "some-name2", }, }, })); await writer.WriteAsync('\n').ConfigureAwait(false); await writer.FlushAsync().ConfigureAwait(false); var result = await watchTask; Assert.Equal(WatchExitReason.ClientDisconnected, result); Assert.Collection( events, e => { Assert.Equal(WatchEventType.Deleted, e.Item1); Assert.Equal("some-namespace", e.Item2.Metadata.NamespaceProperty); Assert.Equal("some-name", e.Item2.Metadata.Name); }, e => { Assert.Equal(WatchEventType.Deleted, e.Item1); Assert.Equal("some-namespace2", e.Item2.Metadata.NamespaceProperty); Assert.Equal("some-name2", e.Item2.Metadata.Name); }); } }