import moment from 'moment' ; import { configServiceMock } from '../config/mocks' ; import { mockOpsCollector } from './metrics_service.test.mocks' ; import { MetricsService } from './metrics_service' ; import { mockCoreContext } from '../core_context.mock' ; import { httpServiceMock } from '../http/http_service.mock' ; import { take } from 'rxjs/operators' ; const testInterval = 100 ; const dummyMetrics = { metricA : 'value' , metricB : 'otherValue' } ; describe ( 'MetricsService' , ( ) => { const httpMock = httpServiceMock . createInternalSetupContract ( ) ; let metricsService ; beforeEach ( ( ) => { jest . useFakeTimers ( ) ; const configService = configServiceMock . create ( { atPath : { interval : moment . duration ( testInterval ) } , } ) ; const coreContext = mockCoreContext . create ( { configService } ) ; metricsService = new MetricsService ( coreContext ) ; } ) ; afterEach ( ( ) => { jest . clearAllMocks ( ) ; jest . clearAllTimers ( ) ; } ) ; describe ( '#start' , ( ) => { it ( 'invokes setInterval with the configured interval' , async ( ) => { await metricsService . setup ( { http : httpMock } ) ; await metricsService . start ( ) ; expect ( setInterval ) . toHaveBeenCalledTimes ( 1 ) ; expect ( setInterval ) . toHaveBeenCalledWith ( expect . any ( Function ) , testInterval ) ; } ) ; it ( 'collects the metrics at every interval' , async ( ) => { mockOpsCollector . collect . mockResolvedValue ( dummyMetrics ) ; await metricsService . setup ( { http : httpMock } ) ; await metricsService . start ( ) ; expect ( mockOpsCollector . collect ) . toHaveBeenCalledTimes ( 1 ) ; jest . advanceTimersByTime ( testInterval ) ; expect ( mockOpsCollector . collect ) . toHaveBeenCalledTimes ( 2 ) ; jest . advanceTimersByTime ( testInterval ) ; expect ( mockOpsCollector . collect ) . toHaveBeenCalledTimes ( 3 ) ; } ) ; it ( 'resets the collector after each collection' , async ( ) => { mockOpsCollector . collect . mockResolvedValue ( dummyMetrics ) ; await metricsService . setup ( { http : httpMock } ) ; const { getOpsMetrics$ } = await metricsService . start ( ) ; const nextEmission = async ( ) => { jest . advanceTimersByTime ( testInterval ) ; await getOpsMetrics$ ( ) . pipe ( take ( 1 ) ) . toPromise ( ) ; await new Promise ( ( resolve ) => process . nextTick ( resolve ) ) ; } ; expect ( mockOpsCollector . collect ) . toHaveBeenCalledTimes ( 1 ) ; expect ( mockOpsCollector . reset ) . toHaveBeenCalledTimes ( 1 ) ; await nextEmission ( ) ; expect ( mockOpsCollector . collect ) . toHaveBeenCalledTimes ( 2 ) ; expect ( mockOpsCollector . reset ) . toHaveBeenCalledTimes ( 2 ) ; await nextEmission ( ) ; expect ( mockOpsCollector . collect ) . toHaveBeenCalledTimes ( 3 ) ; expect ( mockOpsCollector . reset ) . toHaveBeenCalledTimes ( 3 ) ; } ) ; it ( 'throws when called before setup' , async ( ) => { await expect ( metricsService . start ( ) ) . rejects . toThrowErrorMatchingInlineSnapshot ( `"#setup() needs to be run first"` ) ; } ) ; it ( 'emits the last value on each getOpsMetrics$ call' , async ( ) => { const firstMetrics = { metric : 'first' } ; const secondMetrics = { metric : 'second' } ; mockOpsCollector . collect . mockResolvedValueOnce ( firstMetrics ) . mockResolvedValueOnce ( secondMetrics ) ; await metricsService . setup ( { http : httpMock } ) ; const { getOpsMetrics$ } = await metricsService . start ( ) ; const nextEmission = async ( ) => { jest . advanceTimersByTime ( testInterval ) ; const emission = await getOpsMetrics$ ( ) . pipe ( take ( 1 ) ) . toPromise ( ) ; await new Promise ( ( resolve ) => process . nextTick ( resolve ) ) ; return emission ; } ; expect ( await nextEmission ( ) ) . toEqual ( { metric : 'first' } ) ; expect ( await nextEmission ( ) ) . toEqual ( { metric : 'second' } ) ; } ) ; } ) ; describe ( '#stop' , ( ) => { it ( 'stops the metrics interval' , async ( ) => { await metricsService . setup ( { http : httpMock } ) ; const { getOpsMetrics$ } = await metricsService . start ( ) ; expect ( mockOpsCollector . collect ) . toHaveBeenCalledTimes ( 1 ) ; jest . advanceTimersByTime ( testInterval ) ; expect ( mockOpsCollector . collect ) . toHaveBeenCalledTimes ( 2 ) ; await metricsService . stop ( ) ; jest . advanceTimersByTime ( 10 * testInterval ) ; expect ( mockOpsCollector . collect ) . toHaveBeenCalledTimes ( 2 ) ; getOpsMetrics$ ( ) . subscribe ( { complete : ( ) => { } } ) ; } ) ; it ( 'completes the metrics observable' , async ( ) => { await metricsService . setup ( { http : httpMock } ) ; const { getOpsMetrics$ } = await metricsService . start ( ) ; let completed = false ; getOpsMetrics$ ( ) . subscribe ( { complete : ( ) => { completed = true ; } , } ) ; await metricsService . stop ( ) ; expect ( completed ) . toEqual ( true ) ; } ) ; } ) ; } ) ;