Ensure that awaits do not continue on the captured context. (#370)
* Ensure that awaits do not continue on the captured context. * Make functions async for maintainability. * Add documentation detailing the use of UIFact.
This commit is contained in:
@@ -273,7 +273,7 @@ namespace k8s
|
|||||||
{
|
{
|
||||||
// Copy the default (credential-related) request headers from the HttpClient to the WebSocket
|
// Copy the default (credential-related) request headers from the HttpClient to the WebSocket
|
||||||
HttpRequestMessage message = new HttpRequestMessage();
|
HttpRequestMessage message = new HttpRequestMessage();
|
||||||
await this.Credentials.ProcessHttpRequestAsync(message, cancellationToken);
|
await this.Credentials.ProcessHttpRequestAsync(message, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
foreach (var _header in message.Headers)
|
foreach (var _header in message.Headers)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ namespace k8s
|
|||||||
throw new NullReferenceException(nameof(kubeconfig));
|
throw new NullReferenceException(nameof(kubeconfig));
|
||||||
}
|
}
|
||||||
|
|
||||||
var k8SConfig = await LoadKubeConfigAsync(kubeconfig, useRelativePaths);
|
var k8SConfig = await LoadKubeConfigAsync(kubeconfig, useRelativePaths).ConfigureAwait(false);
|
||||||
var k8SConfiguration = GetKubernetesClientConfiguration(currentContext, masterUrl, k8SConfig);
|
var k8SConfiguration = GetKubernetesClientConfiguration(currentContext, masterUrl, k8SConfig);
|
||||||
|
|
||||||
return k8SConfiguration;
|
return k8SConfiguration;
|
||||||
@@ -139,7 +139,7 @@ namespace k8s
|
|||||||
|
|
||||||
kubeconfig.Position = 0;
|
kubeconfig.Position = 0;
|
||||||
|
|
||||||
var k8SConfig = await Yaml.LoadFromStreamAsync<K8SConfiguration>(kubeconfig);
|
var k8SConfig = await Yaml.LoadFromStreamAsync<K8SConfiguration>(kubeconfig).ConfigureAwait(false);
|
||||||
var k8SConfiguration = GetKubernetesClientConfiguration(currentContext, masterUrl, k8SConfig);
|
var k8SConfiguration = GetKubernetesClientConfiguration(currentContext, masterUrl, k8SConfig);
|
||||||
|
|
||||||
return k8SConfiguration;
|
return k8SConfiguration;
|
||||||
@@ -486,7 +486,7 @@ namespace k8s
|
|||||||
{
|
{
|
||||||
var fileInfo = new FileInfo(kubeconfigPath ?? KubeConfigDefaultLocation);
|
var fileInfo = new FileInfo(kubeconfigPath ?? KubeConfigDefaultLocation);
|
||||||
|
|
||||||
return await LoadKubeConfigAsync(fileInfo, useRelativePaths);
|
return await LoadKubeConfigAsync(fileInfo, useRelativePaths).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -517,7 +517,7 @@ namespace k8s
|
|||||||
|
|
||||||
using (var stream = kubeconfig.OpenRead())
|
using (var stream = kubeconfig.OpenRead())
|
||||||
{
|
{
|
||||||
var config = await Yaml.LoadFromStreamAsync<K8SConfiguration>(stream);
|
var config = await Yaml.LoadFromStreamAsync<K8SConfiguration>(stream).ConfigureAwait(false);
|
||||||
|
|
||||||
if (useRelativePaths)
|
if (useRelativePaths)
|
||||||
{
|
{
|
||||||
@@ -547,7 +547,7 @@ namespace k8s
|
|||||||
/// <returns>Instance of the <see cref="K8SConfiguration"/> class</returns>
|
/// <returns>Instance of the <see cref="K8SConfiguration"/> class</returns>
|
||||||
public static async Task<K8SConfiguration> LoadKubeConfigAsync(Stream kubeconfigStream)
|
public static async Task<K8SConfiguration> LoadKubeConfigAsync(Stream kubeconfigStream)
|
||||||
{
|
{
|
||||||
return await Yaml.LoadFromStreamAsync<K8SConfiguration>(kubeconfigStream);
|
return await Yaml.LoadFromStreamAsync<K8SConfiguration>(kubeconfigStream).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ namespace k8s
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
this.runLoop = this.RunLoop(this.cts.Token);
|
this.runLoop = Task.Run(async () => await this.RunLoop(this.cts.Token));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -193,9 +193,6 @@ namespace k8s
|
|||||||
|
|
||||||
protected async Task RunLoop(CancellationToken cancellationToken)
|
protected async Task RunLoop(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// This is a background task. Immediately yield to the caller.
|
|
||||||
await Task.Yield();
|
|
||||||
|
|
||||||
// Get a 1KB buffer
|
// Get a 1KB buffer
|
||||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(1024 * 1024);
|
byte[] buffer = ArrayPool<byte>.Shared.Rent(1024 * 1024);
|
||||||
// This maps remembers bytes skipped for each stream.
|
// This maps remembers bytes skipped for each stream.
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ namespace k8s
|
|||||||
OnClosed += onClosed;
|
OnClosed += onClosed;
|
||||||
|
|
||||||
_cts = new CancellationTokenSource();
|
_cts = new CancellationTokenSource();
|
||||||
_watcherLoop = this.WatcherLoop(_cts.Token);
|
_watcherLoop = Task.Run(async () => await this.WatcherLoop(_cts.Token));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -91,14 +91,11 @@ namespace k8s
|
|||||||
|
|
||||||
private async Task WatcherLoop(CancellationToken cancellationToken)
|
private async Task WatcherLoop(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// Make sure we run async
|
|
||||||
await Task.Yield();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Watching = true;
|
Watching = true;
|
||||||
string line;
|
string line;
|
||||||
_streamReader = await _streamReaderCreator();
|
_streamReader = await _streamReaderCreator().ConfigureAwait(false);
|
||||||
|
|
||||||
// ReadLineAsync will return null when we've reached the end of the stream.
|
// ReadLineAsync will return null when we've reached the end of the stream.
|
||||||
while ((line = await _streamReader.ReadLineAsync().ConfigureAwait(false)) != null)
|
while ((line = await _streamReader.ReadLineAsync().ConfigureAwait(false)) != null)
|
||||||
@@ -164,7 +161,7 @@ namespace k8s
|
|||||||
Action onClosed = null)
|
Action onClosed = null)
|
||||||
{
|
{
|
||||||
return new Watcher<T>(async () => {
|
return new Watcher<T>(async () => {
|
||||||
var response = await responseTask;
|
var response = await responseTask.ConfigureAwait(false);
|
||||||
|
|
||||||
if (!(response.Response.Content is WatcherDelegatingHandler.LineSeparatedHttpContent content))
|
if (!(response.Response.Content is WatcherDelegatingHandler.LineSeparatedHttpContent content))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace k8s
|
|||||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var originResponse = await base.SendAsync(request, cancellationToken);
|
var originResponse = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (originResponse.IsSuccessStatusCode)
|
if (originResponse.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
@@ -47,18 +47,18 @@ namespace k8s
|
|||||||
|
|
||||||
protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
|
protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
|
||||||
{
|
{
|
||||||
_originStream = await _originContent.ReadAsStreamAsync();
|
_originStream = await _originContent.ReadAsStreamAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
StreamReader = new PeekableStreamReader(_originStream);
|
StreamReader = new PeekableStreamReader(_originStream);
|
||||||
|
|
||||||
var firstLine = await StreamReader.PeekLineAsync();
|
var firstLine = await StreamReader.PeekLineAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
var writer = new StreamWriter(stream);
|
var writer = new StreamWriter(stream);
|
||||||
|
|
||||||
// using (writer) // leave open
|
// using (writer) // leave open
|
||||||
{
|
{
|
||||||
await writer.WriteAsync(firstLine);
|
await writer.WriteAsync(firstLine).ConfigureAwait(false);
|
||||||
await writer.FlushAsync();
|
await writer.FlushAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ namespace k8s
|
|||||||
}
|
}
|
||||||
public async Task<string> PeekLineAsync()
|
public async Task<string> PeekLineAsync()
|
||||||
{
|
{
|
||||||
var line = await ReadLineAsync();
|
var line = await ReadLineAsync().ConfigureAwait(false);
|
||||||
_buffer.Enqueue(line);
|
_buffer.Enqueue(line);
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace k8s
|
|||||||
/// </param>
|
/// </param>
|
||||||
public static async Task<List<object>> LoadAllFromStreamAsync(Stream stream, Dictionary<String, Type> typeMap) {
|
public static async Task<List<object>> LoadAllFromStreamAsync(Stream stream, Dictionary<String, Type> typeMap) {
|
||||||
var reader = new StreamReader(stream);
|
var reader = new StreamReader(stream);
|
||||||
var content = await reader.ReadToEndAsync();
|
var content = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||||
return LoadAllFromString(content, typeMap);
|
return LoadAllFromString(content, typeMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,13 +95,13 @@ namespace k8s
|
|||||||
|
|
||||||
public static async Task<T> LoadFromStreamAsync<T>(Stream stream) {
|
public static async Task<T> LoadFromStreamAsync<T>(Stream stream) {
|
||||||
var reader = new StreamReader(stream);
|
var reader = new StreamReader(stream);
|
||||||
var content = await reader.ReadToEndAsync();
|
var content = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||||
return LoadFromString<T>(content);
|
return LoadFromString<T>(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<T> LoadFromFileAsync<T> (string file) {
|
public static async Task<T> LoadFromFileAsync<T> (string file) {
|
||||||
using (FileStream fs = File.OpenRead(file)) {
|
using (FileStream fs = File.OpenRead(file)) {
|
||||||
return await LoadFromStreamAsync<T>(fs);
|
return await LoadFromStreamAsync<T>(fs).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
|
||||||
|
<PackageReference Include="Xunit.StaFact" Version="0.3.18" />
|
||||||
<PackageReference Include="Moq" Version="4.13.1" />
|
<PackageReference Include="Moq" Version="4.13.1" />
|
||||||
|
|
||||||
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
|
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using k8s.Exceptions;
|
using k8s.Exceptions;
|
||||||
using k8s.KubeConfigModels;
|
using k8s.KubeConfigModels;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@@ -406,6 +407,17 @@ namespace k8s.Tests
|
|||||||
AssertConfigEqual(expectedCfg, cfg);
|
AssertConfigEqual(expectedCfg, cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ensures Kube config file can be loaded from within a non-default <see cref="SynchronizationContext"/>.
|
||||||
|
/// The use of <see cref="UIFactAttribute"/> ensures the test is run from within a UI-like <see cref="SynchronizationContext"/>.
|
||||||
|
/// </summary>
|
||||||
|
[UIFact]
|
||||||
|
public void BuildConfigFromConfigFileInfoOnNonDefaultSynchronizationContext()
|
||||||
|
{
|
||||||
|
var fi = new FileInfo("assets/kubeconfig.yml");
|
||||||
|
KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, "federal-context", useRelativePaths: false);
|
||||||
|
}
|
||||||
|
|
||||||
private void AssertConfigEqual(K8SConfiguration expected, K8SConfiguration actual)
|
private void AssertConfigEqual(K8SConfiguration expected, K8SConfiguration actual)
|
||||||
{
|
{
|
||||||
Assert.Equal(expected.ApiVersion, actual.ApiVersion);
|
Assert.Equal(expected.ApiVersion, actual.ApiVersion);
|
||||||
|
|||||||
Reference in New Issue
Block a user