-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Redux Sagas for getting SUSE Manager software updates (#2416)
- Loading branch information
1 parent
0a5ac04
commit 2d08e21
Showing
9 changed files
with
518 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { networkClient } from '@lib/network'; | ||
|
||
export const getSoftwareUpdates = (hostId) => | ||
networkClient.get(`/api/v1/hosts/${hostId}/software_updates`); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { get } from 'lodash'; | ||
import { put, call, takeEvery } from 'redux-saga/effects'; | ||
import { getSoftwareUpdates } from '@lib/api/softwareUpdates'; | ||
|
||
import { | ||
FETCH_SOFTWARE_UPDATES, | ||
startLoadingSoftwareUpdates, | ||
setSoftwareUpdates, | ||
setEmptySoftwareUpdates, | ||
setSoftwareUpdatesErrors, | ||
} from '@state/softwareUpdates'; | ||
|
||
export function* fetchSoftwareUpdates({ payload: { hostId } }) { | ||
yield put(startLoadingSoftwareUpdates()); | ||
|
||
try { | ||
const response = yield call(getSoftwareUpdates, hostId); | ||
yield put(setSoftwareUpdates({ hostId, ...response.data })); | ||
} catch (error) { | ||
yield put(setEmptySoftwareUpdates({ hostId })); | ||
const errors = get(error, ['response', 'data'], []); | ||
yield put(setSoftwareUpdatesErrors(errors)); | ||
} | ||
} | ||
|
||
export function* watchSoftwareUpdates() { | ||
yield takeEvery(FETCH_SOFTWARE_UPDATES, fetchSoftwareUpdates); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { faker } from '@faker-js/faker'; | ||
import MockAdapter from 'axios-mock-adapter'; | ||
|
||
import { recordSaga } from '@lib/test-utils'; | ||
|
||
import { networkClient } from '@lib/network'; | ||
|
||
import { | ||
startLoadingSoftwareUpdates, | ||
setSoftwareUpdates, | ||
setSoftwareUpdatesErrors, | ||
setEmptySoftwareUpdates, | ||
} from '@state/softwareUpdates'; | ||
|
||
import { fetchSoftwareUpdates } from './softwareUpdates'; | ||
|
||
describe('Software Updates saga', () => { | ||
describe('Fetching Software Updates', () => { | ||
it('should successfully fetch software updates', async () => { | ||
const axiosMock = new MockAdapter(networkClient); | ||
const hostId = faker.string.uuid(); | ||
const response = { | ||
relevant_patches: [ | ||
{ | ||
date: '2023-05-18', | ||
advisory_name: 'SUSE-15-SP4-2023-2245', | ||
advisory_type: 'bugfix', | ||
advisory_status: 'stable', | ||
id: 2192, | ||
advisory_synopsis: 'Recommended update for libzypp, zypper', | ||
update_date: '2023-05-18', | ||
}, | ||
], | ||
upgradable_packages: [ | ||
{ | ||
from_epoch: ' ', | ||
to_release: '150400.7.60.2', | ||
name: 'openssl-1_1', | ||
from_release: '150400.7.25.1', | ||
to_epoch: ' ', | ||
arch: 'x86_64', | ||
to_package_id: 37454, | ||
from_version: '1.1.1l', | ||
to_version: '1.1.1l', | ||
from_arch: 'x86_64', | ||
to_arch: 'x86_64', | ||
}, | ||
], | ||
}; | ||
|
||
axiosMock | ||
.onGet(`/api/v1/hosts/${hostId}/software_updates`) | ||
.reply(200, response); | ||
|
||
const dispatched = await recordSaga(fetchSoftwareUpdates, { | ||
payload: { hostId, ...response }, | ||
}); | ||
|
||
expect(dispatched).toEqual([ | ||
startLoadingSoftwareUpdates(), | ||
setSoftwareUpdates({ hostId, ...response }), | ||
]); | ||
}); | ||
|
||
it.each([ | ||
{ status: 404, body: { message: '404 Not found' } }, | ||
{ status: 500, body: { message: 'java.lang.NullPointerException' } }, | ||
])( | ||
'should empty software updates settings on failed fetching', | ||
async ({ status, body }) => { | ||
const axiosMock = new MockAdapter(networkClient); | ||
const hostId = faker.string.uuid(); | ||
|
||
axiosMock | ||
.onGet(`/api/v1/hosts/${hostId}/software_updates`) | ||
.reply(status, body); | ||
|
||
const dispatched = await recordSaga(fetchSoftwareUpdates, { | ||
payload: { hostId }, | ||
}); | ||
|
||
expect(dispatched).toEqual([ | ||
startLoadingSoftwareUpdates(), | ||
setEmptySoftwareUpdates({ hostId }), | ||
setSoftwareUpdatesErrors(body), | ||
]); | ||
} | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { createSelector } from '@reduxjs/toolkit'; | ||
|
||
export const getSoftwareUpdates = (state) => state?.softwareUpdates; | ||
|
||
export const getSoftwareUpdatesForHost = (id) => (state) => | ||
state?.softwareUpdates.softwareUpdates[id]; | ||
|
||
export const getSoftwareUpdatesStats = createSelector( | ||
[(state, id) => getSoftwareUpdatesForHost(id)(state)], | ||
(softwareUpdates) => ({ | ||
numRelevantPatches: softwareUpdates?.relevant_patches?.length, | ||
numUpgradablePackages: softwareUpdates?.upgradable_packages?.length, | ||
}) | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import { faker } from '@faker-js/faker'; | ||
import { getSoftwareUpdates, getSoftwareUpdatesStats } from './softwareUpdates'; | ||
|
||
describe('Software Updates selector', () => { | ||
const hostId = faker.string.uuid(); | ||
const softwareUpdates = { | ||
[hostId]: { | ||
relevant_patches: [ | ||
{ | ||
date: '2024-03-13', | ||
advisory_name: 'SUSE-15-SP4-2024-877', | ||
advisory_type: 'security_advisory', | ||
advisory_status: 'stable', | ||
id: 4263, | ||
advisory_synopsis: 'important: Security update for sudo', | ||
update_date: '2024-03-13', | ||
}, | ||
{ | ||
date: '2024-03-13', | ||
advisory_name: 'SUSE-15-SP4-2024-871', | ||
advisory_type: 'security_advisory', | ||
advisory_status: 'stable', | ||
id: 4261, | ||
advisory_synopsis: 'important: Security update for vim', | ||
update_date: '2024-03-13', | ||
}, | ||
{ | ||
date: '2024-03-13', | ||
advisory_name: 'SUSE-15-SP4-2024-870', | ||
advisory_type: 'security_advisory', | ||
advisory_status: 'stable', | ||
id: 4260, | ||
advisory_synopsis: 'moderate: Security update for glibc', | ||
update_date: '2024-03-13', | ||
}, | ||
{ | ||
date: '2024-02-28', | ||
advisory_name: 'SUSE-15-SP4-2024-641', | ||
advisory_type: 'bugfix', | ||
advisory_status: 'stable', | ||
id: 4189, | ||
advisory_synopsis: 'Recommended update for gcc7', | ||
update_date: '2024-02-28', | ||
}, | ||
], | ||
upgradable_packages: [ | ||
{ | ||
from_epoch: ' ', | ||
to_release: '150400.6.10.1', | ||
name: 'libQt5Network5', | ||
from_release: '150400.6.3.1', | ||
to_epoch: ' ', | ||
arch: 'x86_64', | ||
to_package_id: 38289, | ||
from_version: '5.15.2+kde294', | ||
to_version: '5.15.2+kde294', | ||
from_arch: 'x86_64', | ||
to_arch: 'x86_64', | ||
}, | ||
{ | ||
from_epoch: ' ', | ||
to_release: '150300.10.51.1', | ||
name: 'libpython3_6m1_0', | ||
from_release: '150300.10.40.1', | ||
to_epoch: ' ', | ||
arch: 'x86_64', | ||
to_package_id: 36262, | ||
from_version: '3.6.15', | ||
to_version: '3.6.15', | ||
from_arch: 'x86_64', | ||
to_arch: 'x86_64', | ||
}, | ||
{ | ||
from_epoch: ' ', | ||
to_release: '150400.6.10.1', | ||
name: 'libQt5Gui5', | ||
from_release: '150400.6.3.1', | ||
to_epoch: ' ', | ||
arch: 'x86_64', | ||
to_package_id: 38391, | ||
from_version: '5.15.2+kde294', | ||
to_version: '5.15.2+kde294', | ||
from_arch: 'x86_64', | ||
to_arch: 'x86_64', | ||
}, | ||
], | ||
}, | ||
}; | ||
const state = { | ||
softwareUpdates: { | ||
loading: false, | ||
softwareUpdates, | ||
errors: [], | ||
}, | ||
}; | ||
|
||
it('should return the software updates', () => { | ||
expect(getSoftwareUpdates(state)).toEqual({ | ||
loading: false, | ||
softwareUpdates, | ||
errors: [], | ||
}); | ||
}); | ||
|
||
it('should return the correct software updates statistics', () => { | ||
expect(getSoftwareUpdatesStats(state, hostId)).toEqual({ | ||
numRelevantPatches: 4, | ||
numUpgradablePackages: 3, | ||
}); | ||
}); | ||
|
||
it('should return undefined stats when there is no data for a host', () => { | ||
const unknownHost = faker.string.uuid(); | ||
expect(getSoftwareUpdatesStats(state, unknownHost)).toEqual({ | ||
numRelevantPatches: undefined, | ||
numUpgradablePackages: undefined, | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { createAction, createSlice } from '@reduxjs/toolkit'; | ||
|
||
const initialState = { | ||
loading: false, | ||
softwareUpdates: {}, | ||
errors: [], | ||
}; | ||
|
||
export const softwareUpdatesSlice = createSlice({ | ||
name: 'softwareUpdates', | ||
initialState, | ||
reducers: { | ||
startLoadingSoftwareUpdates: (state) => { | ||
state.loading = true; | ||
}, | ||
setSoftwareUpdates: ( | ||
state, | ||
{ payload: { hostId, relevant_patches, upgradable_packages } } | ||
) => { | ||
state.loading = false; | ||
|
||
state.softwareUpdates = { | ||
...state.softwareUpdates, | ||
[hostId]: { | ||
relevant_patches, | ||
upgradable_packages, | ||
}, | ||
}; | ||
}, | ||
setEmptySoftwareUpdates: (state, { payload: { hostId } }) => { | ||
state.loading = false; | ||
state.softwareUpdates = { ...state.softwareUpdates, [hostId]: {} }; | ||
}, | ||
setSoftwareUpdatesErrors: (state, { payload: errors }) => { | ||
state.loading = false; | ||
state.errors = errors; | ||
}, | ||
}, | ||
}); | ||
|
||
export const FETCH_SOFTWARE_UPDATES = 'FETCH_SOFTWARE_UPDATES'; | ||
|
||
export const fetchSoftwareUpdates = createAction(FETCH_SOFTWARE_UPDATES); | ||
|
||
export const { | ||
startLoadingSoftwareUpdates, | ||
setSoftwareUpdates, | ||
setEmptySoftwareUpdates, | ||
setSoftwareUpdatesErrors, | ||
} = softwareUpdatesSlice.actions; | ||
|
||
export default softwareUpdatesSlice.reducer; |
Oops, something went wrong.