Skip to content

Commit cc08dac

Browse files
work on increasinf test coverage
Signed-off-by: vsanghishetty <vishali.kamenani@ymail.com>
1 parent a620dcb commit cc08dac

4 files changed

Lines changed: 352 additions & 1 deletion

File tree

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/* Copyright Contributors to the Open Cluster Management project */
2+
import { renderHook } from '@testing-library/react-hooks'
3+
import { useFleetK8sAPIPath, getFleetK8sAPIPath } from './useFleetK8sAPIPath'
4+
import { useHubClusterName } from './useHubClusterName'
5+
6+
// Mock dependencies
7+
jest.mock('./useHubClusterName')
8+
jest.mock('../internal/constants', () => ({
9+
BASE_K8S_API_PATH: '/api/kubernetes',
10+
MANAGED_CLUSTER_API_PATH: 'api/clusters',
11+
LOCAL_CLUSTER_LABEL: 'local-cluster',
12+
NO_MULTICLUSTER: 'NO_MULTICLUSTER',
13+
}))
14+
15+
jest.mock('./apiRequests', () => ({
16+
k8sListItems: jest.fn(),
17+
getBackendUrl: () => 'http://localhost:9000',
18+
}))
19+
20+
const mockUseHubClusterName = useHubClusterName as jest.MockedFunction<typeof useHubClusterName>
21+
22+
describe('useFleetK8sAPIPath', () => {
23+
beforeEach(() => {
24+
jest.clearAllMocks()
25+
})
26+
27+
it('should return base path when no cluster is provided', () => {
28+
mockUseHubClusterName.mockReturnValue(['hub-cluster', true, undefined])
29+
30+
const { result } = renderHook(() => useFleetK8sAPIPath())
31+
32+
expect(result.current).toEqual(['/api/kubernetes', true, undefined])
33+
})
34+
35+
it('should return base path when cluster equals hub cluster', () => {
36+
mockUseHubClusterName.mockReturnValue(['hub-cluster', true, undefined])
37+
38+
const { result } = renderHook(() => useFleetK8sAPIPath('hub-cluster'))
39+
40+
expect(result.current).toEqual(['/api/kubernetes', true, undefined])
41+
})
42+
43+
it('should return managed cluster path when cluster differs from hub cluster', () => {
44+
mockUseHubClusterName.mockReturnValue(['hub-cluster', true, undefined])
45+
46+
const { result } = renderHook(() => useFleetK8sAPIPath('managed-cluster-1'))
47+
48+
expect(result.current).toEqual(['http://localhost:9000/api/clusters/managed-cluster-1', true, undefined])
49+
})
50+
51+
it('should return undefined when not loaded', () => {
52+
mockUseHubClusterName.mockReturnValue([undefined, false, undefined])
53+
54+
const { result } = renderHook(() => useFleetK8sAPIPath('managed-cluster-1'))
55+
56+
expect(result.current).toEqual([undefined, false, undefined])
57+
})
58+
59+
it('should return managed cluster path when there is an error getting hub cluster name', () => {
60+
mockUseHubClusterName.mockReturnValue([undefined, true, new Error('Test error')])
61+
62+
const { result } = renderHook(() => useFleetK8sAPIPath('managed-cluster-1'))
63+
64+
expect(result.current).toEqual([
65+
'http://localhost:9000/api/clusters/managed-cluster-1',
66+
true,
67+
new Error('Test error'),
68+
])
69+
})
70+
71+
it('should return managed cluster path when hub cluster name is NO_MULTICLUSTER', () => {
72+
mockUseHubClusterName.mockReturnValue(['NO_MULTICLUSTER', true, undefined])
73+
74+
const { result } = renderHook(() => useFleetK8sAPIPath('managed-cluster-1'))
75+
76+
expect(result.current).toEqual(['http://localhost:9000/api/clusters/managed-cluster-1', true, undefined])
77+
})
78+
})
79+
80+
describe('getFleetK8sAPIPath', () => {
81+
const { k8sListItems } = jest.requireMock('./apiRequests')
82+
const mockK8sListItems = k8sListItems as jest.MockedFunction<typeof k8sListItems>
83+
84+
beforeEach(() => {
85+
jest.clearAllMocks()
86+
// Clear the cached hub cluster name between tests
87+
jest.resetModules()
88+
})
89+
90+
it('should return base path when no cluster is provided', async () => {
91+
const result = await getFleetK8sAPIPath()
92+
expect(result).toBe('/api/kubernetes')
93+
})
94+
95+
it('should return managed cluster path when cluster is provided and hub cluster is found', async () => {
96+
mockK8sListItems.mockResolvedValue([
97+
{
98+
metadata: {
99+
name: 'hub-cluster',
100+
},
101+
},
102+
])
103+
104+
const result = await getFleetK8sAPIPath('managed-cluster-1')
105+
expect(result).toBe('http://localhost:9000/api/clusters/managed-cluster-1')
106+
})
107+
108+
it('should return managed cluster path when ManagedCluster CRD is not available (404 error)', async () => {
109+
mockK8sListItems.mockRejectedValue({ code: 404 })
110+
111+
const result = await getFleetK8sAPIPath('managed-cluster-1')
112+
expect(result).toBe('http://localhost:9000/api/clusters/managed-cluster-1')
113+
})
114+
115+
it('should return managed cluster path when other errors occur', async () => {
116+
mockK8sListItems.mockRejectedValue(new Error('Network error'))
117+
118+
const result = await getFleetK8sAPIPath('managed-cluster-1')
119+
expect(result).toBe('http://localhost:9000/api/clusters/managed-cluster-1')
120+
})
121+
122+
it('should return managed cluster path when hub cluster is not found', async () => {
123+
mockK8sListItems.mockResolvedValue([])
124+
125+
const result = await getFleetK8sAPIPath('managed-cluster-1')
126+
expect(result).toBe('http://localhost:9000/api/clusters/managed-cluster-1')
127+
})
128+
})
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/* Copyright Contributors to the Open Cluster Management project */
2+
import * as components from './index'
3+
4+
describe('components index', () => {
5+
it('should export FleetResourceEventStream', () => {
6+
expect(components.FleetResourceEventStream).toBeDefined()
7+
expect(typeof components.FleetResourceEventStream).toBe('function')
8+
})
9+
})

frontend/packages/multicluster-sdk/src/internal/FleetResourceEventStream/EventComponent.test.tsx

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jest.mock('react-router-dom-v5-compat', () => ({
3333
}))
3434

3535
jest.mock('@openshift-console/dynamic-plugin-sdk', () => ({
36-
useAccessReview: () => true,
36+
useAccessReview: jest.fn(),
3737
ResourceLink: ({ kind, name }: { kind: string; name: string }) => (
3838
<span data-testid={`resource-link-${kind}-${name}`}>{name}</span>
3939
),
@@ -120,4 +120,95 @@ describe('EventComponent', () => {
120120
expect(mockCache.clear).toHaveBeenCalledWith(0, 0)
121121
expect(mockList.recomputeRowHeights).toHaveBeenCalledWith(0)
122122
})
123+
124+
it('should handle different access review scenarios', () => {
125+
const { useAccessReview } = jest.requireMock('@openshift-console/dynamic-plugin-sdk')
126+
127+
// Test with access allowed
128+
useAccessReview.mockReturnValue(true)
129+
const MockEventComponent = jest.fn().mockImplementation(({ cache, list, index }) => {
130+
useEffect(() => {
131+
cache.clear(index, 0)
132+
list?.recomputeRowHeights(index)
133+
}, [cache, list, index])
134+
return null
135+
})
136+
137+
render(<MockEventComponent event={mockEvent} cache={mockCache} list={mockList} index={0} />)
138+
139+
// Test with access denied
140+
useAccessReview.mockReturnValue(false)
141+
render(<MockEventComponent event={mockEvent} cache={mockCache} list={mockList} index={0} />)
142+
})
143+
144+
it('should handle events with different component sources', () => {
145+
const { useAccessReview } = jest.requireMock('@openshift-console/dynamic-plugin-sdk')
146+
useAccessReview.mockReturnValue(true)
147+
148+
const eventWithDifferentSource = {
149+
...mockEvent,
150+
source: {
151+
component: 'scheduler',
152+
host: 'node-2',
153+
},
154+
reportingComponent: 'scheduler',
155+
}
156+
157+
const MockEventComponent = jest.fn().mockImplementation(({ cache, list, index }) => {
158+
useEffect(() => {
159+
cache.clear(index, 0)
160+
list?.recomputeRowHeights(index)
161+
}, [cache, list, index])
162+
return null
163+
})
164+
165+
render(<MockEventComponent event={eventWithDifferentSource} cache={mockCache} list={mockList} index={0} />)
166+
})
167+
168+
it('should handle events with series data', () => {
169+
const { useAccessReview } = jest.requireMock('@openshift-console/dynamic-plugin-sdk')
170+
useAccessReview.mockReturnValue(true)
171+
172+
const eventWithSeries = {
173+
...mockEvent,
174+
series: {
175+
count: 5,
176+
lastObservedTime: '2023-01-01T01:00:00Z',
177+
state: 'active',
178+
},
179+
}
180+
181+
const MockEventComponent = jest.fn().mockImplementation(({ cache, list, index }) => {
182+
useEffect(() => {
183+
cache.clear(index, 0)
184+
list?.recomputeRowHeights(index)
185+
}, [cache, list, index])
186+
return null
187+
})
188+
189+
render(<MockEventComponent event={eventWithSeries} cache={mockCache} list={mockList} index={0} />)
190+
})
191+
192+
it('should handle events without namespace', () => {
193+
const { useAccessReview } = jest.requireMock('@openshift-console/dynamic-plugin-sdk')
194+
useAccessReview.mockReturnValue(true)
195+
196+
const eventWithoutNamespace = {
197+
...mockEvent,
198+
involvedObject: {
199+
...mockEvent.involvedObject,
200+
namespace: undefined,
201+
},
202+
}
203+
204+
const MockEventComponent = jest.fn().mockImplementation(({ cache, list, index }) => {
205+
useEffect(() => {
206+
cache.clear(index, 0)
207+
list?.recomputeRowHeights(index)
208+
}, [cache, list, index])
209+
return null
210+
})
211+
212+
render(<MockEventComponent event={eventWithoutNamespace} cache={mockCache} list={mockList} index={0} />)
213+
})
123214
})
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/* Copyright Contributors to the Open Cluster Management project */
2+
import { MAX_MESSAGES, EventInvolvedObject, EventKind } from './constants'
3+
4+
describe('constants', () => {
5+
describe('MAX_MESSAGES', () => {
6+
it('should export MAX_MESSAGES constant', () => {
7+
expect(MAX_MESSAGES).toBe(500)
8+
})
9+
})
10+
11+
describe('EventInvolvedObject type', () => {
12+
it('should allow optional properties', () => {
13+
const eventInvolvedObject: EventInvolvedObject = {
14+
apiVersion: 'v1',
15+
kind: 'Pod',
16+
name: 'test-pod',
17+
uid: '123',
18+
namespace: 'default',
19+
}
20+
21+
expect(eventInvolvedObject.apiVersion).toBe('v1')
22+
expect(eventInvolvedObject.kind).toBe('Pod')
23+
expect(eventInvolvedObject.name).toBe('test-pod')
24+
expect(eventInvolvedObject.uid).toBe('123')
25+
expect(eventInvolvedObject.namespace).toBe('default')
26+
})
27+
28+
it('should allow partial properties', () => {
29+
const eventInvolvedObject: EventInvolvedObject = {
30+
kind: 'Pod',
31+
name: 'test-pod',
32+
}
33+
34+
expect(eventInvolvedObject.kind).toBe('Pod')
35+
expect(eventInvolvedObject.name).toBe('test-pod')
36+
expect(eventInvolvedObject.apiVersion).toBeUndefined()
37+
expect(eventInvolvedObject.uid).toBeUndefined()
38+
expect(eventInvolvedObject.namespace).toBeUndefined()
39+
})
40+
})
41+
42+
describe('EventKind type', () => {
43+
it('should allow all optional properties', () => {
44+
const eventKind: EventKind = {
45+
reportingComponent: 'test-component',
46+
action: 'test-action',
47+
count: 5,
48+
type: 'Normal',
49+
involvedObject: {
50+
kind: 'Pod',
51+
name: 'test-pod',
52+
},
53+
message: 'Test message',
54+
eventTime: '2023-01-01T00:00:00Z',
55+
lastTimestamp: '2023-01-01T00:00:00Z',
56+
firstTimestamp: '2023-01-01T00:00:00Z',
57+
reason: 'TestReason',
58+
source: {
59+
component: 'test-source',
60+
host: 'test-host',
61+
},
62+
series: {
63+
count: 3,
64+
lastObservedTime: '2023-01-01T00:00:00Z',
65+
state: 'active',
66+
},
67+
apiVersion: 'v1',
68+
kind: 'Event',
69+
metadata: {
70+
name: 'test-event',
71+
uid: '123',
72+
},
73+
}
74+
75+
expect(eventKind.reportingComponent).toBe('test-component')
76+
expect(eventKind.action).toBe('test-action')
77+
expect(eventKind.count).toBe(5)
78+
expect(eventKind.type).toBe('Normal')
79+
expect(eventKind.message).toBe('Test message')
80+
expect(eventKind.eventTime).toBe('2023-01-01T00:00:00Z')
81+
expect(eventKind.lastTimestamp).toBe('2023-01-01T00:00:00Z')
82+
expect(eventKind.firstTimestamp).toBe('2023-01-01T00:00:00Z')
83+
expect(eventKind.reason).toBe('TestReason')
84+
expect(eventKind.source.component).toBe('test-source')
85+
expect(eventKind.source.host).toBe('test-host')
86+
expect(eventKind.series?.count).toBe(3)
87+
expect(eventKind.series?.lastObservedTime).toBe('2023-01-01T00:00:00Z')
88+
expect(eventKind.series?.state).toBe('active')
89+
})
90+
91+
it('should allow minimal required properties', () => {
92+
const eventKind: EventKind = {
93+
involvedObject: {
94+
kind: 'Pod',
95+
name: 'test-pod',
96+
},
97+
source: {
98+
component: 'test-source',
99+
},
100+
apiVersion: 'v1',
101+
kind: 'Event',
102+
metadata: {
103+
name: 'test-event',
104+
uid: '123',
105+
},
106+
}
107+
108+
expect(eventKind.involvedObject.kind).toBe('Pod')
109+
expect(eventKind.source.component).toBe('test-source')
110+
expect(eventKind.reportingComponent).toBeUndefined()
111+
expect(eventKind.action).toBeUndefined()
112+
expect(eventKind.count).toBeUndefined()
113+
expect(eventKind.type).toBeUndefined()
114+
expect(eventKind.message).toBeUndefined()
115+
expect(eventKind.eventTime).toBeUndefined()
116+
expect(eventKind.lastTimestamp).toBeUndefined()
117+
expect(eventKind.firstTimestamp).toBeUndefined()
118+
expect(eventKind.reason).toBeUndefined()
119+
expect(eventKind.source.host).toBeUndefined()
120+
expect(eventKind.series).toBeUndefined()
121+
})
122+
})
123+
})

0 commit comments

Comments
 (0)