Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { renderWithTheme } from 'src/utilities/testHelpers';

import { ServiceURI } from './ServiceURI';

import type { DatabaseStatus } from '@linode/api-v4';
import type { DatabaseStatus, Engine } from '@linode/api-v4';

const mockCredentials = {
password: 'password123',
Expand Down Expand Up @@ -170,7 +170,7 @@ describe('ServiceURI', () => {
refetch: vi.fn(),
});

it('should render the service URI component and copy icon', async () => {
it('should render the PgBouncer service URI component and copy icon', async () => {
const { container } = renderWithTheme(
<ServiceURI database={databaseWithNoVPC} />
);
Expand Down Expand Up @@ -221,6 +221,24 @@ describe('ServiceURI', () => {
);
});

it('should render general service URI with ssl-mode=REQUIRED if isGeneralServiceURI is true and the engine is mysql', () => {
const mockDb = {
...databaseWithNoVPC,
engine: 'mysql' as Engine,
};
renderWithTheme(<ServiceURI database={mockDb} isGeneralServiceURI />);

const revealPasswordBtn = screen.getByRole('button', {
name: '{click to reveal password}',
});
const serviceURIText = screen.getByTestId('service-uri').textContent;

expect(revealPasswordBtn).toBeInTheDocument();
expect(serviceURIText).toBe(
`mysql://{click to reveal password}@${DEFAULT_PRIMARY}:3306/defaultdb?ssl-mode=REQUIRED`
);
});

it('should reveal general service URI password after clicking reveal button', async () => {
renderWithTheme(
<ServiceURI database={databaseWithNoVPC} isGeneralServiceURI />
Expand All @@ -234,7 +252,7 @@ describe('ServiceURI', () => {
const serviceURIText = screen.getByTestId('service-uri').textContent;
expect(revealPasswordBtn).not.toBeInTheDocument();
expect(serviceURIText).toBe(
`postgres://password123@${DEFAULT_PRIMARY}:3306/defaultdb?sslmode=require`
`postgres://lnroot:password123@${DEFAULT_PRIMARY}:3306/defaultdb?sslmode=require`
);
});

Expand Down Expand Up @@ -318,6 +336,22 @@ describe('ServiceURI', () => {
);
});

it('should render private service URI placeholder text if there is a VPC with public access, isGeneralServiceURI and showPrivateVPC is true, but hosts are not yet available', () => {
const mockDb = {
...databaseWithPublicVPC,
hosts: null,
};

renderWithTheme(
<ServiceURI database={mockDb} isGeneralServiceURI showPrivateVPC />
);

const serviceURIText = screen.getByTestId('service-uri').textContent;
expect(serviceURIText).toBe(
'Your Service URI will appear here once it is available.'
);
});

it('should disable the reveal password and copy icon if the Database is suspended', async () => {
const mockDatabase = {
...databaseWithNoVPC,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useDatabaseCredentialsQuery } from '@linode/queries';
import { Button, TooltipIcon } from '@linode/ui';
import { Button, TooltipIcon, Typography } from '@linode/ui';
import { Grid, styled } from '@mui/material';
import copy from 'copy-to-clipboard';
import { enqueueSnackbar } from 'notistack';
Expand Down Expand Up @@ -34,6 +34,8 @@ export const ServiceURI = (props: ServiceURIProps) => {
const [isCopying, setIsCopying] = useState(false);
const engine =
database.engine === 'postgresql' ? 'postgres' : database.engine;
const generalSslmode =
engine === 'mysql' ? 'ssl-mode=REQUIRED' : 'sslmode=require';

const {
data: credentials,
Expand Down Expand Up @@ -87,17 +89,11 @@ export const ServiceURI = (props: ServiceURIProps) => {
isGeneralServiceURI?: boolean
) => {
if (isGeneralServiceURI) {
return `${engine}://${credentials?.password}@${primaryHost?.address}:${primaryHost?.port}/defaultdb?sslmode=require`;
return `${engine}://${credentials?.username}:${credentials?.password}@${primaryHost?.address}:${primaryHost?.port}/defaultdb?${generalSslmode}`;
}
return `postgres://${credentials?.username}:${credentials?.password}@${primaryConnectionPoolHost?.address}:${primaryConnectionPoolHost?.port}/{connection pool label}?sslmode=require`;
};

const getCredentials = (isGeneralServiceURI: boolean) => {
return !isGeneralServiceURI
? `${credentials?.username}:${credentials?.password}`
: credentials?.password;
};

// hide loading state if the user clicks on the copy icon
const showBtnLoading =
!hidePassword && !isCopying && (credentialsLoading || credentialsFetching);
Expand Down Expand Up @@ -141,9 +137,33 @@ export const ServiceURI = (props: ServiceURIProps) => {
);
}

return getCredentials(isGeneralServiceURI);
return `${credentials?.username}:${credentials?.password}`;
};

if (
(isGeneralServiceURI && !primaryHost) ||
(engine === 'postgres' && !primaryConnectionPoolHost)
) {
return (
<Grid display="contents">
<StyledValueGrid
data-testid="service-uri"
size="grow"
sx={{
overflowX: 'auto',
overflowY: 'hidden',
p: '0',
}}
whiteSpace="pre"
>
<Typography fontStyle="italic">
Your Service URI will appear here once it is available.
</Typography>
</StyledValueGrid>
</Grid>
);
}

return (
<Grid display="contents">
<StyledValueGrid
Expand All @@ -161,7 +181,7 @@ export const ServiceURI = (props: ServiceURIProps) => {
{isGeneralServiceURI ? (
<>
@{primaryHost?.address}:
{`${primaryHost?.port}/defaultdb?sslmode=require`}
{`${primaryHost?.port}/defaultdb?${generalSslmode}`}
</>
) : (
<>
Expand Down
Loading