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
3 changes: 2 additions & 1 deletion x-pack/platform/plugins/shared/alerting_v2/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"dataViews",
"esql",
"security",
"encryptedSavedObjects"
"encryptedSavedObjects",
"workflowsManagement"
],
"optionalPlugins": ["management"],
"extraPublicDirs": []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
import type { BulkResponse } from '@elastic/elasticsearch/lib/api/types';
import type { DeeplyMockedApi } from '@kbn/core-elasticsearch-client-server-mocks';
import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server';
import type { WorkflowsServerPluginSetup } from '@kbn/workflows-management-plugin/server';
import moment from 'moment';
import { ALERT_ACTIONS_DATA_STREAM, type AlertAction } from '../../resources/alert_actions';
import { RULE_SAVED_OBJECT_TYPE, NOTIFICATION_POLICY_SAVED_OBJECT_TYPE } from '../../saved_objects';
import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects';
import type { RuleSavedObjectAttributes } from '../../saved_objects';
import { createRuleSoAttributes } from '../test_utils';
import { createLoggerService } from '../services/logger_service/logger_service.mock';
Expand Down Expand Up @@ -63,30 +64,36 @@ function mockRulesBulkGet(
});
}

function mockNpBulkGet(mockSoClient: jest.Mocked<SavedObjectsClientContract>, policyIds: string[]) {
mockSoClient.bulkGet.mockResolvedValue({
saved_objects: policyIds.map((id) => ({
function mockNpBulkGetDecrypted(spy: jest.SpyInstance, policyIds: string[]) {
spy.mockResolvedValue(
policyIds.map((id) => ({
id,
type: NOTIFICATION_POLICY_SAVED_OBJECT_TYPE,
attributes: {
name: `Policy ${id}`,
description: `Description for ${id}`,
destinations: [{ type: 'workflow', id: 'workflow-test-id' }],
auth: { apiKey: 'test-api-key', owner: 'elastic', createdByUser: false },
createdBy: null,
updatedBy: null,
createdAt: '2026-01-01T00:00:00.000Z',
updatedAt: '2026-01-01T00:00:00.000Z',
},
references: [],
})),
});
}))
);
}

const createMockWorkflowsManagement = (): jest.Mocked<WorkflowsServerPluginSetup['management']> =>
({
getWorkflow: jest.fn().mockResolvedValue(null),
runWorkflow: jest.fn().mockResolvedValue('exec-1'),
} as unknown as jest.Mocked<WorkflowsServerPluginSetup['management']>);

function buildDispatcherService(deps: {
queryService: QueryServiceContract;
storageService: StorageServiceContract;
rulesSoService: RulesSavedObjectServiceContract;
npSoService: NotificationPolicySavedObjectServiceContract;
workflowsManagement: WorkflowsServerPluginSetup['management'];
}): DispatcherService {
const { loggerService } = createLoggerService();
const pipeline = new DispatcherPipeline(loggerService, [
Expand All @@ -98,7 +105,7 @@ function buildDispatcherService(deps: {
new EvaluateMatchersStep(),
new BuildGroupsStep(),
new ApplyThrottlingStep(deps.queryService, loggerService),
new DispatchStep(loggerService),
new DispatchStep(loggerService, deps.workflowsManagement),
new StoreActionsStep(deps.storageService),
]);
return new DispatcherService(pipeline);
Expand All @@ -113,7 +120,8 @@ describe('DispatcherService', () => {
let rulesSoService: RulesSavedObjectServiceContract;
let npSoService: NotificationPolicySavedObjectServiceContract;
let rulesMockSoClient: jest.Mocked<SavedObjectsClientContract>;
let npMockSoClient: jest.Mocked<SavedObjectsClientContract>;
let mockBulkGetDecryptedByIds: jest.SpyInstance;
let mockWfm: jest.Mocked<WorkflowsServerPluginSetup['management']>;

beforeEach(() => {
({ queryService, mockEsClient: queryEsClient } = createQueryService());
Expand All @@ -126,14 +134,17 @@ describe('DispatcherService', () => {

const npMock = createNotificationPolicySavedObjectService();
npSoService = npMock.notificationPolicySavedObjectService;
npMockSoClient = npMock.mockSavedObjectsClient;
mockNpBulkGet(npMockSoClient, ['policy_456']);
mockBulkGetDecryptedByIds = npMock.mockBulkGetDecryptedByIds;
mockNpBulkGetDecrypted(mockBulkGetDecryptedByIds, ['policy_456']);

mockWfm = createMockWorkflowsManagement();

dispatcherService = buildDispatcherService({
queryService,
storageService,
rulesSoService,
npSoService,
workflowsManagement: mockWfm,
});
});

Expand Down Expand Up @@ -360,14 +371,17 @@ describe('DispatcherService', () => {

const npMock = createNotificationPolicySavedObjectService();
npSoService = npMock.notificationPolicySavedObjectService;
npMockSoClient = npMock.mockSavedObjectsClient;
mockNpBulkGet(npMockSoClient, ['policy_456']);
mockBulkGetDecryptedByIds = npMock.mockBulkGetDecryptedByIds;
mockNpBulkGetDecrypted(mockBulkGetDecryptedByIds, ['policy_456']);

mockWfm = createMockWorkflowsManagement();

dispatcherService = buildDispatcherService({
queryService,
storageService,
rulesSoService,
npSoService,
workflowsManagement: mockWfm,
});

// Dataset: 5 rules, 9 episodes total
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,28 @@

import type { TestElasticsearchUtils, TestKibanaUtils } from '@kbn/core-test-helpers-kbn-server';
import type { ElasticsearchClient } from '@kbn/core/server';
import type { WorkflowsServerPluginSetup } from '@kbn/workflows-management-plugin/server';
import { ALERT_ACTIONS_DATA_STREAM, type AlertAction } from '../../../resources/alert_actions';
import { ALERT_EVENTS_DATA_STREAM, type AlertEvent } from '../../../resources/alert_events';
import type {
RuleSavedObjectAttributes,
NotificationPolicySavedObjectAttributes,
} from '../../../saved_objects';
import type { LoggerServiceContract } from '../../services/logger_service/logger_service';
import { createLoggerService } from '../../services/logger_service/logger_service.mock';
import { NotificationPolicySavedObjectService } from '../../services/notification_policy_saved_object_service/notification_policy_saved_object_service';
import type { NotificationPolicySavedObjectServiceContract } from '../../services/notification_policy_saved_object_service/notification_policy_saved_object_service';
import {
QueryService,
type QueryServiceContract,
} from '../../services/query_service/query_service';
import { RulesSavedObjectService } from '../../services/rules_saved_object_service/rules_saved_object_service';
import type { RulesSavedObjectServiceContract } from '../../services/rules_saved_object_service/rules_saved_object_service';
import {
StorageService,
type StorageServiceContract,
} from '../../services/storage_service/storage_service';
import type { SpacesPluginStart } from '@kbn/spaces-plugin/server';
import { NotificationPolicySavedObjectService } from '../../services/notification_policy_saved_object_service/notification_policy_saved_object_service';
import type { NotificationPolicySavedObjectServiceContract } from '../../services/notification_policy_saved_object_service/notification_policy_saved_object_service';
import { RulesSavedObjectService } from '../../services/rules_saved_object_service/rules_saved_object_service';
import type { RulesSavedObjectServiceContract } from '../../services/rules_saved_object_service/rules_saved_object_service';
import type {
RuleSavedObjectAttributes,
NotificationPolicySavedObjectAttributes,
} from '../../../saved_objects';
import { DispatcherService, type DispatcherServiceContract } from '../dispatcher';
import { DispatcherPipeline } from '../execution_pipeline';
import {
Expand Down Expand Up @@ -333,6 +334,12 @@ const SUPPRESSION_USER_ACTIONS: AlertAction[] = [
},
];

const createMockWorkflowsManagement = (): WorkflowsServerPluginSetup['management'] =>
({
getWorkflow: jest.fn().mockResolvedValue(null),
runWorkflow: jest.fn().mockResolvedValue('exec-1'),
} as unknown as WorkflowsServerPluginSetup['management']);

describe('DispatcherService integration tests', () => {
let esServer: TestElasticsearchUtils;
let kibanaServer: TestKibanaUtils;
Expand All @@ -343,6 +350,7 @@ describe('DispatcherService integration tests', () => {
let mockLoggerService: LoggerServiceContract;
let rulesSoService: RulesSavedObjectServiceContract;
let npSoService: NotificationPolicySavedObjectServiceContract;
let mockWfm: WorkflowsServerPluginSetup['management'];

beforeAll(async () => {
const servers = await setupTestServers();
Expand Down Expand Up @@ -380,6 +388,15 @@ describe('DispatcherService integration tests', () => {

queryService = new QueryService(esClient, mockLoggerService);
storageService = new StorageService(esClient, mockLoggerService);
mockWfm = createMockWorkflowsManagement();

jest.spyOn(npSoService, 'bulkGetDecryptedByIds').mockImplementation(async () => {
const { saved_objects: allPolicies } = await npSoService.find({
page: 1,
perPage: 1000,
});
return allPolicies.map((doc) => ({ id: doc.id, attributes: doc.attributes }));
});

const pipeline = new DispatcherPipeline(mockLoggerService, [
new FetchEpisodesStep(queryService),
Expand All @@ -390,7 +407,7 @@ describe('DispatcherService integration tests', () => {
new EvaluateMatchersStep(),
new BuildGroupsStep(),
new ApplyThrottlingStep(queryService, mockLoggerService),
new DispatchStep(mockLoggerService),
new DispatchStep(mockLoggerService, mockWfm),
new StoreActionsStep(storageService),
]);
dispatcherService = new DispatcherService(pipeline);
Expand Down
Loading
Loading