mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-11-09 15:32:25 +00:00
chore(ui): cache version response for any hour to avoid frequent calls (#21323)
* chore(ui): cache version response for any hour to avoid frequent calls * fix tests
This commit is contained in:
parent
2e251fccc3
commit
02235cdd9d
@ -10,13 +10,31 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { render, screen } from '@testing-library/react';
|
import { act, render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { ONE_HOUR_MS } from '../../constants/constants';
|
||||||
import { HELP_ITEMS_ENUM } from '../../constants/Navbar.constants';
|
import { HELP_ITEMS_ENUM } from '../../constants/Navbar.constants';
|
||||||
|
|
||||||
import { getVersion } from '../../rest/miscAPI';
|
import { getVersion } from '../../rest/miscAPI';
|
||||||
import { getHelpDropdownItems } from '../../utils/NavbarUtils';
|
import { getHelpDropdownItems } from '../../utils/NavbarUtils';
|
||||||
import NavBar from './NavBar';
|
import NavBarComponent from './NavBar';
|
||||||
|
|
||||||
|
// Place these at the very top of your test file, before any imports!
|
||||||
|
const mockGetItem = jest.fn();
|
||||||
|
const mockSetItem = jest.fn();
|
||||||
|
|
||||||
|
jest.mock('cookie-storage', () => ({
|
||||||
|
CookieStorage: class {
|
||||||
|
getItem(...args: any[]) {
|
||||||
|
return mockGetItem(...args);
|
||||||
|
}
|
||||||
|
setItem(...args: any[]) {
|
||||||
|
return mockSetItem(...args);
|
||||||
|
}
|
||||||
|
constructor() {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
jest.mock('../../hooks/useApplicationStore', () => ({
|
jest.mock('../../hooks/useApplicationStore', () => ({
|
||||||
useApplicationStore: jest.fn().mockImplementation(() => ({
|
useApplicationStore: jest.fn().mockImplementation(() => ({
|
||||||
@ -99,15 +117,6 @@ jest.mock('react-router-dom', () => ({
|
|||||||
useHistory: jest.fn(),
|
useHistory: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('../common/CmdKIcon/CmdKIcon.component', () => {
|
|
||||||
return jest.fn().mockReturnValue(<div data-testid="cmd">CmdKIcon</div>);
|
|
||||||
});
|
|
||||||
jest.mock('../AppBar/SearchOptions', () => {
|
|
||||||
return jest.fn().mockReturnValue(<div data-testid="cmd">SearchOptions</div>);
|
|
||||||
});
|
|
||||||
jest.mock('../AppBar/Suggestions', () => {
|
|
||||||
return jest.fn().mockReturnValue(<div data-testid="cmd">Suggestions</div>);
|
|
||||||
});
|
|
||||||
jest.mock('antd', () => ({
|
jest.mock('antd', () => ({
|
||||||
...jest.requireActual('antd'),
|
...jest.requireActual('antd'),
|
||||||
|
|
||||||
@ -120,16 +129,6 @@ jest.mock('antd', () => ({
|
|||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('../../rest/miscAPI', () => ({
|
|
||||||
getVersion: jest.fn().mockImplementation(() =>
|
|
||||||
Promise.resolve({
|
|
||||||
data: {
|
|
||||||
version: '0.5.0-SNAPSHOT',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.mock('../../utils/NavbarUtils', () => ({
|
jest.mock('../../utils/NavbarUtils', () => ({
|
||||||
getHelpDropdownItems: jest.fn().mockReturnValue([
|
getHelpDropdownItems: jest.fn().mockReturnValue([
|
||||||
{
|
{
|
||||||
@ -139,9 +138,15 @@ jest.mock('../../utils/NavbarUtils', () => ({
|
|||||||
]),
|
]),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock('../../rest/miscAPI', () => ({
|
||||||
|
getVersion: jest.fn().mockResolvedValue({
|
||||||
|
version: '0.5.0-SNAPSHOT',
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
describe('Test NavBar Component', () => {
|
describe('Test NavBar Component', () => {
|
||||||
it('Should render NavBar component', async () => {
|
it('Should render NavBar component', async () => {
|
||||||
render(<NavBar />);
|
render(<NavBarComponent />);
|
||||||
|
|
||||||
expect(await screen.findByTestId('global-search-bar')).toBeInTheDocument();
|
expect(await screen.findByTestId('global-search-bar')).toBeInTheDocument();
|
||||||
expect(await screen.findByTestId('user-profile-icon')).toBeInTheDocument();
|
expect(await screen.findByTestId('user-profile-icon')).toBeInTheDocument();
|
||||||
@ -160,14 +165,61 @@ describe('Test NavBar Component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should call getVersion onMount', () => {
|
it('should call getVersion onMount', () => {
|
||||||
render(<NavBar />);
|
render(<NavBarComponent />);
|
||||||
|
|
||||||
expect(getVersion).toHaveBeenCalled();
|
expect(getVersion).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call getHelpDropdownItems function', async () => {
|
it('should call getHelpDropdownItems function', async () => {
|
||||||
render(<NavBar />);
|
render(<NavBarComponent />);
|
||||||
|
|
||||||
expect(getHelpDropdownItems).toHaveBeenCalled();
|
expect(getHelpDropdownItems).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// --- Additional tests for fetchOMVersion one hour threshold ---
|
||||||
|
describe('fetchOMVersion one hour threshold', () => {
|
||||||
|
const OLD_DATE_NOW = Date.now;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetModules();
|
||||||
|
|
||||||
|
global.Date.now = jest.fn();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
global.Date.now = OLD_DATE_NOW;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT call getVersion if less than one hour since last fetch', async () => {
|
||||||
|
const now = 2000000;
|
||||||
|
const lastFetch = now - (ONE_HOUR_MS - 1000); // less than 1 hour ago
|
||||||
|
mockGetItem.mockReturnValue(String(lastFetch));
|
||||||
|
jest.spyOn(global.Date, 'now').mockReturnValue(now);
|
||||||
|
|
||||||
|
render(<NavBarComponent />);
|
||||||
|
await screen.findByTestId('global-search-bar');
|
||||||
|
|
||||||
|
expect(getVersion).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call getVersion and setItem if more than one hour since last fetch', async () => {
|
||||||
|
const now = 3000000;
|
||||||
|
const lastFetch = now - (ONE_HOUR_MS + 1000); // more than 1 hour ago
|
||||||
|
mockGetItem.mockReturnValue(String(lastFetch));
|
||||||
|
(global.Date.now as jest.Mock).mockReturnValue(now);
|
||||||
|
|
||||||
|
render(<NavBarComponent />);
|
||||||
|
await Promise.resolve();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
expect(getVersion).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockSetItem).toHaveBeenCalledWith(
|
||||||
|
'versionFetchTime',
|
||||||
|
'3000000',
|
||||||
|
expect.objectContaining({ expires: expect.any(Date) })
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@ -46,7 +46,9 @@ import { ReactComponent as SidebarExpandedIcon } from '../../assets/svg/ic-sideb
|
|||||||
import {
|
import {
|
||||||
DEFAULT_DOMAIN_VALUE,
|
DEFAULT_DOMAIN_VALUE,
|
||||||
NOTIFICATION_READ_TIMER,
|
NOTIFICATION_READ_TIMER,
|
||||||
|
ONE_HOUR_MS,
|
||||||
SOCKET_EVENTS,
|
SOCKET_EVENTS,
|
||||||
|
VERSION_FETCH_TIME_KEY,
|
||||||
} from '../../constants/constants';
|
} from '../../constants/constants';
|
||||||
import { GlobalSettingsMenuCategory } from '../../constants/GlobalSettings.constants';
|
import { GlobalSettingsMenuCategory } from '../../constants/GlobalSettings.constants';
|
||||||
import { HELP_ITEMS_ENUM } from '../../constants/Navbar.constants';
|
import { HELP_ITEMS_ENUM } from '../../constants/Navbar.constants';
|
||||||
@ -124,9 +126,22 @@ const NavBar = () => {
|
|||||||
} = useCurrentUserPreferences();
|
} = useCurrentUserPreferences();
|
||||||
|
|
||||||
const fetchOMVersion = async () => {
|
const fetchOMVersion = async () => {
|
||||||
|
// If version fetch happens within an hour, skip fetching
|
||||||
|
const lastFetchTime = cookieStorage.getItem(VERSION_FETCH_TIME_KEY);
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
if (lastFetchTime && now - Number(lastFetchTime) < ONE_HOUR_MS) {
|
||||||
|
// Less than an hour since last fetch, skip fetching
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await getVersion();
|
const res = await getVersion();
|
||||||
setVersion(res.version);
|
setVersion(res.version);
|
||||||
|
// Set/update the cookie with current time, expires in 1 hour
|
||||||
|
cookieStorage.setItem(VERSION_FETCH_TIME_KEY, String(now), {
|
||||||
|
expires: new Date(now + ONE_HOUR_MS),
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorToast(
|
showErrorToast(
|
||||||
err as AxiosError,
|
err as AxiosError,
|
||||||
|
|||||||
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022 Collate.
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { ReactComponent as CmdButton } from '../../../assets/svg/command-button.svg';
|
|
||||||
import { ReactComponent as CtrlButton } from '../../../assets/svg/control-button.svg';
|
|
||||||
import { ReactComponent as KButton } from '../../../assets/svg/k-button.svg';
|
|
||||||
import { NavigatorHelper } from '../../../utils/NavigatorUtils';
|
|
||||||
|
|
||||||
const CmdKIcon = () => {
|
|
||||||
return (
|
|
||||||
<div className="d-flex items-center" data-testid="cmdicon-container">
|
|
||||||
{NavigatorHelper.isMacOs() ? (
|
|
||||||
<CmdButton
|
|
||||||
data-testid="cmd-button"
|
|
||||||
style={{
|
|
||||||
backgroundColor: 'white',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<CtrlButton
|
|
||||||
data-testid="ctrl-button"
|
|
||||||
style={{
|
|
||||||
backgroundColor: 'white',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<KButton
|
|
||||||
data-testid="k-button"
|
|
||||||
style={{
|
|
||||||
marginLeft: '4px',
|
|
||||||
backgroundColor: 'white',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CmdKIcon;
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2024 Collate.
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
import { act, render, screen } from '@testing-library/react';
|
|
||||||
import React from 'react';
|
|
||||||
import { NavigatorHelper } from '../../../utils/NavigatorUtils';
|
|
||||||
import CmdKIcon from './CmdKIcon.component';
|
|
||||||
|
|
||||||
jest.mock('../../../utils/NavigatorUtils', () => ({
|
|
||||||
NavigatorHelper: {
|
|
||||||
isMacOs: jest.fn(),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('CmdKIcon', () => {
|
|
||||||
it('should render CmdKIcon', async () => {
|
|
||||||
await act(async () => {
|
|
||||||
render(<CmdKIcon />);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(screen.getByTestId('cmdicon-container')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render CmdButton when isMacOs is true', () => {
|
|
||||||
(NavigatorHelper.isMacOs as jest.Mock).mockReturnValue(true);
|
|
||||||
const { getByTestId, queryByTestId } = render(<CmdKIcon />);
|
|
||||||
|
|
||||||
expect(getByTestId('cmd-button')).toBeInTheDocument();
|
|
||||||
expect(queryByTestId('ctrl-button')).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render CtrlButton when isMacOs is false', () => {
|
|
||||||
(NavigatorHelper.isMacOs as jest.Mock).mockReturnValue(false);
|
|
||||||
const { getByTestId, queryByTestId } = render(<CmdKIcon />);
|
|
||||||
|
|
||||||
expect(getByTestId('ctrl-button')).toBeInTheDocument();
|
|
||||||
expect(queryByTestId('cmd-button')).toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -424,3 +424,6 @@ export const MAX_VISIBLE_OWNERS_FOR_FEED_TAB = 4;
|
|||||||
export const MAX_VISIBLE_OWNERS_FOR_FEED_CARD = 2;
|
export const MAX_VISIBLE_OWNERS_FOR_FEED_CARD = 2;
|
||||||
|
|
||||||
export const BREADCRUMB_SEPARATOR = '/';
|
export const BREADCRUMB_SEPARATOR = '/';
|
||||||
|
|
||||||
|
export const VERSION_FETCH_TIME_KEY = 'versionFetchTime';
|
||||||
|
export const ONE_HOUR_MS = 60 * 60 * 1000;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user