Skip to content

Commit 163c18b

Browse files
committed
refactor(testing): Adjust test helpers according to breaking changes.
BREAKING CHANGE: This removes the mocked event queue. To test controllers and finalizers, use the provided methods of the KubernetesOperatorFactory to enqueue events and finalizers.
1 parent a63b511 commit 163c18b

21 files changed

+436
-682
lines changed
Lines changed: 96 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
using System;
2+
using System.Linq;
3+
using System.Threading.Tasks;
24
using DotnetKubernetesClient;
35
using k8s;
46
using k8s.Models;
7+
using KubeOps.Operator.Controller;
8+
using KubeOps.Operator.Kubernetes;
9+
using KubeOps.Operator.Leadership;
510
using Microsoft.AspNetCore.Hosting;
611
using Microsoft.AspNetCore.Mvc.Testing;
712
using Microsoft.AspNetCore.TestHost;
@@ -16,83 +21,95 @@ namespace KubeOps.Testing
1621
/// Operator factory for testing an operator created with the asp web server.
1722
/// </summary>
1823
/// <typeparam name="TTestStartup">Type of the Startup type (see asp.net).</typeparam>
19-
// public class KubernetesOperatorFactory<TTestStartup> : WebApplicationFactory<TTestStartup>
20-
// where TTestStartup : class
21-
// {
22-
// private string? _solutionRelativeContentRoot;
23-
//
24-
// /// <summary>
25-
// /// Return a mocked kubernetes client. This client defines
26-
// /// no-op for all related methods.
27-
// /// </summary>
28-
// public MockKubernetesClient MockedKubernetesClient =>
29-
// Services.GetRequiredService<IKubernetesClient>() as MockKubernetesClient ??
30-
// throw new ArgumentException("Wrong kubernetes client registered.");
31-
//
32-
// /// <summary>
33-
// /// Set a specific content root path to the given factory.
34-
// /// </summary>
35-
// /// <param name="root"></param>
36-
// /// <returns></returns>
37-
// public KubernetesOperatorFactory<TTestStartup> WithSolutionRelativeContentRoot(string root)
38-
// {
39-
// _solutionRelativeContentRoot = root;
40-
// return this;
41-
// }
42-
//
43-
// /// <summary>
44-
// /// Start the server.
45-
// /// </summary>
46-
// public void Run()
47-
// {
48-
// // This triggers "EnsureServer()" in the base class.
49-
// var server = Server;
50-
// }
51-
//
52-
// /// <summary>
53-
// /// Return a mocked event queue for the given entity.
54-
// /// </summary>
55-
// /// <typeparam name="TEntity">The type of the entity.</typeparam>
56-
// /// <returns>A mocked event queue for the given type.</returns>
57-
// public MockResourceEventQueue<TEntity> GetMockedEventQueue<TEntity>()
58-
// where TEntity : IKubernetesObject<V1ObjectMeta>
59-
// => Services.GetRequiredService<MockResourceQueueCollection>().Get<TEntity>();
60-
//
61-
// /// <summary>
62-
// /// Create the host builder. Needed for the factory.
63-
// /// </summary>
64-
// /// <returns></returns>
65-
// protected override IHostBuilder CreateHostBuilder() =>
66-
// Host.CreateDefaultBuilder()
67-
// .ConfigureWebHostDefaults(
68-
// webBuilder => webBuilder
69-
// .UseStartup<TTestStartup>());
70-
//
71-
// /// <summary>
72-
// /// Configure the web-host.
73-
// /// This registers the mocked client as well as mocked
74-
// /// event queues.
75-
// /// </summary>
76-
// /// <param name="builder">The web host builder.</param>
77-
// protected override void ConfigureWebHost(IWebHostBuilder builder)
78-
// {
79-
// base.ConfigureWebHost(builder);
80-
// if (_solutionRelativeContentRoot != null)
81-
// {
82-
// builder.UseSolutionRelativeContentRoot(_solutionRelativeContentRoot);
83-
// }
84-
//
85-
// builder.ConfigureTestServices(
86-
// services =>
87-
// {
88-
// // services.RemoveAll(typeof(IResourceEventQueue<>));
89-
// // services.AddTransient(typeof(IResourceEventQueue<>), typeof(MockResourceEventQueue<>));
90-
// // services.AddSingleton<MockResourceQueueCollection>();
91-
//
92-
// services.RemoveAll(typeof(IKubernetesClient));
93-
// services.AddSingleton<IKubernetesClient, MockKubernetesClient>();
94-
// });
95-
// builder.ConfigureLogging(logging => logging.ClearProviders());
96-
// }
97-
// }
24+
public class KubernetesOperatorFactory<TTestStartup> : WebApplicationFactory<TTestStartup>
25+
where TTestStartup : class
26+
{
27+
private string? _solutionRelativeContentRoot;
28+
29+
/// <summary>
30+
/// Return a mocked kubernetes client. This client defines
31+
/// no-op for all related methods.
32+
/// </summary>
33+
public MockKubernetesClient MockedKubernetesClient =>
34+
Services.GetRequiredService<IKubernetesClient>() as MockKubernetesClient ??
35+
throw new ArgumentException("Wrong kubernetes client registered.");
36+
37+
/// <summary>
38+
/// Set a specific content root path to the given factory.
39+
/// </summary>
40+
/// <param name="root">The solution relative content root path to configure.</param>
41+
/// <returns>The <see cref="KubernetesOperatorFactory{TTestStartup}"/> for chaining.</returns>
42+
public KubernetesOperatorFactory<TTestStartup> WithSolutionRelativeContentRoot(string root)
43+
{
44+
_solutionRelativeContentRoot = root;
45+
return this;
46+
}
47+
48+
/// <summary>
49+
/// Start the server.
50+
/// </summary>
51+
public void Run()
52+
{
53+
// This triggers "EnsureServer()" in the base class.
54+
var server = Server;
55+
}
56+
57+
public Task EnqueueEvent<TResource>(ResourceEventType type, TResource resource)
58+
where TResource : class, IKubernetesObject<V1ObjectMeta>
59+
{
60+
var controller = Services.GetRequiredService<ManagedResourceController<TResource>>() as
61+
MockManagedResourceController<TResource>;
62+
63+
return controller?.EnqueueEvent(type, resource) ?? Task.CompletedTask;
64+
}
65+
66+
public Task EnqueueFinalization<TResource>(TResource resource)
67+
where TResource : class, IKubernetesObject<V1ObjectMeta>
68+
{
69+
var controller = Services.GetRequiredService<ManagedResourceController<TResource>>() as
70+
MockManagedResourceController<TResource>;
71+
72+
return controller?.EnqueueFinalization(resource) ?? Task.CompletedTask;
73+
}
74+
75+
/// <summary>
76+
/// Create the host builder. Needed for the factory.
77+
/// </summary>
78+
/// <returns>The created <see cref="IHostBuilder"/>.</returns>
79+
protected override IHostBuilder CreateHostBuilder() =>
80+
Host.CreateDefaultBuilder()
81+
.ConfigureWebHostDefaults(
82+
webBuilder => webBuilder
83+
.UseStartup<TTestStartup>());
84+
85+
/// <summary>
86+
/// Configure the web-host.
87+
/// This registers the mocked client as well as mocked
88+
/// event queues.
89+
/// </summary>
90+
/// <param name="builder">The web host builder.</param>
91+
protected override void ConfigureWebHost(IWebHostBuilder builder)
92+
{
93+
base.ConfigureWebHost(builder);
94+
if (_solutionRelativeContentRoot != null)
95+
{
96+
builder.UseSolutionRelativeContentRoot(_solutionRelativeContentRoot);
97+
}
98+
99+
builder.ConfigureTestServices(
100+
services =>
101+
{
102+
var elector = services.First(
103+
d => d.ServiceType == typeof(IHostedService) && d.ImplementationType == typeof(LeaderElector));
104+
services.Remove(elector);
105+
106+
services.RemoveAll(typeof(IKubernetesClient));
107+
services.AddSingleton<IKubernetesClient, MockKubernetesClient>();
108+
109+
services.RemoveAll(typeof(ManagedResourceController<>));
110+
services.AddSingleton(typeof(ManagedResourceController<>), typeof(MockManagedResourceController<>));
111+
});
112+
builder.ConfigureLogging(logging => logging.ClearProviders());
113+
}
114+
}
98115
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using DotnetKubernetesClient;
4+
using k8s;
5+
using k8s.Models;
6+
using KubeOps.Operator;
7+
using KubeOps.Operator.Caching;
8+
using KubeOps.Operator.Controller;
9+
using KubeOps.Operator.DevOps;
10+
using KubeOps.Operator.Finalizer;
11+
using KubeOps.Operator.Kubernetes;
12+
using Microsoft.Extensions.Logging;
13+
14+
namespace KubeOps.Testing
15+
{
16+
internal class MockManagedResourceController<TResource> : ManagedResourceController<TResource>
17+
where TResource : class, IKubernetesObject<V1ObjectMeta>
18+
{
19+
public MockManagedResourceController(
20+
ILogger<ManagedResourceController<TResource>> logger,
21+
IKubernetesClient client,
22+
ResourceWatcher<TResource> watcher,
23+
ResourceCache<TResource> cache,
24+
IServiceProvider services,
25+
ResourceControllerMetrics<TResource> metrics,
26+
OperatorSettings settings,
27+
IFinalizerManager<TResource> finalizerManager)
28+
: base(logger, client, watcher, cache, services, metrics, settings, finalizerManager)
29+
{
30+
}
31+
32+
public override Task StartAsync() => Task.CompletedTask;
33+
34+
public override Task StopAsync() => Task.CompletedTask;
35+
36+
public Task EnqueueEvent(ResourceEventType type, TResource resource) =>
37+
HandleResourceEvent(new QueuedEvent(type, resource));
38+
39+
public Task EnqueueFinalization(TResource resource) =>
40+
HandleResourceFinalization(new QueuedEvent(ResourceEventType.Finalizing, resource));
41+
}
42+
}

src/KubeOps.Testing/MockResourceEventQueue.cs

Lines changed: 0 additions & 109 deletions
This file was deleted.

src/KubeOps.Testing/MockResourceQueueCollection.cs

Lines changed: 0 additions & 49 deletions
This file was deleted.

0 commit comments

Comments
 (0)