|
@@ -2,17 +2,33 @@ import {
|
|
|
MessageSchemaSourceEnum,
|
|
|
SortOrder,
|
|
|
TopicColumnsToSort,
|
|
|
+ ConfigSource,
|
|
|
} from 'generated-sources';
|
|
|
+import reducer, {
|
|
|
+ clearTopicsMessages,
|
|
|
+ setTopicsSearch,
|
|
|
+ setTopicsOrderBy,
|
|
|
+ fetchTopicConsumerGroups,
|
|
|
+ fetchTopicMessageSchema,
|
|
|
+ recreateTopic,
|
|
|
+ createTopic,
|
|
|
+ deleteTopic,
|
|
|
+ fetchTopicsList,
|
|
|
+ fetchTopicDetails,
|
|
|
+ fetchTopicConfig,
|
|
|
+ updateTopic,
|
|
|
+ updateTopicPartitionsCount,
|
|
|
+ updateTopicReplicationFactor,
|
|
|
+ deleteTopics,
|
|
|
+} from 'redux/reducers/topics/topicsSlice';
|
|
|
import {
|
|
|
- deleteTopicAction,
|
|
|
- clearMessagesTopicAction,
|
|
|
- setTopicsSearchAction,
|
|
|
- setTopicsOrderByAction,
|
|
|
- fetchTopicConsumerGroupsAction,
|
|
|
- fetchTopicMessageSchemaAction,
|
|
|
- recreateTopicAction,
|
|
|
-} from 'redux/actions';
|
|
|
-import reducer from 'redux/reducers/topics/reducer';
|
|
|
+ createTopicPayload,
|
|
|
+ createTopicResponsePayload,
|
|
|
+} from 'components/Topics/New/__test__/fixtures';
|
|
|
+import { consumerGroupPayload } from 'redux/reducers/consumerGroups/__test__/fixtures';
|
|
|
+import fetchMock from 'fetch-mock-jest';
|
|
|
+import mockStoreCreator from 'redux/store/configureStore/mockStoreCreator';
|
|
|
+import { getTypeAndPayload } from 'lib/testHelpers';
|
|
|
|
|
|
const topic = {
|
|
|
name: 'topic',
|
|
@@ -68,6 +84,51 @@ const messageSchema = {
|
|
|
},
|
|
|
};
|
|
|
|
|
|
+const config = [
|
|
|
+ {
|
|
|
+ name: 'compression.type',
|
|
|
+ value: 'producer',
|
|
|
+ defaultValue: 'producer',
|
|
|
+ source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
|
|
+ isSensitive: false,
|
|
|
+ isReadOnly: false,
|
|
|
+ synonyms: [
|
|
|
+ {
|
|
|
+ name: 'compression.type',
|
|
|
+ value: 'producer',
|
|
|
+ source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'compression.type',
|
|
|
+ value: 'producer',
|
|
|
+ source: ConfigSource.DEFAULT_CONFIG,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+];
|
|
|
+const details = {
|
|
|
+ name: 'local',
|
|
|
+ internal: false,
|
|
|
+ partitionCount: 1,
|
|
|
+ replicationFactor: 1,
|
|
|
+ replicas: 1,
|
|
|
+ inSyncReplicas: 1,
|
|
|
+ segmentSize: 0,
|
|
|
+ segmentCount: 0,
|
|
|
+ cleanUpPolicy: 'DELETE',
|
|
|
+ partitions: [
|
|
|
+ {
|
|
|
+ partition: 0,
|
|
|
+ leader: 1,
|
|
|
+ replicas: [{ broker: 1, leader: false, inSync: true }],
|
|
|
+ offsetMax: 0,
|
|
|
+ offsetMin: 0,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ bytesInPerSec: 0.1,
|
|
|
+ bytesOutPerSec: 0.1,
|
|
|
+};
|
|
|
+
|
|
|
let state = {
|
|
|
byName: {
|
|
|
[topic.name]: topic,
|
|
@@ -80,84 +141,756 @@ let state = {
|
|
|
sortOrder: SortOrder.ASC,
|
|
|
consumerGroups: [],
|
|
|
};
|
|
|
+const clusterName = 'local';
|
|
|
|
|
|
-describe('topics reducer', () => {
|
|
|
- describe('delete topic', () => {
|
|
|
- it('deletes the topic from the list on DELETE_TOPIC__SUCCESS', () => {
|
|
|
- expect(reducer(state, deleteTopicAction.success(topic.name))).toEqual({
|
|
|
- ...state,
|
|
|
- byName: {},
|
|
|
- allNames: [],
|
|
|
- consumerGroups: [],
|
|
|
+describe('topics Slice', () => {
|
|
|
+ describe('topics reducer', () => {
|
|
|
+ describe('fetch topic details', () => {
|
|
|
+ it('fetchTopicDetails/fulfilled', () => {
|
|
|
+ expect(
|
|
|
+ reducer(state, {
|
|
|
+ type: fetchTopicDetails.fulfilled,
|
|
|
+ payload: {
|
|
|
+ clusterName,
|
|
|
+ topicName: topic.name,
|
|
|
+ topicDetails: details,
|
|
|
+ },
|
|
|
+ })
|
|
|
+ ).toEqual({
|
|
|
+ ...state,
|
|
|
+ byName: {
|
|
|
+ [topic.name]: {
|
|
|
+ ...topic,
|
|
|
+ ...details,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ allNames: [topic.name],
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ describe('fetch topics', () => {
|
|
|
+ it('fetchTopicsList/fulfilled', () => {
|
|
|
+ expect(
|
|
|
+ reducer(state, {
|
|
|
+ type: fetchTopicsList.fulfilled,
|
|
|
+ payload: { clusterName, topicName: topic.name },
|
|
|
+ })
|
|
|
+ ).toEqual({
|
|
|
+ ...state,
|
|
|
+ byName: { topic },
|
|
|
+ allNames: [topic.name],
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ describe('fetch topic config', () => {
|
|
|
+ it('fetchTopicConfig/fulfilled', () => {
|
|
|
+ expect(
|
|
|
+ reducer(state, {
|
|
|
+ type: fetchTopicConfig.fulfilled,
|
|
|
+ payload: {
|
|
|
+ clusterName,
|
|
|
+ topicName: topic.name,
|
|
|
+ topicConfig: config,
|
|
|
+ },
|
|
|
+ })
|
|
|
+ ).toEqual({
|
|
|
+ ...state,
|
|
|
+ byName: {
|
|
|
+ [topic.name]: {
|
|
|
+ ...topic,
|
|
|
+ config: config.map((conf) => ({ ...conf })),
|
|
|
+ },
|
|
|
+ },
|
|
|
+ allNames: [topic.name],
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ describe('update topic', () => {
|
|
|
+ it('updateTopic/fulfilled', () => {
|
|
|
+ const updatedTopic = {
|
|
|
+ name: 'topic',
|
|
|
+ id: 'id',
|
|
|
+ partitions: 1,
|
|
|
+ };
|
|
|
+ expect(
|
|
|
+ reducer(state, {
|
|
|
+ type: updateTopic.fulfilled,
|
|
|
+ payload: {
|
|
|
+ clusterName,
|
|
|
+ topicName: topic.name,
|
|
|
+ topic: updatedTopic,
|
|
|
+ },
|
|
|
+ })
|
|
|
+ ).toEqual({
|
|
|
+ ...state,
|
|
|
+ byName: {
|
|
|
+ [topic.name]: {
|
|
|
+ ...updatedTopic,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ });
|
|
|
});
|
|
|
});
|
|
|
+ describe('delete topic', () => {
|
|
|
+ it('deleteTopic/fulfilled', () => {
|
|
|
+ expect(
|
|
|
+ reducer(state, {
|
|
|
+ type: deleteTopic.fulfilled,
|
|
|
+ payload: { clusterName, topicName: topic.name },
|
|
|
+ })
|
|
|
+ ).toEqual({
|
|
|
+ ...state,
|
|
|
+ byName: {},
|
|
|
+ allNames: [],
|
|
|
+ });
|
|
|
+ });
|
|
|
|
|
|
- it('delete topic messages on CLEAR_TOPIC_MESSAGES__SUCCESS', () => {
|
|
|
- expect(reducer(state, clearMessagesTopicAction.success())).toEqual(state);
|
|
|
+ it('clearTopicsMessages/fulfilled', () => {
|
|
|
+ expect(
|
|
|
+ reducer(state, {
|
|
|
+ type: clearTopicsMessages.fulfilled,
|
|
|
+ payload: { clusterName, topicName: topic.name },
|
|
|
+ })
|
|
|
+ ).toEqual({
|
|
|
+ ...state,
|
|
|
+ messages: [],
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ it('recreateTopic/fulfilled', () => {
|
|
|
+ expect(
|
|
|
+ reducer(state, {
|
|
|
+ type: recreateTopic.fulfilled,
|
|
|
+ payload: { topic, topicName: topic.name },
|
|
|
+ })
|
|
|
+ ).toEqual({
|
|
|
+ ...state,
|
|
|
+ byName: {
|
|
|
+ [topic.name]: topic,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ });
|
|
|
});
|
|
|
|
|
|
- it('recreate topic', () => {
|
|
|
- expect(reducer(state, recreateTopicAction.success(topic))).toEqual({
|
|
|
- ...state,
|
|
|
- byName: {
|
|
|
- [topic.name]: topic,
|
|
|
- },
|
|
|
+ describe('create topics', () => {
|
|
|
+ it('createTopic/fulfilled', () => {
|
|
|
+ expect(
|
|
|
+ reducer(state, {
|
|
|
+ type: createTopic.fulfilled,
|
|
|
+ payload: { clusterName, data: createTopicPayload },
|
|
|
+ })
|
|
|
+ ).toEqual({
|
|
|
+ ...state,
|
|
|
+ });
|
|
|
});
|
|
|
});
|
|
|
- });
|
|
|
|
|
|
- describe('search topics', () => {
|
|
|
- it('sets the search string', () => {
|
|
|
- expect(reducer(state, setTopicsSearchAction('test'))).toEqual({
|
|
|
- ...state,
|
|
|
- search: 'test',
|
|
|
+ describe('search topics', () => {
|
|
|
+ it('setTopicsSearch', () => {
|
|
|
+ expect(
|
|
|
+ reducer(state, {
|
|
|
+ type: setTopicsSearch,
|
|
|
+ payload: 'test',
|
|
|
+ })
|
|
|
+ ).toEqual({
|
|
|
+ ...state,
|
|
|
+ search: 'test',
|
|
|
+ });
|
|
|
});
|
|
|
});
|
|
|
- });
|
|
|
|
|
|
- describe('order topics', () => {
|
|
|
- it('sets the orderBy', () => {
|
|
|
- expect(
|
|
|
- reducer(state, setTopicsOrderByAction(TopicColumnsToSort.NAME))
|
|
|
- ).toEqual({
|
|
|
- ...state,
|
|
|
- orderBy: TopicColumnsToSort.NAME,
|
|
|
+ describe('order topics', () => {
|
|
|
+ it('setTopicsOrderBy', () => {
|
|
|
+ expect(
|
|
|
+ reducer(state, {
|
|
|
+ type: setTopicsOrderBy,
|
|
|
+ payload: TopicColumnsToSort.NAME,
|
|
|
+ })
|
|
|
+ ).toEqual({
|
|
|
+ ...state,
|
|
|
+ orderBy: TopicColumnsToSort.NAME,
|
|
|
+ });
|
|
|
});
|
|
|
});
|
|
|
- });
|
|
|
|
|
|
- describe('topic consumer groups', () => {
|
|
|
- it('GET_TOPIC_CONSUMER_GROUPS__SUCCESS', () => {
|
|
|
- expect(
|
|
|
- reducer(state, fetchTopicConsumerGroupsAction.success(state))
|
|
|
- ).toEqual(state);
|
|
|
+ describe('topic consumer groups', () => {
|
|
|
+ it('fetchTopicConsumerGroups/fulfilled', () => {
|
|
|
+ expect(
|
|
|
+ reducer(state, {
|
|
|
+ type: fetchTopicConsumerGroups.fulfilled,
|
|
|
+ payload: {
|
|
|
+ clusterName,
|
|
|
+ topicName: topic.name,
|
|
|
+ consumerGroups: consumerGroupPayload,
|
|
|
+ },
|
|
|
+ })
|
|
|
+ ).toEqual({
|
|
|
+ ...state,
|
|
|
+ byName: {
|
|
|
+ [topic.name]: {
|
|
|
+ ...topic,
|
|
|
+ ...consumerGroupPayload,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ describe('message sending', () => {
|
|
|
+ it('fetchTopicMessageSchema/fulfilled', () => {
|
|
|
+ state = {
|
|
|
+ byName: {
|
|
|
+ [topic.name]: topic,
|
|
|
+ },
|
|
|
+ allNames: [topic.name],
|
|
|
+ messages: [],
|
|
|
+ totalPages: 1,
|
|
|
+ search: '',
|
|
|
+ orderBy: null,
|
|
|
+ sortOrder: SortOrder.ASC,
|
|
|
+ consumerGroups: [],
|
|
|
+ };
|
|
|
+ expect(
|
|
|
+ reducer(state, {
|
|
|
+ type: fetchTopicMessageSchema.fulfilled,
|
|
|
+ payload: { topicName: topic.name, schema: messageSchema },
|
|
|
+ }).byName
|
|
|
+ ).toEqual({
|
|
|
+ [topic.name]: { ...topic, messageSchema },
|
|
|
+ });
|
|
|
+ });
|
|
|
});
|
|
|
});
|
|
|
+ describe('Thunks', () => {
|
|
|
+ const store = mockStoreCreator;
|
|
|
+ const topicName = topic.name;
|
|
|
|
|
|
- describe('message sending', () => {
|
|
|
- it('adds message shema after fetching it', () => {
|
|
|
- state = {
|
|
|
- byName: {
|
|
|
- [topic.name]: topic,
|
|
|
+ afterEach(() => {
|
|
|
+ fetchMock.restore();
|
|
|
+ store.clearActions();
|
|
|
+ });
|
|
|
+ describe('fetchTopicsList', () => {
|
|
|
+ const topicResponse = {
|
|
|
+ pageCount: 1,
|
|
|
+ topics: [createTopicResponsePayload],
|
|
|
+ };
|
|
|
+ it('fetchTopicsList/fulfilled', async () => {
|
|
|
+ fetchMock.getOnce(`/api/clusters/${clusterName}/topics`, topicResponse);
|
|
|
+ await store.dispatch(fetchTopicsList({ clusterName }));
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: fetchTopicsList.pending.type },
|
|
|
+ {
|
|
|
+ type: fetchTopicsList.fulfilled.type,
|
|
|
+ payload: { ...topicResponse },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ it('fetchTopicsList/rejected', async () => {
|
|
|
+ fetchMock.getOnce(`/api/clusters/${clusterName}/topics`, 404);
|
|
|
+ await store.dispatch(fetchTopicsList({ clusterName }));
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: fetchTopicsList.pending.type },
|
|
|
+ {
|
|
|
+ type: fetchTopicsList.rejected.type,
|
|
|
+ payload: {
|
|
|
+ status: 404,
|
|
|
+ statusText: 'Not Found',
|
|
|
+ url: `/api/clusters/${clusterName}/topics`,
|
|
|
+ message: undefined,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ describe('fetchTopicDetails', () => {
|
|
|
+ it('fetchTopicDetails/fulfilled', async () => {
|
|
|
+ fetchMock.getOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}`,
|
|
|
+ details
|
|
|
+ );
|
|
|
+ await store.dispatch(fetchTopicDetails({ clusterName, topicName }));
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: fetchTopicDetails.pending.type },
|
|
|
+ {
|
|
|
+ type: fetchTopicDetails.fulfilled.type,
|
|
|
+ payload: { topicDetails: { ...details }, topicName },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ it('fetchTopicDetails/rejected', async () => {
|
|
|
+ fetchMock.getOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}`,
|
|
|
+ 404
|
|
|
+ );
|
|
|
+ await store.dispatch(fetchTopicDetails({ clusterName, topicName }));
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: fetchTopicDetails.pending.type },
|
|
|
+ {
|
|
|
+ type: fetchTopicDetails.rejected.type,
|
|
|
+ payload: {
|
|
|
+ status: 404,
|
|
|
+ statusText: 'Not Found',
|
|
|
+ url: `/api/clusters/${clusterName}/topics/${topicName}`,
|
|
|
+ message: undefined,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ describe('fetchTopicConfig', () => {
|
|
|
+ it('fetchTopicConfig/fulfilled', async () => {
|
|
|
+ fetchMock.getOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}/config`,
|
|
|
+ config
|
|
|
+ );
|
|
|
+ await store.dispatch(fetchTopicConfig({ clusterName, topicName }));
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: fetchTopicConfig.pending.type },
|
|
|
+ {
|
|
|
+ type: fetchTopicConfig.fulfilled.type,
|
|
|
+ payload: {
|
|
|
+ topicConfig: config,
|
|
|
+ topicName,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ it('fetchTopicConfig/rejected', async () => {
|
|
|
+ fetchMock.getOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}/config`,
|
|
|
+ 404
|
|
|
+ );
|
|
|
+ await store.dispatch(fetchTopicConfig({ clusterName, topicName }));
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: fetchTopicConfig.pending.type },
|
|
|
+ {
|
|
|
+ type: fetchTopicConfig.rejected.type,
|
|
|
+ payload: {
|
|
|
+ status: 404,
|
|
|
+ statusText: 'Not Found',
|
|
|
+ url: `/api/clusters/${clusterName}/topics/${topicName}/config`,
|
|
|
+ message: undefined,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ describe('deleteTopic', () => {
|
|
|
+ it('deleteTopic/fulfilled', async () => {
|
|
|
+ fetchMock.deleteOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}`,
|
|
|
+ topicName
|
|
|
+ );
|
|
|
+ await store.dispatch(deleteTopic({ clusterName, topicName }));
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: deleteTopic.pending.type },
|
|
|
+ {
|
|
|
+ type: deleteTopic.fulfilled.type,
|
|
|
+ payload: { topicName },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ it('deleteTopic/rejected', async () => {
|
|
|
+ fetchMock.deleteOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}`,
|
|
|
+ 404
|
|
|
+ );
|
|
|
+ await store.dispatch(deleteTopic({ clusterName, topicName }));
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: deleteTopic.pending.type },
|
|
|
+ {
|
|
|
+ type: deleteTopic.rejected.type,
|
|
|
+ payload: {
|
|
|
+ status: 404,
|
|
|
+ statusText: 'Not Found',
|
|
|
+ url: `/api/clusters/${clusterName}/topics/${topicName}`,
|
|
|
+ message: undefined,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ describe('deleteTopics', () => {
|
|
|
+ it('deleteTopics/fulfilled', async () => {
|
|
|
+ fetchMock.delete(`/api/clusters/${clusterName}/topics/${topicName}`, [
|
|
|
+ topicName,
|
|
|
+ 'topic2',
|
|
|
+ ]);
|
|
|
+ await store.dispatch(
|
|
|
+ deleteTopics({ clusterName, topicNames: [topicName, 'topic2'] })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: deleteTopics.pending.type },
|
|
|
+ { type: deleteTopic.pending.type },
|
|
|
+ { type: deleteTopic.pending.type },
|
|
|
+ { type: deleteTopics.fulfilled.type },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ describe('recreateTopic', () => {
|
|
|
+ const recreateResponse = {
|
|
|
+ cleanUpPolicy: 'DELETE',
|
|
|
+ inSyncReplicas: 1,
|
|
|
+ internal: false,
|
|
|
+ name: topicName,
|
|
|
+ partitionCount: 1,
|
|
|
+ partitions: undefined,
|
|
|
+ replicas: 1,
|
|
|
+ replicationFactor: 1,
|
|
|
+ segmentCount: 0,
|
|
|
+ segmentSize: 0,
|
|
|
+ underReplicatedPartitions: undefined,
|
|
|
+ };
|
|
|
+ it('recreateTopic/fulfilled', async () => {
|
|
|
+ fetchMock.postOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}`,
|
|
|
+ recreateResponse
|
|
|
+ );
|
|
|
+ await store.dispatch(recreateTopic({ clusterName, topicName }));
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: recreateTopic.pending.type },
|
|
|
+ {
|
|
|
+ type: recreateTopic.fulfilled.type,
|
|
|
+ payload: { [topicName]: { ...recreateResponse } },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ it('recreateTopic/rejected', async () => {
|
|
|
+ fetchMock.postOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}`,
|
|
|
+ 404
|
|
|
+ );
|
|
|
+ await store.dispatch(recreateTopic({ clusterName, topicName }));
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: recreateTopic.pending.type },
|
|
|
+ {
|
|
|
+ type: recreateTopic.rejected.type,
|
|
|
+ payload: {
|
|
|
+ status: 404,
|
|
|
+ statusText: 'Not Found',
|
|
|
+ url: `/api/clusters/${clusterName}/topics/${topicName}`,
|
|
|
+ message: undefined,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ describe('fetchTopicConsumerGroups', () => {
|
|
|
+ const consumerGroups = [
|
|
|
+ {
|
|
|
+ groupId: 'groupId1',
|
|
|
+ members: 0,
|
|
|
+ topics: 1,
|
|
|
+ simple: false,
|
|
|
+ partitionAssignor: '',
|
|
|
+ coordinator: {
|
|
|
+ id: 1,
|
|
|
+ port: undefined,
|
|
|
+ host: 'host',
|
|
|
+ },
|
|
|
+ messagesBehind: undefined,
|
|
|
+ state: undefined,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ groupId: 'groupId2',
|
|
|
+ members: 0,
|
|
|
+ topics: 1,
|
|
|
+ simple: false,
|
|
|
+ partitionAssignor: '',
|
|
|
+ coordinator: {
|
|
|
+ id: 1,
|
|
|
+ port: undefined,
|
|
|
+ host: 'host',
|
|
|
+ },
|
|
|
+ messagesBehind: undefined,
|
|
|
+ state: undefined,
|
|
|
+ },
|
|
|
+ ];
|
|
|
+ it('fetchTopicConsumerGroups/fulfilled', async () => {
|
|
|
+ fetchMock.getOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}/consumer-groups`,
|
|
|
+ consumerGroups
|
|
|
+ );
|
|
|
+ await store.dispatch(
|
|
|
+ fetchTopicConsumerGroups({ clusterName, topicName })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: fetchTopicConsumerGroups.pending.type },
|
|
|
+ {
|
|
|
+ type: fetchTopicConsumerGroups.fulfilled.type,
|
|
|
+ payload: { consumerGroups, topicName },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ it('fetchTopicConsumerGroups/rejected', async () => {
|
|
|
+ fetchMock.getOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}/consumer-groups`,
|
|
|
+ 404
|
|
|
+ );
|
|
|
+ await store.dispatch(
|
|
|
+ fetchTopicConsumerGroups({ clusterName, topicName })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: fetchTopicConsumerGroups.pending.type },
|
|
|
+ {
|
|
|
+ type: fetchTopicConsumerGroups.rejected.type,
|
|
|
+ payload: {
|
|
|
+ status: 404,
|
|
|
+ statusText: 'Not Found',
|
|
|
+ url: `/api/clusters/${clusterName}/topics/${topicName}/consumer-groups`,
|
|
|
+ message: undefined,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ describe('updateTopicPartitionsCount', () => {
|
|
|
+ it('updateTopicPartitionsCount/fulfilled', async () => {
|
|
|
+ fetchMock.patchOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}/partitions`,
|
|
|
+ { message: 'success' }
|
|
|
+ );
|
|
|
+ await store.dispatch(
|
|
|
+ updateTopicPartitionsCount({
|
|
|
+ clusterName,
|
|
|
+ topicName,
|
|
|
+ partitions: 1,
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: updateTopicPartitionsCount.pending.type },
|
|
|
+ {
|
|
|
+ type: updateTopicPartitionsCount.fulfilled.type,
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ it('updateTopicPartitionsCount/rejected', async () => {
|
|
|
+ fetchMock.patchOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}/partitions`,
|
|
|
+ 404
|
|
|
+ );
|
|
|
+ await store.dispatch(
|
|
|
+ updateTopicPartitionsCount({
|
|
|
+ clusterName,
|
|
|
+ topicName,
|
|
|
+ partitions: 1,
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: updateTopicPartitionsCount.pending.type },
|
|
|
+ {
|
|
|
+ type: updateTopicPartitionsCount.rejected.type,
|
|
|
+ payload: {
|
|
|
+ status: 404,
|
|
|
+ statusText: 'Not Found',
|
|
|
+ url: `/api/clusters/${clusterName}/topics/${topicName}/partitions`,
|
|
|
+ message: undefined,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ describe('updateTopicReplicationFactor', () => {
|
|
|
+ it('updateTopicReplicationFactor/fulfilled', async () => {
|
|
|
+ fetchMock.patchOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}/replications`,
|
|
|
+ { message: 'success' }
|
|
|
+ );
|
|
|
+ await store.dispatch(
|
|
|
+ updateTopicReplicationFactor({
|
|
|
+ clusterName,
|
|
|
+ topicName,
|
|
|
+ replicationFactor: 1,
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: updateTopicReplicationFactor.pending.type },
|
|
|
+ {
|
|
|
+ type: updateTopicReplicationFactor.fulfilled.type,
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ it('updateTopicReplicationFactor/rejected', async () => {
|
|
|
+ fetchMock.patchOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}/replications`,
|
|
|
+ 404
|
|
|
+ );
|
|
|
+ await store.dispatch(
|
|
|
+ updateTopicReplicationFactor({
|
|
|
+ clusterName,
|
|
|
+ topicName,
|
|
|
+ replicationFactor: 1,
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: updateTopicReplicationFactor.pending.type },
|
|
|
+ {
|
|
|
+ type: updateTopicReplicationFactor.rejected.type,
|
|
|
+ payload: {
|
|
|
+ status: 404,
|
|
|
+ statusText: 'Not Found',
|
|
|
+ url: `/api/clusters/${clusterName}/topics/${topicName}/replications`,
|
|
|
+ message: undefined,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ describe('createTopic', () => {
|
|
|
+ const newTopic = {
|
|
|
+ name: 'newTopic',
|
|
|
+ partitions: 0,
|
|
|
+ replicationFactor: 0,
|
|
|
+ minInsyncReplicas: 0,
|
|
|
+ cleanupPolicy: 'DELETE',
|
|
|
+ retentionMs: 1,
|
|
|
+ retentionBytes: 1,
|
|
|
+ maxMessageBytes: 1,
|
|
|
+ customParams: [
|
|
|
+ {
|
|
|
+ name: '',
|
|
|
+ value: '',
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ it('createTopic/fulfilled', async () => {
|
|
|
+ fetchMock.postOnce(`/api/clusters/${clusterName}/topics`, {
|
|
|
+ message: 'success',
|
|
|
+ });
|
|
|
+ await store.dispatch(
|
|
|
+ createTopic({
|
|
|
+ clusterName,
|
|
|
+ data: newTopic,
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: createTopic.pending.type },
|
|
|
+ {
|
|
|
+ type: createTopic.fulfilled.type,
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ it('createTopic/rejected', async () => {
|
|
|
+ fetchMock.postOnce(`/api/clusters/${clusterName}/topics`, 404);
|
|
|
+ await store.dispatch(
|
|
|
+ createTopic({
|
|
|
+ clusterName,
|
|
|
+ data: newTopic,
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: createTopic.pending.type },
|
|
|
+ {
|
|
|
+ type: createTopic.rejected.type,
|
|
|
+ payload: {
|
|
|
+ status: 404,
|
|
|
+ statusText: 'Not Found',
|
|
|
+ url: `/api/clusters/${clusterName}/topics`,
|
|
|
+ message: undefined,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ describe('updateTopic', () => {
|
|
|
+ const updateTopicResponse = {
|
|
|
+ name: topicName,
|
|
|
+ partitions: 0,
|
|
|
+ replicationFactor: 0,
|
|
|
+ minInsyncReplicas: 0,
|
|
|
+ cleanupPolicy: 'DELETE',
|
|
|
+ retentionMs: 0,
|
|
|
+ retentionBytes: 0,
|
|
|
+ maxMessageBytes: 0,
|
|
|
+ customParams: {
|
|
|
+ byIndex: {},
|
|
|
+ allIndexes: [],
|
|
|
},
|
|
|
- allNames: [topic.name],
|
|
|
- messages: [],
|
|
|
- totalPages: 1,
|
|
|
- search: '',
|
|
|
- orderBy: null,
|
|
|
- sortOrder: SortOrder.ASC,
|
|
|
- consumerGroups: [],
|
|
|
};
|
|
|
- expect(
|
|
|
- reducer(
|
|
|
- state,
|
|
|
- fetchTopicMessageSchemaAction.success({
|
|
|
- topicName: 'topic',
|
|
|
- schema: messageSchema,
|
|
|
- })
|
|
|
- ).byName
|
|
|
- ).toEqual({
|
|
|
- [topic.name]: { ...topic, messageSchema },
|
|
|
+ it('updateTopic/fulfilled', async () => {
|
|
|
+ fetchMock.patchOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}`,
|
|
|
+ createTopicResponsePayload
|
|
|
+ );
|
|
|
+ await store.dispatch(
|
|
|
+ updateTopic({
|
|
|
+ clusterName,
|
|
|
+ topicName,
|
|
|
+ form: updateTopicResponse,
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: updateTopic.pending.type },
|
|
|
+ {
|
|
|
+ type: updateTopic.fulfilled.type,
|
|
|
+ payload: { [topicName]: { ...createTopicResponsePayload } },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ it('updateTopic/rejected', async () => {
|
|
|
+ fetchMock.patchOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}`,
|
|
|
+ 404
|
|
|
+ );
|
|
|
+ await store.dispatch(
|
|
|
+ updateTopic({
|
|
|
+ clusterName,
|
|
|
+ topicName,
|
|
|
+ form: updateTopicResponse,
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: updateTopic.pending.type },
|
|
|
+ {
|
|
|
+ type: updateTopic.rejected.type,
|
|
|
+ payload: {
|
|
|
+ status: 404,
|
|
|
+ statusText: 'Not Found',
|
|
|
+ url: `/api/clusters/${clusterName}/topics/${topicName}`,
|
|
|
+ message: undefined,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ]);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ describe('clearTopicsMessages', () => {
|
|
|
+ it('clearTopicsMessages/fulfilled', async () => {
|
|
|
+ fetchMock.deleteOnce(
|
|
|
+ `/api/clusters/${clusterName}/topics/${topicName}/messages`,
|
|
|
+ [topicName, 'topic2']
|
|
|
+ );
|
|
|
+ await store.dispatch(
|
|
|
+ clearTopicsMessages({
|
|
|
+ clusterName,
|
|
|
+ topicNames: [topicName, 'topic2'],
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(getTypeAndPayload(store)).toEqual([
|
|
|
+ { type: clearTopicsMessages.pending.type },
|
|
|
+ { type: clearTopicsMessages.fulfilled.type },
|
|
|
+ ]);
|
|
|
});
|
|
|
});
|
|
|
});
|