66 */
77
88import { Subject } from 'rxjs' ;
9- import { elasticsearchServiceMock , savedObjectsServiceMock } from '@kbn/core/server/mocks' ;
9+ import { elasticsearchServiceMock } from '@kbn/core/server/mocks' ;
1010import { createPackagePolicyServiceMock } from '@kbn/fleet-plugin/server/mocks' ;
1111import type { PackagePolicyClient } from '@kbn/fleet-plugin/server' ;
12- import type { PackagePolicy , UpdatePackagePolicy } from '@kbn/fleet-plugin/common' ;
12+ import {
13+ PACKAGE_POLICY_SAVED_OBJECT_TYPE ,
14+ type PackagePolicy ,
15+ type UpdatePackagePolicy ,
16+ } from '@kbn/fleet-plugin/common' ;
1317import { createPackagePolicyMock } from '@kbn/fleet-plugin/common/mocks' ;
1418import { policyFactory } from '../../../../common/endpoint/models/policy_config' ;
1519import type { PolicyConfig } from '../../../../common/endpoint/types' ;
1620import { TelemetryConfigWatcher } from './telemetry_watch' ;
1721import { TelemetryConfigProvider } from '../../../../common/telemetry_config/telemetry_config_provider' ;
1822import { createMockEndpointAppContextService } from '../../mocks' ;
23+ import type { MockedLogger } from '@kbn/logging-mocks' ;
24+ import { loggerMock } from '@kbn/logging-mocks' ;
25+ import type { NewPackagePolicyWithId } from '@kbn/fleet-plugin/server/services/package_policy' ;
1926
2027const MockPackagePolicyWithEndpointPolicy = (
2128 cb ?: ( p : PolicyConfig ) => PolicyConfig
2229) : PackagePolicy => {
2330 const packagePolicy = createPackagePolicyMock ( ) ;
24- if ( ! cb ) {
25- // eslint-disable-next-line no-param-reassign
26- cb = ( p ) => p ;
27- }
28- const policyConfig = cb ( policyFactory ( ) ) ;
31+
32+ const policyConfig = cb ?.( policyFactory ( ) ) ?? policyFactory ( ) ;
33+
2934 packagePolicy . inputs [ 0 ] . config = { policy : { value : policyConfig } } ;
3035
3136 return packagePolicy ;
3237} ;
3338
3439describe ( 'Telemetry config watcher' , ( ) => {
35- const soStartMock = savedObjectsServiceMock . createStartContract ( ) ;
3640 const esStartMock = elasticsearchServiceMock . createStart ( ) ;
37- let packagePolicySvcMock : jest . Mocked < PackagePolicyClient > ;
41+
42+ let mockedLogger : MockedLogger ;
43+ let packagePolicyServiceMock : jest . Mocked < PackagePolicyClient > ;
3844 let telemetryWatcher : TelemetryConfigWatcher ;
3945
4046 const preparePackagePolicyMock = ( {
4147 isGlobalTelemetryEnabled,
4248 } : {
4349 isGlobalTelemetryEnabled : boolean ;
4450 } ) => {
45- packagePolicySvcMock . list . mockResolvedValueOnce ( {
51+ packagePolicyServiceMock . list . mockResolvedValueOnce ( {
4652 items : [
4753 MockPackagePolicyWithEndpointPolicy ( ( pc : PolicyConfig ) : PolicyConfig => {
4854 pc . global_telemetry_enabled = isGlobalTelemetryEnabled ;
@@ -56,13 +62,21 @@ describe('Telemetry config watcher', () => {
5662 } ;
5763
5864 beforeEach ( ( ) => {
59- packagePolicySvcMock = createPackagePolicyServiceMock ( ) ;
65+ packagePolicyServiceMock = createPackagePolicyServiceMock ( ) ;
66+ packagePolicyServiceMock . bulkUpdate . mockResolvedValue ( {
67+ updatedPolicies : [ ] ,
68+ failedPolicies : [ ] ,
69+ } ) ;
70+
71+ mockedLogger = loggerMock . create ( ) ;
72+ const endpointAppContextServiceMock = createMockEndpointAppContextService ( ) ;
73+ endpointAppContextServiceMock . createLogger = jest . fn ( ) . mockReturnValue ( mockedLogger ) ;
6074
6175 telemetryWatcher = new TelemetryConfigWatcher (
62- packagePolicySvcMock ,
63- soStartMock ,
76+ packagePolicyServiceMock ,
6477 esStartMock ,
65- createMockEndpointAppContextService ( )
78+ endpointAppContextServiceMock ,
79+ { immediateRetry : true }
6680 ) ;
6781 } ) ;
6882
@@ -90,7 +104,7 @@ describe('Telemetry config watcher', () => {
90104 const TOTAL = 247 ;
91105
92106 // set up the mocked package policy service to return and do what we want
93- packagePolicySvcMock . list
107+ packagePolicyServiceMock . list
94108 . mockResolvedValueOnce ( {
95109 items : Array . from ( { length : 100 } , ( ) => MockPackagePolicyWithEndpointPolicy ( ) ) ,
96110 total : TOTAL ,
@@ -112,12 +126,101 @@ describe('Telemetry config watcher', () => {
112126
113127 await telemetryWatcher . watch ( true ) ; // manual trigger
114128
115- expect ( packagePolicySvcMock . list ) . toBeCalledTimes ( 3 ) ;
129+ expect ( packagePolicyServiceMock . list ) . toBeCalledTimes ( 3 ) ;
116130
117131 // Assert: on the first call to packagePolicy.list, we asked for page 1
118- expect ( packagePolicySvcMock . list . mock . calls [ 0 ] [ 1 ] . page ) . toBe ( 1 ) ;
119- expect ( packagePolicySvcMock . list . mock . calls [ 1 ] [ 1 ] . page ) . toBe ( 2 ) ; // second call, asked for page 2
120- expect ( packagePolicySvcMock . list . mock . calls [ 2 ] [ 1 ] . page ) . toBe ( 3 ) ; // etc
132+ expect ( packagePolicyServiceMock . list . mock . calls [ 0 ] [ 1 ] . page ) . toBe ( 1 ) ;
133+ expect ( packagePolicyServiceMock . list . mock . calls [ 1 ] [ 1 ] . page ) . toBe ( 2 ) ; // second call, asked for page 2
134+ expect ( packagePolicyServiceMock . list . mock . calls [ 2 ] [ 1 ] . page ) . toBe ( 3 ) ; // etc
135+
136+ expect ( mockedLogger . warn ) . not . toHaveBeenCalled ( ) ;
137+ expect ( mockedLogger . error ) . not . toHaveBeenCalled ( ) ;
138+ } ) ;
139+
140+ describe ( 'error handling' , ( ) => {
141+ it ( 'retries fetching package policies' , async ( ) => {
142+ packagePolicyServiceMock . list . mockRejectedValueOnce ( new Error ( ) ) ;
143+
144+ packagePolicyServiceMock . list . mockResolvedValueOnce ( {
145+ items : Array . from ( { length : 6 } , ( ) => MockPackagePolicyWithEndpointPolicy ( ) ) ,
146+ total : 6 ,
147+ page : 1 ,
148+ perPage : 100 ,
149+ } ) ;
150+
151+ await telemetryWatcher . watch ( true ) ;
152+
153+ expect ( packagePolicyServiceMock . list ) . toBeCalledTimes ( 2 ) ;
154+ const expectedParams = {
155+ page : 1 ,
156+ perPage : 100 ,
157+ kuery : `${ PACKAGE_POLICY_SAVED_OBJECT_TYPE } .package.name: endpoint` ,
158+ } ;
159+ expect ( packagePolicyServiceMock . list . mock . calls [ 0 ] [ 1 ] ) . toStrictEqual ( expectedParams ) ;
160+ expect ( packagePolicyServiceMock . list . mock . calls [ 1 ] [ 1 ] ) . toStrictEqual ( expectedParams ) ;
161+
162+ expect ( mockedLogger . warn ) . not . toHaveBeenCalled ( ) ;
163+ expect ( mockedLogger . error ) . not . toHaveBeenCalled ( ) ;
164+ } ) ;
165+
166+ it ( 'retries fetching package policies maximum 5 times' , async ( ) => {
167+ packagePolicyServiceMock . list . mockRejectedValue ( new Error ( ) ) ;
168+
169+ await telemetryWatcher . watch ( true ) ;
170+
171+ expect ( packagePolicyServiceMock . list ) . toBeCalledTimes ( 5 ) ;
172+ expect ( mockedLogger . warn ) . toHaveBeenCalledTimes ( 1 ) ;
173+ expect ( mockedLogger . error ) . not . toHaveBeenCalled ( ) ;
174+ } ) ;
175+
176+ it ( 'retries bulk updating package policies' , async ( ) => {
177+ preparePackagePolicyMock ( { isGlobalTelemetryEnabled : true } ) ;
178+ packagePolicyServiceMock . bulkUpdate . mockRejectedValueOnce ( new Error ( ) ) ;
179+
180+ await telemetryWatcher . watch ( false ) ;
181+
182+ expect ( packagePolicyServiceMock . bulkUpdate ) . toHaveBeenCalledTimes ( 2 ) ;
183+ expect ( mockedLogger . warn ) . not . toHaveBeenCalled ( ) ;
184+ expect ( mockedLogger . error ) . not . toHaveBeenCalled ( ) ;
185+ } ) ;
186+
187+ it ( 'retries bulk updating package policies maximum 5 times' , async ( ) => {
188+ preparePackagePolicyMock ( { isGlobalTelemetryEnabled : true } ) ;
189+ packagePolicyServiceMock . bulkUpdate . mockRejectedValue ( new Error ( ) ) ;
190+
191+ await telemetryWatcher . watch ( false ) ;
192+
193+ expect ( packagePolicyServiceMock . bulkUpdate ) . toHaveBeenCalledTimes ( 5 ) ;
194+ expect ( mockedLogger . warn ) . toHaveBeenCalledTimes ( 1 ) ;
195+ expect ( mockedLogger . error ) . not . toHaveBeenCalled ( ) ;
196+ } ) ;
197+
198+ it ( 'logs the ids of package policies that are failed to be updated' , async ( ) => {
199+ preparePackagePolicyMock ( { isGlobalTelemetryEnabled : true } ) ;
200+ packagePolicyServiceMock . bulkUpdate . mockResolvedValueOnce ( {
201+ updatedPolicies : [ ] ,
202+ failedPolicies : [
203+ {
204+ error : new Error ( 'error message 1' ) ,
205+ packagePolicy : { id : 'policy-id-1' } as NewPackagePolicyWithId ,
206+ } ,
207+ {
208+ error : new Error ( 'error message 2' ) ,
209+ packagePolicy : { id : 'policy-id-2' } as NewPackagePolicyWithId ,
210+ } ,
211+ ] ,
212+ } ) ;
213+
214+ await telemetryWatcher . watch ( false ) ;
215+
216+ expect ( packagePolicyServiceMock . bulkUpdate ) . toHaveBeenCalledTimes ( 1 ) ;
217+ expect ( mockedLogger . warn ) . toHaveBeenCalledTimes ( 1 ) ;
218+ expect ( mockedLogger . error ) . not . toHaveBeenCalled ( ) ;
219+
220+ const logMessage = mockedLogger . warn . mock . calls [ 0 ] [ 0 ] as string ;
221+ expect ( logMessage ) . toMatch ( / - i d : p o l i c y - i d - 1 , e r r o r : .+ e r r o r m e s s a g e 1 / ) ;
222+ expect ( logMessage ) . toMatch ( / - i d : p o l i c y - i d - 2 , e r r o r : .+ e r r o r m e s s a g e 2 / ) ;
223+ } ) ;
121224 } ) ;
122225
123226 it . each ( [ true , false ] ) (
@@ -127,17 +230,18 @@ describe('Telemetry config watcher', () => {
127230
128231 await telemetryWatcher . watch ( value ) ;
129232
130- expect ( packagePolicySvcMock . bulkUpdate ) . not . toHaveBeenCalled ( ) ;
233+ expect ( packagePolicyServiceMock . bulkUpdate ) . not . toHaveBeenCalled ( ) ;
131234 }
132235 ) ;
133236
134- it . each ( [ true , false ] ) ( 'updates `global_telemetry_config ` field to %s' , async ( value ) => {
237+ it . each ( [ true , false ] ) ( 'updates `global_telemetry_enabled ` field to %s' , async ( value ) => {
135238 preparePackagePolicyMock ( { isGlobalTelemetryEnabled : ! value } ) ;
136239
137240 await telemetryWatcher . watch ( value ) ;
138241
139- expect ( packagePolicySvcMock . bulkUpdate ) . toHaveBeenCalled ( ) ;
140- const policyUpdates : UpdatePackagePolicy [ ] = packagePolicySvcMock . bulkUpdate . mock . calls [ 0 ] [ 2 ] ;
242+ expect ( packagePolicyServiceMock . bulkUpdate ) . toHaveBeenCalled ( ) ;
243+ const policyUpdates : UpdatePackagePolicy [ ] =
244+ packagePolicyServiceMock . bulkUpdate . mock . calls [ 0 ] [ 2 ] ;
141245 expect ( policyUpdates . length ) . toBe ( 1 ) ;
142246 const updatedPolicyConfigs : PolicyConfig = policyUpdates [ 0 ] . inputs [ 0 ] . config ?. policy . value ;
143247 expect ( updatedPolicyConfigs . global_telemetry_enabled ) . toBe ( value ) ;
0 commit comments