Skip to content

Commit

Permalink
Synchronize zookeeper clusters with UI (#1888)
Browse files Browse the repository at this point in the history
  • Loading branch information
moscicky authored Aug 21, 2024
1 parent af320d6 commit 8057c70
Show file tree
Hide file tree
Showing 19 changed files with 1,134 additions and 4 deletions.
26 changes: 26 additions & 0 deletions hermes-console/json-server/db.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,32 @@
]
}
],
"inconsistentGroups3":[
{
"name": "pl.allegro.public.group",
"inconsistentMetadata": [],
"inconsistentTopics": [
{
"name": "pl.allegro.public.group.DummyEvent",
"inconsistentMetadata": [],
"inconsistentSubscriptions": [
{
"name": "pl.allegro.public.group.DummyEvent$foobar-service",
"inconsistentMetadata": [
{
"datacenter": "DC1"
},
{
"datacenter": "DC2",
"content": "{\n \"id\": \"foobar-service\",\n \"topicName\": \"pl.allegro.public.group.DummyEvent\",\n \"name\": \"foobar-service\",\n \"endpoint\": \"service://foobar-service/events/dummy-event\",\n \"state\": \"ACTIVE\",\n \"description\": \"Test Hermes endpoint\",\n \"subscriptionPolicy\": {\n \"rate\": 10,\n \"messageTtl\": 60,\n \"messageBackoff\": 100,\n \"requestTimeout\": 1000,\n \"socketTimeout\": 0,\n \"sendingDelay\": 0,\n \"backoffMultiplier\": 1.0,\n \"backoffMaxIntervalInSec\": 600,\n \"retryClientErrors\": true,\n \"backoffMaxIntervalMillis\": 600000\n },\n \"trackingEnabled\": false,\n \"trackingMode\": \"trackingOff\",\n \"owner\": {\n \"source\": \"Service Catalog\",\n \"id\": \"42\"\n },\n \"monitoringDetails\": {\n \"severity\": \"NON_IMPORTANT\",\n \"reaction\": \"\"\n },\n \"contentType\": \"JSON\",\n \"deliveryType\": \"SERIAL\",\n \"filters\": [\n {\n \"type\": \"avropath\",\n \"path\": \"foobar\",\n \"matcher\": \"^FOO_BAR$|^BAZ_BAR$\",\n \"matchingStrategy\": \"any\"\n },\n {\n \"type\": \"avropath\",\n \"path\": \".foo.bar.baz\",\n \"matcher\": \"true\",\n \"matchingStrategy\": \"all\"\n }\n ],\n \"mode\": \"ANYCAST\",\n \"headers\": [\n {\n \"name\": \"X-My-Header\",\n \"value\": \"boobar\"\n },\n {\n \"name\": \"X-Another-Header\",\n \"value\": \"foobar\"\n }\n ],\n \"endpointAddressResolverMetadata\": {\n \"additionalMetadata\": false,\n \"nonSupportedProperty\": 2\n },\n \"http2Enabled\": false,\n \"subscriptionIdentityHeadersEnabled\": false,\n \"autoDeleteWithTopicEnabled\": false,\n \"createdAt\": 1579507131.238,\n \"modifiedAt\": 1672140855.813\n}"
}
]
}
]
}
]
}
],
"topicNames": [
"pl.allegro.public.offer.product.ProductEventV1",
"pl.allegro.public.offer.product.ProductEventV2",
Expand Down
1 change: 1 addition & 0 deletions hermes-console/json-server/routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"/consistency/groups": "/consistencyGroups",
"/consistency/inconsistencies/groups?groupNames=pl.allegro.public.offer*": "/inconsistentGroups",
"/consistency/inconsistencies/groups?groupNames=pl.allegro.public.group2*": "/inconsistentGroups2",
"/consistency/inconsistencies/groups?groupNames=pl.allegro.public.group": "/inconsistentGroups3",
"/groups": "/groups",
"/owners/sources/Service%20Catalog/:id": "/topicsOwners/:id",
"/readiness/datacenters": "/readinessDatacenters",
Expand Down
16 changes: 16 additions & 0 deletions hermes-console/json-server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,22 @@ server.put(
},
);

server.post(
'/consistency/sync/topics/pl.allegro.public.group.DummyEvent/subscriptions/barbaz-service*',
(req, res) => {
res.sendStatus(200);
},
);

server.post(
'/consistency/sync/topics/pl.allegro.public.group.DummyEvent*',
(req, res) => {
res.status(404).jsonp({
message: 'Group pl.allegro.public.group not found',
});
},
);

server.post('/filters/:topic', (req, res) => {
res.jsonp(filterDebug);
});
Expand Down
42 changes: 42 additions & 0 deletions hermes-console/src/api/hermes-client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,3 +464,45 @@ export function verifyFilters(
},
);
}

export function syncGroup(
groupName: string,
primaryDatacenter: string,
): ResponsePromise<void> {
return axios.post<void>(`/consistency/sync/groups/${groupName}`, null, {
params: {
primaryDatacenter: primaryDatacenter,
},
});
}

export function syncTopic(
topicQualifiedName: string,
primaryDatacenter: string,
): ResponsePromise<void> {
return axios.post<void>(
`/consistency/sync/topics/${topicQualifiedName}`,
null,
{
params: {
primaryDatacenter: primaryDatacenter,
},
},
);
}

export function syncSubscription(
topicQualifiedName: string,
subscriptionName: string,
primaryDatacenter: string,
): ResponsePromise<void> {
return axios.post<void>(
`/consistency/sync/topics/${topicQualifiedName}/subscriptions/${subscriptionName}`,
null,
{
params: {
primaryDatacenter: primaryDatacenter,
},
},
);
}
175 changes: 175 additions & 0 deletions hermes-console/src/composables/sync/use-sync/useSync.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { afterEach, describe, expect } from 'vitest';
import { createTestingPinia } from '@pinia/testing';
import {
expectNotificationDispatched,
notificationStoreSpy,
} from '@/utils/test-utils';
import { setActivePinia } from 'pinia';
import { setupServer } from 'msw/node';
import {
syncGroupHandler,
syncSubscriptionHandler,
syncTopicHandler,
} from '@/mocks/handlers';
import { useSync } from '@/composables/sync/use-sync/useSync';
import { waitFor } from '@testing-library/vue';

describe('useSync', () => {
const server = setupServer();

const pinia = createTestingPinia({
fakeApp: true,
});

beforeEach(() => {
setActivePinia(pinia);
});

afterEach(() => {
server.resetHandlers();
});

it('should show error notification when group sync fails', async () => {
// given
const groupName = 'group';
server.use(syncGroupHandler({ groupName, statusCode: 500 }));
server.listen();

const notificationStore = notificationStoreSpy();

// when
const { syncGroup } = useSync();
const result = await syncGroup(groupName, 'DC1');

// then
expect(result).toBeFalsy();

await waitFor(() => {
expectNotificationDispatched(notificationStore, {
type: 'error',
title: 'notifications.consistency.sync.failure',
});
});
});

it('should show error notification when topic sync fails', async () => {
// given
const topicName = 'group.topic';
server.use(syncTopicHandler({ topicName, statusCode: 500 }));
server.listen();

const notificationStore = notificationStoreSpy();

// when
const { syncTopic } = useSync();
const result = await syncTopic(topicName, 'DC1');

// then
expect(result).toBeFalsy();

await waitFor(() => {
expectNotificationDispatched(notificationStore, {
type: 'error',
title: 'notifications.consistency.sync.failure',
});
});
});

it('should show error notification when subscription sync fails', async () => {
// given
const topicName = 'group.topic';
const subscriptionName = 'subscription';
server.use(
syncSubscriptionHandler({ topicName, subscriptionName, statusCode: 500 }),
);
server.listen();

const notificationStore = notificationStoreSpy();

// when
const { syncSubscription } = useSync();
const result = await syncSubscription(topicName, subscriptionName, 'DC1');

// then
expect(result).toBeFalsy();

await waitFor(() => {
expectNotificationDispatched(notificationStore, {
type: 'error',
title: 'notifications.consistency.sync.failure',
});
});
});

it('should show success notification when group sync is successful', async () => {
const groupName = 'group';

server.use(syncGroupHandler({ groupName, statusCode: 200 }));
server.listen();

const notificationStore = notificationStoreSpy();

// when
const { syncGroup } = useSync();
const result = await syncGroup(groupName, 'DC1');

// then
expect(result).toBeTruthy();

await waitFor(() => {
expectNotificationDispatched(notificationStore, {
type: 'success',
text: 'notifications.consistency.sync.success',
});
});
});

it('should show success notification when topic sync is successful', async () => {
// given
const topicName = 'group.topic';
server.use(syncTopicHandler({ topicName, statusCode: 200 }));
server.listen();

const notificationStore = notificationStoreSpy();

// when
const { syncTopic } = useSync();
const result = await syncTopic(topicName, 'DC1');

// then
expect(result).toBeTruthy();

await waitFor(() => {
expectNotificationDispatched(notificationStore, {
type: 'success',
text: 'notifications.consistency.sync.success',
});
});
});

it('should show success notification when subscription sync is successful', async () => {
// given
const topicName = 'group.topic';
const subscriptionName = 'subscription';
server.use(
syncSubscriptionHandler({ topicName, subscriptionName, statusCode: 200 }),
);
server.listen();

const notificationStore = notificationStoreSpy();

// when
const { syncSubscription } = useSync();
const result = await syncSubscription(topicName, subscriptionName, 'DC1');

// then
expect(result).toBeTruthy();

await waitFor(() => {
expectNotificationDispatched(notificationStore, {
type: 'success',
text: 'notifications.consistency.sync.success',
});
});
});
});
Loading

0 comments on commit 8057c70

Please sign in to comment.