Fix SR subject encoding (#2483) (#2471) (#1995)

* 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:
Shubham Jain 2022-08-26 22:21:00 +05:30 committed by GitHub
parent a9c31e6a32
commit 01127d8f10
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 114 additions and 6 deletions

View file

@ -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) {

View file

@ -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()

View file

@ -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(

View file

@ -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',

View file

@ -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();
});
});
});
}); });

View file

@ -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,

View file

@ -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(

View file

@ -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

View file

@ -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 };