fix: remove Kubernetes provider from map when disposed (#11767)

Signed-off-by: Philippe Martin <phmartin@redhat.com>
This commit is contained in:
Philippe Martin 2025-03-20 10:04:56 +01:00 committed by GitHub
parent 5fc39cbc5a
commit d54afb5a4d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 76 additions and 20 deletions

View file

@ -52,7 +52,7 @@ import { ProviderRegistry } from './provider-registry.js';
import type { Telemetry } from './telemetry/telemetry.js';
import { Disposable } from './types/disposable.js';
let providerRegistry: ProviderRegistry;
let providerRegistry: TestProviderRegistry;
let autostartEngine: AutostartEngine;
const telemetryTrackMock = vi.fn();
@ -60,6 +60,12 @@ const apiSenderSendMock = vi.fn();
let containerRegistry: ContainerProviderRegistry;
class TestProviderRegistry extends ProviderRegistry {
getKubernetesProviders(): Map<string, KubernetesProviderConnection> {
return this.kubernetesProviders;
}
}
beforeEach(() => {
vi.clearAllMocks();
vi.restoreAllMocks();
@ -75,7 +81,7 @@ beforeEach(() => {
isApiAttached: vi.fn(),
onApiAttached: vi.fn(),
} as unknown as ContainerProviderRegistry;
providerRegistry = new ProviderRegistry(apiSender, containerRegistry, telemetry);
providerRegistry = new TestProviderRegistry(apiSender, containerRegistry, telemetry);
autostartEngine = {
registerProvider: vi.fn(),
} as unknown as AutostartEngine;
@ -314,26 +320,75 @@ test('expect isProviderContainerConnection returns false with a ProviderKubernet
expect(res).toBe(false);
});
test('should register kubernetes provider', async () => {
const provider = providerRegistry.createProvider('id', 'name', {
id: 'internal',
name: 'internal',
status: 'installed',
describe('a Kubernetes provider is registered', async () => {
let provider: Provider;
let disposable: Disposable;
let connection: KubernetesProviderConnection;
beforeEach(() => {
vi.useFakeTimers();
provider = providerRegistry.createProvider('id', 'name', {
id: 'internal',
name: 'internal',
status: 'installed',
});
connection = {
name: 'connection',
endpoint: {
apiURL: 'url',
},
lifecycle: undefined,
status: (): ProviderConnectionStatus => 'started',
};
disposable = providerRegistry.registerKubernetesConnection(provider, connection);
});
const connection: KubernetesProviderConnection = {
name: 'connection',
endpoint: {
apiURL: 'url',
},
lifecycle: undefined,
status: () => 'started',
};
providerRegistry.registerKubernetesConnection(provider, connection);
test('should send telemetry and be added to registry', async () => {
expect(telemetryTrackMock).toHaveBeenLastCalledWith('registerKubernetesProviderConnection', {
name: 'connection',
total: 1,
});
expect(telemetryTrackMock).toHaveBeenLastCalledWith('registerKubernetesProviderConnection', {
name: 'connection',
total: 1,
expect(providerRegistry.getKubernetesProviders().keys()).toContain('internal.connection');
});
test('should be removed from registry when disposed', async () => {
disposable.dispose();
expect(providerRegistry.getKubernetesProviders().keys()).not.toContain('internal.connection');
});
test('should send provider-change when status of vm changes', async () => {
// status unchanged, do not send event
vi.advanceTimersByTime(2005);
expect(apiSenderSendMock).not.toHaveBeenCalledWith('provider-change', expect.anything());
connection.status = (): ProviderConnectionStatus => 'stopped';
// status changed, send event
vi.advanceTimersByTime(2000);
expect(apiSenderSendMock).toHaveBeenCalledWith('provider-change', {});
});
test('should send provider-change when Kubernetes provider disposed', async () => {
expect(apiSenderSendMock).not.toHaveBeenCalledWith('provider-change', expect.anything());
disposable.dispose();
expect(apiSenderSendMock).toHaveBeenCalledWith('provider-change', {});
});
test('should not send provider-change when Kubernetes provider disposed and status changes', async () => {
expect(apiSenderSendMock).not.toHaveBeenCalledWith('provider-change', expect.anything());
disposable.dispose();
expect(apiSenderSendMock).toHaveBeenCalledWith('provider-change', {});
apiSenderSendMock.mockClear();
connection.status = (): ProviderConnectionStatus => 'stopped';
// status changed, do not send event
vi.advanceTimersByTime(20_000);
expect(apiSenderSendMock).not.toHaveBeenCalledWith('provider-change', {});
});
});

View file

@ -106,7 +106,7 @@ export class ProviderRegistry {
private lifecycleListeners: ProviderLifecycleListener[];
private containerConnectionLifecycleListeners: ContainerConnectionProviderLifecycleListener[];
private kubernetesProviders: Map<string, KubernetesProviderConnection> = new Map();
protected kubernetesProviders: Map<string, KubernetesProviderConnection> = new Map();
private readonly _onDidUpdateProvider = new Emitter<ProviderEvent>();
readonly onDidUpdateProvider: Event<ProviderEvent> = this._onDidUpdateProvider.event;
@ -1268,6 +1268,7 @@ export class ProviderRegistry {
// listen to events
return Disposable.create(() => {
clearInterval(timer);
this.kubernetesProviders.delete(id);
this.apiSender.send('provider-change', {});
});
}