export context for testing,
added tests for indicator icons, use wrapped indicator icon for backward compatibility.
This commit is contained in:
parent
56a8fd65cc
commit
44a67c1f89
21
ui/src/app/components/routes/FlagIcon.js
Normal file
21
ui/src/app/components/routes/FlagIcon.js
Normal file
@ -0,0 +1,21 @@
|
||||
import { FontAwesomeIcon }
|
||||
from '@fortawesome/react-fontawesome';
|
||||
|
||||
/**
|
||||
* Display a route flag icon indicator with a tooltip.
|
||||
*
|
||||
* @param icon - The icon to display.
|
||||
* @param tooltip - The tooltip to display.
|
||||
*/
|
||||
const FlagIcon = ({icon, tooltip}) => {
|
||||
return (
|
||||
<>
|
||||
<i><FontAwesomeIcon icon={icon} /></i>
|
||||
<div>{tooltip}</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default FlagIcon;
|
||||
|
||||
|
23
ui/src/app/components/routes/FlagIcon.test.js
Normal file
23
ui/src/app/components/routes/FlagIcon.test.js
Normal file
@ -0,0 +1,23 @@
|
||||
import { render, screen }
|
||||
from '@testing-library/react';
|
||||
|
||||
import { faCircle }
|
||||
from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
import FlagIcon
|
||||
from './FlagIcon';
|
||||
|
||||
/**
|
||||
* Test rendering of the flag icon component.
|
||||
*/
|
||||
test('renders flag icon', () => {
|
||||
render(
|
||||
<div data-testid="icon">
|
||||
<FlagIcon icon={faCircle} tooltip="A flag icon" />
|
||||
</div>
|
||||
);
|
||||
|
||||
// Check that the tooltip is in the document.
|
||||
expect(screen.getByText('A flag icon')).toBeInTheDocument();
|
||||
});
|
||||
|
@ -1,6 +1,4 @@
|
||||
|
||||
import { FontAwesomeIcon }
|
||||
from '@fortawesome/react-fontawesome';
|
||||
import { faCircle }
|
||||
from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
@ -11,7 +9,13 @@ import { matchCommunityRange
|
||||
}
|
||||
from 'app/context/bgp';
|
||||
|
||||
import FlagIcon
|
||||
from 'app/components/routes/FlagIcon';
|
||||
|
||||
/**
|
||||
* BlackholeIndicator
|
||||
* Displays a blackhole indicator if the route is a blackhole.
|
||||
*/
|
||||
const BlackholeIndicator = ({route}) => {
|
||||
const routeServer = useRouteServer(); // blackholes are store per RS
|
||||
const blackholeCommunities = useBlackholeCommunities();
|
||||
@ -56,8 +60,7 @@ const BlackholeIndicator = ({route}) => {
|
||||
if (isBlackhole) {
|
||||
return(
|
||||
<span className="route-prefix-flag blackhole-route is-blackhole-route">
|
||||
<FontAwesomeIcon icon={faCircle} />
|
||||
<div>Blackhole</div>
|
||||
<FlagIcon icon={faCircle} tooltip="Blackhole" />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
@ -1,15 +1,20 @@
|
||||
|
||||
import { FontAwesomeIcon }
|
||||
from '@fortawesome/react-fontawesome';
|
||||
import { faStar }
|
||||
from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
import FlagIcon
|
||||
from 'app/components/routes/FlagIcon';
|
||||
|
||||
/**
|
||||
* Show a primary route indicator icon
|
||||
*
|
||||
* @param route - The route object
|
||||
*/
|
||||
const PrimaryIndicator = ({route}) => {
|
||||
if (route.primary) {
|
||||
return(
|
||||
<span className="route-prefix-flag primary-route is-primary-route">
|
||||
<FontAwesomeIcon icon={faStar} />
|
||||
<div>Best Route</div>
|
||||
<FlagIcon icon={faStar} tooltip="Best Route" />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
28
ui/src/app/components/routes/flags/PrimaryIndicator.test.js
Normal file
28
ui/src/app/components/routes/flags/PrimaryIndicator.test.js
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
import { render, screen }
|
||||
from '@testing-library/react';
|
||||
|
||||
import PrimaryIndicator
|
||||
from './PrimaryIndicator';
|
||||
|
||||
/**
|
||||
* Test rendering the primary indicator
|
||||
*/
|
||||
test('renders primary indicator', () => {
|
||||
// Routes for testing: primary and not primary
|
||||
const primaryRoute = {
|
||||
primary: true,
|
||||
};
|
||||
const notPrimaryRoute = {
|
||||
primary: false,
|
||||
};
|
||||
|
||||
// Render the non primary route indicator
|
||||
render(<PrimaryIndicator route={notPrimaryRoute} />);
|
||||
expect(screen.queryByText('Best Route')).not.toBeInTheDocument();
|
||||
|
||||
// Render the primary indicator
|
||||
render(<PrimaryIndicator route={primaryRoute} />);
|
||||
expect(screen.getByText('Best Route')).toBeInTheDocument();
|
||||
});
|
||||
|
@ -1,24 +1,28 @@
|
||||
|
||||
import { FontAwesomeIcon }
|
||||
from '@fortawesome/react-fontawesome';
|
||||
import { faCircleExclamation }
|
||||
from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
import { useRejectCandidate }
|
||||
from 'app/context/bgp';
|
||||
|
||||
import FlagIcon
|
||||
from 'app/components/routes/FlagIcon';
|
||||
|
||||
/**
|
||||
* RejectCandidateIndicator
|
||||
* Displays a flag if the route is a reject candidate.
|
||||
*
|
||||
* @param route - The route to check
|
||||
*/
|
||||
const RejectCandidateIndicator = ({route}) => {
|
||||
const isRejectCandidate = useRejectCandidate(route);
|
||||
if (!isRejectCandidate) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cls = `route-prefix-flag reject-candidate-route`;
|
||||
return (
|
||||
<span className={cls}>
|
||||
<FontAwesomeIcon icon={faCircleExclamation} />
|
||||
<div>Reject Candidate</div>
|
||||
<span className="route-prefix-flag reject-candidate-route">
|
||||
<FlagIcon icon={faCircleExclamation} tooltip="Reject Candidate" />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
import { render, screen }
|
||||
from '@testing-library/react';
|
||||
|
||||
import RejectCandidateIndicator
|
||||
from './RejectCandidateIndicator';
|
||||
|
||||
import { ConfigContext }
|
||||
from 'app/context/config';
|
||||
|
||||
|
||||
// Mock config with reject candidate community
|
||||
const config = {
|
||||
reject_candidates: {
|
||||
communities: {
|
||||
1111: {
|
||||
1234: {
|
||||
1: "reject-candidate-2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Test the RejectCandidateIndicator component with
|
||||
*/
|
||||
test('renders reject candidate indicator' , () => {
|
||||
const route = {
|
||||
bgp: {
|
||||
large_communities: [
|
||||
[1111, 1234, 1],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
// Render the component
|
||||
render(
|
||||
<ConfigContext.Provider value={config}>
|
||||
<RejectCandidateIndicator route={route} />
|
||||
</ConfigContext.Provider>
|
||||
);
|
||||
|
||||
// Check that the indicator is rendered
|
||||
expect(screen.getByText('Reject Candidate')).toBeInTheDocument();
|
||||
});
|
||||
|
@ -1,6 +1,4 @@
|
||||
|
||||
import { FontAwesomeIcon }
|
||||
from '@fortawesome/react-fontawesome';
|
||||
import { faCircleCheck
|
||||
, faCircleMinus
|
||||
, faCircleQuestion
|
||||
@ -12,6 +10,9 @@ import { faCircle }
|
||||
import { useConfig }
|
||||
from 'app/context/config';
|
||||
|
||||
import FlagIcon
|
||||
from 'app/components/routes/FlagIcon';
|
||||
|
||||
const RpkiIndicator = ({route}) => {
|
||||
const { rpki } = useConfig();
|
||||
|
||||
@ -19,6 +20,7 @@ const RpkiIndicator = ({route}) => {
|
||||
if (rpki.enabled === false) { return null; }
|
||||
|
||||
// Check for BGP large communities as configured in the alice.conf
|
||||
// FIXME: why are we using strings here?! ['1234', '123', '1'].
|
||||
const rpkiValid = rpki.valid;
|
||||
const rpkiUnknown = rpki.unknown;
|
||||
const rpkiNotChecked = rpki.not_checked;
|
||||
@ -32,8 +34,7 @@ const RpkiIndicator = ({route}) => {
|
||||
com[2].toFixed() === rpkiValid[2]) {
|
||||
return (
|
||||
<span className="route-prefix-flag rpki-route rpki-valid">
|
||||
<FontAwesomeIcon icon={faCircleCheck} />
|
||||
<div>RPKI Valid</div>
|
||||
<FlagIcon icon={faCircleCheck} tooltip="RPKI Valid" />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@ -44,8 +45,7 @@ const RpkiIndicator = ({route}) => {
|
||||
com[2].toFixed() === rpkiUnknown[2]) {
|
||||
return (
|
||||
<span className="route-prefix-flag rpki-route rpki-unknown">
|
||||
<FontAwesomeIcon icon={faCircleQuestion} />
|
||||
<div>RPKI Unknown</div>
|
||||
<FlagIcon icon={faCircleQuestion} tooltip="RPKI Unknown" />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@ -56,8 +56,7 @@ const RpkiIndicator = ({route}) => {
|
||||
com[2].toFixed() === rpkiNotChecked[2]) {
|
||||
return (
|
||||
<span className="route-prefix-flag rpki-route rpki-not-checked">
|
||||
<FontAwesomeIcon icon={faCircle} />
|
||||
<div>RPKI not checked</div>
|
||||
<FlagIcon icon={faCircle} tooltip="RPKI Not Checked" />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@ -88,8 +87,7 @@ const RpkiIndicator = ({route}) => {
|
||||
const cls = `route-prefix-flag rpki-route rpki-invalid rpki-invalid-${rpkiInvalidReason}`
|
||||
return (
|
||||
<span className={cls}>
|
||||
<FontAwesomeIcon icon={faCircleMinus} />
|
||||
<div>RPKI Invalid</div>
|
||||
<FlagIcon icon={faCircleMinus} tooltip="RPKI Invalid" />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
102
ui/src/app/components/routes/flags/RpkiIndicator.test.js
Normal file
102
ui/src/app/components/routes/flags/RpkiIndicator.test.js
Normal file
@ -0,0 +1,102 @@
|
||||
import { render, screen }
|
||||
from '@testing-library/react';
|
||||
|
||||
import { ConfigContext }
|
||||
from 'app/context/config';
|
||||
import RpkiIndicator
|
||||
from './RpkiIndicator';
|
||||
|
||||
// Provide config context with rpki settings
|
||||
const config = {
|
||||
rpki: {
|
||||
enabled: true,
|
||||
valid: ["1234", "1111", "1"],
|
||||
unknown: ["1234", "1111", "0"],
|
||||
not_checked: ["1234", "1111", "10"],
|
||||
invalid: ["1234", "1111", "100"],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Test rendering the RpkiIndicator component.
|
||||
*/
|
||||
test('renders RpkiIndicator with a valid route', () => {
|
||||
// Render the RpkiIndicator component for a valid prefix
|
||||
const route = {
|
||||
bgp: {
|
||||
large_communities: [
|
||||
[1234, 1111, 1],
|
||||
],
|
||||
},
|
||||
};
|
||||
render(
|
||||
<ConfigContext.Provider value={config}>
|
||||
<RpkiIndicator route={route} />
|
||||
</ConfigContext.Provider>
|
||||
);
|
||||
expect(screen.getByText('RPKI Valid')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test rendering the RpkiIndicator component with
|
||||
* an rpki unknown route.
|
||||
*/
|
||||
test('renders RpkiIndicator with an unknown route', () => {
|
||||
// Render the RpkiIndicator component for an unknown prefix
|
||||
const route = {
|
||||
bgp: {
|
||||
large_communities: [
|
||||
[1234, 1111, 0],
|
||||
],
|
||||
},
|
||||
};
|
||||
render(
|
||||
<ConfigContext.Provider value={config}>
|
||||
<RpkiIndicator route={route} />
|
||||
</ConfigContext.Provider>
|
||||
);
|
||||
expect(screen.getByText('RPKI Unknown')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test rendering the RpkiIndicator component with
|
||||
* an rpki not checked route.
|
||||
*/
|
||||
test('renders RpkiIndicator with a not checked route', () => {
|
||||
// Render the RpkiIndicator component for a not checked prefix
|
||||
const route = {
|
||||
bgp: {
|
||||
large_communities: [
|
||||
[1234, 1111, 10],
|
||||
],
|
||||
},
|
||||
};
|
||||
render(
|
||||
<ConfigContext.Provider value={config}>
|
||||
<RpkiIndicator route={route} />
|
||||
</ConfigContext.Provider>
|
||||
);
|
||||
expect(screen.getByText('RPKI Not Checked')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test rendering the RpkiIndicator component with an
|
||||
* rpki invalid route.
|
||||
*/
|
||||
test('renders RpkiIndicator with an invalid route', () => {
|
||||
// Render the RpkiIndicator component for an invalid prefix
|
||||
const route = {
|
||||
bgp: {
|
||||
large_communities: [
|
||||
[1234, 1111, 100],
|
||||
],
|
||||
},
|
||||
};
|
||||
render(
|
||||
<ConfigContext.Provider value={config}>
|
||||
<RpkiIndicator route={route} />
|
||||
</ConfigContext.Provider>
|
||||
);
|
||||
expect(screen.getByText('RPKI Invalid')).toBeInTheDocument();
|
||||
});
|
@ -40,7 +40,7 @@ const initialState = {
|
||||
asns: {}, // Map ASNs to routeservers (for future use)
|
||||
};
|
||||
|
||||
const ConfigContext = createContext(null);
|
||||
export const ConfigContext = createContext(null);
|
||||
export const useConfig = () => useContext(ConfigContext);
|
||||
|
||||
export const ConfigProvider = ({children}) => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user