import { ObjectType , STATE } from 'apache-ignite-client' ; import { Test , TestingModule } from '@nestjs/testing' ; import { ConfigService } from '@fc/config' ; import { LoggerService } from '@fc/logger' ; import { ApacheIgniteService } from './apache-ignite.service' ; import { ApacheIgniteInvalidSocketException } from './exceptions' ; describe ( 'ApacheIgniteService' , ( ) => { let service ; const configServiceMock = { get : jest . fn ( ) , } ; const loggerServiceMock = { debug : jest . fn ( ) , setContext : jest . fn ( ) , } ; const igniteClientMock = { _socket : { _socket : { _socket : { setKeepAlive : jest . fn ( ) , } , } , } , connect : jest . fn ( ) , disconnect : jest . fn ( ) , getCache : jest . fn ( ) , setKeyType : jest . fn ( ) , setValueType : jest . fn ( ) , } ; const cacheObjectMock = { foo : 'bar' , } ; beforeEach ( async ( ) => { jest . clearAllMocks ( ) ; jest . resetAllMocks ( ) ; jest . restoreAllMocks ( ) ; igniteClientMock . getCache . mockReturnValueOnce ( igniteClientMock ) ; igniteClientMock . setKeyType . mockReturnValueOnce ( igniteClientMock ) ; igniteClientMock . setValueType . mockReturnValueOnce ( cacheObjectMock ) ; ApacheIgniteService [ 'IgniteClientProxy' ] = jest . fn ( ) . mockReturnValueOnce ( igniteClientMock ) ; ApacheIgniteService [ 'IgniteClientConfigurationProxy' ] = jest . fn ( ) ; const module = await Test . createTestingModule ( { providers : [ ApacheIgniteService , ConfigService , LoggerService ] , } ) . overrideProvider ( ConfigService ) . useValue ( configServiceMock ) . overrideProvider ( LoggerService ) . useValue ( loggerServiceMock ) . compile ( ) ; service = module . get < ApacheIgniteService > ( ApacheIgniteService ) ; } ) ; it ( 'should be defined' , ( ) => { expect ( service ) . toBeDefined ( ) ; } ) ; it ( 'should set the logger context with the service name' , ( ) => { expect ( loggerServiceMock . setContext ) . toHaveBeenCalledTimes ( 1 ) ; expect ( loggerServiceMock . setContext ) . toHaveBeenCalledWith ( 'ApacheIgniteService' ) ; } ) ; describe ( 'onModuleInit' , ( ) => { const configMock = { endpoint : 'apache-ignite:1644' , socketKeepAlive : { enable : true , initialDelay : 150000 , } , } ; beforeEach ( ( ) => { configServiceMock . get . mockReturnValueOnce ( configMock ) ; } ) ; it ( 'should retrieve the ignite endpoint from the config' , async ( ) => { await service [ 'onModuleInit' ] ( ) ; expect ( configServiceMock . get ) . toHaveBeenCalledTimes ( 1 ) ; expect ( configServiceMock . get ) . toHaveBeenCalledWith ( 'ApacheIgnite' ) ; } ) ; it ( 'should initialize the client ignite with an event callback' , async ( ) => { await service [ 'onModuleInit' ] ( ) ; expect ( ApacheIgniteService [ 'IgniteClientProxy' ] ) . toHaveBeenCalledTimes ( 1 ) ; expect ( ApacheIgniteService [ 'IgniteClientProxy' ] ) . toHaveBeenCalledWith ( expect . any ( Function ) ) ; } ) ; it ( 'should initialize the client ignite configuration with the endpoint' , async ( ) => { await service [ 'onModuleInit' ] ( ) ; expect ( ApacheIgniteService [ 'IgniteClientConfigurationProxy' ] ) . toHaveBeenCalledTimes ( 1 ) ; expect ( ApacheIgniteService [ 'IgniteClientConfigurationProxy' ] ) . toHaveBeenCalledWith ( configMock . endpoint ) ; } ) ; it ( 'should connect to ignite with the configuration built' , async ( ) => { ApacheIgniteService [ 'IgniteClientConfigurationProxy' ] . mockReturnValueOnce ( configMock ) ; await service [ 'onModuleInit' ] ( ) ; expect ( igniteClientMock . connect ) . toHaveBeenCalledTimes ( 1 ) ; expect ( igniteClientMock . connect ) . toHaveBeenCalledWith ( configMock ) ; } ) ; it ( 'should set the keep alive of the socket' , async ( ) => { service [ 'setSocketKeepAlive' ] = jest . fn ( ) ; ApacheIgniteService [ 'IgniteClientConfigurationProxy' ] . mockReturnValueOnce ( configMock ) ; await service [ 'onModuleInit' ] ( ) ; expect ( service [ 'setSocketKeepAlive' ] ) . toHaveBeenCalledTimes ( 1 ) ; expect ( service [ 'setSocketKeepAlive' ] ) . toHaveBeenCalledWith ( configMock . socketKeepAlive . enable , configMock . socketKeepAlive . initialDelay ) ; } ) ; } ) ; describe ( 'onModuleDestroy' , ( ) => { it ( 'should disconnect the ignite client on module destroy' , async ( ) => { await service [ 'onModuleDestroy' ] ( ) ; expect ( igniteClientMock . disconnect ) . toHaveBeenCalledTimes ( 1 ) ; expect ( igniteClientMock . disconnect ) . toHaveBeenCalledWith ( ) ; } ) ; } ) ; describe ( 'getCache' , ( ) => { const cache = 'mycache' ; it ( 'should call igniteClient.getCache with the cache name' , async ( ) => { await service [ 'getCache' ] ( cache ) ; expect ( igniteClientMock . getCache ) . toHaveBeenCalledTimes ( 1 ) ; expect ( igniteClientMock . getCache ) . toHaveBeenCalledWith ( cache ) ; } ) ; it ( 'should call the cache setKeyType with the primitive string type if no key type is provided' , async ( ) => { await service [ 'getCache' ] ( cache ) ; expect ( igniteClientMock . setKeyType ) . toHaveBeenCalledTimes ( 1 ) ; expect ( igniteClientMock . setKeyType ) . toHaveBeenCalledWith ( ObjectType . PRIMITIVE_TYPE . STRING ) ; } ) ; it ( 'should call the cache setValueType with the primitive string type if no value type is provided' , async ( ) => { await service [ 'getCache' ] ( cache ) ; expect ( igniteClientMock . setValueType ) . toHaveBeenCalledTimes ( 1 ) ; expect ( igniteClientMock . setValueType ) . toHaveBeenCalledWith ( ObjectType . PRIMITIVE_TYPE . STRING ) ; } ) ; it ( 'should call the cache setKeyType with the primitive string type if no key type is provided' , async ( ) => { await service [ 'getCache' ] ( cache , ObjectType . PRIMITIVE_TYPE . INTEGER ) ; expect ( igniteClientMock . setKeyType ) . toHaveBeenCalledTimes ( 1 ) ; expect ( igniteClientMock . setKeyType ) . toHaveBeenCalledWith ( ObjectType . PRIMITIVE_TYPE . INTEGER ) ; } ) ; it ( 'should call the cache setValueType with the primitive string type if no value type is provided' , async ( ) => { await service [ 'getCache' ] ( cache , ObjectType . PRIMITIVE_TYPE . STRING , ObjectType . PRIMITIVE_TYPE . INTEGER ) ; expect ( igniteClientMock . setValueType ) . toHaveBeenCalledTimes ( 1 ) ; expect ( igniteClientMock . setValueType ) . toHaveBeenCalledWith ( ObjectType . PRIMITIVE_TYPE . INTEGER ) ; } ) ; it ( 'should return the cache' , async ( ) => { const result = await service [ 'getCache' ] ( cache , ObjectType . PRIMITIVE_TYPE . STRING , ObjectType . PRIMITIVE_TYPE . INTEGER ) ; expect ( result ) . toStrictEqual ( cacheObjectMock ) ; } ) ; } ) ; describe ( 'onStateChanged' , ( ) => { it ( 'should log when a connection event occurs' , ( ) => { service [ 'onStateChanged' ] ( STATE . CONNECTED ) ; expect ( loggerServiceMock . debug ) . toHaveBeenCalledTimes ( 1 ) ; expect ( loggerServiceMock . debug ) . toHaveBeenCalledWith ( 'Apache ignite client is connected' ) ; } ) ; it ( 'should log when a disconnection event occurs' , ( ) => { service [ 'onStateChanged' ] ( STATE . DISCONNECTED ) ; expect ( loggerServiceMock . debug ) . toHaveBeenCalledTimes ( 1 ) ; expect ( loggerServiceMock . debug ) . toHaveBeenCalledWith ( 'Apache ignite client disconnected' ) ; } ) ; it ( 'should log the reason when a disconnection event occurs if provided' , ( ) => { const reason = 'Why do we always need a reason ?' ; service [ 'onStateChanged' ] ( STATE . DISCONNECTED , reason ) ; expect ( loggerServiceMock . debug ) . toHaveBeenCalledTimes ( 2 ) ; expect ( loggerServiceMock . debug ) . toHaveBeenCalledWith ( 'Apache ignite client disconnected' ) ; expect ( loggerServiceMock . debug ) . toHaveBeenCalledWith ( reason ) ; } ) ; it ( 'should not log anything if the state is not CONNECTED or DISCONNECTED' , ( ) => { const STATE_UNKNOWWN_MOCK = 42 ; service [ 'onStateChanged' ] ( STATE_UNKNOWWN_MOCK ) ; expect ( loggerServiceMock . debug ) . toHaveBeenCalledTimes ( 0 ) ; } ) ; } ) ; describe ( 'setSocketKeepAlive' , ( ) => { it ( 'should set the keep alive of the low level NodeJs socket instance' , ( ) => { const socketKeepAliveConfig = { enable : true , initialDelay : 150000 , } ; service [ 'setSocketKeepAlive' ] ( socketKeepAliveConfig . enable , socketKeepAliveConfig . initialDelay ) ; expect ( igniteClientMock . _socket . _socket . _socket . setKeepAlive ) . toHaveBeenCalledTimes ( 1 ) ; expect ( igniteClientMock . _socket . _socket . _socket . setKeepAlive ) . toHaveBeenCalledWith ( socketKeepAliveConfig . enable , socketKeepAliveConfig . initialDelay ) ; } ) ; it ( 'should throw an ApacheIgniteInvalidSocketException id there is no socket' , ( ) => { service [ 'igniteClient' ] = { _socket : undefined } ; const socketKeepAliveConfig = { enable : true , initialDelay : 150000 , } ; expect ( ( ) => service [ 'setSocketKeepAlive' ] ( socketKeepAliveConfig . enable , socketKeepAliveConfig . initialDelay ) ) . toThrow ( ApacheIgniteInvalidSocketException ) ; } ) ; } ) ; } ) ;