mirror of
https://github.com/podman-desktop/podman-desktop
synced 2026-05-24 10:18:53 +00:00
feat(RecommendationsRegistry): uses deterministic method to choose which banner is displayed (#6947)
feat(RecommendationsRegistry): uses deterministic to provide list of extension banners Signed-off-by: axel7083 <42176370+axel7083@users.noreply.github.com>
This commit is contained in:
parent
2b40abad53
commit
299fb52774
2 changed files with 101 additions and 20 deletions
|
|
@ -248,6 +248,85 @@ describe('getExtensionBanners', () => {
|
|||
|
||||
expect(featuredMock.getFeaturedExtensions).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('same time should return same arrays', async () => {
|
||||
getRecommendationIgnored.mockReturnValue(false);
|
||||
vi.mocked(featuredMock.getFeaturedExtensions).mockResolvedValue(
|
||||
Array.from({ length: 10 }, (_, i) => ({
|
||||
id: `dummy.id-${i}`,
|
||||
builtin: false,
|
||||
description: '',
|
||||
categories: [],
|
||||
displayName: '',
|
||||
fetchable: false,
|
||||
icon: '',
|
||||
installed: false,
|
||||
})),
|
||||
);
|
||||
|
||||
vi.setSystemTime(new Date(2050, 1, 1, 1));
|
||||
const base = await recommendationsRegistry.getExtensionBanners(5);
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
expect(base).toStrictEqual(await recommendationsRegistry.getExtensionBanners(5));
|
||||
}
|
||||
});
|
||||
|
||||
test('different hours should return different arrays', async () => {
|
||||
getRecommendationIgnored.mockReturnValue(false);
|
||||
vi.mocked(featuredMock.getFeaturedExtensions).mockResolvedValue(
|
||||
Array.from({ length: 10 }, (_, i) => ({
|
||||
id: `dummy.id-${i}`,
|
||||
builtin: false,
|
||||
description: '',
|
||||
categories: [],
|
||||
displayName: '',
|
||||
fetchable: false,
|
||||
icon: '',
|
||||
installed: false,
|
||||
})),
|
||||
);
|
||||
|
||||
vi.setSystemTime(new Date(2050, 1, 1, 1));
|
||||
const resultA = await recommendationsRegistry.getExtensionBanners(5);
|
||||
expect(resultA.length).toBe(5);
|
||||
|
||||
vi.setSystemTime(new Date(2050, 1, 1, 2));
|
||||
const resultB = await recommendationsRegistry.getExtensionBanners(5);
|
||||
expect(resultB.length).toBe(5);
|
||||
|
||||
expect(resultA).not.toStrictEqual(resultB);
|
||||
});
|
||||
|
||||
test('all elements should have been shown in one day', async () => {
|
||||
getRecommendationIgnored.mockReturnValue(false);
|
||||
const featured = Array.from({ length: 10 }, (_, i) => ({
|
||||
id: `dummy.id-${i}`,
|
||||
builtin: false,
|
||||
description: '',
|
||||
categories: [],
|
||||
displayName: '',
|
||||
fetchable: false,
|
||||
icon: '',
|
||||
installed: false,
|
||||
}));
|
||||
vi.mocked(featuredMock.getFeaturedExtensions).mockResolvedValue(featured);
|
||||
|
||||
const expectedIds: Set<string> = new Set(featured.map(item => item.id));
|
||||
|
||||
const actualsIds: Set<string> = new Set();
|
||||
|
||||
for (let h = 0; h < 24; h++) {
|
||||
vi.setSystemTime(new Date(2050, 1, 1, h));
|
||||
|
||||
const banners = await recommendationsRegistry.getExtensionBanners(1);
|
||||
expect(banners.length).toBe(1);
|
||||
|
||||
actualsIds.add(banners[0].extensionId);
|
||||
}
|
||||
|
||||
expect(expectedIds).toStrictEqual(actualsIds);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRegistries', () => {
|
||||
|
|
|
|||
|
|
@ -93,33 +93,35 @@ export class RecommendationsRegistry {
|
|||
);
|
||||
|
||||
// Filter and shuffle the extensions
|
||||
const extensionBanners: ExtensionBanner[] = recommendations.extensions
|
||||
.reduce((prev, extension) => {
|
||||
// ensure the extension is in the featured extensions and is not install
|
||||
if (!(extension.extensionId in featuredExtensions) || featuredExtensions[extension.extensionId].installed) {
|
||||
const extensionBanners: ExtensionBanner[] = recommendations.extensions.reduce((prev, extension) => {
|
||||
// ensure the extension is in the featured extensions and is not install
|
||||
if (!(extension.extensionId in featuredExtensions) || featuredExtensions[extension.extensionId].installed) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
// Check for publishDate property
|
||||
if ('publishDate' in extension && typeof extension.publishDate === 'string') {
|
||||
const publishDate = new Date(extension.publishDate).getTime();
|
||||
if (isNaN(publishDate) || publishDate > Date.now()) {
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for publishDate property
|
||||
if ('publishDate' in extension && typeof extension.publishDate === 'string') {
|
||||
const publishDate = new Date(extension.publishDate).getTime();
|
||||
if (isNaN(publishDate) || publishDate > Date.now()) {
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
prev.push({
|
||||
...extension,
|
||||
featured: featuredExtensions[extension.extensionId],
|
||||
});
|
||||
|
||||
prev.push({
|
||||
...extension,
|
||||
featured: featuredExtensions[extension.extensionId],
|
||||
});
|
||||
|
||||
return prev;
|
||||
}, [] as ExtensionBanner[])
|
||||
.toSorted(() => Math.random() - 0.5);
|
||||
return prev;
|
||||
}, [] as ExtensionBanner[]);
|
||||
|
||||
// Limit the number of
|
||||
if (limit >= 0 && extensionBanners.length > limit) {
|
||||
return extensionBanners.toSpliced(limit);
|
||||
// instead of using random generator we ensure deterministic results for a period of time (here by the hours)
|
||||
const startingIndex = new Date().getHours() % extensionBanners.length;
|
||||
|
||||
// Let's return the subset of banners starting at the chosen index
|
||||
return Array.from({ length: limit }, (_, i) => extensionBanners[(startingIndex + i) % extensionBanners.length]);
|
||||
}
|
||||
return extensionBanners;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue