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
|
||||
HttpRequestMessage message = new HttpRequestMessage();
|
||||
await this.Credentials.ProcessHttpRequestAsync(message, cancellationToken);
|
||||
await this.Credentials.ProcessHttpRequestAsync(message, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
foreach (var _header in message.Headers)
|
||||
{
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace k8s
|
||||
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);
|
||||
|
||||
return k8SConfiguration;
|
||||
@@ -139,7 +139,7 @@ namespace k8s
|
||||
|
||||
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);
|
||||
|
||||
return k8SConfiguration;
|
||||
@@ -486,7 +486,7 @@ namespace k8s
|
||||
{
|
||||
var fileInfo = new FileInfo(kubeconfigPath ?? KubeConfigDefaultLocation);
|
||||
|
||||
return await LoadKubeConfigAsync(fileInfo, useRelativePaths);
|
||||
return await LoadKubeConfigAsync(fileInfo, useRelativePaths).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -517,7 +517,7 @@ namespace k8s
|
||||
|
||||
using (var stream = kubeconfig.OpenRead())
|
||||
{
|
||||
var config = await Yaml.LoadFromStreamAsync<K8SConfiguration>(stream);
|
||||
var config = await Yaml.LoadFromStreamAsync<K8SConfiguration>(stream).ConfigureAwait(false);
|
||||
|
||||
if (useRelativePaths)
|
||||
{
|
||||
@@ -547,7 +547,7 @@ namespace k8s
|
||||
/// <returns>Instance of the <see cref="K8SConfiguration"/> class</returns>
|
||||
public static async Task<K8SConfiguration> LoadKubeConfigAsync(Stream kubeconfigStream)
|
||||
{
|
||||
return await Yaml.LoadFromStreamAsync<K8SConfiguration>(kubeconfigStream);
|
||||
return await Yaml.LoadFromStreamAsync<K8SConfiguration>(kubeconfigStream).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace k8s
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
this.runLoop = this.RunLoop(this.cts.Token);
|
||||
this.runLoop = Task.Run(async () => await this.RunLoop(this.cts.Token));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -193,9 +193,6 @@ namespace k8s
|
||||
|
||||
protected async Task RunLoop(CancellationToken cancellationToken)
|
||||
{
|
||||
// This is a background task. Immediately yield to the caller.
|
||||
await Task.Yield();
|
||||
|
||||
// Get a 1KB buffer
|
||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(1024 * 1024);
|
||||
// This maps remembers bytes skipped for each stream.
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace k8s
|
||||
OnClosed += onClosed;
|
||||
|
||||
_cts = new CancellationTokenSource();
|
||||
_watcherLoop = this.WatcherLoop(_cts.Token);
|
||||
_watcherLoop = Task.Run(async () => await this.WatcherLoop(_cts.Token));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -91,14 +91,11 @@ namespace k8s
|
||||
|
||||
private async Task WatcherLoop(CancellationToken cancellationToken)
|
||||
{
|
||||
// Make sure we run async
|
||||
await Task.Yield();
|
||||
|
||||
try
|
||||
{
|
||||
Watching = true;
|
||||
string line;
|
||||
_streamReader = await _streamReaderCreator();
|
||||
_streamReader = await _streamReaderCreator().ConfigureAwait(false);
|
||||
|
||||
// ReadLineAsync will return null when we've reached the end of the stream.
|
||||
while ((line = await _streamReader.ReadLineAsync().ConfigureAwait(false)) != null)
|
||||
@@ -164,7 +161,7 @@ namespace k8s
|
||||
Action onClosed = null)
|
||||
{
|
||||
return new Watcher<T>(async () => {
|
||||
var response = await responseTask;
|
||||
var response = await responseTask.ConfigureAwait(false);
|
||||
|
||||
if (!(response.Response.Content is WatcherDelegatingHandler.LineSeparatedHttpContent content))
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace k8s
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var originResponse = await base.SendAsync(request, cancellationToken);
|
||||
var originResponse = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (originResponse.IsSuccessStatusCode)
|
||||
{
|
||||
@@ -47,18 +47,18 @@ namespace k8s
|
||||
|
||||
protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
|
||||
{
|
||||
_originStream = await _originContent.ReadAsStreamAsync();
|
||||
_originStream = await _originContent.ReadAsStreamAsync().ConfigureAwait(false);
|
||||
|
||||
StreamReader = new PeekableStreamReader(_originStream);
|
||||
|
||||
var firstLine = await StreamReader.PeekLineAsync();
|
||||
var firstLine = await StreamReader.PeekLineAsync().ConfigureAwait(false);
|
||||
|
||||
var writer = new StreamWriter(stream);
|
||||
|
||||
// using (writer) // leave open
|
||||
{
|
||||
await writer.WriteAsync(firstLine);
|
||||
await writer.FlushAsync();
|
||||
await writer.WriteAsync(firstLine).ConfigureAwait(false);
|
||||
await writer.FlushAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace k8s
|
||||
}
|
||||
public async Task<string> PeekLineAsync()
|
||||
{
|
||||
var line = await ReadLineAsync();
|
||||
var line = await ReadLineAsync().ConfigureAwait(false);
|
||||
_buffer.Enqueue(line);
|
||||
return line;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace k8s
|
||||
/// </param>
|
||||
public static async Task<List<object>> LoadAllFromStreamAsync(Stream stream, Dictionary<String, Type> typeMap) {
|
||||
var reader = new StreamReader(stream);
|
||||
var content = await reader.ReadToEndAsync();
|
||||
var content = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||
return LoadAllFromString(content, typeMap);
|
||||
}
|
||||
|
||||
@@ -95,13 +95,13 @@ namespace k8s
|
||||
|
||||
public static async Task<T> LoadFromStreamAsync<T>(Stream stream) {
|
||||
var reader = new StreamReader(stream);
|
||||
var content = await reader.ReadToEndAsync();
|
||||
var content = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||
return LoadFromString<T>(content);
|
||||
}
|
||||
|
||||
public static async Task<T> LoadFromFileAsync<T> (string 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="xunit" 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" />
|
||||
|
||||
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using k8s.Exceptions;
|
||||
using k8s.KubeConfigModels;
|
||||
using Xunit;
|
||||
@@ -406,6 +407,17 @@ namespace k8s.Tests
|
||||
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)
|
||||
{
|
||||
Assert.Equal(expected.ApiVersion, actual.ApiVersion);
|
||||
|
||||
Reference in New Issue
Block a user