5
5
* 2.0.
6
6
*/
7
7
import expect from '@kbn/expect' ;
8
- import type { Ecs , EcsHost } from '@elastic/ecs' ;
8
+ import { Ecs , EcsHost } from '@elastic/ecs' ;
9
9
import type {
10
10
IndexRequest ,
11
11
SearchHit ,
@@ -28,7 +28,7 @@ export default function (providerContext: FtrProviderContext) {
28
28
const dataView = dataViewRouteHelpersFactory ( supertest ) ;
29
29
const utils = EntityStoreUtils ( providerContext . getService ) ;
30
30
31
- describe ( 'Host transform logic' , ( ) => {
31
+ describe ( '@ess Host transform logic' , ( ) => {
32
32
describe ( 'Entity Store is not installed by default' , ( ) => {
33
33
it ( "Should return 200 and status 'not_installed'" , async ( ) => {
34
34
const { body } = await supertest . get ( '/api/entity_store/status' ) . expect ( 200 ) ;
@@ -46,7 +46,14 @@ export default function (providerContext: FtrProviderContext) {
46
46
await dataView . create ( 'security-solution' ) ;
47
47
// Create a test index matching transform's pattern to store test documents
48
48
await es . indices . createDataStream ( { name : DATASTREAM_NAME } ) ;
49
+ } ) ;
50
+
51
+ after ( async ( ) => {
52
+ await es . indices . deleteDataStream ( { name : DATASTREAM_NAME } ) ;
53
+ await dataView . delete ( 'security-solution' ) ;
54
+ } ) ;
49
55
56
+ beforeEach ( async ( ) => {
50
57
// Now we can enable the Entity Store...
51
58
const response = await supertest
52
59
. post ( '/api/entity_store/enable' )
@@ -66,11 +73,6 @@ export default function (providerContext: FtrProviderContext) {
66
73
} ) ;
67
74
} ) ;
68
75
69
- after ( async ( ) => {
70
- await es . indices . deleteDataStream ( { name : DATASTREAM_NAME } ) ;
71
- await dataView . delete ( 'security-solution' ) ;
72
- } ) ;
73
-
74
76
afterEach ( async ( ) => {
75
77
await utils . cleanEngines ( ) ;
76
78
} ) ;
@@ -96,37 +98,9 @@ export default function (providerContext: FtrProviderContext) {
96
98
97
99
it ( 'Should successfully trigger a host transform' , async ( ) => {
98
100
const HOST_NAME : string = 'host-transform-test-ip' ;
99
- const IPs : string [ ] = [ '1.1.1.1' , '2.2.2.2' ] ;
100
- const { count, transforms } = await es . transform . getTransformStats ( {
101
- transform_id : HOST_TRANSFORM_ID ,
102
- } ) ;
103
- expect ( count ) . to . eql ( 1 ) ;
104
- let transform = transforms [ 0 ] ;
105
- expect ( transform . id ) . to . eql ( HOST_TRANSFORM_ID ) ;
106
- const triggerCount : number = transform . stats . trigger_count ;
107
- const docsProcessed : number = transform . stats . documents_processed ;
108
-
109
- // Create two documents with the same host.name, different IPs
110
- for ( const ip of IPs ) {
111
- const { result } = await es . index ( buildHostTransformDocument ( HOST_NAME , { ip } ) ) ;
112
- expect ( result ) . to . eql ( 'created' ) ;
113
- }
101
+ const testDocs : EcsHost [ ] = [ { ip : '1.1.1.1' } , { ip : '2.2.2.2' } ] ;
114
102
115
- // Trigger the transform manually
116
- const { acknowledged } = await es . transform . scheduleNowTransform ( {
117
- transform_id : HOST_TRANSFORM_ID ,
118
- } ) ;
119
- expect ( acknowledged ) . to . be ( true ) ;
120
-
121
- await retry . waitForWithTimeout ( 'Transform to run again' , TIMEOUT_MS , async ( ) => {
122
- const response = await es . transform . getTransformStats ( {
123
- transform_id : HOST_TRANSFORM_ID ,
124
- } ) ;
125
- transform = response . transforms [ 0 ] ;
126
- expect ( transform . stats . trigger_count ) . to . greaterThan ( triggerCount ) ;
127
- expect ( transform . stats . documents_processed ) . to . greaterThan ( docsProcessed ) ;
128
- return true ;
129
- } ) ;
103
+ await createDocumentsAndTriggerTransform ( providerContext , HOST_NAME , testDocs ) ;
130
104
131
105
await retry . waitForWithTimeout (
132
106
'Document to be processed and transformed' ,
@@ -145,7 +119,75 @@ export default function (providerContext: FtrProviderContext) {
145
119
const hit = result . hits . hits [ 0 ] as SearchHit < Ecs > ;
146
120
expect ( hit . _source ) . ok ( ) ;
147
121
expect ( hit . _source ?. host ?. name ) . to . eql ( HOST_NAME ) ;
148
- expect ( hit . _source ?. host ?. ip ) . to . eql ( IPs ) ;
122
+ expect ( hit . _source ?. host ?. ip ) . to . eql ( [ '1.1.1.1' , '2.2.2.2' ] ) ;
123
+
124
+ return true ;
125
+ }
126
+ ) ;
127
+ } ) ;
128
+
129
+ it ( 'Should successfully collect all expected fields' , async ( ) => {
130
+ const HOST_NAME : string = 'host-transform-test-all-fields' ;
131
+ const testDocs : EcsHost [ ] = [
132
+ {
133
+ domain : 'example.com' ,
134
+ hostname : 'example.com' ,
135
+ id : 'alpha' ,
136
+ os : {
137
+ name : 'ubuntu' ,
138
+ type : 'linux' ,
139
+ } ,
140
+ mac : 'abc' ,
141
+ architecture : 'x86-64' ,
142
+ type : 'machineA' ,
143
+ ip : '1.1.1.1' ,
144
+ } ,
145
+ {
146
+ domain : 'example.com' ,
147
+ hostname : 'sub.example.com' ,
148
+ id : 'beta' ,
149
+ os : {
150
+ name : 'macos' ,
151
+ type : 'darwin' ,
152
+ } ,
153
+ mac : 'def' ,
154
+ architecture : 'arm64' ,
155
+ type : 'machineB' ,
156
+ ip : '2.2.2.2' ,
157
+ } ,
158
+ ] ;
159
+
160
+ await createDocumentsAndTriggerTransform ( providerContext , HOST_NAME , testDocs ) ;
161
+
162
+ await retry . waitForWithTimeout (
163
+ 'Document to be processed and transformed' ,
164
+ TIMEOUT_MS ,
165
+ async ( ) => {
166
+ const result = await es . search ( {
167
+ index : INDEX_NAME ,
168
+ query : {
169
+ term : {
170
+ 'host.name' : HOST_NAME ,
171
+ } ,
172
+ } ,
173
+ } ) ;
174
+ const total = result . hits . total as SearchTotalHits ;
175
+ expect ( total . value ) . to . eql ( 1 ) ;
176
+ expect ( result . hits . hits [ 0 ] . _source ) . ok ( ) ;
177
+ const source = result . hits . hits [ 0 ] . _source as HostTransformResult ;
178
+ expect ( source . host ) . ok ( ) ;
179
+ const hit = source . host as HostTransformResultHost ;
180
+
181
+ expect ( hit . name ) . to . eql ( HOST_NAME ) ;
182
+ expectFieldToEqualValues ( hit . domain , [ 'example.com' ] ) ;
183
+ expectFieldToEqualValues ( hit . hostname , [ 'example.com' , 'sub.example.com' ] ) ;
184
+ expectFieldToEqualValues ( hit . id , [ 'alpha' , 'beta' ] ) ;
185
+ expectFieldToEqualValues ( hit . os ?. name , [ 'ubuntu' , 'macos' ] ) ;
186
+ expectFieldToEqualValues ( hit . os ?. type , [ 'linux' , 'darwin' ] ) ;
187
+ expectFieldToEqualValues ( hit . ip , [ '1.1.1.1' , '2.2.2.2' ] ) ;
188
+ expectFieldToEqualValues ( hit . mac , [ 'abc' , 'def' ] ) ;
189
+ expectFieldToEqualValues ( hit . type , [ 'machineA' , 'machineB' ] ) ;
190
+ expectFieldToEqualValues ( hit . architecture , [ 'x86-64' , 'arm64' ] ) ;
149
191
150
192
return true ;
151
193
}
@@ -155,6 +197,20 @@ export default function (providerContext: FtrProviderContext) {
155
197
} ) ;
156
198
}
157
199
200
+ function expectFieldToEqualValues ( field : string [ ] | undefined , values : string [ ] | undefined ) {
201
+ if ( values === undefined ) {
202
+ expect ( field ) . to . not . be ( undefined ) ;
203
+ }
204
+ expect ( field ) . to . ok ( ) ;
205
+ const definedValues = values as string [ ] ;
206
+ expect ( ( field as string [ ] ) . length ) . to . eql ( definedValues . length ) ;
207
+ const sortedField : string [ ] = ( field as string [ ] ) . sort ( ( a , b ) => ( a > b ? 1 : - 1 ) ) ;
208
+ const sortedValues : string [ ] = definedValues . sort ( ( a , b ) => ( a > b ? 1 : - 1 ) ) ;
209
+ for ( let i = 0 ; i < sortedField . length ; i ++ ) {
210
+ expect ( sortedField [ i ] ) . to . eql ( sortedValues [ i ] ) ;
211
+ }
212
+ }
213
+
158
214
function buildHostTransformDocument ( name : string , host : EcsHost ) : IndexRequest {
159
215
host . name = name ;
160
216
// Get timestamp without the millisecond part
@@ -168,3 +224,61 @@ function buildHostTransformDocument(name: string, host: EcsHost): IndexRequest {
168
224
} ;
169
225
return document ;
170
226
}
227
+
228
+ async function createDocumentsAndTriggerTransform (
229
+ providerContext : FtrProviderContext ,
230
+ documentName : string ,
231
+ docs : EcsHost [ ]
232
+ ) : Promise < void > {
233
+ const retry = providerContext . getService ( 'retry' ) ;
234
+ const es = providerContext . getService ( 'es' ) ;
235
+
236
+ const { count, transforms } = await es . transform . getTransformStats ( {
237
+ transform_id : HOST_TRANSFORM_ID ,
238
+ } ) ;
239
+ expect ( count ) . to . eql ( 1 ) ;
240
+ let transform = transforms [ 0 ] ;
241
+ expect ( transform . id ) . to . eql ( HOST_TRANSFORM_ID ) ;
242
+ const triggerCount : number = transform . stats . trigger_count ;
243
+ const docsProcessed : number = transform . stats . documents_processed ;
244
+
245
+ for ( let i = 0 ; i < docs . length ; i ++ ) {
246
+ const { result } = await es . index ( buildHostTransformDocument ( documentName , docs [ i ] ) ) ;
247
+ expect ( result ) . to . eql ( 'created' ) ;
248
+ }
249
+
250
+ // Trigger the transform manually
251
+ const { acknowledged } = await es . transform . scheduleNowTransform ( {
252
+ transform_id : HOST_TRANSFORM_ID ,
253
+ } ) ;
254
+ expect ( acknowledged ) . to . be ( true ) ;
255
+
256
+ await retry . waitForWithTimeout ( 'Transform to run again' , TIMEOUT_MS , async ( ) => {
257
+ const response = await es . transform . getTransformStats ( {
258
+ transform_id : HOST_TRANSFORM_ID ,
259
+ } ) ;
260
+ transform = response . transforms [ 0 ] ;
261
+ expect ( transform . stats . trigger_count ) . to . greaterThan ( triggerCount ) ;
262
+ expect ( transform . stats . documents_processed ) . to . greaterThan ( docsProcessed ) ;
263
+ return true ;
264
+ } ) ;
265
+ }
266
+
267
+ interface HostTransformResult {
268
+ host : HostTransformResultHost ;
269
+ }
270
+
271
+ interface HostTransformResultHost {
272
+ name : string ;
273
+ domain : string [ ] | undefined ;
274
+ hostname : string [ ] | undefined ;
275
+ id : string [ ] | undefined ;
276
+ os : {
277
+ name : string [ ] | undefined ;
278
+ type : string [ ] | undefined ;
279
+ } ;
280
+ mac : string [ ] | undefined ;
281
+ architecture : string [ ] | undefined ;
282
+ type : string [ ] | undefined ;
283
+ ip : string [ ] | undefined ;
284
+ }
0 commit comments