From e38525c13bae1c2e40feac6906ba326ff6cd1e2c Mon Sep 17 00:00:00 2001 From: Boshi Lian Date: Fri, 23 Oct 2020 08:31:57 -0700 Subject: [PATCH] Squashed commit of the following: (#492) commit dc93612024202e651a9cbe4194c1495c823bff12 Author: Boshi Lian Date: Fri Oct 9 16:24:33 2020 -0700 fix SA1505 commit dc9fdbc4a4fbce7f4362a24e1ff98be4d27e16a8 Author: Boshi Lian Date: Fri Oct 9 16:24:02 2020 -0700 add () commit 16fb7357fcd7e288a4b8fb201fda2b0aae92e5bc Author: Boshi Lian Date: Fri Oct 9 16:21:37 2020 -0700 disable SA1117 commit 544a7e5891e853e2e222f855e5446f3fd79ce2ba Author: Boshi Lian Date: Fri Oct 9 16:21:16 2020 -0700 fix SA1508 commit 4e998adf440dda4f13512d1e10f8cb5d5fbc6bd9 Author: Boshi Lian Date: Fri Oct 9 16:08:28 2020 -0700 allow sa1623 commit baf787255c657a00a6074598c6875e0ab4c9d065 Author: Boshi Lian Date: Fri Oct 9 16:07:23 2020 -0700 fix SA1413 commit 5ef2ca65de62e6c3cbe513902e3954d78f6dc315 Author: Boshi Lian Date: Fri Oct 9 16:05:45 2020 -0700 fix SA1413 commit 6cb71f08060b8252a18b01a5788eb2ddcee67c3e Author: Boshi Lian Date: Fri Oct 9 06:44:55 2020 -0700 fix throw stack commit e6ada0b1cb3aa72df5fcaa0b4690aadcbd4bda5a Author: Boshi Lian Date: Fri Oct 9 06:44:35 2020 -0700 allow CA2225 commit 2e79edec5843c20b7e8f8e9ec5b61cf95284466a Author: Boshi Lian Date: Fri Oct 9 06:35:50 2020 -0700 allow SA1507 commit 108f5a6361f4faa211a8e01f783803295fac0453 Author: Boshi Lian Date: Fri Oct 9 06:35:31 2020 -0700 force SA1413 commit 20f33b64972bfafeada513ae1a46a030934673fd Author: Boshi Lian Date: Fri Oct 9 06:30:58 2020 -0700 force SA1413 commit 6b0de102d68a116e149868731e155bc374f56cc8 Author: Boshi Lian Date: Fri Oct 9 06:28:33 2020 -0700 fix encoding commit 4bd8892c2f0e0fa3666e59b0b77f5b23a2e4ca50 Author: Boshi Lian Date: Fri Oct 9 06:26:00 2020 -0700 fix xunit order commit e28556b37ecd782df2d740321e782622ecd277ca Author: Boshi Lian Date: Fri Oct 9 06:10:20 2020 -0700 fix spacing SA1012 SA1004 commit e8cf4b1e0be951babe04cc3674e17718319b8476 Author: Boshi Lian Date: Fri Oct 9 06:04:44 2020 -0700 fix SA1211 commit b4164446f7f9d82fb872243e59e3f5c46fbb1f3c Author: Boshi Lian Date: Fri Oct 9 06:02:34 2020 -0700 fix attribute related warning commit 2f17ef45947f6ade36593ede6ba4d27bd1991508 Author: Boshi Lian Date: Fri Oct 9 05:56:53 2020 -0700 allow ca1801 ca1052 ca1054 commit 49b857f3f1b4a44a809c9186108caab0412c101e Author: Boshi Lian Date: Fri Oct 9 05:50:07 2020 -0700 fix SA1001 commit 3389662a32cfc481a3fdf50b6fd651e23aadd9dd Author: Boshi LIAN Date: Fri Oct 9 06:24:32 2020 -0700 fix dotnet format commit f9d55fc925e8a7d2f2b403bd3ae35673068134da Merge: 8e81532 0d68823 Author: Boshi Lian Date: Fri Oct 9 05:44:30 2020 -0700 Merge branch 'master' into style_fix0 commit 8e815324040837714efb323580cc5dcd79e58310 Author: Boshi Lian Date: Fri Oct 9 05:33:02 2020 -0700 fix remaing build err commit ecf0152f9e989c4c68274b488d4b3ed6ee88daf9 Author: Boshi Lian Date: Wed Oct 7 05:24:00 2020 -0700 fix SA1707 commit 462d94794848ebfcd102b56a4344ffc33b50f591 Author: Boshi Lian Date: Wed Oct 7 05:19:38 2020 -0700 fix underscore naming commit 5271b113603e469021348523f19555e6be22aebc Author: Boshi Lian Date: Wed Oct 7 05:19:12 2020 -0700 allow CA1822 commit 602713ce631026e88d8ff7e8803bb12c2addc3c2 Author: Boshi Lian Date: Wed Oct 7 04:37:16 2020 -0700 fix CA1822 commit bd4fee4d31c1054eadf6d03aa10f443eee9654c0 Author: Boshi Lian Date: Wed Oct 7 04:36:36 2020 -0700 fix CA1822 commit 257d461f21ef7df65fbc787d5c42c59a89d0eced Author: Boshi Lian Date: Wed Oct 7 04:34:25 2020 -0700 introduce dispose pattern commit 1d668c7926f877ea196edb67acbfe9bfeddb9e15 Author: Boshi Lian Date: Wed Oct 7 04:23:09 2020 -0700 allow CA2008 commit e4fa6acaf36b84298c8c2ab125ff8aa9efc097b7 Author: Boshi Lian Date: Wed Oct 7 04:20:28 2020 -0700 allow CA1827 commit dd931d99fa3a95f936ed566320fffa85efb22838 Author: Boshi Lian Date: Wed Oct 7 04:14:35 2020 -0700 allow SA1314 CA1825 commit 13b6cf11df439be8020e17bc5d30addc62f90c39 Author: Boshi Lian Date: Wed Oct 7 04:13:51 2020 -0700 Revert "fix CA1825" This reverts commit 17e03bcd4e0f129a64e57d54fbe72acb7d1d226b. commit 368664139c75d61ab5a0c432a7fbbdad956c54cf Author: Boshi Lian Date: Wed Oct 7 04:09:52 2020 -0700 move class to single files commit 0015631805d6bc31e4695881989058bb3955766f Author: Boshi Lian Date: Wed Oct 7 04:09:27 2020 -0700 disable CA2000 / TODO commit 0a1241e84ba1247c8ab4ab8d32bd5d800114420b Author: Boshi Lian Date: Wed Oct 7 04:07:23 2020 -0700 allow SA1715 commit 17e03bcd4e0f129a64e57d54fbe72acb7d1d226b Author: Boshi Lian Date: Wed Oct 7 04:06:57 2020 -0700 fix CA1825 commit 7baf350ca93cb45e2587d86fb6ab6e4cf665b6da Author: Boshi Lian Date: Wed Oct 7 03:42:04 2020 -0700 fix SA1312 SA1306 commit 44ad5934182adfc871215637e9612295bc26e6f2 Author: Boshi Lian Date: Wed Oct 7 03:30:35 2020 -0700 fix CA2007 commit 325fa2c2d16d541db6e21b791c5170f39f832d43 Author: Boshi Lian Date: Wed Oct 7 03:25:11 2020 -0700 fix SA1131 commit 8f1f46b065dd7e9b316491676bb0b93ef91d0595 Author: Boshi Lian Date: Wed Oct 7 03:17:08 2020 -0700 allow SA1119 commit 57c0fe7cc26932cc30b4d7cc75a809746d74d5aa Author: Boshi Lian Date: Wed Oct 7 03:14:14 2020 -0700 fix SA1400 commit 0afcbbc09d5ef66fbbd4b291d14e7804a8e5a1d3 Author: Boshi Lian Date: Wed Oct 7 03:12:18 2020 -0700 fix SA1513 commit 45f2424531d35a2a106e10e788aff1a18d745078 Author: Boshi Lian Date: Wed Oct 7 03:09:17 2020 -0700 allow ca1720 ca1716 sa1405 commit 3403814130a1bf730c4e275f74e9cf5d03bedb41 Author: Boshi Lian Date: Wed Oct 7 02:16:37 2020 -0700 fix model oper not contains generated header commit 11377d916cf8cd3ad9109388aff6cf989ff4b7b0 Author: Boshi Lian Date: Wed Oct 7 02:14:05 2020 -0700 fix SA1649 commit 92b00051a8c80542a63e1dddbb6eed4e98ad26f9 Author: Boshi Lian Date: Wed Oct 7 02:11:16 2020 -0700 fix SA1124 commit 901a9dd2426fa316bcc5a3c2fc411e583f0e07df Author: Boshi Lian Date: Wed Oct 7 02:09:27 2020 -0700 save 1122 commit a8f17b6bac1f1c115b7ed9ebb70d16697a3e81b7 Author: Boshi Lian Date: Wed Oct 7 02:09:07 2020 -0700 1507 followup commit a143184921abb38a09e28a7ef07379003fb19563 Author: Boshi Lian Date: Wed Oct 7 02:07:38 2020 -0700 fix sa1507 commit 54b56026265cbbbfa6e5b8b4dcfab281ffbfa272 Author: Boshi Lian Date: Wed Oct 7 02:06:44 2020 -0700 fix sa1513 commit 53a009205c88a1d63d8daf32599bbc6428619638 Author: Boshi Lian Date: Wed Oct 7 02:05:36 2020 -0700 fix SA1649 commit 26d3e78f61ffc381887baaf5c8b56d92aa0ec563 Author: Boshi Lian Date: Wed Oct 7 02:01:01 2020 -0700 fix ca1816 commit 1ce5a04ce7a32d901cbece3e18d59e3c068cfd27 Author: Boshi Lian Date: Wed Oct 7 01:56:43 2020 -0700 readable ruleset commit dafc55f1c2cdc8466919276291333ba46176161a Author: Boshi Lian Date: Wed May 27 19:13:56 2020 -0700 sync none from guideline --- examples/attach/Attach.cs | 4 +- examples/exec/Exec.cs | 4 +- .../httpClientFactory/PodListHostedService.cs | 4 +- examples/logs/Logs.cs | 2 +- examples/metrics/{Metrics.cs => Program.cs} | 9 +- .../{Namespace.cs => NamespaceExample.cs} | 16 +- .../KubernetesWatchGenerator.csproj | 2 +- .../ModelOperators.cs.template | 5 + gen/KubernetesWatchGenerator/Program.cs | 49 ++- kubernetes-client.ruleset | 290 +++++++++++++++- .../Authentication/GcpTokenProvider.cs | 11 +- .../Authentication/TokenFileAuth.cs | 19 +- src/KubernetesClient/ByteBuffer.cs | 36 +- src/KubernetesClient/ChannelIndex.cs | 1 + src/KubernetesClient/Extensions.cs | 4 +- src/KubernetesClient/IntOrStringConverter.cs | 32 ++ .../IntOrStringYamlConverter.cs | 42 +++ src/KubernetesClient/IntstrIntOrString.cs | 67 +--- src/KubernetesClient/Kubernetes.ConfigInit.cs | 1 + src/KubernetesClient/Kubernetes.Watch.cs | 18 +- src/KubernetesClient/Kubernetes.WebSocket.cs | 54 +-- ...ubernetesClientConfiguration.ConfigFile.cs | 25 +- ...KubernetesClientConfiguration.InCluster.cs | 12 +- .../KubernetesEntityAttribute.cs | 1 + src/KubernetesClient/KubernetesList.cs | 1 - src/KubernetesClient/ModelExtensions.cs | 23 +- src/KubernetesClient/QuantityConverter.cs | 32 ++ src/KubernetesClient/ResourceQuantity.cs | 69 +--- src/KubernetesClient/StreamDemuxer.cs | 69 ++-- src/KubernetesClient/V1Patch.cs | 20 -- src/KubernetesClient/V1PathJsonConverter.cs | 25 ++ src/KubernetesClient/V1Status.cs | 20 ++ ...aritor.cs => KubernetesVersionComparer.cs} | 4 +- src/KubernetesClient/Watcher.cs | 73 ++-- .../WatcherDelegatingHandler.cs | 3 +- src/KubernetesClient/WatcherExt.cs | 60 ++++ src/KubernetesClient/Yaml.cs | 12 +- .../generated/ModelOperators.cs | 320 ++++++++++++++++++ .../generated/VersionConverter.cs | 4 - tests/KubernetesClient.Tests/AuthTests.cs | 15 +- .../KubernetesClient.Tests/ByteBufferTests.cs | 14 +- .../ExternalExecutionTests.cs | 2 +- .../GcpTokenProviderTests.cs | 3 +- .../KubernetesClient.Tests.csproj | 6 +- .../KubernetesClientConfigurationTests.cs | 8 +- ...ockets.Tests.cs => KubernetesExecTests.cs} | 2 + ...ics.Tests.cs => KubernetesMetricsTests.cs} | 0 .../Logging/TestOutputLogger.cs | 6 +- .../Logging/TestOutputLoggerProvider.cs | 4 +- .../Mock/MockKubeApiServer.cs | 4 +- .../Mock/MockWebSocket.cs | 43 ++- .../Server/Controllers/PodExecController.cs | 6 +- .../Controllers/PodPortForwardController.cs | 6 +- .../Mock/Server/Startup.cs | 4 +- .../Mock/Server/WebSocketTestAdapter.cs | 4 +- .../ModelExtensionTests.cs | 2 +- .../KubernetesClient.Tests/OperatingSystem.cs | 2 +- ... OperatingSystemDependentFactAttribute.cs} | 0 ...bernetes.Exec.Tests.cs => PodExecTests.cs} | 45 ++- .../StreamDemuxerTests.cs | 87 ++--- tests/KubernetesClient.Tests/TaskAssert.cs | 19 +- ...TokenFileAuth.cs => TokenFileAuthTests.cs} | 12 +- tests/KubernetesClient.Tests/WatchTests.cs | 160 ++++----- .../WebSocketTestBase.cs | 52 ++- tests/KubernetesClient.Tests/YamlTests.cs | 18 +- 65 files changed, 1350 insertions(+), 617 deletions(-) rename examples/metrics/{Metrics.cs => Program.cs} (87%) rename examples/namespace/{Namespace.cs => NamespaceExample.cs} (83%) create mode 100644 src/KubernetesClient/IntOrStringConverter.cs create mode 100644 src/KubernetesClient/IntOrStringYamlConverter.cs create mode 100644 src/KubernetesClient/QuantityConverter.cs create mode 100644 src/KubernetesClient/V1PathJsonConverter.cs create mode 100644 src/KubernetesClient/V1Status.cs rename src/KubernetesClient/Versioning/{KubernetesVersionComparitor.cs => KubernetesVersionComparer.cs} (95%) create mode 100644 src/KubernetesClient/WatcherExt.cs rename tests/KubernetesClient.Tests/{Kubernetes.WebSockets.Tests.cs => KubernetesExecTests.cs} (99%) rename tests/KubernetesClient.Tests/{Kubernetes.Metrics.Tests.cs => KubernetesMetricsTests.cs} (100%) rename tests/KubernetesClient.Tests/{OperatingSystemFact.cs => OperatingSystemDependentFactAttribute.cs} (100%) rename tests/KubernetesClient.Tests/{Kubernetes.Exec.Tests.cs => PodExecTests.cs} (90%) rename tests/KubernetesClient.Tests/{TokenFileAuth.cs => TokenFileAuthTests.cs} (74%) diff --git a/examples/attach/Attach.cs b/examples/attach/Attach.cs index dafefe3..2542e1c 100755 --- a/examples/attach/Attach.cs +++ b/examples/attach/Attach.cs @@ -18,14 +18,14 @@ namespace attach var list = client.ListNamespacedPod("default"); var pod = list.Items[0]; - await AttachToPod(client, pod); + await AttachToPod(client, pod).ConfigureAwait(false); } private async static Task AttachToPod(IKubernetes client, V1Pod pod) { var webSocket = await client.WebSocketNamespacedPodAttachAsync(pod.Metadata.Name, "default", - pod.Spec.Containers[0].Name); + pod.Spec.Containers[0].Name).ConfigureAwait(false); var demux = new StreamDemuxer(webSocket); demux.Start(); diff --git a/examples/exec/Exec.cs b/examples/exec/Exec.cs index b035589..fe796ae 100755 --- a/examples/exec/Exec.cs +++ b/examples/exec/Exec.cs @@ -15,14 +15,14 @@ namespace exec var list = client.ListNamespacedPod("default"); var pod = list.Items[0]; - await ExecInPod(client, pod); + await ExecInPod(client, pod).ConfigureAwait(false); } private async static Task ExecInPod(IKubernetes client, V1Pod pod) { var webSocket = await client.WebSocketNamespacedPodExecAsync(pod.Metadata.Name, "default", "ls", - pod.Spec.Containers[0].Name); + pod.Spec.Containers[0].Name).ConfigureAwait(false); var demux = new StreamDemuxer(webSocket); demux.Start(); diff --git a/examples/httpClientFactory/PodListHostedService.cs b/examples/httpClientFactory/PodListHostedService.cs index 66f61e8..c104fc8 100644 --- a/examples/httpClientFactory/PodListHostedService.cs +++ b/examples/httpClientFactory/PodListHostedService.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace httpClientFactory { // Learn more about IHostedServices at https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-2.2&tabs=visual-studio - internal class PodListHostedService : IHostedService + public class PodListHostedService : IHostedService { private readonly IKubernetes _kubernetesClient; private readonly ILogger _logger; @@ -23,7 +23,7 @@ namespace httpClientFactory { _logger.LogInformation("Starting Request!"); - var list = await _kubernetesClient.ListNamespacedPodAsync("default", cancellationToken: cancellationToken); + var list = await _kubernetesClient.ListNamespacedPodAsync("default", cancellationToken: cancellationToken).ConfigureAwait(false); foreach (var item in list.Items) { _logger.LogInformation(item.Metadata.Name); diff --git a/examples/logs/Logs.cs b/examples/logs/Logs.cs index d21dbb7..ebd7716 100755 --- a/examples/logs/Logs.cs +++ b/examples/logs/Logs.cs @@ -23,7 +23,7 @@ namespace logs var pod = list.Items[0]; var response = await client.ReadNamespacedPodLogWithHttpMessagesAsync(pod.Metadata.Name, - pod.Metadata.NamespaceProperty, follow: true); + pod.Metadata.NamespaceProperty, follow: true).ConfigureAwait(false); var stream = response.Body; stream.CopyTo(Console.OpenStandardOutput()); } diff --git a/examples/metrics/Metrics.cs b/examples/metrics/Program.cs similarity index 87% rename from examples/metrics/Metrics.cs rename to examples/metrics/Program.cs index ef47886..33a779f 100644 --- a/examples/metrics/Metrics.cs +++ b/examples/metrics/Program.cs @@ -5,9 +5,9 @@ using System.Threading.Tasks; namespace metrics { - class Program + internal class Program { - static async Task NodesMetrics(IKubernetes client) + private static async Task NodesMetrics(IKubernetes client) { var nodesMetrics = await client.GetKubernetesNodesMetricsAsync().ConfigureAwait(false); @@ -22,7 +22,7 @@ namespace metrics } } - static async Task PodsMetrics(IKubernetes client) + private static async Task PodsMetrics(IKubernetes client) { var podsMetrics = await client.GetKubernetesPodsMetricsAsync().ConfigureAwait(false); @@ -42,11 +42,12 @@ namespace metrics Console.WriteLine($"{metric.Key}: {metric.Value}"); } } + Console.Write(Environment.NewLine); } } - static async Task Main(string[] args) + private static async Task Main(string[] args) { var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(); var client = new Kubernetes(config); diff --git a/examples/namespace/Namespace.cs b/examples/namespace/NamespaceExample.cs similarity index 83% rename from examples/namespace/Namespace.cs rename to examples/namespace/NamespaceExample.cs index a7db12e..83fd3c8 100644 --- a/examples/namespace/Namespace.cs +++ b/examples/namespace/NamespaceExample.cs @@ -6,9 +6,9 @@ using k8s.Models; namespace @namespace { - class NamespaceExample + internal class NamespaceExample { - static void ListNamespaces(IKubernetes client) + private static void ListNamespaces(IKubernetes client) { var list = client.ListNamespace(); foreach (var item in list.Items) @@ -22,14 +22,14 @@ namespace @namespace } } - static async Task DeleteAsync(IKubernetes client, string name, int delayMillis) + private static async Task DeleteAsync(IKubernetes client, string name, int delayMillis) { while (true) { - await Task.Delay(delayMillis); + await Task.Delay(delayMillis).ConfigureAwait(false); try { - await client.ReadNamespaceAsync(name); + await client.ReadNamespaceAsync(name).ConfigureAwait(false); } catch (AggregateException ex) { @@ -43,7 +43,7 @@ namespace @namespace return; } - throw ex; + throw; } } } @@ -54,12 +54,12 @@ namespace @namespace return; } - throw ex; + throw; } } } - static void Delete(IKubernetes client, string name, int delayMillis) + private static void Delete(IKubernetes client, string name, int delayMillis) { DeleteAsync(client, name, delayMillis).Wait(); } diff --git a/gen/KubernetesWatchGenerator/KubernetesWatchGenerator.csproj b/gen/KubernetesWatchGenerator/KubernetesWatchGenerator.csproj index f6c1011..b170c91 100644 --- a/gen/KubernetesWatchGenerator/KubernetesWatchGenerator.csproj +++ b/gen/KubernetesWatchGenerator/KubernetesWatchGenerator.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/gen/KubernetesWatchGenerator/ModelOperators.cs.template b/gen/KubernetesWatchGenerator/ModelOperators.cs.template index 029adea..b453b0b 100644 --- a/gen/KubernetesWatchGenerator/ModelOperators.cs.template +++ b/gen/KubernetesWatchGenerator/ModelOperators.cs.template @@ -1,3 +1,8 @@ +// +// Code generated by gen/KubernetesWatchGenerator +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. +// using k8s.Versioning; namespace k8s.Models diff --git a/gen/KubernetesWatchGenerator/Program.cs b/gen/KubernetesWatchGenerator/Program.cs index 1649a49..0bdf141 100644 --- a/gen/KubernetesWatchGenerator/Program.cs +++ b/gen/KubernetesWatchGenerator/Program.cs @@ -11,15 +11,15 @@ using System.Threading.Tasks; namespace KubernetesWatchGenerator { - class Program + internal class Program { private static HashSet _classesWithValidation; - static readonly Dictionary ClassNameMap = new Dictionary(); + private static readonly Dictionary ClassNameMap = new Dictionary(); private static Dictionary _schemaToNameMap; private static HashSet _schemaDefinitionsInMultipleGroups; private static Dictionary _classNameToPluralMap; - static async Task Main(string[] args) + private static async Task Main(string[] args) { if (args.Length < 2) { @@ -31,7 +31,7 @@ namespace KubernetesWatchGenerator // Read the spec trimmed // here we cache all name in gen project for later use - var swagger = await SwaggerDocument.FromFileAsync(Path.Combine(args[1], "swagger.json")); + var swagger = await SwaggerDocument.FromFileAsync(Path.Combine(args[1], "swagger.json")).ConfigureAwait(false); foreach (var (k, v) in swagger.Definitions) { if (v.ExtensionData?.TryGetValue("x-kubernetes-group-version-kind", out var _) == true) @@ -46,9 +46,8 @@ namespace KubernetesWatchGenerator } } - // gen project removed all watch operations, so here we switch back to unprocessed version - swagger = await SwaggerDocument.FromFileAsync(Path.Combine(args[1], "swagger.json.unprocessed")); + swagger = await SwaggerDocument.FromFileAsync(Path.Combine(args[1], "swagger.json.unprocessed")).ConfigureAwait(false); _schemaToNameMap = swagger.Definitions.ToDictionary(x => x.Value, x => x.Key); _schemaDefinitionsInMultipleGroups = _schemaToNameMap.Values.Select(x => { @@ -90,7 +89,6 @@ namespace KubernetesWatchGenerator .Union(_classNameToPluralMap) .ToDictionary(x => x.Key, x => x.Value); - // Register helpers used in the templating. Helpers.Register(nameof(ToXmlDoc), ToXmlDoc); Helpers.Register(nameof(GetClassName), GetClassName); @@ -166,12 +164,9 @@ namespace KubernetesWatchGenerator Render.FileToFile("VersionConverter.cs.template", versionConverterPairs, Path.Combine(outputDirectory, "VersionConverter.cs")); Render.FileToFile("ModelOperators.cs.template", typePairs, Path.Combine(outputDirectory, "ModelOperators.cs")); - } - - - static void ToXmlDoc(RenderContext context, IList arguments, IDictionary options, + private static void ToXmlDoc(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is string) @@ -199,7 +194,7 @@ namespace KubernetesWatchGenerator } } - static void GetTuple(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) + private static void GetTuple(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] is ITuple && options.TryGetValue("index", out var indexObj) && int.TryParse(indexObj?.ToString(), out var index)) { @@ -209,9 +204,7 @@ namespace KubernetesWatchGenerator } } - - - static void GetClassName(RenderContext context, IList arguments, IDictionary options, + private static void GetClassName(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is SwaggerOperation) @@ -224,7 +217,7 @@ namespace KubernetesWatchGenerator } } - static string GetClassName(SwaggerOperation watchOperation) + private static string GetClassName(SwaggerOperation watchOperation) { var groupVersionKind = (Dictionary)watchOperation.ExtensionData["x-kubernetes-group-version-kind"]; @@ -257,7 +250,7 @@ namespace KubernetesWatchGenerator } } - static string GetClassNameForSchemaDefinition(JsonSchema4 definition) + private static string GetClassNameForSchemaDefinition(JsonSchema4 definition) { if (definition.ExtensionData != null && definition.ExtensionData.ContainsKey("x-kubernetes-group-version-kind")) @@ -280,7 +273,7 @@ namespace KubernetesWatchGenerator return className; } - static string GetInterfaceName(JsonSchema4 definition) + private static string GetInterfaceName(JsonSchema4 definition) { var groupVersionKindElements = (object[])definition.ExtensionData["x-kubernetes-group-version-kind"]; var groupVersionKind = (Dictionary)groupVersionKindElements[0]; @@ -321,8 +314,7 @@ namespace KubernetesWatchGenerator return result; } - - static void GetKind(RenderContext context, IList arguments, IDictionary options, + private static void GetKind(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is JsonSchema4) @@ -339,7 +331,7 @@ namespace KubernetesWatchGenerator return groupVersionKind["kind"] as string; } - static void GetPlural(RenderContext context, IList arguments, IDictionary options, + private static void GetPlural(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is JsonSchema4) @@ -362,7 +354,7 @@ namespace KubernetesWatchGenerator return _classNameToPluralMap.GetValueOrDefault(className, null); } - static void GetGroup(RenderContext context, IList arguments, IDictionary options, + private static void GetGroup(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is JsonSchema4) @@ -379,7 +371,7 @@ namespace KubernetesWatchGenerator return groupVersionKind["group"] as string; } - static void GetMethodName(RenderContext context, IList arguments, IDictionary options, + private static void GetMethodName(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is SwaggerOperation) @@ -388,8 +380,7 @@ namespace KubernetesWatchGenerator } } - - static string GetMethodName(SwaggerOperation watchOperation) + private static string GetMethodName(SwaggerOperation watchOperation) { var tag = watchOperation.Tags[0]; tag = tag.Replace("_", string.Empty); @@ -402,7 +393,7 @@ namespace KubernetesWatchGenerator return methodName; } - static void GetDotNetType(RenderContext context, IList arguments, IDictionary options, + private static void GetDotNetType(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is SwaggerParameter) @@ -463,7 +454,7 @@ namespace KubernetesWatchGenerator } } - static void GetDotNetName(RenderContext context, IList arguments, IDictionary options, + private static void GetDotNetName(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is SwaggerParameter) @@ -492,7 +483,7 @@ namespace KubernetesWatchGenerator return jsonName; } - static void GetPathExpression(RenderContext context, IList arguments, + private static void GetPathExpression(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && @@ -516,7 +507,7 @@ namespace KubernetesWatchGenerator return pathExpression; } - static void GetApiVersion(RenderContext context, IList arguments, IDictionary options, + private static void GetApiVersion(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is JsonSchema4) diff --git a/kubernetes-client.ruleset b/kubernetes-client.ruleset index 2853cab..a6bbe9d 100644 --- a/kubernetes-client.ruleset +++ b/kubernetes-client.ruleset @@ -1,13 +1,297 @@ + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/KubernetesClient/Authentication/GcpTokenProvider.cs b/src/KubernetesClient/Authentication/GcpTokenProvider.cs index ba7119f..a5d86b3 100644 --- a/src/KubernetesClient/Authentication/GcpTokenProvider.cs +++ b/src/KubernetesClient/Authentication/GcpTokenProvider.cs @@ -24,8 +24,9 @@ namespace k8s.Authentication { if (DateTime.UtcNow.AddSeconds(30) > _expiry) { - await RefreshToken(); + await RefreshToken().ConfigureAwait(false); } + return new AuthenticationHeaderValue("Bearer", _token); } @@ -40,9 +41,9 @@ namespace k8s.Authentication UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, - RedirectStandardError = true + RedirectStandardError = true, }, - EnableRaisingEvents = true + EnableRaisingEvents = true, }; var tcs = new TaskCompletionSource(); process.Exited += (sender, arg) => @@ -53,14 +54,14 @@ namespace k8s.Authentication var output = process.StandardOutput.ReadToEndAsync(); var err = process.StandardError.ReadToEndAsync(); - await Task.WhenAll(tcs.Task, output, err); + await Task.WhenAll(tcs.Task, output, err).ConfigureAwait(false); if (process.ExitCode != 0) { throw new KubernetesClientException($"Unable to obtain a token via gcloud command. Error code {process.ExitCode}. \n {err}"); } - var json = JToken.Parse(await output); + var json = JToken.Parse(await output.ConfigureAwait(false)); _token = json["credential"]["access_token"].Value(); _expiry = json["credential"]["token_expiry"].Value(); } diff --git a/src/KubernetesClient/Authentication/TokenFileAuth.cs b/src/KubernetesClient/Authentication/TokenFileAuth.cs index 4d33c14..ec9ea4d 100644 --- a/src/KubernetesClient/Authentication/TokenFileAuth.cs +++ b/src/KubernetesClient/Authentication/TokenFileAuth.cs @@ -9,29 +9,30 @@ namespace k8s.Authentication { public class TokenFileAuth : ITokenProvider { - private string _token; - internal string _token_file { get; set; } - internal DateTime _token_expires_at { get; set; } + private string token; + internal string TokenFile { get; set; } + internal DateTime TokenExpiresAt { get; set; } - public TokenFileAuth(string token_file) + public TokenFileAuth(string tokenFile) { - _token_file = token_file; + TokenFile = tokenFile; } public async Task GetAuthenticationHeaderAsync(CancellationToken cancellationToken) { - if (_token_expires_at < DateTime.UtcNow) + if (TokenExpiresAt < DateTime.UtcNow) { - _token = File.ReadAllText(_token_file).Trim(); + token = File.ReadAllText(TokenFile).Trim(); // in fact, the token has a expiry of 10 minutes and kubelet // refreshes it at 8 minutes of its lifetime. setting the expiry // of 1 minute makes sure the token is reloaded regularly so // that its actual expiry is after the declared expiry here, // which is as suffciently true as the time of reading a token // < 10-8-1 minute. - _token_expires_at = DateTime.UtcNow.AddMinutes(1); + TokenExpiresAt = DateTime.UtcNow.AddMinutes(1); } - return new AuthenticationHeaderValue("Bearer", _token); + + return new AuthenticationHeaderValue("Bearer", token); } } } diff --git a/src/KubernetesClient/ByteBuffer.cs b/src/KubernetesClient/ByteBuffer.cs index 8b5d25e..0dc638f 100644 --- a/src/KubernetesClient/ByteBuffer.cs +++ b/src/KubernetesClient/ByteBuffer.cs @@ -34,6 +34,7 @@ namespace k8s /// more data is available. /// private bool endOfFile; + private bool disposedValue; /// /// Initializes a new instance of the class using the default buffer size and limit. @@ -145,12 +146,6 @@ namespace k8s } } - /// - public void Dispose() - { - ArrayPool.Shared.Return(this.buffer); - } - /// /// Writes bytes to the buffer. /// @@ -307,5 +302,34 @@ namespace k8s Debug.Assert(this.bytesRead + this.AvailableReadableBytes == this.bytesWritten); this.OnResize?.Invoke(this, EventArgs.Empty); } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + ArrayPool.Shared.Return(this.buffer); + } + + // TODO: free unmanaged resources (unmanaged objects) and override finalizer + // TODO: set large fields to null + disposedValue = true; + } + } + + // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources + // ~ByteBuffer() + // { + // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + // Dispose(disposing: false); + // } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } } } diff --git a/src/KubernetesClient/ChannelIndex.cs b/src/KubernetesClient/ChannelIndex.cs index 1d2445e..ca521a8 100644 --- a/src/KubernetesClient/ChannelIndex.cs +++ b/src/KubernetesClient/ChannelIndex.cs @@ -5,6 +5,7 @@ namespace k8s /// pod. /// /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1028:Enum Storage should be Int32", Justification = "byte only")] public enum ChannelIndex : byte { /// diff --git a/src/KubernetesClient/Extensions.cs b/src/KubernetesClient/Extensions.cs index cb4eb6c..aa4829c 100644 --- a/src/KubernetesClient/Extensions.cs +++ b/src/KubernetesClient/Extensions.cs @@ -16,7 +16,6 @@ namespace k8s { public static class Extensions { - public static KubernetesEntityAttribute GetKubernetesTypeMetadata(this T obj) where T : IKubernetesObject => obj.GetType().GetKubernetesTypeMetadata(); public static KubernetesEntityAttribute GetKubernetesTypeMetadata(this Type currentType) @@ -26,6 +25,7 @@ namespace k8s { throw new InvalidOperationException($"Custom resource must have {nameof(KubernetesEntityAttribute)} applied to it"); } + return attr; } @@ -43,7 +43,5 @@ namespace k8s } internal static bool IsValidKubernetesName(this string value) => !Regex.IsMatch(value, "^[a-z0-9-]+$"); - - } } diff --git a/src/KubernetesClient/IntOrStringConverter.cs b/src/KubernetesClient/IntOrStringConverter.cs new file mode 100644 index 0000000..c5acb17 --- /dev/null +++ b/src/KubernetesClient/IntOrStringConverter.cs @@ -0,0 +1,32 @@ +using System; +using Newtonsoft.Json; + +namespace k8s.Models +{ + internal class IntOrStringConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var s = (value as IntstrIntOrString)?.Value; + + if (int.TryParse(s, out var intv)) + { + serializer.Serialize(writer, intv); + return; + } + + serializer.Serialize(writer, s); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + JsonSerializer serializer) + { + return (IntstrIntOrString)serializer.Deserialize(reader); + } + + public override bool CanConvert(Type objectType) + { + return objectType == typeof(int) || objectType == typeof(string); + } + } +} diff --git a/src/KubernetesClient/IntOrStringYamlConverter.cs b/src/KubernetesClient/IntOrStringYamlConverter.cs new file mode 100644 index 0000000..6a62384 --- /dev/null +++ b/src/KubernetesClient/IntOrStringYamlConverter.cs @@ -0,0 +1,42 @@ +using System; +using YamlDotNet.Core; +using YamlDotNet.Serialization; + +namespace k8s.Models +{ + public class IntOrStringYamlConverter : IYamlTypeConverter + { + public bool Accepts(Type type) + { + return type == typeof(IntstrIntOrString); + } + + public object ReadYaml(IParser parser, Type type) + { + if (parser.Current is YamlDotNet.Core.Events.Scalar scalar) + { + try + { + if (string.IsNullOrEmpty(scalar.Value)) + { + return null; + } + + return new IntstrIntOrString(scalar.Value); + } + finally + { + parser.MoveNext(); + } + } + + throw new InvalidOperationException(parser.Current?.ToString()); + } + + public void WriteYaml(IEmitter emitter, object value, Type type) + { + var obj = (IntstrIntOrString)value; + emitter.Emit(new YamlDotNet.Core.Events.Scalar(obj.Value)); + } + } +} diff --git a/src/KubernetesClient/IntstrIntOrString.cs b/src/KubernetesClient/IntstrIntOrString.cs index be0b344..f02473e 100644 --- a/src/KubernetesClient/IntstrIntOrString.cs +++ b/src/KubernetesClient/IntstrIntOrString.cs @@ -1,75 +1,10 @@ using System; using Newtonsoft.Json; -using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.Tokens; -using YamlDotNet.Serialization; namespace k8s.Models { - public class IntOrStringYamlConverter : IYamlTypeConverter - { - public bool Accepts(Type type) - { - return type == typeof(IntstrIntOrString); - } - - public object ReadYaml(IParser parser, Type type) - { - if (parser.Current is YamlDotNet.Core.Events.Scalar scalar) - { - try - { - if (string.IsNullOrEmpty(scalar.Value)) - { - return null; - } - - return new IntstrIntOrString(scalar.Value); - } - finally - { - parser.MoveNext(); - } - } - - throw new InvalidOperationException(parser.Current?.ToString()); - } - - public void WriteYaml(IEmitter emitter, object value, Type type) - { - var obj = (IntstrIntOrString)value; - emitter.Emit(new YamlDotNet.Core.Events.Scalar(obj.Value)); - } - } - - internal class IntOrStringConverter : JsonConverter - { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var s = (value as IntstrIntOrString)?.Value; - - if (int.TryParse(s, out var intv)) - { - serializer.Serialize(writer, intv); - return; - } - - serializer.Serialize(writer, s); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, - JsonSerializer serializer) - { - return (IntstrIntOrString)serializer.Deserialize(reader); - } - - public override bool CanConvert(Type objectType) - { - return objectType == typeof(int) || objectType == typeof(string); - } - } - [JsonConverter(typeof(IntOrStringConverter))] public partial class IntstrIntOrString { @@ -120,7 +55,7 @@ namespace k8s.Models public override int GetHashCode() { - return (Value != null ? Value.GetHashCode() : 0); + return Value != null ? Value.GetHashCode() : 0; } } } diff --git a/src/KubernetesClient/Kubernetes.ConfigInit.cs b/src/KubernetesClient/Kubernetes.ConfigInit.cs index 6d4eeb8..c43c1b8 100644 --- a/src/KubernetesClient/Kubernetes.ConfigInit.cs +++ b/src/KubernetesClient/Kubernetes.ConfigInit.cs @@ -306,6 +306,7 @@ namespace k8s { throw new ArgumentNullException(nameof(config)); } + if (config.TokenProvider != null) { return new TokenCredentials(config.TokenProvider); diff --git a/src/KubernetesClient/Kubernetes.Watch.cs b/src/KubernetesClient/Kubernetes.Watch.cs index d0d65e1..b849858 100644 --- a/src/KubernetesClient/Kubernetes.Watch.cs +++ b/src/KubernetesClient/Kubernetes.Watch.cs @@ -21,11 +21,11 @@ namespace k8s CancellationToken cancellationToken = default(CancellationToken)) { // Tracing - bool _shouldTrace = ServiceClientTracing.IsEnabled; - string _invocationId = null; - if (_shouldTrace) + bool shouldTrace = ServiceClientTracing.IsEnabled; + string invocationId = null; + if (shouldTrace) { - _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + invocationId = ServiceClientTracing.NextInvocationId.ToString(); Dictionary tracingParameters = new Dictionary(); tracingParameters.Add("path", path); tracingParameters.Add("continue", @continue); @@ -36,7 +36,7 @@ namespace k8s tracingParameters.Add("pretty", pretty); tracingParameters.Add("timeoutSeconds", timeoutSeconds); tracingParameters.Add("resourceVersion", resourceVersion); - ServiceClientTracing.Enter(_invocationId, this, nameof(WatchObjectAsync), tracingParameters); + ServiceClientTracing.Enter(invocationId, this, nameof(WatchObjectAsync), tracingParameters); } // Construct URL @@ -124,9 +124,9 @@ namespace k8s } // Send Request - if (_shouldTrace) + if (shouldTrace) { - ServiceClientTracing.SendRequest(_invocationId, httpRequest); + ServiceClientTracing.SendRequest(invocationId, httpRequest); } cancellationToken.ThrowIfCancellationRequested(); @@ -134,9 +134,9 @@ namespace k8s .SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken) .ConfigureAwait(false); - if (_shouldTrace) + if (shouldTrace) { - ServiceClientTracing.ReceiveResponse(_invocationId, httpResponse); + ServiceClientTracing.ReceiveResponse(invocationId, httpResponse); } cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/KubernetesClient/Kubernetes.WebSocket.cs b/src/KubernetesClient/Kubernetes.WebSocket.cs index 25d57b8..84f68bd 100644 --- a/src/KubernetesClient/Kubernetes.WebSocket.cs +++ b/src/KubernetesClient/Kubernetes.WebSocket.cs @@ -90,11 +90,11 @@ namespace k8s } // Tracing - bool _shouldTrace = ServiceClientTracing.IsEnabled; - string _invocationId = null; - if (_shouldTrace) + bool shouldTrace = ServiceClientTracing.IsEnabled; + string invocationId = null; + if (shouldTrace) { - _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + invocationId = ServiceClientTracing.NextInvocationId.ToString(); Dictionary tracingParameters = new Dictionary(); tracingParameters.Add("command", command); tracingParameters.Add("container", container); @@ -106,7 +106,7 @@ namespace k8s tracingParameters.Add("tty", tty); tracingParameters.Add("webSocketSubProtol", webSocketSubProtol); tracingParameters.Add("cancellationToken", cancellationToken); - ServiceClientTracing.Enter(_invocationId, this, nameof(WebSocketNamespacedPodExecAsync), + ServiceClientTracing.Enter(invocationId, this, nameof(WebSocketNamespacedPodExecAsync), tracingParameters); } @@ -143,7 +143,7 @@ namespace k8s uriBuilder.Query = query.ToString(1, query.Length - 1); // UriBuilder.Query doesn't like leading '?' chars, so trim it - return this.StreamConnectAsync(uriBuilder.Uri, _invocationId, webSocketSubProtol, customHeaders, + return this.StreamConnectAsync(uriBuilder.Uri, invocationId, webSocketSubProtol, customHeaders, cancellationToken); } @@ -169,18 +169,18 @@ namespace k8s } // Tracing - bool _shouldTrace = ServiceClientTracing.IsEnabled; - string _invocationId = null; - if (_shouldTrace) + bool shouldTrace = ServiceClientTracing.IsEnabled; + string invocationId = null; + if (shouldTrace) { - _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + invocationId = ServiceClientTracing.NextInvocationId.ToString(); Dictionary tracingParameters = new Dictionary(); tracingParameters.Add("name", name); tracingParameters.Add("@namespace", @namespace); tracingParameters.Add("ports", ports); tracingParameters.Add("webSocketSubProtocol", webSocketSubProtocol); tracingParameters.Add("cancellationToken", cancellationToken); - ServiceClientTracing.Enter(_invocationId, this, nameof(WebSocketNamespacedPodPortForwardAsync), + ServiceClientTracing.Enter(invocationId, this, nameof(WebSocketNamespacedPodPortForwardAsync), tracingParameters); } @@ -208,7 +208,7 @@ namespace k8s uriBuilder.Query = q.ToString(); - return StreamConnectAsync(uriBuilder.Uri, _invocationId, webSocketSubProtocol, customHeaders, + return StreamConnectAsync(uriBuilder.Uri, invocationId, webSocketSubProtocol, customHeaders, cancellationToken); } @@ -229,11 +229,11 @@ namespace k8s } // Tracing - bool _shouldTrace = ServiceClientTracing.IsEnabled; - string _invocationId = null; - if (_shouldTrace) + bool shouldTrace = ServiceClientTracing.IsEnabled; + string invocationId = null; + if (shouldTrace) { - _invocationId = ServiceClientTracing.NextInvocationId.ToString(); + invocationId = ServiceClientTracing.NextInvocationId.ToString(); Dictionary tracingParameters = new Dictionary(); tracingParameters.Add("container", container); tracingParameters.Add("name", name); @@ -244,7 +244,7 @@ namespace k8s tracingParameters.Add("tty", tty); tracingParameters.Add("webSocketSubProtol", webSocketSubProtol); tracingParameters.Add("cancellationToken", cancellationToken); - ServiceClientTracing.Enter(_invocationId, this, nameof(WebSocketNamespacedPodAttachAsync), + ServiceClientTracing.Enter(invocationId, this, nameof(WebSocketNamespacedPodAttachAsync), tracingParameters); } @@ -268,7 +268,7 @@ namespace k8s uriBuilder.Query = query.ToString(1, query.Length - 1); // UriBuilder.Query doesn't like leading '?' chars, so trim it - return StreamConnectAsync(uriBuilder.Uri, _invocationId, webSocketSubProtol, customHeaders, + return StreamConnectAsync(uriBuilder.Uri, invocationId, webSocketSubProtol, customHeaders, cancellationToken); } @@ -276,7 +276,7 @@ namespace k8s string webSocketSubProtocol = null, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) { - bool _shouldTrace = ServiceClientTracing.IsEnabled; + bool shouldTrace = ServiceClientTracing.IsEnabled; // Create WebSocket transport objects WebSocketBuilder webSocketBuilder = this.CreateWebSocketBuilder(); @@ -284,9 +284,9 @@ namespace k8s // Set Headers if (customHeaders != null) { - foreach (var _header in customHeaders) + foreach (var header in customHeaders) { - webSocketBuilder.SetRequestHeader(_header.Key, string.Join(" ", _header.Value)); + webSocketBuilder.SetRequestHeader(header.Key, string.Join(" ", header.Value)); } } @@ -306,9 +306,9 @@ namespace k8s HttpRequestMessage message = new HttpRequestMessage(); await this.Credentials.ProcessHttpRequestAsync(message, cancellationToken).ConfigureAwait(false); - foreach (var _header in message.Headers) + foreach (var header in message.Headers) { - webSocketBuilder.SetRequestHeader(_header.Key, string.Join(" ", _header.Value)); + webSocketBuilder.SetRequestHeader(header.Key, string.Join(" ", header.Value)); } } @@ -347,8 +347,8 @@ namespace k8s } catch (WebSocketException wse) when (wse.WebSocketErrorCode == WebSocketError.HeaderError || (wse.InnerException is WebSocketException && - ((WebSocketException)wse.InnerException).WebSocketErrorCode == - WebSocketError.HeaderError)) + ((WebSocketException)wse.InnerException).WebSocketErrorCode == + WebSocketError.HeaderError)) { // This usually indicates the server sent an error message, like 400 Bad Request. Unfortunately, the WebSocket client // class doesn't give us a lot of information about what went wrong. So, retry the connection. @@ -392,7 +392,7 @@ namespace k8s } catch (Exception ex) { - if (_shouldTrace) + if (shouldTrace) { ServiceClientTracing.Error(invocationId, ex); } @@ -401,7 +401,7 @@ namespace k8s } finally { - if (_shouldTrace) + if (shouldTrace) { ServiceClientTracing.Exit(invocationId, null); } diff --git a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs index 5a19236..0cb058e 100644 --- a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs +++ b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs @@ -11,7 +11,6 @@ using k8s.Authentication; using k8s.Exceptions; using k8s.KubeConfigModels; - namespace k8s { public partial class KubernetesClientConfiguration @@ -334,7 +333,7 @@ namespace k8s var config = userDetails.UserCredentials.AuthProvider.Config; if (config.ContainsKey("expires-on")) { - var expiresOn = Int32.Parse(config["expires-on"]); + var expiresOn = int.Parse(config["expires-on"]); DateTimeOffset expires; #if NET452 var epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); @@ -344,18 +343,18 @@ namespace k8s expires = DateTimeOffset.FromUnixTimeSeconds(expiresOn); #endif - if (DateTimeOffset.Compare(expires - , DateTimeOffset.Now) + if (DateTimeOffset.Compare(expires, + DateTimeOffset.Now) <= 0) { var tenantId = config["tenant-id"]; var clientId = config["client-id"]; var apiServerId = config["apiserver-id"]; var refresh = config["refresh-token"]; - var newToken = RenewAzureToken(tenantId - , clientId - , apiServerId - , refresh); + var newToken = RenewAzureToken(tenantId, + clientId, + apiServerId, + refresh); config["access-token"] = newToken; } } @@ -364,6 +363,7 @@ namespace k8s userCredentialsFound = true; break; } + case "gcp": { // config @@ -416,9 +416,9 @@ namespace k8s { var execInfo = new Dictionary { - {"apiVersion", config.ApiVersion }, - {"kind", "ExecCredentials" }, - {"spec", new Dictionary { {"interactive", Environment.UserInteractive } } }, + { "apiVersion", config.ApiVersion }, + { "kind", "ExecCredentials" }, + { "spec", new Dictionary { { "interactive", Environment.UserInteractive } } }, }; var process = new Process(); @@ -508,6 +508,7 @@ namespace k8s { throw new KubeConfigException($"external exec failed missing clientKeyData field in plugin output"); } + return (null, responseObject.Status["clientCertificateData"], responseObject.Status["clientKeyData"]); } else @@ -733,7 +734,7 @@ namespace k8s private static IEnumerable MergeLists(IEnumerable baseList, IEnumerable mergeList, Func getNameFunc) { - if (mergeList != null && mergeList.Count() > 0) + if (mergeList != null && mergeList.Any()) { var mapping = new Dictionary(); foreach (var item in baseList) diff --git a/src/KubernetesClient/KubernetesClientConfiguration.InCluster.cs b/src/KubernetesClient/KubernetesClientConfiguration.InCluster.cs index 54c167d..ad32fb7 100644 --- a/src/KubernetesClient/KubernetesClientConfiguration.InCluster.cs +++ b/src/KubernetesClient/KubernetesClientConfiguration.InCluster.cs @@ -7,7 +7,7 @@ namespace k8s { public partial class KubernetesClientConfiguration { - private static string ServiceAccountPath = + private static string serviceAccountPath = Path.Combine(new string[] { $"{Path.DirectorySeparatorChar}var", "run", "secrets", "kubernetes.io", "serviceaccount", @@ -16,7 +16,7 @@ namespace k8s private const string ServiceAccountTokenKeyFileName = "token"; private const string ServiceAccountRootCAKeyFileName = "ca.crt"; - public static Boolean IsInCluster() + public static bool IsInCluster() { var host = Environment.GetEnvironmentVariable("KUBERNETES_SERVICE_HOST"); var port = Environment.GetEnvironmentVariable("KUBERNETES_SERVICE_PORT"); @@ -25,13 +25,13 @@ namespace k8s return false; } - var tokenPath = Path.Combine(ServiceAccountPath, ServiceAccountTokenKeyFileName); + var tokenPath = Path.Combine(serviceAccountPath, ServiceAccountTokenKeyFileName); if (!File.Exists(tokenPath)) { return false; } - var certPath = Path.Combine(ServiceAccountPath, ServiceAccountRootCAKeyFileName); + var certPath = Path.Combine(serviceAccountPath, ServiceAccountRootCAKeyFileName); return File.Exists(certPath); } @@ -43,14 +43,14 @@ namespace k8s "unable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined"); } - var rootCAFile = Path.Combine(ServiceAccountPath, ServiceAccountRootCAKeyFileName); + var rootCAFile = Path.Combine(serviceAccountPath, ServiceAccountRootCAKeyFileName); var host = Environment.GetEnvironmentVariable("KUBERNETES_SERVICE_HOST"); var port = Environment.GetEnvironmentVariable("KUBERNETES_SERVICE_PORT"); return new KubernetesClientConfiguration { Host = new UriBuilder("https", host, Convert.ToInt32(port)).ToString(), - TokenProvider = new TokenFileAuth(Path.Combine(ServiceAccountPath, ServiceAccountTokenKeyFileName)), + TokenProvider = new TokenFileAuth(Path.Combine(serviceAccountPath, ServiceAccountTokenKeyFileName)), SslCaCerts = CertUtils.LoadPemFileCert(rootCAFile), }; } diff --git a/src/KubernetesClient/KubernetesEntityAttribute.cs b/src/KubernetesClient/KubernetesEntityAttribute.cs index c3f1000..5c98709 100644 --- a/src/KubernetesClient/KubernetesEntityAttribute.cs +++ b/src/KubernetesClient/KubernetesEntityAttribute.cs @@ -5,6 +5,7 @@ namespace k8s.Models /// /// Describes object type in Kubernetes /// + [AttributeUsage(AttributeTargets.Class)] public sealed class KubernetesEntityAttribute : Attribute { /// diff --git a/src/KubernetesClient/KubernetesList.cs b/src/KubernetesClient/KubernetesList.cs index d13a8c7..f1ef5a5 100644 --- a/src/KubernetesClient/KubernetesList.cs +++ b/src/KubernetesClient/KubernetesList.cs @@ -17,7 +17,6 @@ namespace k8s.Models Metadata = metadata; } - /// /// Gets or sets aPIVersion defines the versioned schema of this /// representation of an object. Servers should convert recognized diff --git a/src/KubernetesClient/ModelExtensions.cs b/src/KubernetesClient/ModelExtensions.cs index 1f856b3..cb3ac33 100644 --- a/src/KubernetesClient/ModelExtensions.cs +++ b/src/KubernetesClient/ModelExtensions.cs @@ -1,15 +1,14 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Net; namespace k8s.Models { - ///Adds convenient extensions for Kubernetes objects. + /// Adds convenient extensions for Kubernetes objects. public static class ModelExtensions { - ///Adds the given finalizer to a Kubernetes object if it doesn't already exist. - ///Returns true if the finalizer was added and false if it already existed. + /// Adds the given finalizer to a Kubernetes object if it doesn't already exist. + /// Returns true if the finalizer was added and false if it already existed. public static bool AddFinalizer(this IMetadata obj, string finalizer) { if (string.IsNullOrEmpty(finalizer)) @@ -505,20 +504,4 @@ namespace k8s.Models owner.Uid == obj.Uid(); } } - - public partial class V1Status - { - /// Converts a object into a short description of the status. - public override string ToString() - { - string reason = Reason; - if (string.IsNullOrEmpty(reason) && Code.GetValueOrDefault() != 0) - { - reason = ((HttpStatusCode)Code.Value).ToString(); - } - - return string.IsNullOrEmpty(Message) ? string.IsNullOrEmpty(reason) ? Status : reason : - string.IsNullOrEmpty(reason) ? Message : $"{reason} - {Message}"; - } - } } diff --git a/src/KubernetesClient/QuantityConverter.cs b/src/KubernetesClient/QuantityConverter.cs new file mode 100644 index 0000000..e498fae --- /dev/null +++ b/src/KubernetesClient/QuantityConverter.cs @@ -0,0 +1,32 @@ +using System; +using Newtonsoft.Json; + +namespace k8s.Models +{ + internal class QuantityConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var q = (ResourceQuantity)value; + + if (q != null) + { + serializer.Serialize(writer, q.ToString()); + return; + } + + serializer.Serialize(writer, value); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + JsonSerializer serializer) + { + return new ResourceQuantity(serializer.Deserialize(reader)); + } + + public override bool CanConvert(Type objectType) + { + return objectType == typeof(string); + } + } +} diff --git a/src/KubernetesClient/ResourceQuantity.cs b/src/KubernetesClient/ResourceQuantity.cs index e672e07..672b03d 100644 --- a/src/KubernetesClient/ResourceQuantity.cs +++ b/src/KubernetesClient/ResourceQuantity.cs @@ -11,33 +11,6 @@ using YamlDotNet.Serialization; namespace k8s.Models { - internal class QuantityConverter : JsonConverter - { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var q = (ResourceQuantity)value; - - if (q != null) - { - serializer.Serialize(writer, q.ToString()); - return; - } - - serializer.Serialize(writer, value); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, - JsonSerializer serializer) - { - return new ResourceQuantity(serializer.Deserialize(reader)); - } - - public override bool CanConvert(Type objectType) - { - return objectType == typeof(string); - } - } - /// /// port https://github.com/kubernetes/apimachinery/blob/master/pkg/api/resource/quantity.go to c# /// Quantity is a fixed-point representation of a number. @@ -166,7 +139,7 @@ namespace k8s.Models { if (suffixFormat == SuffixFormat.BinarySI) { - if (-1024 < _unitlessValue && _unitlessValue < 1024) + if (_unitlessValue > -1024 && _unitlessValue < 1024) { return Suffixer.AppendMaxSuffix(_unitlessValue, SuffixFormat.DecimalSI); } @@ -253,8 +226,6 @@ namespace k8s.Models return new ResourceQuantity(v, 0, SuffixFormat.DecimalExponent); } - #region suffixer - private class Suffixer { private static readonly IReadOnlyDictionary BinSuffixes = @@ -262,28 +233,28 @@ namespace k8s.Models { // Don't emit an error when trying to produce // a suffix for 2^0. - {"", (2, 0) }, - {"Ki", (2, 10) }, - {"Mi", (2, 20) }, - {"Gi", (2, 30) }, - {"Ti", (2, 40) }, - {"Pi", (2, 50) }, - {"Ei", (2, 60) }, + { "", (2, 0) }, + { "Ki", (2, 10) }, + { "Mi", (2, 20) }, + { "Gi", (2, 30) }, + { "Ti", (2, 40) }, + { "Pi", (2, 50) }, + { "Ei", (2, 60) }, }; private static readonly IReadOnlyDictionary DecSuffixes = new Dictionary { - {"n", (10, -9) }, - {"u", (10, -6) }, - {"m", (10, -3) }, - {"", (10, 0) }, - {"k", (10, 3) }, - {"M", (10, 6) }, - {"G", (10, 9) }, - {"T", (10, 12) }, - {"P", (10, 15) }, - {"E", (10, 18) }, + { "n", (10, -9) }, + { "u", (10, -6) }, + { "m", (10, -3) }, + { "", (10, 0) }, + { "k", (10, 3) }, + { "M", (10, 6) }, + { "G", (10, 9) }, + { "T", (10, 12) }, + { "P", (10, 15) }, + { "E", (10, 18) }, }; public Suffixer(string suffix) @@ -325,7 +296,6 @@ namespace k8s.Models public int Base { get; } public int Exponent { get; } - public static string AppendMaxSuffix(Fraction value, SuffixFormat format) { if (value.IsZero) @@ -352,7 +322,6 @@ namespace k8s.Models lastv = v; } - if (minE == 0) { return $"{(decimal)lastv}"; @@ -402,7 +371,5 @@ namespace k8s.Models return lastv; } } - - #endregion } } diff --git a/src/KubernetesClient/StreamDemuxer.cs b/src/KubernetesClient/StreamDemuxer.cs index c8d859e..3560a4d 100644 --- a/src/KubernetesClient/StreamDemuxer.cs +++ b/src/KubernetesClient/StreamDemuxer.cs @@ -29,6 +29,7 @@ namespace k8s private readonly StreamType streamType; private readonly bool ownsSocket; private Task runLoop; + private bool disposedValue; /// /// Initializes a new instance of the class. @@ -58,31 +59,9 @@ namespace k8s /// public void Start() { - this.runLoop = Task.Run(async () => await this.RunLoop(this.cts.Token)); + this.runLoop = Task.Run(async () => await RunLoop(cts.Token).ConfigureAwait(false)); } - /// - public void Dispose() - { - try - { - if (this.runLoop != null) - { - this.cts.Cancel(); - this.runLoop.Wait(); - } - } - catch (Exception ex) - { - // Dispose methods can never throw. - Debug.Write(ex); - } - - if (this.ownsSocket) - { - this.webSocket.Dispose(); - } - } /// /// Gets a which allows you to read to and/or write from a remote channel. @@ -276,5 +255,49 @@ namespace k8s this.ConnectionClosed?.Invoke(this, EventArgs.Empty); } } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + try + { + if (this.runLoop != null) + { + this.cts.Cancel(); + this.runLoop.Wait(); + } + } + catch (Exception ex) + { + // Dispose methods can never throw. + Debug.Write(ex); + } + + if (this.ownsSocket) + { + this.webSocket.Dispose(); + } + } + + disposedValue = true; + } + } + + // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources + // ~StreamDemuxer() + // { + // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + // Dispose(disposing: false); + // } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } } } diff --git a/src/KubernetesClient/V1Patch.cs b/src/KubernetesClient/V1Patch.cs index 827e207..8f32fe2 100644 --- a/src/KubernetesClient/V1Patch.cs +++ b/src/KubernetesClient/V1Patch.cs @@ -4,26 +4,6 @@ using Newtonsoft.Json; namespace k8s.Models { - internal class V1PathJsonConverter : JsonConverter - { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - serializer.Serialize(writer, (value as V1Patch)?.Content); - } - - // no read patch object supported at the moment - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, - JsonSerializer serializer) - { - throw new NotImplementedException(); - } - - public override bool CanConvert(Type objectType) - { - return objectType == typeof(V1Patch); - } - } - [JsonConverter(typeof(V1PathJsonConverter))] public partial class V1Patch { diff --git a/src/KubernetesClient/V1PathJsonConverter.cs b/src/KubernetesClient/V1PathJsonConverter.cs new file mode 100644 index 0000000..82611ae --- /dev/null +++ b/src/KubernetesClient/V1PathJsonConverter.cs @@ -0,0 +1,25 @@ +using System; +using Newtonsoft.Json; + +namespace k8s.Models +{ + internal class V1PathJsonConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + serializer.Serialize(writer, (value as V1Patch)?.Content); + } + + // no read patch object supported at the moment + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + JsonSerializer serializer) + { + throw new NotImplementedException(); + } + + public override bool CanConvert(Type objectType) + { + return objectType == typeof(V1Patch); + } + } +} diff --git a/src/KubernetesClient/V1Status.cs b/src/KubernetesClient/V1Status.cs new file mode 100644 index 0000000..020c696 --- /dev/null +++ b/src/KubernetesClient/V1Status.cs @@ -0,0 +1,20 @@ +using System.Net; + +namespace k8s.Models +{ + public partial class V1Status + { + /// Converts a object into a short description of the status. + public override string ToString() + { + string reason = Reason; + if (string.IsNullOrEmpty(reason) && Code.GetValueOrDefault() != 0) + { + reason = ((HttpStatusCode)Code.Value).ToString(); + } + + return string.IsNullOrEmpty(Message) ? string.IsNullOrEmpty(reason) ? Status : reason : + string.IsNullOrEmpty(reason) ? Message : $"{reason} - {Message}"; + } + } +} diff --git a/src/KubernetesClient/Versioning/KubernetesVersionComparitor.cs b/src/KubernetesClient/Versioning/KubernetesVersionComparer.cs similarity index 95% rename from src/KubernetesClient/Versioning/KubernetesVersionComparitor.cs rename to src/KubernetesClient/Versioning/KubernetesVersionComparer.cs index e2443f5..5dd87fa 100644 --- a/src/KubernetesClient/Versioning/KubernetesVersionComparitor.cs +++ b/src/KubernetesClient/Versioning/KubernetesVersionComparer.cs @@ -7,7 +7,7 @@ namespace k8s.Versioning public class KubernetesVersionComparer : IComparer { public static KubernetesVersionComparer Instance { get; private set; } - static readonly Regex _kubernetesVersionRegex; + private static readonly Regex _kubernetesVersionRegex; static KubernetesVersionComparer() { @@ -59,7 +59,7 @@ namespace k8s.Versioning { Alpha = 1, Beta = 2, - Final = 3 + Final = 3, } } } diff --git a/src/KubernetesClient/Watcher.cs b/src/KubernetesClient/Watcher.cs index 78417f6..1a7db5e 100644 --- a/src/KubernetesClient/Watcher.cs +++ b/src/KubernetesClient/Watcher.cs @@ -3,9 +3,7 @@ using System.IO; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using k8s.Exceptions; using k8s.Models; -using Microsoft.Rest; using Microsoft.Rest.Serialization; namespace k8s @@ -44,6 +42,7 @@ namespace k8s private readonly Func> _streamReaderCreator; private TextReader _streamReader; + private bool disposedValue; private readonly Task _watcherLoop; /// @@ -93,14 +92,7 @@ namespace k8s OnClosed += onClosed; _cts = new CancellationTokenSource(); - _watcherLoop = Task.Run(async () => await this.WatcherLoop(_cts.Token)); - } - - /// - public void Dispose() - { - _cts.Cancel(); - _streamReader?.Dispose(); + _watcherLoop = Task.Run(async () => await WatcherLoop(_cts.Token).ConfigureAwait(false)); } /// @@ -176,58 +168,33 @@ namespace k8s OnClosed?.Invoke(); } } - } - public static class WatcherExt - { - /// - /// create a watch object from a call to api server with watch=true - /// - /// type of the event object - /// type of the HttpOperationResponse object - /// the api response - /// a callback when any event raised from api server - /// a callbak when any exception was caught during watching - /// - /// The action to invoke when the server closes the connection. - /// - /// a watch object - public static Watcher Watch(this Task> responseTask, - Action onEvent, - Action onError = null, - Action onClosed = null) + protected virtual void Dispose(bool disposing) { - return new Watcher(async () => + if (!disposedValue) { - var response = await responseTask.ConfigureAwait(false); - - if (!(response.Response.Content is WatcherDelegatingHandler.LineSeparatedHttpContent content)) + if (disposing) { - throw new KubernetesClientException("not a watchable request or failed response"); + _cts.Cancel(); + _streamReader?.Dispose(); } - return content.StreamReader; - }, onEvent, onError, onClosed); + disposedValue = true; + } } - /// - /// create a watch object from a call to api server with watch=true - /// - /// type of the event object - /// type of the HttpOperationResponse object - /// the api response - /// a callback when any event raised from api server - /// a callbak when any exception was caught during watching - /// - /// The action to invoke when the server closes the connection. - /// - /// a watch object - public static Watcher Watch(this HttpOperationResponse response, - Action onEvent, - Action onError = null, - Action onClosed = null) + // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources + // ~Watcher() + // { + // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + // Dispose(disposing: false); + // } + + public void Dispose() { - return Watch(Task.FromResult(response), onEvent, onError, onClosed); + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); } } } diff --git a/src/KubernetesClient/WatcherDelegatingHandler.cs b/src/KubernetesClient/WatcherDelegatingHandler.cs index f65ed31..8ce0402 100644 --- a/src/KubernetesClient/WatcherDelegatingHandler.cs +++ b/src/KubernetesClient/WatcherDelegatingHandler.cs @@ -20,7 +20,8 @@ namespace k8s { var originResponse = await base.SendAsync(request, cancellationToken).ConfigureAwait(false); - if (originResponse.IsSuccessStatusCode && request.Method == HttpMethod.Get) // all watches are GETs, so we can ignore others + // all watches are GETs, so we can ignore others + if (originResponse.IsSuccessStatusCode && request.Method == HttpMethod.Get) { string query = request.RequestUri.Query; int index = query.IndexOf("watch=true"); diff --git a/src/KubernetesClient/WatcherExt.cs b/src/KubernetesClient/WatcherExt.cs new file mode 100644 index 0000000..5f2fc68 --- /dev/null +++ b/src/KubernetesClient/WatcherExt.cs @@ -0,0 +1,60 @@ +using System; +using System.Threading.Tasks; +using k8s.Exceptions; +using Microsoft.Rest; + +namespace k8s +{ + public static class WatcherExt + { + /// + /// create a watch object from a call to api server with watch=true + /// + /// type of the event object + /// type of the HttpOperationResponse object + /// the api response + /// a callback when any event raised from api server + /// a callbak when any exception was caught during watching + /// + /// The action to invoke when the server closes the connection. + /// + /// a watch object + public static Watcher Watch(this Task> responseTask, + Action onEvent, + Action onError = null, + Action onClosed = null) + { + return new Watcher(async () => + { + var response = await responseTask.ConfigureAwait(false); + + if (!(response.Response.Content is WatcherDelegatingHandler.LineSeparatedHttpContent content)) + { + throw new KubernetesClientException("not a watchable request or failed response"); + } + + return content.StreamReader; + }, onEvent, onError, onClosed); + } + + /// + /// create a watch object from a call to api server with watch=true + /// + /// type of the event object + /// type of the HttpOperationResponse object + /// the api response + /// a callback when any event raised from api server + /// a callbak when any exception was caught during watching + /// + /// The action to invoke when the server closes the connection. + /// + /// a watch object + public static Watcher Watch(this HttpOperationResponse response, + Action onEvent, + Action onError = null, + Action onClosed = null) + { + return Watch(Task.FromResult(response), onEvent, onError, onClosed); + } + } +} diff --git a/src/KubernetesClient/Yaml.cs b/src/KubernetesClient/Yaml.cs index 309a38e..04a3c09 100644 --- a/src/KubernetesClient/Yaml.cs +++ b/src/KubernetesClient/Yaml.cs @@ -22,7 +22,7 @@ namespace k8s { public bool Accepts(Type type) { - return type == typeof(System.Byte[]); + return type == typeof(byte[]); } public object ReadYaml(IParser parser, Type type) @@ -49,7 +49,7 @@ namespace k8s public void WriteYaml(IEmitter emitter, object value, Type type) { - var obj = (System.Byte[])value; + var obj = (byte[])value; emitter.Emit(new YamlDotNet.Core.Events.Scalar(Encoding.UTF8.GetString(obj))); } } @@ -63,7 +63,7 @@ namespace k8s /// /// A map from / to Type. For example "v1/Pod" -> typeof(V1Pod) /// - public static async Task> LoadAllFromStreamAsync(Stream stream, Dictionary typeMap) + public static async Task> LoadAllFromStreamAsync(Stream stream, Dictionary typeMap) { var reader = new StreamReader(stream); var content = await reader.ReadToEndAsync().ConfigureAwait(false); @@ -79,7 +79,7 @@ namespace k8s /// /// A map from / to Type. For example "v1/Pod" -> typeof(V1Pod) /// - public static Task> LoadAllFromFileAsync(String fileName, Dictionary typeMap) + public static Task> LoadAllFromFileAsync(string fileName, Dictionary typeMap) { var reader = File.OpenRead(fileName); return LoadAllFromStreamAsync(reader, typeMap); @@ -94,7 +94,7 @@ namespace k8s /// /// A map from / to Type. For example "v1/Pod" -> typeof(V1Pod) /// - public static List LoadAllFromString(String content, Dictionary typeMap) + public static List LoadAllFromString(string content, Dictionary typeMap) { var deserializer = new DeserializerBuilder() @@ -221,7 +221,7 @@ namespace k8s // This might have been renamed by AutoRest. See if there is a // JsonPropertyAttribute.PropertyName and use that instead if there is. var jpa = pd.GetCustomAttribute(); - if (jpa == null || String.IsNullOrEmpty(jpa.PropertyName)) + if (jpa == null || string.IsNullOrEmpty(jpa.PropertyName)) { return pd; } diff --git a/src/KubernetesClient/generated/ModelOperators.cs b/src/KubernetesClient/generated/ModelOperators.cs index 13a909c..a9a85ba 100644 --- a/src/KubernetesClient/generated/ModelOperators.cs +++ b/src/KubernetesClient/generated/ModelOperators.cs @@ -1,3 +1,8 @@ +// +// Code generated by gen/KubernetesWatchGenerator +// Changes may cause incorrect behavior and will be lost if the code is +// regenerated. +// using k8s.Versioning; namespace k8s.Models @@ -6,1262 +11,1577 @@ namespace k8s.Models { public static explicit operator Admissionregistrationv1beta1ServiceReference(Admissionregistrationv1ServiceReference s) => VersionConverter.Mapper.Map(s); } + public partial class Admissionregistrationv1ServiceReference { public static explicit operator Admissionregistrationv1ServiceReference(Admissionregistrationv1beta1ServiceReference s) => VersionConverter.Mapper.Map(s); } + public partial class Admissionregistrationv1beta1WebhookClientConfig { public static explicit operator Admissionregistrationv1beta1WebhookClientConfig(Admissionregistrationv1WebhookClientConfig s) => VersionConverter.Mapper.Map(s); } + public partial class Admissionregistrationv1WebhookClientConfig { public static explicit operator Admissionregistrationv1WebhookClientConfig(Admissionregistrationv1beta1WebhookClientConfig s) => VersionConverter.Mapper.Map(s); } + public partial class V1AggregationRule { public static explicit operator V1AggregationRule(V1alpha1AggregationRule s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1AggregationRule { public static explicit operator V1alpha1AggregationRule(V1AggregationRule s) => VersionConverter.Mapper.Map(s); } + public partial class V1AggregationRule { public static explicit operator V1AggregationRule(V1beta1AggregationRule s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1AggregationRule { public static explicit operator V1beta1AggregationRule(V1AggregationRule s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1AggregationRule { public static explicit operator V1alpha1AggregationRule(V1beta1AggregationRule s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1AggregationRule { public static explicit operator V1beta1AggregationRule(V1alpha1AggregationRule s) => VersionConverter.Mapper.Map(s); } + public partial class Apiextensionsv1beta1ServiceReference { public static explicit operator Apiextensionsv1beta1ServiceReference(Apiextensionsv1ServiceReference s) => VersionConverter.Mapper.Map(s); } + public partial class Apiextensionsv1ServiceReference { public static explicit operator Apiextensionsv1ServiceReference(Apiextensionsv1beta1ServiceReference s) => VersionConverter.Mapper.Map(s); } + public partial class Apiextensionsv1beta1WebhookClientConfig { public static explicit operator Apiextensionsv1beta1WebhookClientConfig(Apiextensionsv1WebhookClientConfig s) => VersionConverter.Mapper.Map(s); } + public partial class Apiextensionsv1WebhookClientConfig { public static explicit operator Apiextensionsv1WebhookClientConfig(Apiextensionsv1beta1WebhookClientConfig s) => VersionConverter.Mapper.Map(s); } + public partial class Apiregistrationv1beta1ServiceReference { public static explicit operator Apiregistrationv1beta1ServiceReference(Apiregistrationv1ServiceReference s) => VersionConverter.Mapper.Map(s); } + public partial class Apiregistrationv1ServiceReference { public static explicit operator Apiregistrationv1ServiceReference(Apiregistrationv1beta1ServiceReference s) => VersionConverter.Mapper.Map(s); } + public partial class V1APIService { public static explicit operator V1APIService(V1beta1APIService s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1APIService { public static explicit operator V1beta1APIService(V1APIService s) => VersionConverter.Mapper.Map(s); } + public partial class V1APIServiceCondition { public static explicit operator V1APIServiceCondition(V1beta1APIServiceCondition s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1APIServiceCondition { public static explicit operator V1beta1APIServiceCondition(V1APIServiceCondition s) => VersionConverter.Mapper.Map(s); } + public partial class V1APIServiceList { public static explicit operator V1APIServiceList(V1beta1APIServiceList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1APIServiceList { public static explicit operator V1beta1APIServiceList(V1APIServiceList s) => VersionConverter.Mapper.Map(s); } + public partial class V1APIServiceSpec { public static explicit operator V1APIServiceSpec(V1beta1APIServiceSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1APIServiceSpec { public static explicit operator V1beta1APIServiceSpec(V1APIServiceSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1APIServiceStatus { public static explicit operator V1APIServiceStatus(V1beta1APIServiceStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1APIServiceStatus { public static explicit operator V1beta1APIServiceStatus(V1APIServiceStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1ClusterRole { public static explicit operator V1alpha1ClusterRole(V1beta1ClusterRole s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1ClusterRole { public static explicit operator V1beta1ClusterRole(V1alpha1ClusterRole s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1ClusterRole { public static explicit operator V1alpha1ClusterRole(V1ClusterRole s) => VersionConverter.Mapper.Map(s); } + public partial class V1ClusterRole { public static explicit operator V1ClusterRole(V1alpha1ClusterRole s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1ClusterRole { public static explicit operator V1beta1ClusterRole(V1ClusterRole s) => VersionConverter.Mapper.Map(s); } + public partial class V1ClusterRole { public static explicit operator V1ClusterRole(V1beta1ClusterRole s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1ClusterRoleBinding { public static explicit operator V1alpha1ClusterRoleBinding(V1beta1ClusterRoleBinding s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1ClusterRoleBinding { public static explicit operator V1beta1ClusterRoleBinding(V1alpha1ClusterRoleBinding s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1ClusterRoleBinding { public static explicit operator V1alpha1ClusterRoleBinding(V1ClusterRoleBinding s) => VersionConverter.Mapper.Map(s); } + public partial class V1ClusterRoleBinding { public static explicit operator V1ClusterRoleBinding(V1alpha1ClusterRoleBinding s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1ClusterRoleBinding { public static explicit operator V1beta1ClusterRoleBinding(V1ClusterRoleBinding s) => VersionConverter.Mapper.Map(s); } + public partial class V1ClusterRoleBinding { public static explicit operator V1ClusterRoleBinding(V1beta1ClusterRoleBinding s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1ClusterRoleBindingList { public static explicit operator V1alpha1ClusterRoleBindingList(V1beta1ClusterRoleBindingList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1ClusterRoleBindingList { public static explicit operator V1beta1ClusterRoleBindingList(V1alpha1ClusterRoleBindingList s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1ClusterRoleBindingList { public static explicit operator V1alpha1ClusterRoleBindingList(V1ClusterRoleBindingList s) => VersionConverter.Mapper.Map(s); } + public partial class V1ClusterRoleBindingList { public static explicit operator V1ClusterRoleBindingList(V1alpha1ClusterRoleBindingList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1ClusterRoleBindingList { public static explicit operator V1beta1ClusterRoleBindingList(V1ClusterRoleBindingList s) => VersionConverter.Mapper.Map(s); } + public partial class V1ClusterRoleBindingList { public static explicit operator V1ClusterRoleBindingList(V1beta1ClusterRoleBindingList s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1ClusterRoleList { public static explicit operator V1alpha1ClusterRoleList(V1beta1ClusterRoleList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1ClusterRoleList { public static explicit operator V1beta1ClusterRoleList(V1alpha1ClusterRoleList s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1ClusterRoleList { public static explicit operator V1alpha1ClusterRoleList(V1ClusterRoleList s) => VersionConverter.Mapper.Map(s); } + public partial class V1ClusterRoleList { public static explicit operator V1ClusterRoleList(V1alpha1ClusterRoleList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1ClusterRoleList { public static explicit operator V1beta1ClusterRoleList(V1ClusterRoleList s) => VersionConverter.Mapper.Map(s); } + public partial class V1ClusterRoleList { public static explicit operator V1ClusterRoleList(V1beta1ClusterRoleList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CronJob { public static explicit operator V1beta1CronJob(V2alpha1CronJob s) => VersionConverter.Mapper.Map(s); } + public partial class V2alpha1CronJob { public static explicit operator V2alpha1CronJob(V1beta1CronJob s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CronJobList { public static explicit operator V1beta1CronJobList(V2alpha1CronJobList s) => VersionConverter.Mapper.Map(s); } + public partial class V2alpha1CronJobList { public static explicit operator V2alpha1CronJobList(V1beta1CronJobList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CronJobSpec { public static explicit operator V1beta1CronJobSpec(V2alpha1CronJobSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V2alpha1CronJobSpec { public static explicit operator V2alpha1CronJobSpec(V1beta1CronJobSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CronJobStatus { public static explicit operator V1beta1CronJobStatus(V2alpha1CronJobStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V2alpha1CronJobStatus { public static explicit operator V2alpha1CronJobStatus(V1beta1CronJobStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1CrossVersionObjectReference { public static explicit operator V1CrossVersionObjectReference(V2beta1CrossVersionObjectReference s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1CrossVersionObjectReference { public static explicit operator V2beta1CrossVersionObjectReference(V1CrossVersionObjectReference s) => VersionConverter.Mapper.Map(s); } + public partial class V1CrossVersionObjectReference { public static explicit operator V1CrossVersionObjectReference(V2beta2CrossVersionObjectReference s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2CrossVersionObjectReference { public static explicit operator V2beta2CrossVersionObjectReference(V1CrossVersionObjectReference s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1CrossVersionObjectReference { public static explicit operator V2beta1CrossVersionObjectReference(V2beta2CrossVersionObjectReference s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2CrossVersionObjectReference { public static explicit operator V2beta2CrossVersionObjectReference(V2beta1CrossVersionObjectReference s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CSIDriver { public static explicit operator V1beta1CSIDriver(V1CSIDriver s) => VersionConverter.Mapper.Map(s); } + public partial class V1CSIDriver { public static explicit operator V1CSIDriver(V1beta1CSIDriver s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CSIDriverList { public static explicit operator V1beta1CSIDriverList(V1CSIDriverList s) => VersionConverter.Mapper.Map(s); } + public partial class V1CSIDriverList { public static explicit operator V1CSIDriverList(V1beta1CSIDriverList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CSIDriverSpec { public static explicit operator V1beta1CSIDriverSpec(V1CSIDriverSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1CSIDriverSpec { public static explicit operator V1CSIDriverSpec(V1beta1CSIDriverSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CSINode { public static explicit operator V1beta1CSINode(V1CSINode s) => VersionConverter.Mapper.Map(s); } + public partial class V1CSINode { public static explicit operator V1CSINode(V1beta1CSINode s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CSINodeDriver { public static explicit operator V1beta1CSINodeDriver(V1CSINodeDriver s) => VersionConverter.Mapper.Map(s); } + public partial class V1CSINodeDriver { public static explicit operator V1CSINodeDriver(V1beta1CSINodeDriver s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CSINodeList { public static explicit operator V1beta1CSINodeList(V1CSINodeList s) => VersionConverter.Mapper.Map(s); } + public partial class V1CSINodeList { public static explicit operator V1CSINodeList(V1beta1CSINodeList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CSINodeSpec { public static explicit operator V1beta1CSINodeSpec(V1CSINodeSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1CSINodeSpec { public static explicit operator V1CSINodeSpec(V1beta1CSINodeSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CustomResourceColumnDefinition { public static explicit operator V1beta1CustomResourceColumnDefinition(V1CustomResourceColumnDefinition s) => VersionConverter.Mapper.Map(s); } + public partial class V1CustomResourceColumnDefinition { public static explicit operator V1CustomResourceColumnDefinition(V1beta1CustomResourceColumnDefinition s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CustomResourceConversion { public static explicit operator V1beta1CustomResourceConversion(V1CustomResourceConversion s) => VersionConverter.Mapper.Map(s); } + public partial class V1CustomResourceConversion { public static explicit operator V1CustomResourceConversion(V1beta1CustomResourceConversion s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CustomResourceDefinition { public static explicit operator V1beta1CustomResourceDefinition(V1CustomResourceDefinition s) => VersionConverter.Mapper.Map(s); } + public partial class V1CustomResourceDefinition { public static explicit operator V1CustomResourceDefinition(V1beta1CustomResourceDefinition s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CustomResourceDefinitionCondition { public static explicit operator V1beta1CustomResourceDefinitionCondition(V1CustomResourceDefinitionCondition s) => VersionConverter.Mapper.Map(s); } + public partial class V1CustomResourceDefinitionCondition { public static explicit operator V1CustomResourceDefinitionCondition(V1beta1CustomResourceDefinitionCondition s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CustomResourceDefinitionList { public static explicit operator V1beta1CustomResourceDefinitionList(V1CustomResourceDefinitionList s) => VersionConverter.Mapper.Map(s); } + public partial class V1CustomResourceDefinitionList { public static explicit operator V1CustomResourceDefinitionList(V1beta1CustomResourceDefinitionList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CustomResourceDefinitionNames { public static explicit operator V1beta1CustomResourceDefinitionNames(V1CustomResourceDefinitionNames s) => VersionConverter.Mapper.Map(s); } + public partial class V1CustomResourceDefinitionNames { public static explicit operator V1CustomResourceDefinitionNames(V1beta1CustomResourceDefinitionNames s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CustomResourceDefinitionSpec { public static explicit operator V1beta1CustomResourceDefinitionSpec(V1CustomResourceDefinitionSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1CustomResourceDefinitionSpec { public static explicit operator V1CustomResourceDefinitionSpec(V1beta1CustomResourceDefinitionSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CustomResourceDefinitionStatus { public static explicit operator V1beta1CustomResourceDefinitionStatus(V1CustomResourceDefinitionStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1CustomResourceDefinitionStatus { public static explicit operator V1CustomResourceDefinitionStatus(V1beta1CustomResourceDefinitionStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CustomResourceDefinitionVersion { public static explicit operator V1beta1CustomResourceDefinitionVersion(V1CustomResourceDefinitionVersion s) => VersionConverter.Mapper.Map(s); } + public partial class V1CustomResourceDefinitionVersion { public static explicit operator V1CustomResourceDefinitionVersion(V1beta1CustomResourceDefinitionVersion s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CustomResourceSubresources { public static explicit operator V1beta1CustomResourceSubresources(V1CustomResourceSubresources s) => VersionConverter.Mapper.Map(s); } + public partial class V1CustomResourceSubresources { public static explicit operator V1CustomResourceSubresources(V1beta1CustomResourceSubresources s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CustomResourceSubresourceScale { public static explicit operator V1beta1CustomResourceSubresourceScale(V1CustomResourceSubresourceScale s) => VersionConverter.Mapper.Map(s); } + public partial class V1CustomResourceSubresourceScale { public static explicit operator V1CustomResourceSubresourceScale(V1beta1CustomResourceSubresourceScale s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1CustomResourceValidation { public static explicit operator V1beta1CustomResourceValidation(V1CustomResourceValidation s) => VersionConverter.Mapper.Map(s); } + public partial class V1CustomResourceValidation { public static explicit operator V1CustomResourceValidation(V1beta1CustomResourceValidation s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1EndpointPort { public static explicit operator V1beta1EndpointPort(V1EndpointPort s) => VersionConverter.Mapper.Map(s); } + public partial class V1EndpointPort { public static explicit operator V1EndpointPort(V1beta1EndpointPort s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1Event { public static explicit operator V1beta1Event(V1Event s) => VersionConverter.Mapper.Map(s); } + public partial class V1Event { public static explicit operator V1Event(V1beta1Event s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1EventList { public static explicit operator V1beta1EventList(V1EventList s) => VersionConverter.Mapper.Map(s); } + public partial class V1EventList { public static explicit operator V1EventList(V1beta1EventList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1EventSeries { public static explicit operator V1beta1EventSeries(V1EventSeries s) => VersionConverter.Mapper.Map(s); } + public partial class V1EventSeries { public static explicit operator V1EventSeries(V1beta1EventSeries s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1ExternalDocumentation { public static explicit operator V1beta1ExternalDocumentation(V1ExternalDocumentation s) => VersionConverter.Mapper.Map(s); } + public partial class V1ExternalDocumentation { public static explicit operator V1ExternalDocumentation(V1beta1ExternalDocumentation s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1ExternalMetricSource { public static explicit operator V2beta1ExternalMetricSource(V2beta2ExternalMetricSource s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2ExternalMetricSource { public static explicit operator V2beta2ExternalMetricSource(V2beta1ExternalMetricSource s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1ExternalMetricStatus { public static explicit operator V2beta1ExternalMetricStatus(V2beta2ExternalMetricStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2ExternalMetricStatus { public static explicit operator V2beta2ExternalMetricStatus(V2beta1ExternalMetricStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1HorizontalPodAutoscaler { public static explicit operator V1HorizontalPodAutoscaler(V2beta1HorizontalPodAutoscaler s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1HorizontalPodAutoscaler { public static explicit operator V2beta1HorizontalPodAutoscaler(V1HorizontalPodAutoscaler s) => VersionConverter.Mapper.Map(s); } + public partial class V1HorizontalPodAutoscaler { public static explicit operator V1HorizontalPodAutoscaler(V2beta2HorizontalPodAutoscaler s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2HorizontalPodAutoscaler { public static explicit operator V2beta2HorizontalPodAutoscaler(V1HorizontalPodAutoscaler s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1HorizontalPodAutoscaler { public static explicit operator V2beta1HorizontalPodAutoscaler(V2beta2HorizontalPodAutoscaler s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2HorizontalPodAutoscaler { public static explicit operator V2beta2HorizontalPodAutoscaler(V2beta1HorizontalPodAutoscaler s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1HorizontalPodAutoscalerCondition { public static explicit operator V2beta1HorizontalPodAutoscalerCondition(V2beta2HorizontalPodAutoscalerCondition s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2HorizontalPodAutoscalerCondition { public static explicit operator V2beta2HorizontalPodAutoscalerCondition(V2beta1HorizontalPodAutoscalerCondition s) => VersionConverter.Mapper.Map(s); } + public partial class V1HorizontalPodAutoscalerList { public static explicit operator V1HorizontalPodAutoscalerList(V2beta1HorizontalPodAutoscalerList s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1HorizontalPodAutoscalerList { public static explicit operator V2beta1HorizontalPodAutoscalerList(V1HorizontalPodAutoscalerList s) => VersionConverter.Mapper.Map(s); } + public partial class V1HorizontalPodAutoscalerList { public static explicit operator V1HorizontalPodAutoscalerList(V2beta2HorizontalPodAutoscalerList s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2HorizontalPodAutoscalerList { public static explicit operator V2beta2HorizontalPodAutoscalerList(V1HorizontalPodAutoscalerList s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1HorizontalPodAutoscalerList { public static explicit operator V2beta1HorizontalPodAutoscalerList(V2beta2HorizontalPodAutoscalerList s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2HorizontalPodAutoscalerList { public static explicit operator V2beta2HorizontalPodAutoscalerList(V2beta1HorizontalPodAutoscalerList s) => VersionConverter.Mapper.Map(s); } + public partial class V1HorizontalPodAutoscalerSpec { public static explicit operator V1HorizontalPodAutoscalerSpec(V2beta1HorizontalPodAutoscalerSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1HorizontalPodAutoscalerSpec { public static explicit operator V2beta1HorizontalPodAutoscalerSpec(V1HorizontalPodAutoscalerSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1HorizontalPodAutoscalerSpec { public static explicit operator V1HorizontalPodAutoscalerSpec(V2beta2HorizontalPodAutoscalerSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2HorizontalPodAutoscalerSpec { public static explicit operator V2beta2HorizontalPodAutoscalerSpec(V1HorizontalPodAutoscalerSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1HorizontalPodAutoscalerSpec { public static explicit operator V2beta1HorizontalPodAutoscalerSpec(V2beta2HorizontalPodAutoscalerSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2HorizontalPodAutoscalerSpec { public static explicit operator V2beta2HorizontalPodAutoscalerSpec(V2beta1HorizontalPodAutoscalerSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1HorizontalPodAutoscalerStatus { public static explicit operator V1HorizontalPodAutoscalerStatus(V2beta1HorizontalPodAutoscalerStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1HorizontalPodAutoscalerStatus { public static explicit operator V2beta1HorizontalPodAutoscalerStatus(V1HorizontalPodAutoscalerStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1HorizontalPodAutoscalerStatus { public static explicit operator V1HorizontalPodAutoscalerStatus(V2beta2HorizontalPodAutoscalerStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2HorizontalPodAutoscalerStatus { public static explicit operator V2beta2HorizontalPodAutoscalerStatus(V1HorizontalPodAutoscalerStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1HorizontalPodAutoscalerStatus { public static explicit operator V2beta1HorizontalPodAutoscalerStatus(V2beta2HorizontalPodAutoscalerStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2HorizontalPodAutoscalerStatus { public static explicit operator V2beta2HorizontalPodAutoscalerStatus(V2beta1HorizontalPodAutoscalerStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1JobTemplateSpec { public static explicit operator V1beta1JobTemplateSpec(V2alpha1JobTemplateSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V2alpha1JobTemplateSpec { public static explicit operator V2alpha1JobTemplateSpec(V1beta1JobTemplateSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1JSONSchemaProps { public static explicit operator V1beta1JSONSchemaProps(V1JSONSchemaProps s) => VersionConverter.Mapper.Map(s); } + public partial class V1JSONSchemaProps { public static explicit operator V1JSONSchemaProps(V1beta1JSONSchemaProps s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1Lease { public static explicit operator V1beta1Lease(V1Lease s) => VersionConverter.Mapper.Map(s); } + public partial class V1Lease { public static explicit operator V1Lease(V1beta1Lease s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1LeaseList { public static explicit operator V1beta1LeaseList(V1LeaseList s) => VersionConverter.Mapper.Map(s); } + public partial class V1LeaseList { public static explicit operator V1LeaseList(V1beta1LeaseList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1LeaseSpec { public static explicit operator V1beta1LeaseSpec(V1LeaseSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1LeaseSpec { public static explicit operator V1LeaseSpec(V1beta1LeaseSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1LocalSubjectAccessReview { public static explicit operator V1beta1LocalSubjectAccessReview(V1LocalSubjectAccessReview s) => VersionConverter.Mapper.Map(s); } + public partial class V1LocalSubjectAccessReview { public static explicit operator V1LocalSubjectAccessReview(V1beta1LocalSubjectAccessReview s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1MetricSpec { public static explicit operator V2beta1MetricSpec(V2beta2MetricSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2MetricSpec { public static explicit operator V2beta2MetricSpec(V2beta1MetricSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1MetricStatus { public static explicit operator V2beta1MetricStatus(V2beta2MetricStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2MetricStatus { public static explicit operator V2beta2MetricStatus(V2beta1MetricStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1MutatingWebhook { public static explicit operator V1beta1MutatingWebhook(V1MutatingWebhook s) => VersionConverter.Mapper.Map(s); } + public partial class V1MutatingWebhook { public static explicit operator V1MutatingWebhook(V1beta1MutatingWebhook s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1MutatingWebhookConfiguration { public static explicit operator V1beta1MutatingWebhookConfiguration(V1MutatingWebhookConfiguration s) => VersionConverter.Mapper.Map(s); } + public partial class V1MutatingWebhookConfiguration { public static explicit operator V1MutatingWebhookConfiguration(V1beta1MutatingWebhookConfiguration s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1MutatingWebhookConfigurationList { public static explicit operator V1beta1MutatingWebhookConfigurationList(V1MutatingWebhookConfigurationList s) => VersionConverter.Mapper.Map(s); } + public partial class V1MutatingWebhookConfigurationList { public static explicit operator V1MutatingWebhookConfigurationList(V1beta1MutatingWebhookConfigurationList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1NonResourceAttributes { public static explicit operator V1beta1NonResourceAttributes(V1NonResourceAttributes s) => VersionConverter.Mapper.Map(s); } + public partial class V1NonResourceAttributes { public static explicit operator V1NonResourceAttributes(V1beta1NonResourceAttributes s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1NonResourceRule { public static explicit operator V1beta1NonResourceRule(V1NonResourceRule s) => VersionConverter.Mapper.Map(s); } + public partial class V1NonResourceRule { public static explicit operator V1NonResourceRule(V1beta1NonResourceRule s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1ObjectMetricSource { public static explicit operator V2beta1ObjectMetricSource(V2beta2ObjectMetricSource s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2ObjectMetricSource { public static explicit operator V2beta2ObjectMetricSource(V2beta1ObjectMetricSource s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1ObjectMetricStatus { public static explicit operator V2beta1ObjectMetricStatus(V2beta2ObjectMetricStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2ObjectMetricStatus { public static explicit operator V2beta2ObjectMetricStatus(V2beta1ObjectMetricStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1Overhead { public static explicit operator V1alpha1Overhead(V1beta1Overhead s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1Overhead { public static explicit operator V1beta1Overhead(V1alpha1Overhead s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1PodsMetricSource { public static explicit operator V2beta1PodsMetricSource(V2beta2PodsMetricSource s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2PodsMetricSource { public static explicit operator V2beta2PodsMetricSource(V2beta1PodsMetricSource s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1PodsMetricStatus { public static explicit operator V2beta1PodsMetricStatus(V2beta2PodsMetricStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2PodsMetricStatus { public static explicit operator V2beta2PodsMetricStatus(V2beta1PodsMetricStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1PolicyRule { public static explicit operator V1alpha1PolicyRule(V1beta1PolicyRule s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1PolicyRule { public static explicit operator V1beta1PolicyRule(V1alpha1PolicyRule s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1PolicyRule { public static explicit operator V1alpha1PolicyRule(V1PolicyRule s) => VersionConverter.Mapper.Map(s); } + public partial class V1PolicyRule { public static explicit operator V1PolicyRule(V1alpha1PolicyRule s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1PolicyRule { public static explicit operator V1beta1PolicyRule(V1PolicyRule s) => VersionConverter.Mapper.Map(s); } + public partial class V1PolicyRule { public static explicit operator V1PolicyRule(V1beta1PolicyRule s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1PriorityClass { public static explicit operator V1alpha1PriorityClass(V1beta1PriorityClass s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1PriorityClass { public static explicit operator V1beta1PriorityClass(V1alpha1PriorityClass s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1PriorityClass { public static explicit operator V1alpha1PriorityClass(V1PriorityClass s) => VersionConverter.Mapper.Map(s); } + public partial class V1PriorityClass { public static explicit operator V1PriorityClass(V1alpha1PriorityClass s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1PriorityClass { public static explicit operator V1beta1PriorityClass(V1PriorityClass s) => VersionConverter.Mapper.Map(s); } + public partial class V1PriorityClass { public static explicit operator V1PriorityClass(V1beta1PriorityClass s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1PriorityClassList { public static explicit operator V1alpha1PriorityClassList(V1beta1PriorityClassList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1PriorityClassList { public static explicit operator V1beta1PriorityClassList(V1alpha1PriorityClassList s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1PriorityClassList { public static explicit operator V1alpha1PriorityClassList(V1PriorityClassList s) => VersionConverter.Mapper.Map(s); } + public partial class V1PriorityClassList { public static explicit operator V1PriorityClassList(V1alpha1PriorityClassList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1PriorityClassList { public static explicit operator V1beta1PriorityClassList(V1PriorityClassList s) => VersionConverter.Mapper.Map(s); } + public partial class V1PriorityClassList { public static explicit operator V1PriorityClassList(V1beta1PriorityClassList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1ResourceAttributes { public static explicit operator V1beta1ResourceAttributes(V1ResourceAttributes s) => VersionConverter.Mapper.Map(s); } + public partial class V1ResourceAttributes { public static explicit operator V1ResourceAttributes(V1beta1ResourceAttributes s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1ResourceMetricSource { public static explicit operator V2beta1ResourceMetricSource(V2beta2ResourceMetricSource s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2ResourceMetricSource { public static explicit operator V2beta2ResourceMetricSource(V2beta1ResourceMetricSource s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta1ResourceMetricStatus { public static explicit operator V2beta1ResourceMetricStatus(V2beta2ResourceMetricStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V2beta2ResourceMetricStatus { public static explicit operator V2beta2ResourceMetricStatus(V2beta1ResourceMetricStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1ResourceRule { public static explicit operator V1beta1ResourceRule(V1ResourceRule s) => VersionConverter.Mapper.Map(s); } + public partial class V1ResourceRule { public static explicit operator V1ResourceRule(V1beta1ResourceRule s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1Role { public static explicit operator V1alpha1Role(V1beta1Role s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1Role { public static explicit operator V1beta1Role(V1alpha1Role s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1Role { public static explicit operator V1alpha1Role(V1Role s) => VersionConverter.Mapper.Map(s); } + public partial class V1Role { public static explicit operator V1Role(V1alpha1Role s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1Role { public static explicit operator V1beta1Role(V1Role s) => VersionConverter.Mapper.Map(s); } + public partial class V1Role { public static explicit operator V1Role(V1beta1Role s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1RoleBinding { public static explicit operator V1alpha1RoleBinding(V1beta1RoleBinding s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1RoleBinding { public static explicit operator V1beta1RoleBinding(V1alpha1RoleBinding s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1RoleBinding { public static explicit operator V1alpha1RoleBinding(V1RoleBinding s) => VersionConverter.Mapper.Map(s); } + public partial class V1RoleBinding { public static explicit operator V1RoleBinding(V1alpha1RoleBinding s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1RoleBinding { public static explicit operator V1beta1RoleBinding(V1RoleBinding s) => VersionConverter.Mapper.Map(s); } + public partial class V1RoleBinding { public static explicit operator V1RoleBinding(V1beta1RoleBinding s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1RoleBindingList { public static explicit operator V1alpha1RoleBindingList(V1beta1RoleBindingList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1RoleBindingList { public static explicit operator V1beta1RoleBindingList(V1alpha1RoleBindingList s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1RoleBindingList { public static explicit operator V1alpha1RoleBindingList(V1RoleBindingList s) => VersionConverter.Mapper.Map(s); } + public partial class V1RoleBindingList { public static explicit operator V1RoleBindingList(V1alpha1RoleBindingList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1RoleBindingList { public static explicit operator V1beta1RoleBindingList(V1RoleBindingList s) => VersionConverter.Mapper.Map(s); } + public partial class V1RoleBindingList { public static explicit operator V1RoleBindingList(V1beta1RoleBindingList s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1RoleList { public static explicit operator V1alpha1RoleList(V1beta1RoleList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1RoleList { public static explicit operator V1beta1RoleList(V1alpha1RoleList s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1RoleList { public static explicit operator V1alpha1RoleList(V1RoleList s) => VersionConverter.Mapper.Map(s); } + public partial class V1RoleList { public static explicit operator V1RoleList(V1alpha1RoleList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1RoleList { public static explicit operator V1beta1RoleList(V1RoleList s) => VersionConverter.Mapper.Map(s); } + public partial class V1RoleList { public static explicit operator V1RoleList(V1beta1RoleList s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1RoleRef { public static explicit operator V1alpha1RoleRef(V1beta1RoleRef s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1RoleRef { public static explicit operator V1beta1RoleRef(V1alpha1RoleRef s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1RoleRef { public static explicit operator V1alpha1RoleRef(V1RoleRef s) => VersionConverter.Mapper.Map(s); } + public partial class V1RoleRef { public static explicit operator V1RoleRef(V1alpha1RoleRef s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1RoleRef { public static explicit operator V1beta1RoleRef(V1RoleRef s) => VersionConverter.Mapper.Map(s); } + public partial class V1RoleRef { public static explicit operator V1RoleRef(V1beta1RoleRef s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1RuleWithOperations { public static explicit operator V1beta1RuleWithOperations(V1RuleWithOperations s) => VersionConverter.Mapper.Map(s); } + public partial class V1RuleWithOperations { public static explicit operator V1RuleWithOperations(V1beta1RuleWithOperations s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1RuntimeClass { public static explicit operator V1alpha1RuntimeClass(V1beta1RuntimeClass s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1RuntimeClass { public static explicit operator V1beta1RuntimeClass(V1alpha1RuntimeClass s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1RuntimeClassList { public static explicit operator V1alpha1RuntimeClassList(V1beta1RuntimeClassList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1RuntimeClassList { public static explicit operator V1beta1RuntimeClassList(V1alpha1RuntimeClassList s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1Scheduling { public static explicit operator V1alpha1Scheduling(V1beta1Scheduling s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1Scheduling { public static explicit operator V1beta1Scheduling(V1alpha1Scheduling s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1SelfSubjectAccessReview { public static explicit operator V1beta1SelfSubjectAccessReview(V1SelfSubjectAccessReview s) => VersionConverter.Mapper.Map(s); } + public partial class V1SelfSubjectAccessReview { public static explicit operator V1SelfSubjectAccessReview(V1beta1SelfSubjectAccessReview s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1SelfSubjectAccessReviewSpec { public static explicit operator V1beta1SelfSubjectAccessReviewSpec(V1SelfSubjectAccessReviewSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1SelfSubjectAccessReviewSpec { public static explicit operator V1SelfSubjectAccessReviewSpec(V1beta1SelfSubjectAccessReviewSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1SelfSubjectRulesReview { public static explicit operator V1beta1SelfSubjectRulesReview(V1SelfSubjectRulesReview s) => VersionConverter.Mapper.Map(s); } + public partial class V1SelfSubjectRulesReview { public static explicit operator V1SelfSubjectRulesReview(V1beta1SelfSubjectRulesReview s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1SelfSubjectRulesReviewSpec { public static explicit operator V1beta1SelfSubjectRulesReviewSpec(V1SelfSubjectRulesReviewSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1SelfSubjectRulesReviewSpec { public static explicit operator V1SelfSubjectRulesReviewSpec(V1beta1SelfSubjectRulesReviewSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1StorageClass { public static explicit operator V1beta1StorageClass(V1StorageClass s) => VersionConverter.Mapper.Map(s); } + public partial class V1StorageClass { public static explicit operator V1StorageClass(V1beta1StorageClass s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1StorageClassList { public static explicit operator V1beta1StorageClassList(V1StorageClassList s) => VersionConverter.Mapper.Map(s); } + public partial class V1StorageClassList { public static explicit operator V1StorageClassList(V1beta1StorageClassList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1Subject { public static explicit operator V1beta1Subject(V1Subject s) => VersionConverter.Mapper.Map(s); } + public partial class V1Subject { public static explicit operator V1Subject(V1beta1Subject s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1SubjectAccessReview { public static explicit operator V1beta1SubjectAccessReview(V1SubjectAccessReview s) => VersionConverter.Mapper.Map(s); } + public partial class V1SubjectAccessReview { public static explicit operator V1SubjectAccessReview(V1beta1SubjectAccessReview s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1SubjectAccessReviewSpec { public static explicit operator V1beta1SubjectAccessReviewSpec(V1SubjectAccessReviewSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1SubjectAccessReviewSpec { public static explicit operator V1SubjectAccessReviewSpec(V1beta1SubjectAccessReviewSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1SubjectAccessReviewStatus { public static explicit operator V1beta1SubjectAccessReviewStatus(V1SubjectAccessReviewStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1SubjectAccessReviewStatus { public static explicit operator V1SubjectAccessReviewStatus(V1beta1SubjectAccessReviewStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1SubjectRulesReviewStatus { public static explicit operator V1beta1SubjectRulesReviewStatus(V1SubjectRulesReviewStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1SubjectRulesReviewStatus { public static explicit operator V1SubjectRulesReviewStatus(V1beta1SubjectRulesReviewStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1TokenReview { public static explicit operator V1beta1TokenReview(V1TokenReview s) => VersionConverter.Mapper.Map(s); } + public partial class V1TokenReview { public static explicit operator V1TokenReview(V1beta1TokenReview s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1TokenReviewSpec { public static explicit operator V1beta1TokenReviewSpec(V1TokenReviewSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1TokenReviewSpec { public static explicit operator V1TokenReviewSpec(V1beta1TokenReviewSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1TokenReviewStatus { public static explicit operator V1beta1TokenReviewStatus(V1TokenReviewStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1TokenReviewStatus { public static explicit operator V1TokenReviewStatus(V1beta1TokenReviewStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1UserInfo { public static explicit operator V1beta1UserInfo(V1UserInfo s) => VersionConverter.Mapper.Map(s); } + public partial class V1UserInfo { public static explicit operator V1UserInfo(V1beta1UserInfo s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1ValidatingWebhook { public static explicit operator V1beta1ValidatingWebhook(V1ValidatingWebhook s) => VersionConverter.Mapper.Map(s); } + public partial class V1ValidatingWebhook { public static explicit operator V1ValidatingWebhook(V1beta1ValidatingWebhook s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1ValidatingWebhookConfiguration { public static explicit operator V1beta1ValidatingWebhookConfiguration(V1ValidatingWebhookConfiguration s) => VersionConverter.Mapper.Map(s); } + public partial class V1ValidatingWebhookConfiguration { public static explicit operator V1ValidatingWebhookConfiguration(V1beta1ValidatingWebhookConfiguration s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1ValidatingWebhookConfigurationList { public static explicit operator V1beta1ValidatingWebhookConfigurationList(V1ValidatingWebhookConfigurationList s) => VersionConverter.Mapper.Map(s); } + public partial class V1ValidatingWebhookConfigurationList { public static explicit operator V1ValidatingWebhookConfigurationList(V1beta1ValidatingWebhookConfigurationList s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1VolumeAttachment { public static explicit operator V1alpha1VolumeAttachment(V1beta1VolumeAttachment s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1VolumeAttachment { public static explicit operator V1beta1VolumeAttachment(V1alpha1VolumeAttachment s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1VolumeAttachment { public static explicit operator V1alpha1VolumeAttachment(V1VolumeAttachment s) => VersionConverter.Mapper.Map(s); } + public partial class V1VolumeAttachment { public static explicit operator V1VolumeAttachment(V1alpha1VolumeAttachment s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1VolumeAttachment { public static explicit operator V1beta1VolumeAttachment(V1VolumeAttachment s) => VersionConverter.Mapper.Map(s); } + public partial class V1VolumeAttachment { public static explicit operator V1VolumeAttachment(V1beta1VolumeAttachment s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1VolumeAttachmentList { public static explicit operator V1alpha1VolumeAttachmentList(V1beta1VolumeAttachmentList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1VolumeAttachmentList { public static explicit operator V1beta1VolumeAttachmentList(V1alpha1VolumeAttachmentList s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1VolumeAttachmentList { public static explicit operator V1alpha1VolumeAttachmentList(V1VolumeAttachmentList s) => VersionConverter.Mapper.Map(s); } + public partial class V1VolumeAttachmentList { public static explicit operator V1VolumeAttachmentList(V1alpha1VolumeAttachmentList s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1VolumeAttachmentList { public static explicit operator V1beta1VolumeAttachmentList(V1VolumeAttachmentList s) => VersionConverter.Mapper.Map(s); } + public partial class V1VolumeAttachmentList { public static explicit operator V1VolumeAttachmentList(V1beta1VolumeAttachmentList s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1VolumeAttachmentSource { public static explicit operator V1alpha1VolumeAttachmentSource(V1beta1VolumeAttachmentSource s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1VolumeAttachmentSource { public static explicit operator V1beta1VolumeAttachmentSource(V1alpha1VolumeAttachmentSource s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1VolumeAttachmentSource { public static explicit operator V1alpha1VolumeAttachmentSource(V1VolumeAttachmentSource s) => VersionConverter.Mapper.Map(s); } + public partial class V1VolumeAttachmentSource { public static explicit operator V1VolumeAttachmentSource(V1alpha1VolumeAttachmentSource s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1VolumeAttachmentSource { public static explicit operator V1beta1VolumeAttachmentSource(V1VolumeAttachmentSource s) => VersionConverter.Mapper.Map(s); } + public partial class V1VolumeAttachmentSource { public static explicit operator V1VolumeAttachmentSource(V1beta1VolumeAttachmentSource s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1VolumeAttachmentSpec { public static explicit operator V1alpha1VolumeAttachmentSpec(V1beta1VolumeAttachmentSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1VolumeAttachmentSpec { public static explicit operator V1beta1VolumeAttachmentSpec(V1alpha1VolumeAttachmentSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1VolumeAttachmentSpec { public static explicit operator V1alpha1VolumeAttachmentSpec(V1VolumeAttachmentSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1VolumeAttachmentSpec { public static explicit operator V1VolumeAttachmentSpec(V1alpha1VolumeAttachmentSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1VolumeAttachmentSpec { public static explicit operator V1beta1VolumeAttachmentSpec(V1VolumeAttachmentSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1VolumeAttachmentSpec { public static explicit operator V1VolumeAttachmentSpec(V1beta1VolumeAttachmentSpec s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1VolumeAttachmentStatus { public static explicit operator V1alpha1VolumeAttachmentStatus(V1beta1VolumeAttachmentStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1VolumeAttachmentStatus { public static explicit operator V1beta1VolumeAttachmentStatus(V1alpha1VolumeAttachmentStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1VolumeAttachmentStatus { public static explicit operator V1alpha1VolumeAttachmentStatus(V1VolumeAttachmentStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1VolumeAttachmentStatus { public static explicit operator V1VolumeAttachmentStatus(V1alpha1VolumeAttachmentStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1VolumeAttachmentStatus { public static explicit operator V1beta1VolumeAttachmentStatus(V1VolumeAttachmentStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1VolumeAttachmentStatus { public static explicit operator V1VolumeAttachmentStatus(V1beta1VolumeAttachmentStatus s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1VolumeError { public static explicit operator V1alpha1VolumeError(V1beta1VolumeError s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1VolumeError { public static explicit operator V1beta1VolumeError(V1alpha1VolumeError s) => VersionConverter.Mapper.Map(s); } + public partial class V1alpha1VolumeError { public static explicit operator V1alpha1VolumeError(V1VolumeError s) => VersionConverter.Mapper.Map(s); } + public partial class V1VolumeError { public static explicit operator V1VolumeError(V1alpha1VolumeError s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1VolumeError { public static explicit operator V1beta1VolumeError(V1VolumeError s) => VersionConverter.Mapper.Map(s); } + public partial class V1VolumeError { public static explicit operator V1VolumeError(V1beta1VolumeError s) => VersionConverter.Mapper.Map(s); } + public partial class V1beta1VolumeNodeResources { public static explicit operator V1beta1VolumeNodeResources(V1VolumeNodeResources s) => VersionConverter.Mapper.Map(s); } + public partial class V1VolumeNodeResources { public static explicit operator V1VolumeNodeResources(V1beta1VolumeNodeResources s) => VersionConverter.Mapper.Map(s); diff --git a/src/KubernetesClient/generated/VersionConverter.cs b/src/KubernetesClient/generated/VersionConverter.cs index f841e7b..4066371 100644 --- a/src/KubernetesClient/generated/VersionConverter.cs +++ b/src/KubernetesClient/generated/VersionConverter.cs @@ -3,8 +3,6 @@ using k8s.Models; namespace k8s.Versioning { - - public static partial class VersionConverter { private static void AutoConfigurations(IMapperConfigurationExpression cfg) @@ -155,6 +153,4 @@ namespace k8s.Versioning cfg.CreateMap().ReverseMap(); } } - - } diff --git a/tests/KubernetesClient.Tests/AuthTests.cs b/tests/KubernetesClient.Tests/AuthTests.cs index 64359a9..dfebfb1 100644 --- a/tests/KubernetesClient.Tests/AuthTests.cs +++ b/tests/KubernetesClient.Tests/AuthTests.cs @@ -321,6 +321,7 @@ namespace k8s.Tests Assert.True(listTask.Response.IsSuccessStatusCode); Assert.Equal(1, listTask.Body.Items.Count); } + { var clientCertificateText = File.ReadAllText("assets/client.crt").Replace("\n", "\\n"); var clientCertificateKeyText = File.ReadAllText("assets/client.key").Replace("\n", "\\n"); @@ -357,7 +358,6 @@ namespace k8s.Tests })) { { - var responseJson = $"{{\"apiVersion\":\"testingversion\",\"status\":{{\"token\":\"{token}\"}}}}"; var kubernetesConfig = GetK8SConfiguration(server.Uri.ToString(), responseJson, name); var clientConfig = KubernetesClientConfiguration.BuildConfigFromConfigObject(kubernetesConfig, name); @@ -366,6 +366,7 @@ namespace k8s.Tests Assert.True(listTask.Response.IsSuccessStatusCode); Assert.Equal(1, listTask.Body.Items.Count); } + { var responseJson = "{\"apiVersion\":\"testingversion\",\"status\":{\"token\":\"wrong_token\"}}"; var kubernetesConfig = GetK8SConfiguration(server.Uri.ToString(), responseJson, name); @@ -421,7 +422,6 @@ namespace k8s.Tests Assert.Equal(HttpStatusCode.Unauthorized, listTask.Response.StatusCode); } - { var client = new Kubernetes(new KubernetesClientConfiguration { @@ -472,16 +472,15 @@ namespace k8s.Tests var contexts = new List { - new Context {Name = name, ContextDetails = new ContextDetails {Cluster = name, User = username } }, + new Context { Name = name, ContextDetails = new ContextDetails { Cluster = name, User = username } }, }; - { var clusters = new List { new Cluster { Name = name, - ClusterEndpoint = new ClusterEndpoint {SkipTlsVerify = true, Server = serverUri } + ClusterEndpoint = new ClusterEndpoint { SkipTlsVerify = true, Server = serverUri }, }, }; @@ -518,9 +517,9 @@ namespace k8s.Tests { ApiVersion = "testingversion", Command = command, - Arguments = arguments.ToList() - } - } + Arguments = arguments.ToList(), + }, + }, }, }; var kubernetesConfig = new K8SConfiguration { Clusters = clusters, Users = users, Contexts = contexts }; diff --git a/tests/KubernetesClient.Tests/ByteBufferTests.cs b/tests/KubernetesClient.Tests/ByteBufferTests.cs index f3f47a5..6b7a796 100644 --- a/tests/KubernetesClient.Tests/ByteBufferTests.cs +++ b/tests/KubernetesClient.Tests/ByteBufferTests.cs @@ -256,7 +256,7 @@ namespace k8s.Tests // Kick off a read operation var readTask = Task.Run(() => read = buffer.Read(readData, 0, readData.Length)); - await Task.Delay(250); + await Task.Delay(250).ConfigureAwait(false); Assert.False(readTask.IsCompleted, "Read task completed before data was available."); // Write data to the buffer @@ -264,7 +264,7 @@ namespace k8s.Tests await TaskAssert.Completed(readTask, timeout: TimeSpan.FromMilliseconds(1000), - message: "Timed out waiting for read task to complete."); + message: "Timed out waiting for read task to complete.").ConfigureAwait(false); Assert.Equal(3, read); Assert.Equal(0xF0, readData[0]); @@ -411,10 +411,10 @@ namespace k8s.Tests byte[] output = new byte[buffer.Size + 1]; var readTask = Task.Run(() => buffer.Read(output, 0, output.Length)); - await Task.Delay(TimeSpan.FromSeconds(1)); + await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); buffer.Write(data, 0, data.Length); - await readTask; + await readTask.ConfigureAwait(false); } #if NETCOREAPP2_0 @@ -437,12 +437,12 @@ namespace k8s.Tests var consumerTask = Task.Run(() => this.Consume(buffer, SHA256.Create())); - await Task.WhenAll(generatorTask, consumerTask); + await Task.WhenAll(generatorTask, consumerTask).ConfigureAwait(false); var generatorHash - = await generatorTask; + = await generatorTask.ConfigureAwait(false); var consumerHash - = await consumerTask; + = await consumerTask.ConfigureAwait(false); Assert.Equal(generatorHash, consumerHash); } diff --git a/tests/KubernetesClient.Tests/ExternalExecutionTests.cs b/tests/KubernetesClient.Tests/ExternalExecutionTests.cs index c33ebf8..46f28e3 100644 --- a/tests/KubernetesClient.Tests/ExternalExecutionTests.cs +++ b/tests/KubernetesClient.Tests/ExternalExecutionTests.cs @@ -16,7 +16,7 @@ namespace k8s.Tests Command = "command", Arguments = new List { "arg1", "arg2" }, EnvironmentVariables = new List> - { new Dictionary { { "name", "testkey" }, { "value", "testvalue" } } } + { new Dictionary { { "name", "testkey" }, { "value", "testvalue" } } }, }); var actualExecInfo = JsonConvert.DeserializeObject>(actual.StartInfo.EnvironmentVariables["KUBERNETES_EXEC_INFO"]); diff --git a/tests/KubernetesClient.Tests/GcpTokenProviderTests.cs b/tests/KubernetesClient.Tests/GcpTokenProviderTests.cs index c1ba1ce..b22cee9 100644 --- a/tests/KubernetesClient.Tests/GcpTokenProviderTests.cs +++ b/tests/KubernetesClient.Tests/GcpTokenProviderTests.cs @@ -19,8 +19,9 @@ namespace k8s.Tests { System.Diagnostics.Process.Start("chmod", $"+x {cmd}").WaitForExit(); } + var sut = new GcpTokenProvider(cmd); - var result = await sut.GetAuthenticationHeaderAsync(CancellationToken.None); + var result = await sut.GetAuthenticationHeaderAsync(CancellationToken.None).ConfigureAwait(false); result.Scheme.Should().Be("Bearer"); result.Parameter.Should().Be("ACCESS-TOKEN"); } diff --git a/tests/KubernetesClient.Tests/KubernetesClient.Tests.csproj b/tests/KubernetesClient.Tests/KubernetesClient.Tests.csproj index 452aa0b..b4276b8 100755 --- a/tests/KubernetesClient.Tests/KubernetesClient.Tests.csproj +++ b/tests/KubernetesClient.Tests/KubernetesClient.Tests.csproj @@ -5,7 +5,7 @@ true ..\..\src\KubernetesClient\kubernetes-client.snk k8s.Tests - netcoreapp2.1;netcoreapp2.0 + netcoreapp2.1 @@ -20,12 +20,12 @@ - + diff --git a/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs b/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs index 80416f5..a62cc34 100755 --- a/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs +++ b/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs @@ -434,7 +434,7 @@ namespace k8s.Tests } [Fact] - public void LoadKubeConfigFromEnvironmentVariable_MultipleConfigs() + public void LoadKubeConfigFromEnvironmentVariableMultipleConfigs() { // This test makes sure that a list of environment variables works (no exceptions), // doesn't check validity of configuration, which is done in other tests. @@ -564,7 +564,7 @@ namespace k8s.Tests } } - private void AssertContextEqual(Context expected, Context actual) + private static void AssertContextEqual(Context expected, Context actual) { Assert.Equal(expected.Name, actual.Name); Assert.Equal(expected.ContextDetails.Cluster, actual.ContextDetails.Cluster); @@ -572,7 +572,7 @@ namespace k8s.Tests Assert.Equal(expected.ContextDetails.Namespace, actual.ContextDetails.Namespace); } - private void AssertClusterEqual(Cluster expected, Cluster actual) + private static void AssertClusterEqual(Cluster expected, Cluster actual) { Assert.Equal(expected.Name, actual.Name); Assert.Equal(expected.ClusterEndpoint.CertificateAuthority, actual.ClusterEndpoint.CertificateAuthority); @@ -582,7 +582,7 @@ namespace k8s.Tests Assert.Equal(expected.ClusterEndpoint.SkipTlsVerify, actual.ClusterEndpoint.SkipTlsVerify); } - private void AssertUserEqual(User expected, User actual) + private static void AssertUserEqual(User expected, User actual) { Assert.Equal(expected.Name, actual.Name); diff --git a/tests/KubernetesClient.Tests/Kubernetes.WebSockets.Tests.cs b/tests/KubernetesClient.Tests/KubernetesExecTests.cs similarity index 99% rename from tests/KubernetesClient.Tests/Kubernetes.WebSockets.Tests.cs rename to tests/KubernetesClient.Tests/KubernetesExecTests.cs index 71cb886..27d1583 100644 --- a/tests/KubernetesClient.Tests/Kubernetes.WebSockets.Tests.cs +++ b/tests/KubernetesClient.Tests/KubernetesExecTests.cs @@ -1,3 +1,4 @@ +#if !NETCOREAPP2_1 /* * These tests are only for the netstandard version of the client (there are separate tests for netcoreapp that connect to a local test-hosted server). */ @@ -153,3 +154,4 @@ namespace k8s.Tests } } } +#endif diff --git a/tests/KubernetesClient.Tests/Kubernetes.Metrics.Tests.cs b/tests/KubernetesClient.Tests/KubernetesMetricsTests.cs similarity index 100% rename from tests/KubernetesClient.Tests/Kubernetes.Metrics.Tests.cs rename to tests/KubernetesClient.Tests/KubernetesMetricsTests.cs diff --git a/tests/KubernetesClient.Tests/Logging/TestOutputLogger.cs b/tests/KubernetesClient.Tests/Logging/TestOutputLogger.cs index 220d209..5ef9e03 100644 --- a/tests/KubernetesClient.Tests/Logging/TestOutputLogger.cs +++ b/tests/KubernetesClient.Tests/Logging/TestOutputLogger.cs @@ -8,7 +8,7 @@ namespace k8s.Tests.Logging /// /// An implementation of that writes to the output of the current Xunit test. /// - sealed class TestOutputLogger + internal sealed class TestOutputLogger : ILogger { /// @@ -30,7 +30,7 @@ namespace k8s.Tests.Logging throw new ArgumentNullException(nameof(testOutput)); } - if (String.IsNullOrWhiteSpace(loggerCategory)) + if (string.IsNullOrWhiteSpace(loggerCategory)) { throw new ArgumentException( "Argument cannot be null, empty, or entirely composed of whitespace: 'loggerCategory'.", @@ -83,7 +83,7 @@ namespace k8s.Tests.Logging throw new ArgumentNullException(nameof(formatter)); } - TestOutput.WriteLine(String.Format("[{0}] {1}: {2}", + TestOutput.WriteLine(string.Format("[{0}] {1}: {2}", level, LoggerCategory, formatter(state, exception))); diff --git a/tests/KubernetesClient.Tests/Logging/TestOutputLoggerProvider.cs b/tests/KubernetesClient.Tests/Logging/TestOutputLoggerProvider.cs index 4fad342..ac66b5a 100644 --- a/tests/KubernetesClient.Tests/Logging/TestOutputLoggerProvider.cs +++ b/tests/KubernetesClient.Tests/Logging/TestOutputLoggerProvider.cs @@ -7,7 +7,7 @@ namespace k8s.Tests.Logging /// /// Logger provider for logging to Xunit test output. /// - sealed class TestOutputLoggerProvider + internal sealed class TestOutputLoggerProvider : ILoggerProvider { /// @@ -40,7 +40,7 @@ namespace k8s.Tests.Logging /// /// The output for the current test. /// - ITestOutputHelper TestOutput { get; } + private ITestOutputHelper TestOutput { get; } /// /// The logger's minimum log level. diff --git a/tests/KubernetesClient.Tests/Mock/MockKubeApiServer.cs b/tests/KubernetesClient.Tests/Mock/MockKubeApiServer.cs index 02f8e9c..fd8e8a3 100644 --- a/tests/KubernetesClient.Tests/Mock/MockKubeApiServer.cs +++ b/tests/KubernetesClient.Tests/Mock/MockKubeApiServer.cs @@ -32,9 +32,9 @@ namespace k8s.Tests.Mock _webHost = WebHost.CreateDefaultBuilder() .Configure(app => app.Run(async httpContext => { - if (await shouldNext(httpContext)) + if (await shouldNext(httpContext).ConfigureAwait(false)) { - await httpContext.Response.WriteAsync(resp); + await httpContext.Response.WriteAsync(resp).ConfigureAwait(false); } })) .UseKestrel(options => { options.Listen(IPAddress.Loopback, 0, listenConfigure); }) diff --git a/tests/KubernetesClient.Tests/Mock/MockWebSocket.cs b/tests/KubernetesClient.Tests/Mock/MockWebSocket.cs index 559cf11..93cdb9e 100644 --- a/tests/KubernetesClient.Tests/Mock/MockWebSocket.cs +++ b/tests/KubernetesClient.Tests/Mock/MockWebSocket.cs @@ -15,6 +15,7 @@ namespace k8s.Tests.Mock private string subProtocol; private ConcurrentQueue receiveBuffers = new ConcurrentQueue(); private AsyncAutoResetEvent receiveEvent = new AsyncAutoResetEvent(false); + private bool disposedValue; public MockWebSocket(string subProtocol = null) { @@ -26,7 +27,7 @@ namespace k8s.Tests.Mock this.state = state; } - public EventHandler MessageSent; + public EventHandler MessageSent { get; set; } public Task InvokeReceiveAsync(ArraySegment buffer, WebSocketMessageType messageType, bool endOfMessage) { @@ -40,8 +41,6 @@ namespace k8s.Tests.Mock return Task.CompletedTask; } - #region WebSocket overrides - public override WebSocketCloseStatus? CloseStatus => this.closeStatus; public override string CloseStatusDescription => this.closeStatusDescription; @@ -76,12 +75,6 @@ namespace k8s.Tests.Mock throw new NotImplementedException(); } - public override void Dispose() - { - this.receiveBuffers.Clear(); - this.receiveEvent.Set(); - } - public override async Task ReceiveAsync(ArraySegment buffer, CancellationToken cancellationToken) { @@ -127,14 +120,12 @@ namespace k8s.Tests.Mock { Buffer = buffer, MessageType = messageType, - EndOfMessage = endOfMessage + EndOfMessage = endOfMessage, }, }); return Task.CompletedTask; } - #endregion - public class MessageData { public ArraySegment Buffer { get; set; } @@ -146,5 +137,33 @@ namespace k8s.Tests.Mock { public MessageData Data { get; set; } } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + this.receiveBuffers.Clear(); + this.receiveEvent.Set(); + } + + disposedValue = true; + } + } + + // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources + // ~MockWebSocket() + // { + // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + // Dispose(disposing: false); + // } + + public override void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } } } diff --git a/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodExecController.cs b/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodExecController.cs index cece75e..2e555dd 100644 --- a/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodExecController.cs +++ b/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodExecController.cs @@ -32,7 +32,7 @@ namespace k8s.Tests.Mock.Server.Controllers /// /// The adapter used to capture sockets accepted by the test server and provide them to the calling test. /// - WebSocketTestAdapter WebSocketTestAdapter { get; } + private WebSocketTestAdapter WebSocketTestAdapter { get; } /// /// Mock Kubernetes API: exec-in-pod. @@ -52,11 +52,11 @@ namespace k8s.Tests.Mock.Server.Controllers } WebSocket webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync( - subProtocol: WebSocketProtocol.ChannelWebSocketProtocol); + subProtocol: WebSocketProtocol.ChannelWebSocketProtocol).ConfigureAwait(false); WebSocketTestAdapter.AcceptedPodExecV1Connection.AcceptServerSocket(webSocket); - await WebSocketTestAdapter.TestCompleted; + await WebSocketTestAdapter.TestCompleted.ConfigureAwait(false); return Ok(); } diff --git a/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodPortForwardController.cs b/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodPortForwardController.cs index 6436682..45d1c2d 100644 --- a/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodPortForwardController.cs +++ b/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodPortForwardController.cs @@ -33,7 +33,7 @@ namespace k8s.Tests.Mock.Server.Controllers /// /// The adapter used to capture sockets accepted by the test server and provide them to the calling test. /// - WebSocketTestAdapter WebSocketTestAdapter { get; } + private WebSocketTestAdapter WebSocketTestAdapter { get; } /// /// Mock Kubernetes API: port-forward for pod. @@ -56,11 +56,11 @@ namespace k8s.Tests.Mock.Server.Controllers } WebSocket webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync( - subProtocol: WebSocketProtocol.ChannelWebSocketProtocol); + subProtocol: WebSocketProtocol.ChannelWebSocketProtocol).ConfigureAwait(false); WebSocketTestAdapter.AcceptedPodPortForwardV1Connection.AcceptServerSocket(webSocket); - await WebSocketTestAdapter.TestCompleted; + await WebSocketTestAdapter.TestCompleted.ConfigureAwait(false); return Ok(); } diff --git a/tests/KubernetesClient.Tests/Mock/Server/Startup.cs b/tests/KubernetesClient.Tests/Mock/Server/Startup.cs index c8297e0..6c8687d 100644 --- a/tests/KubernetesClient.Tests/Mock/Server/Startup.cs +++ b/tests/KubernetesClient.Tests/Mock/Server/Startup.cs @@ -23,7 +23,7 @@ namespace k8s.Tests.Mock.Server /// /// The service collection to configure. /// - public void ConfigureServices(IServiceCollection services) + public static void ConfigureServices(IServiceCollection services) { if (services == null) { @@ -43,7 +43,7 @@ namespace k8s.Tests.Mock.Server /// /// The application pipeline builder. /// - public void Configure(IApplicationBuilder app) + public static void Configure(IApplicationBuilder app) { app.UseWebSockets(new WebSocketOptions { diff --git a/tests/KubernetesClient.Tests/Mock/Server/WebSocketTestAdapter.cs b/tests/KubernetesClient.Tests/Mock/Server/WebSocketTestAdapter.cs index 25a0aff..c8a780f 100644 --- a/tests/KubernetesClient.Tests/Mock/Server/WebSocketTestAdapter.cs +++ b/tests/KubernetesClient.Tests/Mock/Server/WebSocketTestAdapter.cs @@ -18,7 +18,7 @@ namespace k8s.Tests.Mock.Server /// /// Completion source for the task. /// - readonly TaskCompletionSource _testCompletion = new TaskCompletionSource(); + private readonly TaskCompletionSource _testCompletion = new TaskCompletionSource(); /// /// A that completes when the test is complete (providing is called). @@ -51,7 +51,7 @@ namespace k8s.Tests.Mock.Server /// /// Completion source for the task. /// - readonly TaskCompletionSource _completion = new TaskCompletionSource(); + private readonly TaskCompletionSource _completion = new TaskCompletionSource(); /// /// A that completes when the server accepts a WebSocket connection (i.e. when or is called). diff --git a/tests/KubernetesClient.Tests/ModelExtensionTests.cs b/tests/KubernetesClient.Tests/ModelExtensionTests.cs index f31bb40..59e5490 100644 --- a/tests/KubernetesClient.Tests/ModelExtensionTests.cs +++ b/tests/KubernetesClient.Tests/ModelExtensionTests.cs @@ -69,7 +69,7 @@ namespace k8s.Tests Name = "name", NamespaceProperty = "ns", ResourceVersion = "42", - Uid = "id" + Uid = "id", }; Assert.Equal(ts, pod.CreationTimestamp().Value); Assert.Equal(ts2, pod.DeletionTimestamp().Value); diff --git a/tests/KubernetesClient.Tests/OperatingSystem.cs b/tests/KubernetesClient.Tests/OperatingSystem.cs index 534ef11..4f23ecc 100644 --- a/tests/KubernetesClient.Tests/OperatingSystem.cs +++ b/tests/KubernetesClient.Tests/OperatingSystem.cs @@ -7,6 +7,6 @@ namespace k8s.Tests { Windows = 1, Linux = 2, - OSX = 4 + OSX = 4, } } diff --git a/tests/KubernetesClient.Tests/OperatingSystemFact.cs b/tests/KubernetesClient.Tests/OperatingSystemDependentFactAttribute.cs similarity index 100% rename from tests/KubernetesClient.Tests/OperatingSystemFact.cs rename to tests/KubernetesClient.Tests/OperatingSystemDependentFactAttribute.cs diff --git a/tests/KubernetesClient.Tests/Kubernetes.Exec.Tests.cs b/tests/KubernetesClient.Tests/PodExecTests.cs similarity index 90% rename from tests/KubernetesClient.Tests/Kubernetes.Exec.Tests.cs rename to tests/KubernetesClient.Tests/PodExecTests.cs index dacff3b..3c02fe2 100644 --- a/tests/KubernetesClient.Tests/Kubernetes.Exec.Tests.cs +++ b/tests/KubernetesClient.Tests/PodExecTests.cs @@ -43,7 +43,7 @@ namespace k8s.Tests /// Verify that the client can request execution of a command in a pod's default container, with only the STDOUT stream enabled. /// [Fact(DisplayName = "Can exec in pod's default container, STDOUT only")] - public async Task Exec_DefaultContainer_StdOut() + public async Task ExecDefaultContainerStdOut() { if (!Debugger.IsAttached) { @@ -51,7 +51,7 @@ namespace k8s.Tests TimeSpan.FromSeconds(5)); } - await Host.StartAsync(TestCancellation); + await Host.StartAsync(TestCancellation).ConfigureAwait(false); using (Kubernetes client = CreateTestClient()) { @@ -66,7 +66,7 @@ namespace k8s.Tests stdin: false, stdout: true, webSocketSubProtol: WebSocketProtocol.ChannelWebSocketProtocol, - cancellationToken: TestCancellation); + cancellationToken: TestCancellation).ConfigureAwait(false); Assert.Equal(WebSocketProtocol.ChannelWebSocketProtocol, clientSocket .SubProtocol); // For WebSockets, the Kubernetes API defaults to the binary channel (v1) protocol. @@ -81,10 +81,10 @@ namespace k8s.Tests const int STDOUT = 1; const string expectedOutput = "This is text send to STDOUT."; - int bytesSent = await SendMultiplexed(serverSocket, STDOUT, expectedOutput); + int bytesSent = await SendMultiplexed(serverSocket, STDOUT, expectedOutput).ConfigureAwait(false); testOutput.WriteLine($"Sent {bytesSent} bytes to server socket; receiving from client socket..."); - (string receivedText, byte streamIndex, int bytesReceived) = await ReceiveTextMultiplexed(clientSocket); + (string receivedText, byte streamIndex, int bytesReceived) = await ReceiveTextMultiplexed(clientSocket).ConfigureAwait(false); testOutput.WriteLine( $"Received {bytesReceived} bytes from client socket ('{receivedText}', stream {streamIndex})."); @@ -93,15 +93,14 @@ namespace k8s.Tests await Disconnect(clientSocket, serverSocket, closeStatus: WebSocketCloseStatus.NormalClosure, - closeStatusDescription: "Normal Closure"); + closeStatusDescription: "Normal Closure").ConfigureAwait(false); WebSocketTestAdapter.CompleteTest(); } } - [Fact] - public void GetExitCodeOrThrow_Success() + public void GetExitCodeOrThrowSuccess() { var status = new V1Status() { Metadata = null, Status = "Success", }; @@ -109,7 +108,7 @@ namespace k8s.Tests } [Fact] - public void GetExitCodeOrThrow_NonZeroExitCode() + public void GetExitCodeOrThrowNonZeroExitCode() { var status = new V1Status() { @@ -121,8 +120,8 @@ namespace k8s.Tests { Causes = new List() { - new V1StatusCause() {Reason = "ExitCode", Message = "1" } - } + new V1StatusCause() { Reason = "ExitCode", Message = "1" }, + }, }, }; @@ -130,7 +129,7 @@ namespace k8s.Tests } [Fact] - public void GetExitCodeOrThrow_InvalidExitCode() + public void GetExitCodeOrThrowInvalidExitCode() { var status = new V1Status() { @@ -142,8 +141,8 @@ namespace k8s.Tests { Causes = new List() { - new V1StatusCause() {Reason = "ExitCode", Message = "abc" } - } + new V1StatusCause() { Reason = "ExitCode", Message = "abc" }, + }, }, }; @@ -152,7 +151,7 @@ namespace k8s.Tests } [Fact] - public void GetExitCodeOrThrow_NoExitCode() + public void GetExitCodeOrThrowNoExitCode() { var status = new V1Status() { @@ -168,7 +167,7 @@ namespace k8s.Tests } [Fact] - public void GetExitCodeOrThrow_OtherError() + public void GetExitCodeOrThrowOtherError() { var status = new V1Status() { Metadata = null, Status = "Failure", Reason = "SomethingElse" }; @@ -177,7 +176,7 @@ namespace k8s.Tests } [Fact] - public async Task NamespacedPodExecAsync_ActionNull() + public async Task NamespacedPodExecAsyncActionNull() { using (MemoryStream stdIn = new MemoryStream()) using (MemoryStream stdOut = new MemoryStream()) @@ -209,7 +208,7 @@ namespace k8s.Tests } [Fact] - public async Task NamespacedPodExecAsync_HttpException_WithStatus() + public async Task NamespacedPodExecAsyncHttpExceptionWithStatus() { var kubernetesMock = new Moq.Mock( new object[] { Moq.Mock.Of(), new DelegatingHandler[] { } }); @@ -232,7 +231,7 @@ namespace k8s.Tests } [Fact] - public async Task NamespacedPodExecAsync_HttpException_NoStatus() + public async Task NamespacedPodExecAsyncHttpExceptionNoStatus() { var kubernetesMock = new Moq.Mock( new object[] { Moq.Mock.Of(), new DelegatingHandler[] { } }); @@ -255,7 +254,7 @@ namespace k8s.Tests } [Fact] - public async Task NamespacedPodExecAsync_GenericException() + public async Task NamespacedPodExecAsyncGenericException() { var kubernetesMock = new Moq.Mock( new object[] { Moq.Mock.Of(), new DelegatingHandler[] { } }); @@ -278,7 +277,7 @@ namespace k8s.Tests } [Fact] - public async Task NamespacedPodExecAsync_ExitCode_NonZero() + public async Task NamespacedPodExecAsyncExitCodeNonZero() { var processStatus = new V1Status() { @@ -290,8 +289,8 @@ namespace k8s.Tests { Causes = new List() { - new V1StatusCause() {Reason = "ExitCode", Message = "1" } - } + new V1StatusCause() { Reason = "ExitCode", Message = "1" }, + }, }, }; diff --git a/tests/KubernetesClient.Tests/StreamDemuxerTests.cs b/tests/KubernetesClient.Tests/StreamDemuxerTests.cs index 81df910..4bead3b 100644 --- a/tests/KubernetesClient.Tests/StreamDemuxerTests.cs +++ b/tests/KubernetesClient.Tests/StreamDemuxerTests.cs @@ -37,7 +37,7 @@ namespace k8s.Tests stream.Write(b, 0, b.Length); // Send 100 bytes, expect 1 (channel index) + 100 (payload) = 101 bytes - Assert.True(await WaitForAsync(() => sentBuffer.Count == 101), + Assert.True(await WaitForAsync(() => sentBuffer.Count == 101).ConfigureAwait(false), $"Demuxer error: expect to send 101 bytes, but actually send {sentBuffer.Count} bytes."); Assert.True(sentBuffer[0] == channelIndex, "The first sent byte is not channel index!"); Assert.True(sentBuffer[1] == 0xEF, "Incorrect payload!"); @@ -63,7 +63,7 @@ namespace k8s.Tests stream.Write(b, 0, b.Length); // Send 300 bytes in 2 messages, expect 1 (channel index) * 2 + 300 (payload) = 302 bytes - Assert.True(await WaitForAsync(() => sentBuffer.Count == 302), + Assert.True(await WaitForAsync(() => sentBuffer.Count == 302).ConfigureAwait(false), $"Demuxer error: expect to send 302 bytes, but actually send {sentBuffer.Count} bytes."); Assert.True(sentBuffer[0] == channelIndex, "The first sent byte is not channel index!"); Assert.True(sentBuffer[1] == 0xEF, "The first part of payload incorrect!"); @@ -91,21 +91,21 @@ namespace k8s.Tests { await ws.InvokeReceiveAsync( new ArraySegment(GenerateRandomBuffer(100, channelIndex, 0xAA, false)), - WebSocketMessageType.Binary, true); + WebSocketMessageType.Binary, true).ConfigureAwait(false); await ws.InvokeReceiveAsync( new ArraySegment(GenerateRandomBuffer(200, channelIndex, 0xAB, false)), - WebSocketMessageType.Binary, true); + WebSocketMessageType.Binary, true).ConfigureAwait(false); await ws.InvokeReceiveAsync( new ArraySegment(GenerateRandomBuffer(300, channelIndex, 0xAC, false)), - WebSocketMessageType.Binary, true); + WebSocketMessageType.Binary, true).ConfigureAwait(false); - await WaitForAsync(() => receivedBuffer.Count == expectedCount); - await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None); + await WaitForAsync(() => receivedBuffer.Count == expectedCount).ConfigureAwait(false); + await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None).ConfigureAwait(false); }); var buffer = new byte[50]; while (true) { - var cRead = await stream.ReadAsync(buffer, 0, buffer.Length); + var cRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (cRead == 0) { break; @@ -117,7 +117,7 @@ namespace k8s.Tests } } - await t; + await t.ConfigureAwait(false); Assert.True(receivedBuffer.Count == expectedCount, $"Demuxer error: expect to receive {expectedCount} bytes, but actually got {receivedBuffer.Count} bytes."); @@ -150,21 +150,21 @@ namespace k8s.Tests { await ws.InvokeReceiveAsync( new ArraySegment(GenerateRandomBuffer(100, channelIndex, 0xB1, true)), - WebSocketMessageType.Binary, true); + WebSocketMessageType.Binary, true).ConfigureAwait(false); await ws.InvokeReceiveAsync( new ArraySegment(GenerateRandomBuffer(200, channelIndex, 0xB2, false)), - WebSocketMessageType.Binary, true); + WebSocketMessageType.Binary, true).ConfigureAwait(false); await ws.InvokeReceiveAsync( new ArraySegment(GenerateRandomBuffer(300, channelIndex, 0xB3, false)), - WebSocketMessageType.Binary, true); + WebSocketMessageType.Binary, true).ConfigureAwait(false); - await WaitForAsync(() => receivedBuffer.Count == expectedCount); - await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None); + await WaitForAsync(() => receivedBuffer.Count == expectedCount).ConfigureAwait(false); + await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None).ConfigureAwait(false); }); var buffer = new byte[50]; while (true) { - var cRead = await stream.ReadAsync(buffer, 0, buffer.Length); + var cRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (cRead == 0) { break; @@ -176,7 +176,7 @@ namespace k8s.Tests } } - await t; + await t.ConfigureAwait(false); Assert.True(receivedBuffer.Count == expectedCount, $"Demuxer error: expect to receive {expectedCount} bytes, but actually got {receivedBuffer.Count} bytes."); @@ -209,21 +209,21 @@ namespace k8s.Tests { await ws.InvokeReceiveAsync( new ArraySegment(GenerateRandomBuffer(2, channelIndex, 0xC1, true)), - WebSocketMessageType.Binary, false); + WebSocketMessageType.Binary, false).ConfigureAwait(false); await ws.InvokeReceiveAsync( new ArraySegment(GenerateRandomBuffer(100, channelIndex, 0xC2, false)), - WebSocketMessageType.Binary, true); + WebSocketMessageType.Binary, true).ConfigureAwait(false); await ws.InvokeReceiveAsync( new ArraySegment(GenerateRandomBuffer(300, channelIndex, 0xC3, false)), - WebSocketMessageType.Binary, true); + WebSocketMessageType.Binary, true).ConfigureAwait(false); - await WaitForAsync(() => receivedBuffer.Count == expectedCount); - await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None); + await WaitForAsync(() => receivedBuffer.Count == expectedCount).ConfigureAwait(false); + await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None).ConfigureAwait(false); }); var buffer = new byte[50]; while (true) { - var cRead = await stream.ReadAsync(buffer, 0, buffer.Length); + var cRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (cRead == 0) { break; @@ -235,7 +235,7 @@ namespace k8s.Tests } } - await t; + await t.ConfigureAwait(false); Assert.True(receivedBuffer.Count == expectedCount, $"Demuxer error: expect to receive {expectedCount} bytes, but actually got {receivedBuffer.Count} bytes."); @@ -272,24 +272,24 @@ namespace k8s.Tests // Simulate WebSocket received remote data to multiple streams await ws.InvokeReceiveAsync( new ArraySegment(GenerateRandomBuffer(100, channelIndex1, 0xD1, false)), - WebSocketMessageType.Binary, true); + WebSocketMessageType.Binary, true).ConfigureAwait(false); await ws.InvokeReceiveAsync( new ArraySegment(GenerateRandomBuffer(200, channelIndex2, 0xD2, false)), - WebSocketMessageType.Binary, true); + WebSocketMessageType.Binary, true).ConfigureAwait(false); await ws.InvokeReceiveAsync( new ArraySegment(GenerateRandomBuffer(300, channelIndex1, 0xD3, false)), - WebSocketMessageType.Binary, true); + WebSocketMessageType.Binary, true).ConfigureAwait(false); - await WaitForAsync(() => receivedBuffer1.Count == expectedCount1); - await WaitForAsync(() => receivedBuffer2.Count == expectedCount2); - await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None); + await WaitForAsync(() => receivedBuffer1.Count == expectedCount1).ConfigureAwait(false); + await WaitForAsync(() => receivedBuffer2.Count == expectedCount2).ConfigureAwait(false); + await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None).ConfigureAwait(false); }); var t2 = Task.Run(async () => { var buffer = new byte[50]; while (true) { - var cRead = await stream1.ReadAsync(buffer, 0, buffer.Length); + var cRead = await stream1.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (cRead == 0) { break; @@ -306,7 +306,7 @@ namespace k8s.Tests var buffer = new byte[50]; while (true) { - var cRead = await stream2.ReadAsync(buffer, 0, buffer.Length); + var cRead = await stream2.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (cRead == 0) { break; @@ -318,7 +318,7 @@ namespace k8s.Tests } } }); - await Task.WhenAll(t1, t2, t3); + await Task.WhenAll(t1, t2, t3).ConfigureAwait(false); Assert.True(receivedBuffer1.Count == expectedCount1, $"Demuxer error: expect to receive {expectedCount1} bytes, but actually got {receivedBuffer1.Count} bytes."); @@ -361,24 +361,24 @@ namespace k8s.Tests // Simulate WebSocket received remote data to multiple streams await ws.InvokeReceiveAsync( new ArraySegment(GenerateRandomBuffer(100, channelIndex1, 0xE1, true)), - WebSocketMessageType.Binary, true); + WebSocketMessageType.Binary, true).ConfigureAwait(false); await ws.InvokeReceiveAsync( new ArraySegment(GenerateRandomBuffer(200, channelIndex2, 0xE2, true)), - WebSocketMessageType.Binary, true); + WebSocketMessageType.Binary, true).ConfigureAwait(false); await ws.InvokeReceiveAsync( new ArraySegment(GenerateRandomBuffer(300, channelIndex1, 0xE3, false)), - WebSocketMessageType.Binary, true); + WebSocketMessageType.Binary, true).ConfigureAwait(false); - await WaitForAsync(() => receivedBuffer1.Count == expectedCount1); - await WaitForAsync(() => receivedBuffer2.Count == expectedCount2); - await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None); + await WaitForAsync(() => receivedBuffer1.Count == expectedCount1).ConfigureAwait(false); + await WaitForAsync(() => receivedBuffer2.Count == expectedCount2).ConfigureAwait(false); + await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None).ConfigureAwait(false); }); var t2 = Task.Run(async () => { var buffer = new byte[50]; while (true) { - var cRead = await stream1.ReadAsync(buffer, 0, buffer.Length); + var cRead = await stream1.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (cRead == 0) { break; @@ -395,7 +395,7 @@ namespace k8s.Tests var buffer = new byte[50]; while (true) { - var cRead = await stream2.ReadAsync(buffer, 0, buffer.Length); + var cRead = await stream2.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (cRead == 0) { break; @@ -407,7 +407,7 @@ namespace k8s.Tests } } }); - await Task.WhenAll(t1, t2, t3); + await Task.WhenAll(t1, t2, t3).ConfigureAwait(false); Assert.True(receivedBuffer1.Count == expectedCount1, $"Demuxer error: expect to receive {expectedCount1} bytes, but actually got {receivedBuffer1.Count} bytes."); @@ -465,8 +465,9 @@ namespace k8s.Tests return true; } - await Task.Delay(10); - } while (w.Elapsed.Duration().TotalSeconds < waitForSeconds); + await Task.Delay(10).ConfigureAwait(false); + } + while (w.Elapsed.Duration().TotalSeconds < waitForSeconds); return false; } diff --git a/tests/KubernetesClient.Tests/TaskAssert.cs b/tests/KubernetesClient.Tests/TaskAssert.cs index 488b8ad..a45c0dc 100644 --- a/tests/KubernetesClient.Tests/TaskAssert.cs +++ b/tests/KubernetesClient.Tests/TaskAssert.cs @@ -5,7 +5,7 @@ using Xunit; namespace k8s.Tests { - static class TaskAssert + internal static class TaskAssert { public static void NotCompleted(Task task, string message = "Task should not be completed") { @@ -17,25 +17,22 @@ namespace k8s.Tests var timeoutTask = Task.Delay( TimeSpan.FromMilliseconds(1000)); - var completedTask = await Task.WhenAny(task, timeoutTask); + var completedTask = await Task.WhenAny(task, timeoutTask).ConfigureAwait(false); Assert.True(ReferenceEquals(task, completedTask), message); - await completedTask; + await completedTask.ConfigureAwait(false); } public static async Task Completed(Task task, TimeSpan timeout, string message = "Task timed out") { - var timeoutTask = - Task.Delay( - TimeSpan.FromMilliseconds(1000)) - .ContinueWith( - completedTimeoutTask => - default(T)); // Value is never returned, but we need a task of the same result type in order to use Task.WhenAny. + var timeoutTask = Task.Delay(TimeSpan.FromMilliseconds(1000)).ContinueWith(completedTimeoutTask => default(T)); - var completedTask = await Task.WhenAny(task, timeoutTask); + // Value is never returned, but we need a task of the same result type in order to use Task.WhenAny. + + var completedTask = await Task.WhenAny(task, timeoutTask).ConfigureAwait(false); Assert.True(ReferenceEquals(task, completedTask), message); - return await completedTask; + return await completedTask.ConfigureAwait(false); } } } diff --git a/tests/KubernetesClient.Tests/TokenFileAuth.cs b/tests/KubernetesClient.Tests/TokenFileAuthTests.cs similarity index 74% rename from tests/KubernetesClient.Tests/TokenFileAuth.cs rename to tests/KubernetesClient.Tests/TokenFileAuthTests.cs index fe5940e..e4bc43f 100644 --- a/tests/KubernetesClient.Tests/TokenFileAuth.cs +++ b/tests/KubernetesClient.Tests/TokenFileAuthTests.cs @@ -9,20 +9,20 @@ namespace k8s.Tests { public class TokenFileAuthTests { - public async Task Token() + public async Task TestToken() { var auth = new TokenFileAuth("assets/token1"); - var result = await auth.GetAuthenticationHeaderAsync(CancellationToken.None); + var result = await auth.GetAuthenticationHeaderAsync(CancellationToken.None).ConfigureAwait(false); result.Scheme.Should().Be("Bearer"); result.Parameter.Should().Be("token1"); - auth._token_file = "assets/token2"; - result = await auth.GetAuthenticationHeaderAsync(CancellationToken.None); + auth.TokenFile = "assets/token2"; + result = await auth.GetAuthenticationHeaderAsync(CancellationToken.None).ConfigureAwait(false); result.Scheme.Should().Be("Bearer"); result.Parameter.Should().Be("token1"); - auth._token_expires_at = DateTime.UtcNow; - result = await auth.GetAuthenticationHeaderAsync(CancellationToken.None); + auth.TokenExpiresAt = DateTime.UtcNow; + result = await auth.GetAuthenticationHeaderAsync(CancellationToken.None).ConfigureAwait(false); result.Scheme.Should().Be("Bearer"); result.Parameter.Should().Be("token2"); } diff --git a/tests/KubernetesClient.Tests/WatchTests.cs b/tests/KubernetesClient.Tests/WatchTests.cs index 97a98a8..ef6da0f 100644 --- a/tests/KubernetesClient.Tests/WatchTests.cs +++ b/tests/KubernetesClient.Tests/WatchTests.cs @@ -27,7 +27,7 @@ namespace k8s.Tests private static readonly string MockDeletedStreamLine = BuildWatchEventStreamLine(WatchEventType.Deleted); private static readonly string MockModifiedStreamLine = BuildWatchEventStreamLine(WatchEventType.Modified); private static readonly string MockErrorStreamLine = BuildWatchEventStreamLine(WatchEventType.Error); - private static readonly string MockBadStreamLine = "bad json"; + private const string MockBadStreamLine = "bad json"; private static readonly TimeSpan TestTimeout = TimeSpan.FromSeconds(150); private readonly ITestOutputHelper testOutput; @@ -48,9 +48,9 @@ namespace k8s.Tests private static async Task WriteStreamLine(HttpContext httpContext, string reponseLine) { const string crlf = "\r\n"; - await httpContext.Response.WriteAsync(reponseLine.Replace(crlf, "")); - await httpContext.Response.WriteAsync(crlf); - await httpContext.Response.Body.FlushAsync(); + await httpContext.Response.WriteAsync(reponseLine.Replace(crlf, "")).ConfigureAwait(false); + await httpContext.Response.WriteAsync(crlf).ConfigureAwait(false); + await httpContext.Response.Body.FlushAsync().ConfigureAwait(false); } [Fact] @@ -68,7 +68,7 @@ namespace k8s.Tests { } - await Task.Delay(TimeSpan.FromSeconds(1)); // delay for onerror to be called + await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); // delay for onerror to be called Assert.True(onErrorCalled); @@ -79,7 +79,7 @@ namespace k8s.Tests // this line did not throw // listTask.Watch((type, item) => { }); - }); + }).ConfigureAwait(false); } } @@ -92,8 +92,8 @@ namespace k8s.Tests using (var server = new MockKubeApiServer(testOutput, async httpContext => { // block until reponse watcher obj created - await created.WaitAsync(); - await WriteStreamLine(httpContext, MockAddedEventStreamLine); + await created.WaitAsync().ConfigureAwait(false); + await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false); return false; })) { @@ -105,7 +105,7 @@ namespace k8s.Tests { // here watcher is ready to use, but http server has not responsed yet. created.Set(); - await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); + await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false); } Assert.True(eventsReceived.IsSet); @@ -128,20 +128,20 @@ namespace k8s.Tests httpContext.Response.StatusCode = (int)HttpStatusCode.OK; httpContext.Response.ContentLength = null; - await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse); - await WriteStreamLine(httpContext, MockBadStreamLine); - await WriteStreamLine(httpContext, MockAddedEventStreamLine); - await WriteStreamLine(httpContext, MockBadStreamLine); - await WriteStreamLine(httpContext, MockModifiedStreamLine); + await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockBadStreamLine).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockBadStreamLine).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockModifiedStreamLine).ConfigureAwait(false); // make server alive, cannot set to int.max as of it would block response - await serverShutdown.WaitAsync(); + await serverShutdown.WaitAsync().ConfigureAwait(false); return false; })) { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); - var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true); + var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true).ConfigureAwait(false); var events = new HashSet(); var errors = 0; @@ -164,7 +164,7 @@ namespace k8s.Tests onClosed: connectionClosed.Set); // wait server yields all events - await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); + await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false); Assert.True( eventsReceived.CurrentCount == 0, @@ -180,7 +180,7 @@ namespace k8s.Tests // Let the server know it can initiate a shut down. serverShutdown.Set(); - await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TestTimeout)); + await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false); Assert.True(connectionClosed.IsSet); } } @@ -194,11 +194,11 @@ namespace k8s.Tests using (var server = new MockKubeApiServer(testOutput, async httpContext => { - await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse); + await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse).ConfigureAwait(false); while (serverRunning) { - await WriteStreamLine(httpContext, MockAddedEventStreamLine); + await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false); } return true; @@ -206,7 +206,7 @@ namespace k8s.Tests { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); - var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true); + var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true).ConfigureAwait(false); var events = new HashSet(); @@ -219,7 +219,7 @@ namespace k8s.Tests onClosed: connectionClosed.Set); // wait at least an event - await Task.WhenAny(Task.Run(() => eventsReceived.Wait()), Task.Delay(TestTimeout)); + await Task.WhenAny(Task.Run(() => eventsReceived.Wait()), Task.Delay(TestTimeout)).ConfigureAwait(false); Assert.True( eventsReceived.CurrentCount == 0, "Timed out waiting for events."); @@ -256,19 +256,19 @@ namespace k8s.Tests using (var server = new MockKubeApiServer(testOutput, async httpContext => { - await WriteStreamLine(httpContext, MockAddedEventStreamLine); - await WriteStreamLine(httpContext, MockDeletedStreamLine); - await WriteStreamLine(httpContext, MockModifiedStreamLine); - await WriteStreamLine(httpContext, MockErrorStreamLine); + await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockDeletedStreamLine).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockModifiedStreamLine).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockErrorStreamLine).ConfigureAwait(false); // make server alive, cannot set to int.max as of it would block response - await serverShutdown.WaitAsync(); + await serverShutdown.WaitAsync().ConfigureAwait(false); return false; })) { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); - var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true); + var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true).ConfigureAwait(false); var events = new HashSet(); var errors = 0; @@ -291,7 +291,7 @@ namespace k8s.Tests onClosed: waitForClosed.Set); // wait server yields all events - await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); + await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false); Assert.True( eventsReceived.CurrentCount == 0, @@ -308,7 +308,7 @@ namespace k8s.Tests serverShutdown.Set(); - await Task.WhenAny(waitForClosed.WaitAsync(), Task.Delay(TestTimeout)); + await Task.WhenAny(waitForClosed.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false); Assert.True(waitForClosed.IsSet); Assert.False(watcher.Watching); } @@ -323,21 +323,21 @@ namespace k8s.Tests using (var server = new MockKubeApiServer(testOutput, async httpContext => { - await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse); - await Task.Delay(TimeSpan.FromSeconds(120)); // The default timeout is 100 seconds - await WriteStreamLine(httpContext, MockAddedEventStreamLine); - await WriteStreamLine(httpContext, MockDeletedStreamLine); - await WriteStreamLine(httpContext, MockModifiedStreamLine); - await WriteStreamLine(httpContext, MockErrorStreamLine); + await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse).ConfigureAwait(false); + await Task.Delay(TimeSpan.FromSeconds(120)).ConfigureAwait(false); // The default timeout is 100 seconds + await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockDeletedStreamLine).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockModifiedStreamLine).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockErrorStreamLine).ConfigureAwait(false); // make server alive, cannot set to int.max as of it would block response - await serverShutdown.WaitAsync(); + await serverShutdown.WaitAsync().ConfigureAwait(false); return false; })) { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); - var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true); + var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true).ConfigureAwait(false); var events = new HashSet(); var errors = 0; @@ -360,7 +360,7 @@ namespace k8s.Tests onClosed: connectionClosed.Set); // wait server yields all events - await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); + await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false); Assert.True( eventsReceived.CurrentCount == 0, @@ -377,7 +377,7 @@ namespace k8s.Tests serverShutdown.Set(); - await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TestTimeout)); + await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false); Assert.True(connectionClosed.IsSet); } } @@ -392,14 +392,14 @@ namespace k8s.Tests using (var server = new MockKubeApiServer(testOutput, async httpContext => { - await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse); - await waitForException.WaitAsync(); + await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse).ConfigureAwait(false); + await waitForException.WaitAsync().ConfigureAwait(false); throw new IOException("server down"); })) { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); - var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true); + var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true).ConfigureAwait(false); waitForException.Set(); Watcher watcher; @@ -413,13 +413,13 @@ namespace k8s.Tests onClosed: waitForClosed.Set); // wait server down - await Task.WhenAny(exceptionReceived.WaitAsync(), Task.Delay(TestTimeout)); + await Task.WhenAny(exceptionReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false); Assert.True( exceptionReceived.IsSet, "Timed out waiting for exception"); - await Task.WhenAny(waitForClosed.WaitAsync(), Task.Delay(TestTimeout)); + await Task.WhenAny(waitForClosed.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false); Assert.True(waitForClosed.IsSet); Assert.False(watcher.Watching); Assert.IsType(exceptionCatched); @@ -446,11 +446,11 @@ namespace k8s.Tests using (var server = new MockKubeApiServer(testOutput, async httpContext => { - await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse); - await WriteStreamLine(httpContext, MockAddedEventStreamLine); + await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false); // make server alive, cannot set to int.max as of it would block response - await serverShutdown.WaitAsync(); + await serverShutdown.WaitAsync().ConfigureAwait(false); return false; })) { @@ -463,7 +463,7 @@ namespace k8s.Tests Assert.False(handler1.Called); Assert.False(handler2.Called); - var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true); + var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true).ConfigureAwait(false); var events = new HashSet(); @@ -475,7 +475,7 @@ namespace k8s.Tests }); // wait server yields all events - await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); + await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false); Assert.True( eventsReceived.CurrentCount == 0, @@ -499,13 +499,13 @@ namespace k8s.Tests using (var server = new MockKubeApiServer(testOutput, async httpContext => { - await WriteStreamLine(httpContext, MockAddedEventStreamLine); - await WriteStreamLine(httpContext, MockDeletedStreamLine); - await WriteStreamLine(httpContext, MockModifiedStreamLine); - await WriteStreamLine(httpContext, MockErrorStreamLine); + await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockDeletedStreamLine).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockModifiedStreamLine).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockErrorStreamLine).ConfigureAwait(false); // make server alive, cannot set to int.max as of it would block response - await serverShutdown.WaitAsync(); + await serverShutdown.WaitAsync().ConfigureAwait(false); return false; })) { @@ -533,10 +533,10 @@ namespace k8s.Tests errors += 1; eventsReceived.Signal(); }, - onClosed: connectionClosed.Set); + onClosed: connectionClosed.Set).ConfigureAwait(false); // wait server yields all events - await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); + await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false); Assert.True( eventsReceived.CurrentCount == 0, @@ -553,7 +553,7 @@ namespace k8s.Tests serverShutdown.Set(); - await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TestTimeout)); + await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false); Assert.True(connectionClosed.IsSet); } } @@ -584,19 +584,19 @@ namespace k8s.Tests { Image = "ubuntu/xenial", Name = "runner", - Command = new List() {"/bin/bash", "-c", "--" }, + Command = new List() { "/bin/bash", "-c", "--" }, Args = new List() { - "trap : TERM INT; sleep infinity & wait" - } - } + "trap : TERM INT; sleep infinity & wait", + }, + }, }, - RestartPolicy = "Never" + RestartPolicy = "Never", }, - } + }, }, }, - "default"); + "default").ConfigureAwait(false); Collection> events = new Collection>(); @@ -618,15 +618,15 @@ namespace k8s.Tests }, onClosed: connectionClosed.Set).ConfigureAwait(false); - await started.WaitAsync(); + await started.WaitAsync().ConfigureAwait(false); - await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TimeSpan.FromMinutes(3))); + await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TimeSpan.FromMinutes(3))).ConfigureAwait(false); Assert.True(connectionClosed.IsSet); await kubernetes.DeleteNamespacedJobAsync( job.Metadata.Name, job.Metadata.NamespaceProperty, - new V1DeleteOptions()); + new V1DeleteOptions()).ConfigureAwait(false); } [Fact(Skip = "https://github.com/kubernetes-client/csharp/issues/165")] @@ -637,14 +637,14 @@ namespace k8s.Tests using (var server = new MockKubeApiServer(testOutput, async httpContext => { - await Task.Delay(TimeSpan.FromSeconds(120)); // The default timeout is 100 seconds - await WriteStreamLine(httpContext, MockAddedEventStreamLine); - await WriteStreamLine(httpContext, MockDeletedStreamLine); - await WriteStreamLine(httpContext, MockModifiedStreamLine); - await WriteStreamLine(httpContext, MockErrorStreamLine); + await Task.Delay(TimeSpan.FromSeconds(120)).ConfigureAwait(false); // The default timeout is 100 seconds + await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockDeletedStreamLine).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockModifiedStreamLine).ConfigureAwait(false); + await WriteStreamLine(httpContext, MockErrorStreamLine).ConfigureAwait(false); // make server alive, cannot set to int.max as of it would block response - await serverShutdown.WaitAsync(); + await serverShutdown.WaitAsync().ConfigureAwait(false); return false; })) { @@ -671,10 +671,10 @@ namespace k8s.Tests errors += 1; eventsReceived.Signal(); - }); + }).ConfigureAwait(false); // wait server yields all events - await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); + await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false); Assert.True( eventsReceived.CurrentCount == 0, @@ -701,8 +701,8 @@ namespace k8s.Tests using (var server = new MockKubeApiServer(testOutput, async httpContext => { httpContext.Response.StatusCode = 200; - await httpContext.Response.Body.FlushAsync(); - await Task.Delay(TimeSpan.FromSeconds(5)); // The default timeout is 100 seconds + await httpContext.Response.Body.FlushAsync().ConfigureAwait(false); + await Task.Delay(TimeSpan.FromSeconds(5)).ConfigureAwait(false); // The default timeout is 100 seconds return true; }, resp: "")) @@ -715,8 +715,8 @@ namespace k8s.Tests await Assert.ThrowsAnyAsync(async () => { await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true, - cancellationToken: cts.Token); - }); + cancellationToken: cts.Token).ConfigureAwait(false); + }).ConfigureAwait(false); } } } diff --git a/tests/KubernetesClient.Tests/WebSocketTestBase.cs b/tests/KubernetesClient.Tests/WebSocketTestBase.cs index d665716..ed0b193 100644 --- a/tests/KubernetesClient.Tests/WebSocketTestBase.cs +++ b/tests/KubernetesClient.Tests/WebSocketTestBase.cs @@ -24,8 +24,8 @@ namespace k8s.Tests /// /// The next server port to use. /// - static int NextPort = 13255; - + private static int nextPort = 13255; + private bool disposedValue; private readonly ITestOutputHelper testOutput; /// @@ -38,7 +38,7 @@ namespace k8s.Tests { this.testOutput = testOutput; - int port = Interlocked.Increment(ref NextPort); + int port = Interlocked.Increment(ref nextPort); // Useful to diagnose test timeouts. TestCancellation.Register( @@ -199,7 +199,7 @@ namespace k8s.Tests await serverSocket.CloseAsync( received.Result.CloseStatus.Value, received.Result.CloseStatusDescription, - TestCancellation); + TestCancellation).ConfigureAwait(false); testOutput.WriteLine("Server socket closed."); } @@ -260,7 +260,7 @@ namespace k8s.Tests await webSocket.SendAsync(sendBuffer, WebSocketMessageType.Binary, endOfMessage: true, - cancellationToken: TestCancellation); + cancellationToken: TestCancellation).ConfigureAwait(false); return sendBuffer.Length; } @@ -289,7 +289,7 @@ namespace k8s.Tests using (MemoryStream buffer = new MemoryStream()) { byte[] receiveBuffer = new byte[1024]; - WebSocketReceiveResult receiveResult = await webSocket.ReceiveAsync(receiveBuffer, TestCancellation); + WebSocketReceiveResult receiveResult = await webSocket.ReceiveAsync(receiveBuffer, TestCancellation).ConfigureAwait(false); if (receiveResult.MessageType != WebSocketMessageType.Binary) { throw new IOException( @@ -300,7 +300,7 @@ namespace k8s.Tests while (!receiveResult.EndOfMessage) { - receiveResult = await webSocket.ReceiveAsync(receiveBuffer, TestCancellation); + receiveResult = await webSocket.ReceiveAsync(receiveBuffer, TestCancellation).ConfigureAwait(false); buffer.Write(receiveBuffer, 0, receiveResult.Count); } @@ -315,11 +315,7 @@ namespace k8s.Tests totalBytes: receivedData.Length); } - public void Dispose() - { - this.CancellationSource.Dispose(); - this.Host.Dispose(); - } + /// /// A implementation representing no credentials (i.e. anonymous). @@ -335,7 +331,7 @@ namespace k8s.Tests /// /// Create new . /// - AnonymousClientCredentials() + private AnonymousClientCredentials() { } } @@ -348,7 +344,35 @@ namespace k8s.Tests /// /// An error occurred while closing the server-side socket. /// - static readonly EventId ErrorClosingServerSocket = new EventId(1000, nameof(ErrorClosingServerSocket)); + private static readonly EventId ErrorClosingServerSocket = new EventId(1000, nameof(ErrorClosingServerSocket)); + } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + CancellationSource.Dispose(); + Host.Dispose(); + } + + disposedValue = true; + } + } + + // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources + // ~WebSocketTestBase() + // { + // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + // Dispose(disposing: false); + // } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); } } } diff --git a/tests/KubernetesClient.Tests/YamlTests.cs b/tests/KubernetesClient.Tests/YamlTests.cs index f3ecc2f..7b1fc43 100644 --- a/tests/KubernetesClient.Tests/YamlTests.cs +++ b/tests/KubernetesClient.Tests/YamlTests.cs @@ -23,7 +23,7 @@ kind: Namespace metadata: name: ns"; - var types = new Dictionary(); + var types = new Dictionary(); types.Add("v1/Pod", typeof(V1Pod)); types.Add("v1/Namespace", typeof(V1Namespace)); @@ -157,15 +157,15 @@ metadata: { new V1VolumeMount { - Name = "vm1", MountPath = "/vm1", ReadOnlyProperty = true + Name = "vm1", MountPath = "/vm1", ReadOnlyProperty = true, }, new V1VolumeMount { - Name = "vm2", MountPath = "/vm2", ReadOnlyProperty = false + Name = "vm2", MountPath = "/vm2", ReadOnlyProperty = false, }, - } - } - } + }, + }, + }, }, }; @@ -284,7 +284,7 @@ spec: ApiVersion = "v1", Spec = new V1ServiceSpec { - Ports = new List { new V1ServicePort { Port = 3000, TargetPort = 3000 } } + Ports = new List { new V1ServicePort { Port = 3000, TargetPort = 3000 } }, }, }; @@ -336,8 +336,8 @@ data: "; var result = Yaml.LoadFromString(kManifest); - Assert.Equal(Encoding.UTF8.GetString(result.Data["username"]), "bXktYXBw"); - Assert.Equal(Encoding.UTF8.GetString(result.Data["password"]), "Mzk1MjgkdmRnN0pi"); + Assert.Equal("bXktYXBw", Encoding.UTF8.GetString(result.Data["username"])); + Assert.Equal("Mzk1MjgkdmRnN0pi", Encoding.UTF8.GetString(result.Data["password"])); } } }