| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- /**
- * Contract test for IUniversalHttpClient.registerPlatform()
- *
- * This test validates the platform registration functionality of the Universal HTTP Client
- * according to the contract specification. Tests MUST FAIL until implementation is complete.
- */
- import { describe, test, expect, beforeEach, jest } from '@jest/globals'
- // Import types that will be implemented
- import type { IUniversalHttpClient, IPlatformAdapter, HealthStatus } from '@/types/httpClientCore'
- describe('IUniversalHttpClient.registerPlatform() Contract', () => {
- let httpClient: IUniversalHttpClient
- beforeEach(() => {
- // This will fail until IUniversalHttpClient is implemented
- // eslint-disable-next-line @typescript-eslint/no-require-imports
- const { HttpClientCore } = require('@/core/http-client/HttpClientCore')
- httpClient = new HttpClientCore()
- })
- describe('Platform Registration', () => {
- test('should register a new platform adapter successfully', () => {
- const mockAdapter: IPlatformAdapter = {
- platform: 'test-platform',
- baseUrl: 'https://api.test-platform.com',
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- checkHealth: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(true)
- }
- expect(() => {
- httpClient.registerPlatform('test-platform', mockAdapter)
- }).not.toThrow()
- // Verify the platform is registered by checking if it's available for requests
- expect(httpClient.isPlatformRegistered?.('test-platform')).toBe(true)
- })
- test('should register multiple platform adapters', () => {
- const adapters = [
- {
- platform: 'platform-1',
- baseUrl: 'https://api.platform-1.com',
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- checkHealth: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(true)
- },
- {
- platform: 'platform-2',
- baseUrl: 'https://api.platform-2.com',
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- checkHealth: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(true)
- }
- ]
- adapters.forEach(adapter => {
- expect(() => {
- httpClient.registerPlatform(adapter.platform, adapter as IPlatformAdapter)
- }).not.toThrow()
- })
- // Verify both platforms are registered
- expect(httpClient.isPlatformRegistered?.('platform-1')).toBe(true)
- expect(httpClient.isPlatformRegistered?.('platform-2')).toBe(true)
- })
- test('should replace existing platform adapter when re-registered', () => {
- const originalAdapter: IPlatformAdapter = {
- platform: 'replaceable-platform',
- baseUrl: 'https://api.original.com',
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- checkHealth: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(true)
- }
- const newAdapter: IPlatformAdapter = {
- platform: 'replaceable-platform',
- baseUrl: 'https://api.new.com',
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- checkHealth: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(true)
- }
- // Register original adapter
- httpClient.registerPlatform('replaceable-platform', originalAdapter)
- expect(httpClient.isPlatformRegistered?.('replaceable-platform')).toBe(true)
- // Register new adapter with same platform name
- httpClient.registerPlatform('replaceable-platform', newAdapter)
- expect(httpClient.isPlatformRegistered?.('replaceable-platform')).toBe(true)
- // Verify the new adapter is being used (baseUrl should be from new adapter)
- const registeredAdapter = httpClient.getPlatformAdapter?.('replaceable-platform')
- expect(registeredAdapter?.baseUrl).toBe('https://api.new.com')
- })
- test('should validate adapter configuration before registration', () => {
- const invalidAdapter: IPlatformAdapter = {
- platform: 'invalid-platform',
- baseUrl: 'https://api.invalid.com',
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- checkHealth: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(false) // Invalid configuration
- }
- expect(() => {
- httpClient.registerPlatform('invalid-platform', invalidAdapter)
- }).toThrow('Invalid platform configuration')
- })
- })
- describe('Platform Access', () => {
- test('should provide access to registered platform adapters', () => {
- const adapter: IPlatformAdapter = {
- platform: 'accessible-platform',
- baseUrl: 'https://api.accessible.com',
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- checkHealth: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(true)
- }
- httpClient.registerPlatform('accessible-platform', adapter)
- const retrievedAdapter = httpClient.getPlatformAdapter?.('accessible-platform')
- expect(retrievedAdapter).toBeDefined()
- expect(retrievedAdapter?.platform).toBe('accessible-platform')
- expect(retrievedAdapter?.baseUrl).toBe('https://api.accessible.com')
- })
- test('should return list of registered platforms', () => {
- const platforms = ['platform-a', 'platform-b', 'platform-c']
- platforms.forEach(platform => {
- const adapter: IPlatformAdapter = {
- platform,
- baseUrl: `https://api.${platform}.com`,
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- checkHealth: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(true)
- }
- httpClient.registerPlatform(platform, adapter)
- })
- const registeredPlatforms = httpClient.getRegisteredPlatforms?.()
- expect(registeredPlatforms).toEqual(expect.arrayContaining(platforms))
- expect(registeredPlatforms).toHaveLength(platforms.length)
- })
- test('should check if specific platform is registered', () => {
- const adapter: IPlatformAdapter = {
- platform: 'checkable-platform',
- baseUrl: 'https://api.checkable.com',
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- checkHealth: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(true)
- }
- expect(httpClient.isPlatformRegistered?.('checkable-platform')).toBe(false)
- httpClient.registerPlatform('checkable-platform', adapter)
- expect(httpClient.isPlatformRegistered?.('checkable-platform')).toBe(true)
- expect(httpClient.isPlatformRegistered?.('non-existent-platform')).toBe(false)
- })
- })
- describe('Platform Management', () => {
- test('should support unregistering platforms', async () => {
- const adapter: IPlatformAdapter = {
- platform: 'removable-platform',
- baseUrl: 'https://api.removable.com',
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- checkHealth: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(true)
- }
- httpClient.registerPlatform('removable-platform', adapter)
- expect(httpClient.isPlatformRegistered?.('removable-platform')).toBe(true)
- const result = await httpClient.unregisterPlatform?.('removable-platform')
- expect(result?.success).toBe(true)
- expect(httpClient.isPlatformRegistered?.('removable-platform')).toBe(false)
- })
- test('should support updating platform configuration', async () => {
- const adapter: IPlatformAdapter = {
- platform: 'updatable-platform',
- baseUrl: 'https://api.updatable.com',
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- checkHealth: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(true)
- }
- httpClient.registerPlatform('updatable-platform', adapter)
- const updatedConfig = {
- baseUrl: 'https://api.updated.com',
- timeout: { connect: 10000, read: 60000, write: 30000 }
- }
- const result = await httpClient.updatePlatformConfig?.('updatable-platform', updatedConfig)
- expect(result?.success).toBe(true)
- const retrievedAdapter = httpClient.getPlatformAdapter?.('updatable-platform')
- expect(retrievedAdapter?.baseUrl).toBe('https://api.updated.com')
- })
- test('should provide platform configuration information', () => {
- const adapter: IPlatformAdapter = {
- platform: 'info-platform',
- baseUrl: 'https://api.info.com',
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- checkHealth: jest.fn(),
- getConfig: jest.fn().mockReturnValue({
- platform: 'info-platform',
- baseUrl: 'https://api.info.com',
- authConfig: { type: 'signature' },
- timeouts: { connect: 5000, read: 30000, write: 15000 }
- }),
- validateConfig: jest.fn().mockReturnValue(true)
- }
- httpClient.registerPlatform('info-platform', adapter)
- const platformInfo = httpClient.getPlatformInfo?.('info-platform')
- expect(platformInfo).toBeDefined()
- expect(platformInfo?.platform).toBe('info-platform')
- expect(platformInfo?.baseUrl).toBe('https://api.info.com')
- })
- })
- describe('Health and Status', () => {
- test('should provide overall client health status', async () => {
- const adapters = [
- {
- platform: 'healthy-platform-1',
- baseUrl: 'https://api.healthy1.com',
- checkHealth: jest.fn().mockResolvedValue({ status: 'healthy', responseTime: 50 })
- },
- {
- platform: 'healthy-platform-2',
- baseUrl: 'https://api.healthy2.com',
- checkHealth: jest.fn().mockResolvedValue({ status: 'healthy', responseTime: 75 })
- }
- ]
- adapters.forEach(adapter => {
- const fullAdapter: IPlatformAdapter = {
- ...adapter,
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(true)
- }
- httpClient.registerPlatform(adapter.platform, fullAdapter)
- })
- const health: HealthStatus = await httpClient.getHealth()
- expect(health).toBeDefined()
- expect(health.status).toBe('healthy')
- expect(health.platforms).toBeDefined()
- expect(Object.keys(health.platforms)).toHaveLength(2)
- expect(health.platforms['healthy-platform-1']?.status).toBe('healthy')
- expect(health.platforms['healthy-platform-2']?.status).toBe('healthy')
- })
- test('should detect unhealthy platforms', async () => {
- const adapters = [
- {
- platform: 'healthy-platform',
- baseUrl: 'https://api.healthy.com',
- checkHealth: jest.fn().mockResolvedValue({ status: 'healthy', responseTime: 50 })
- },
- {
- platform: 'unhealthy-platform',
- baseUrl: 'https://api.unhealthy.com',
- checkHealth: jest.fn().mockRejectedValue(new Error('Platform unavailable'))
- }
- ]
- adapters.forEach(adapter => {
- const fullAdapter: IPlatformAdapter = {
- ...adapter,
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(true)
- }
- httpClient.registerPlatform(adapter.platform, fullAdapter)
- })
- const health: HealthStatus = await httpClient.getHealth()
- expect(health).toBeDefined()
- expect(health.status).toBe('degraded') // Overall status should be degraded
- expect(health.platforms['healthy-platform']?.status).toBe('healthy')
- expect(health.platforms['unhealthy-platform']?.status).toBe('unhealthy')
- })
- })
- describe('Error Handling', () => {
- test('should reject registration with empty platform name', () => {
- const adapter: IPlatformAdapter = {
- platform: '',
- baseUrl: 'https://api.test.com',
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- checkHealth: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(true)
- }
- expect(() => {
- httpClient.registerPlatform('', adapter)
- }).toThrow('Platform name cannot be empty')
- })
- test('should reject registration with mismatched platform name', () => {
- const adapter: IPlatformAdapter = {
- platform: 'adapter-platform',
- baseUrl: 'https://api.test.com',
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- checkHealth: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(true)
- }
- expect(() => {
- httpClient.registerPlatform('different-platform', adapter)
- }).toThrow('Platform name mismatch')
- })
- test('should reject registration with null or undefined adapter', () => {
- expect(() => {
- httpClient.registerPlatform('test-platform', null as any)
- }).toThrow('Platform adapter cannot be null or undefined')
- expect(() => {
- httpClient.registerPlatform('test-platform', undefined as any)
- }).toThrow('Platform adapter cannot be null or undefined')
- })
- })
- describe('Resource Cleanup', () => {
- test('should properly clean up resources when client is closed', async () => {
- const adapter: IPlatformAdapter = {
- platform: 'cleanup-platform',
- baseUrl: 'https://api.cleanup.com',
- request: jest.fn(),
- prepareRequest: jest.fn(),
- setProxyConfig: jest.fn(),
- getProxyStatus: jest.fn(),
- processResponse: jest.fn(),
- checkHealth: jest.fn(),
- getConfig: jest.fn(),
- validateConfig: jest.fn().mockReturnValue(true)
- }
- httpClient.registerPlatform('cleanup-platform', adapter)
- expect(httpClient.isPlatformRegistered?.('cleanup-platform')).toBe(true)
- await httpClient.close()
- // After closing, platform should still be registered but client should be inactive
- expect(httpClient.isPlatformRegistered?.('cleanup-platform')).toBe(true)
- // Attempting to make requests should fail
- await expect(httpClient.request({
- platform: 'cleanup-platform',
- accountId: 'test',
- method: 'GET',
- url: '/test'
- })).rejects.toThrow('Client is closed')
- })
- })
- })
|