* Fix subject encoding frontend (#1995) * Add tests for schemas with non ascii chars #1995 * Backend: Fix URL encoding while getting schemas (#2471) Add Test for subject name with non ascii chars Closes #1995 Co-authored-by: Roman Zabaluev <rzabaluev@provectus.com> Co-authored-by: Roman Zabaluev <rzabaluev@provectus.com>
This commit is contained in:
parent
a9c31e6a32
commit
01127d8f10
9 changed files with 114 additions and 6 deletions
|
@ -381,7 +381,7 @@ public class SchemaRegistryService {
|
||||||
final var builder = UriComponentsBuilder
|
final var builder = UriComponentsBuilder
|
||||||
.fromHttpUrl(schemaRegistry.getUri() + path);
|
.fromHttpUrl(schemaRegistry.getUri() + path);
|
||||||
builder.queryParams(queryParams);
|
builder.queryParams(queryParams);
|
||||||
return builder.buildAndExpand(uriVariables.toArray()).toUri();
|
return builder.build(uriVariables.toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Function<ClientResponse, Mono<? extends Throwable>> errorOnSchemaDeleteFailure(String schemaName) {
|
private Function<ClientResponse, Mono<? extends Throwable>> errorOnSchemaDeleteFailure(String schemaName) {
|
||||||
|
|
|
@ -274,6 +274,21 @@ class SchemaRegistryServiceTests extends AbstractIntegrationTest {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldCreateNewSchemaWhenSubjectIncludesNonAsciiCharacters() {
|
||||||
|
String schema =
|
||||||
|
"{\"subject\":\"test/test\",\"schemaType\":\"JSON\",\"schema\":"
|
||||||
|
+ "\"{\\\"type\\\": \\\"string\\\"}\"}";
|
||||||
|
|
||||||
|
webTestClient
|
||||||
|
.post()
|
||||||
|
.uri("/api/clusters/{clusterName}/schemas", LOCAL)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.body(BodyInserters.fromValue(schema))
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().isOk();
|
||||||
|
}
|
||||||
|
|
||||||
private void createNewSubjectAndAssert(String subject) {
|
private void createNewSubjectAndAssert(String subject) {
|
||||||
webTestClient
|
webTestClient
|
||||||
.post()
|
.post()
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { screen, waitFor } from '@testing-library/dom';
|
||||||
import {
|
import {
|
||||||
schemasInitialState,
|
schemasInitialState,
|
||||||
schemaVersion,
|
schemaVersion,
|
||||||
|
schemaVersionWithNonAsciiChars,
|
||||||
} from 'redux/reducers/schemas/__test__/fixtures';
|
} from 'redux/reducers/schemas/__test__/fixtures';
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
import ClusterContext, {
|
import ClusterContext, {
|
||||||
|
@ -98,6 +99,36 @@ describe('Details', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('fetch success schema with non ascii characters', () => {
|
||||||
|
describe('has schema versions', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
const schemasAPILatestMock = fetchMock.getOnce(
|
||||||
|
schemasAPILatestUrl,
|
||||||
|
schemaVersionWithNonAsciiChars
|
||||||
|
);
|
||||||
|
const schemasAPIVersionsMock = fetchMock.getOnce(
|
||||||
|
schemasAPIVersionsUrl,
|
||||||
|
versionPayload
|
||||||
|
);
|
||||||
|
await act(() => {
|
||||||
|
renderComponent();
|
||||||
|
});
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(schemasAPILatestMock.called()).toBeTruthy();
|
||||||
|
});
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(schemasAPIVersionsMock.called()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders component with schema info', () => {
|
||||||
|
expect(screen.getByText('Edit Schema')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('table')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('empty schema versions', () => {
|
describe('empty schema versions', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const schemasAPILatestMock = fetchMock.getOnce(
|
const schemasAPILatestMock = fetchMock.getOnce(
|
||||||
|
|
|
@ -2,12 +2,21 @@ import { SchemaSubject, SchemaType } from 'generated-sources';
|
||||||
import {
|
import {
|
||||||
schemaVersion1,
|
schemaVersion1,
|
||||||
schemaVersion2,
|
schemaVersion2,
|
||||||
|
schemaVersionWithNonAsciiChars,
|
||||||
} from 'redux/reducers/schemas/__test__/fixtures';
|
} from 'redux/reducers/schemas/__test__/fixtures';
|
||||||
|
|
||||||
export const versionPayload = [schemaVersion1, schemaVersion2];
|
export const versionPayload = [
|
||||||
|
schemaVersion1,
|
||||||
|
schemaVersion2,
|
||||||
|
schemaVersionWithNonAsciiChars,
|
||||||
|
];
|
||||||
export const versionEmptyPayload = [];
|
export const versionEmptyPayload = [];
|
||||||
|
|
||||||
export const versions = [schemaVersion1, schemaVersion2];
|
export const versions = [
|
||||||
|
schemaVersion1,
|
||||||
|
schemaVersion2,
|
||||||
|
schemaVersionWithNonAsciiChars,
|
||||||
|
];
|
||||||
|
|
||||||
export const jsonSchema: SchemaSubject = {
|
export const jsonSchema: SchemaSubject = {
|
||||||
subject: 'test',
|
subject: 'test',
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { clusterSchemaEditPath } from 'lib/paths';
|
||||||
import {
|
import {
|
||||||
schemasInitialState,
|
schemasInitialState,
|
||||||
schemaVersion,
|
schemaVersion,
|
||||||
|
schemaVersionWithNonAsciiChars,
|
||||||
} from 'redux/reducers/schemas/__test__/fixtures';
|
} from 'redux/reducers/schemas/__test__/fixtures';
|
||||||
import { screen, waitFor } from '@testing-library/dom';
|
import { screen, waitFor } from '@testing-library/dom';
|
||||||
import ClusterContext, {
|
import ClusterContext, {
|
||||||
|
@ -70,4 +71,21 @@ describe('Edit', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('fetch success schema with non ascii characters', () => {
|
||||||
|
describe('has schema versions', () => {
|
||||||
|
it('renders component with schema info', async () => {
|
||||||
|
const schemasAPILatestMock = fetchMock.getOnce(
|
||||||
|
schemasAPILatestUrl,
|
||||||
|
schemaVersionWithNonAsciiChars
|
||||||
|
);
|
||||||
|
await act(() => {
|
||||||
|
renderComponent();
|
||||||
|
});
|
||||||
|
await waitFor(() => expect(schemasAPILatestMock.called()).toBeTruthy());
|
||||||
|
expect(screen.getByText('Submit')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
import {
|
import {
|
||||||
schemaVersion1,
|
schemaVersion1,
|
||||||
schemaVersion2,
|
schemaVersion2,
|
||||||
|
schemaVersionWithNonAsciiChars,
|
||||||
} from 'redux/reducers/schemas/__test__/fixtures';
|
} from 'redux/reducers/schemas/__test__/fixtures';
|
||||||
|
|
||||||
const schemas = [schemaVersion1, schemaVersion2];
|
const schemas = [
|
||||||
|
schemaVersion1,
|
||||||
|
schemaVersion2,
|
||||||
|
schemaVersionWithNonAsciiChars,
|
||||||
|
];
|
||||||
|
|
||||||
export const schemasPayload = {
|
export const schemasPayload = {
|
||||||
pageCount: 1,
|
pageCount: 1,
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { RouteParams } from 'lib/paths';
|
||||||
const clusterName = 'test-cluster-name';
|
const clusterName = 'test-cluster-name';
|
||||||
const groupId = 'test-group-id';
|
const groupId = 'test-group-id';
|
||||||
const schemaId = 'test-schema-id';
|
const schemaId = 'test-schema-id';
|
||||||
|
const schemaIdWithNonAsciiChars = 'test/test';
|
||||||
|
const schemaIdWithNonAsciiCharsEncoded = 'test%2Ftest';
|
||||||
const topicId = 'test-topic-id';
|
const topicId = 'test-topic-id';
|
||||||
const brokerId = 'test-Broker-id';
|
const brokerId = 'test-Broker-id';
|
||||||
const connectName = 'test-connect-name';
|
const connectName = 'test-connect-name';
|
||||||
|
@ -112,6 +114,13 @@ describe('Paths', () => {
|
||||||
expect(paths.clusterSchemaPath()).toEqual(
|
expect(paths.clusterSchemaPath()).toEqual(
|
||||||
paths.clusterSchemaPath(RouteParams.clusterName, RouteParams.subject)
|
paths.clusterSchemaPath(RouteParams.clusterName, RouteParams.subject)
|
||||||
);
|
);
|
||||||
|
expect(
|
||||||
|
paths.clusterSchemaPath(clusterName, schemaIdWithNonAsciiChars)
|
||||||
|
).toEqual(
|
||||||
|
`${paths.clusterSchemasPath(
|
||||||
|
clusterName
|
||||||
|
)}/${schemaIdWithNonAsciiCharsEncoded}`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('clusterSchemaEditPath', () => {
|
it('clusterSchemaEditPath', () => {
|
||||||
expect(paths.clusterSchemaEditPath(clusterName, schemaId)).toEqual(
|
expect(paths.clusterSchemaEditPath(clusterName, schemaId)).toEqual(
|
||||||
|
@ -120,6 +129,11 @@ describe('Paths', () => {
|
||||||
expect(paths.clusterSchemaEditPath()).toEqual(
|
expect(paths.clusterSchemaEditPath()).toEqual(
|
||||||
paths.clusterSchemaEditPath(RouteParams.clusterName, RouteParams.subject)
|
paths.clusterSchemaEditPath(RouteParams.clusterName, RouteParams.subject)
|
||||||
);
|
);
|
||||||
|
expect(
|
||||||
|
paths.clusterSchemaEditPath(clusterName, schemaIdWithNonAsciiChars)
|
||||||
|
).toEqual(
|
||||||
|
`${paths.clusterSchemaPath(clusterName, schemaIdWithNonAsciiChars)}/edit`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('clusterSchemaComparePath', () => {
|
it('clusterSchemaComparePath', () => {
|
||||||
expect(paths.clusterSchemaComparePath(clusterName, schemaId)).toEqual(
|
expect(paths.clusterSchemaComparePath(clusterName, schemaId)).toEqual(
|
||||||
|
|
|
@ -94,11 +94,19 @@ export const clusterSchemaNewPath = (
|
||||||
export const clusterSchemaPath = (
|
export const clusterSchemaPath = (
|
||||||
clusterName: ClusterName = RouteParams.clusterName,
|
clusterName: ClusterName = RouteParams.clusterName,
|
||||||
subject: SchemaName = RouteParams.subject
|
subject: SchemaName = RouteParams.subject
|
||||||
) => `${clusterSchemasPath(clusterName)}/${subject}`;
|
) => {
|
||||||
|
let subjectName = subject;
|
||||||
|
if (subject !== ':subject') subjectName = encodeURIComponent(subject);
|
||||||
|
return `${clusterSchemasPath(clusterName)}/${subjectName}`;
|
||||||
|
};
|
||||||
export const clusterSchemaEditPath = (
|
export const clusterSchemaEditPath = (
|
||||||
clusterName: ClusterName = RouteParams.clusterName,
|
clusterName: ClusterName = RouteParams.clusterName,
|
||||||
subject: SchemaName = RouteParams.subject
|
subject: SchemaName = RouteParams.subject
|
||||||
) => `${clusterSchemasPath(clusterName)}/${subject}/edit`;
|
) => {
|
||||||
|
let subjectName = subject;
|
||||||
|
if (subject !== ':subject') subjectName = encodeURIComponent(subject);
|
||||||
|
return `${clusterSchemasPath(clusterName)}/${subjectName}/edit`;
|
||||||
|
};
|
||||||
export const clusterSchemaComparePath = (
|
export const clusterSchemaComparePath = (
|
||||||
clusterName: ClusterName = RouteParams.clusterName,
|
clusterName: ClusterName = RouteParams.clusterName,
|
||||||
subject: SchemaName = RouteParams.subject
|
subject: SchemaName = RouteParams.subject
|
||||||
|
|
|
@ -29,6 +29,14 @@ export const schemaVersion2: SchemaSubject = {
|
||||||
compatibilityLevel: 'FORWARD_TRANSITIVE',
|
compatibilityLevel: 'FORWARD_TRANSITIVE',
|
||||||
schemaType: SchemaType.JSON,
|
schemaType: SchemaType.JSON,
|
||||||
};
|
};
|
||||||
|
export const schemaVersionWithNonAsciiChars: SchemaSubject = {
|
||||||
|
subject: 'test/test',
|
||||||
|
version: '1',
|
||||||
|
id: 29,
|
||||||
|
schema: '13',
|
||||||
|
compatibilityLevel: 'FORWARD_TRANSITIVE',
|
||||||
|
schemaType: SchemaType.JSON,
|
||||||
|
};
|
||||||
|
|
||||||
export { schemaVersion1 as schemaVersion };
|
export { schemaVersion1 as schemaVersion };
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue