Merge pull request #13539 from tomasaschan/plugin-kubernetes/reset-error

Reset error on success path
This commit is contained in:
Patrik Oldsberg
2022-09-07 14:33:05 +02:00
committed by GitHub
4 changed files with 176 additions and 17 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-kubernetes': patch
---
Reset error state on success
+2 -2
View File
@@ -337,9 +337,9 @@ export const KubernetesDrawer: <T extends KubernetesDrawerable>({
// @public (undocumented)
export interface KubernetesObjects {
// (undocumented)
error: string | undefined;
error?: string;
// (undocumented)
kubernetesObjects: ObjectsByEntityResponse | undefined;
kubernetesObjects?: ObjectsByEntityResponse;
}
// Warning: (ae-missing-release-tag) "kubernetesPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -125,6 +125,8 @@ describe('useKubernetesObjects', () => {
);
await waitForNextUpdate();
expect(result.current.error).toBeUndefined();
await waitForNextUpdate();
expect(result.current.error).toBeUndefined();
@@ -199,4 +201,159 @@ describe('useKubernetesObjects', () => {
});
expect(mockGetObjectsByEntity).toHaveBeenCalledTimes(0);
});
describe('when retrying', () => {
it('should reset error after getClusters has failed and then succeeded', async () => {
(useApi as any).mockReturnValue({
getClusters: mockGetClusters
.mockRejectedValueOnce({ message: 'some-error' })
.mockResolvedValue(getClustersResponse),
decorateRequestBodyForAuth:
mockDecorateRequestBodyForAuth.mockResolvedValue(entityWithAuthToken),
getObjectsByEntity:
mockGetObjectsByEntity.mockResolvedValue(mockResponse),
});
const { result, waitForNextUpdate } = renderHook(() =>
useKubernetesObjects(entity, 100),
);
await waitForNextUpdate();
expect(result.current.error).toBe('some-error');
expect(result.current.kubernetesObjects).toBeUndefined();
await waitForNextUpdate();
expect(result.current.error).toBeUndefined();
expect(result.current.kubernetesObjects).not.toBeUndefined();
});
it('should reset error after decorateRequestBodyForAuth has failed and then succeeded', async () => {
(useApi as any).mockReturnValue({
getClusters: mockGetClusters.mockResolvedValue(getClustersResponse),
decorateRequestBodyForAuth: mockDecorateRequestBodyForAuth
.mockRejectedValueOnce({ message: 'decoration failed' })
.mockResolvedValue(entityWithAuthToken),
getObjectsByEntity:
mockGetObjectsByEntity.mockResolvedValue(mockResponse),
});
const { result, waitForNextUpdate } = renderHook(() =>
useKubernetesObjects(entity, 100),
);
await waitForNextUpdate();
expect(result.current.error).toBe('decoration failed');
expect(result.current.kubernetesObjects).toBeUndefined();
await waitForNextUpdate();
expect(result.current.error).toBeUndefined();
expect(result.current.kubernetesObjects).not.toBeUndefined();
});
it('should reset error after getObjectsByEntity has failed and then succeeded', async () => {
(useApi as any).mockReturnValue({
getClusters: mockGetClusters.mockResolvedValue(getClustersResponse),
decorateRequestBodyForAuth:
mockDecorateRequestBodyForAuth.mockResolvedValue(entityWithAuthToken),
getObjectsByEntity: mockGetObjectsByEntity
.mockRejectedValueOnce({ message: 'failed to fetch' })
.mockResolvedValue(mockResponse),
});
const { result, waitForNextUpdate } = renderHook(() =>
useKubernetesObjects(entity, 100),
);
await waitForNextUpdate();
expect(result.current.error).toBe('failed to fetch');
expect(result.current.kubernetesObjects).toBeUndefined();
await waitForNextUpdate();
expect(result.current.error).toBeUndefined();
expect(result.current.kubernetesObjects).not.toBeUndefined();
});
it('should reset data after getClusters succeeded then failed', async () => {
(useApi as any).mockReturnValue({
getClusters: mockGetClusters
.mockResolvedValueOnce(getClustersResponse)
.mockRejectedValue({ message: 'fetch clusters failed' }),
decorateRequestBodyForAuth:
mockDecorateRequestBodyForAuth.mockResolvedValue(entityWithAuthToken),
getObjectsByEntity:
mockGetObjectsByEntity.mockResolvedValue(mockResponse),
});
const { result, waitForNextUpdate } = renderHook(() =>
useKubernetesObjects(entity, 100),
);
await waitForNextUpdate();
expect(result.current.error).toBeUndefined();
expect(result.current.kubernetesObjects).not.toBeUndefined();
await waitForNextUpdate();
expect(result.current.error).toBe('fetch clusters failed');
expect(result.current.kubernetesObjects).toBeUndefined();
});
it('should reset data after decorateBodyForAuth succeeded then failed', async () => {
(useApi as any).mockReturnValue({
getClusters: mockGetClusters.mockResolvedValue(getClustersResponse),
decorateRequestBodyForAuth: mockDecorateRequestBodyForAuth
// this call happens twice per successful hook render
.mockResolvedValueOnce(entityWithAuthToken)
.mockResolvedValueOnce(entityWithAuthToken)
.mockRejectedValue({ message: 'decorate failed' }),
getObjectsByEntity:
mockGetObjectsByEntity.mockResolvedValue(mockResponse),
});
const { result, waitForNextUpdate } = renderHook(() =>
useKubernetesObjects(entity, 100),
);
await waitForNextUpdate();
expect(result.current.error).toBeUndefined();
expect(result.current.kubernetesObjects).not.toBeUndefined();
await waitForNextUpdate();
expect(result.current.error).toBe('decorate failed');
expect(result.current.kubernetesObjects).toBeUndefined();
});
it('should reset data after getObjectsByEntity succeeded then failed', async () => {
(useApi as any).mockReturnValue({
getClusters: mockGetClusters.mockResolvedValue(getClustersResponse),
decorateRequestBodyForAuth:
mockDecorateRequestBodyForAuth.mockResolvedValue(entityWithAuthToken),
getObjectsByEntity: mockGetObjectsByEntity
.mockResolvedValueOnce(mockResponse)
.mockRejectedValue({ message: 'failed to fetch' }),
});
const { result, waitForNextUpdate } = renderHook(() =>
useKubernetesObjects(entity, 100),
);
await waitForNextUpdate();
expect(result.current.error).toBeUndefined();
expect(result.current.kubernetesObjects).not.toBeUndefined();
await waitForNextUpdate();
expect(result.current.error).toBe('failed to fetch');
expect(result.current.kubernetesObjects).toBeUndefined();
});
});
});
@@ -26,8 +26,8 @@ import {
import { useApi } from '@backstage/core-plugin-api';
export interface KubernetesObjects {
kubernetesObjects: ObjectsByEntityResponse | undefined;
error: string | undefined;
kubernetesObjects?: ObjectsByEntityResponse;
error?: string;
}
export const useKubernetesObjects = (
@@ -36,11 +36,10 @@ export const useKubernetesObjects = (
): KubernetesObjects => {
const kubernetesApi = useApi(kubernetesApiRef);
const kubernetesAuthProvidersApi = useApi(kubernetesAuthProvidersApiRef);
const [kubernetesObjects, setKubernetesObjects] = useState<
ObjectsByEntityResponse | undefined
>(undefined);
const [error, setError] = useState<string | undefined>(undefined);
const [result, setResult] = useState<KubernetesObjects>({
kubernetesObjects: undefined,
error: undefined,
});
const getObjects = async () => {
let clusters = [];
@@ -48,7 +47,7 @@ export const useKubernetesObjects = (
try {
clusters = await kubernetesApi.getClusters();
} catch (e) {
setError(e.message);
setResult({ error: e.message });
return;
}
@@ -76,15 +75,16 @@ export const useKubernetesObjects = (
requestBody,
);
} catch (e) {
setError(e.message);
setResult({ error: e.message });
return;
}
}
try {
setKubernetesObjects(await kubernetesApi.getObjectsByEntity(requestBody));
const objects = await kubernetesApi.getObjectsByEntity(requestBody);
setResult({ kubernetesObjects: objects });
} catch (e) {
setError(e.message);
setResult({ error: e.message });
return;
}
};
@@ -99,8 +99,5 @@ export const useKubernetesObjects = (
getObjects();
}, intervalMs);
return {
kubernetesObjects,
error,
};
return result;
};