Back to home page

EIC code displayed by LXR

 
 

    


Warning, /firebird/packages/firebird-ng/api/src/lib/services/url.service.spec.ts is written in an unsupported language. File is not indexed.

0001 /**
0002  * UrlService against the real ConfigService: the backend keys the config
0003  * page writes (`server.useApi`, `server.url`) are the keys this service
0004  * reads, through every config source.
0005  */
0006 import { TestBed } from '@angular/core/testing';
0007 import { provideZonelessChangeDetection, signal, type WritableSignal } from '@angular/core';
0008 import { ConfigService, ServerConfigService, URL_ALIASES } from '@dexvis/app-features';
0009 import { UrlService } from './url.service';
0010 import { BACKEND_URL_CONFIG, BACKEND_USE_API_CONFIG } from '../config-keys';
0011 import { defaultFirebirdConfig, type ServerConfig } from './server-config';
0012 
0013 describe('UrlService', () => {
0014   let serverConfig: WritableSignal<ServerConfig>;
0015   let config: ConfigService;
0016 
0017   /** Creates the service; config sources set before this call act as pending layers. */
0018   function createService(): UrlService {
0019     return TestBed.inject(UrlService);
0020   }
0021 
0022   /** What the config page's controls do: a runtime write of the declared key. */
0023   function useBackend(url?: string): void {
0024     config.declare(BACKEND_USE_API_CONFIG).value = true;
0025     if (url !== undefined) config.declare(BACKEND_URL_CONFIG).value = url;
0026   }
0027 
0028   beforeEach(() => {
0029     localStorage.clear();
0030     serverConfig = signal<ServerConfig>({ ...defaultFirebirdConfig });
0031     TestBed.configureTestingModule({
0032       providers: [
0033         provideZonelessChangeDetection(),
0034         // The real ConfigService (root); the server config is a plain signal holder
0035         { provide: ServerConfigService, useValue: { configSignal: serverConfig } },
0036         // Aliases are DI-contributed (withUrlAlias feature)
0037         { provide: URL_ALIASES, useValue: { prefix: 'exp://', base: 'https://data.example.org/artifacts/' }, multi: true },
0038       ],
0039     });
0040     config = TestBed.inject(ConfigService);
0041   });
0042 
0043   describe('backend selection', () => {
0044     it('has no backend on a static deployment by default', () => {
0045       const service = createService();
0046       expect(service.isBackendAvailable()).toBe(false);
0047       expect(service.serverAddress()).toBe('');
0048     });
0049 
0050     it('reads the keys the config page writes, with the page default URL', () => {
0051       const service = createService();
0052       useBackend();
0053       expect(service.isBackendAvailable()).toBe(true);
0054       expect(service.serverAddress()).toBe('http://localhost:5454');
0055       // One canonical property per key: the page and the service share it
0056       expect(config.getConfig('server.useApi')).toBe(config.declare(BACKEND_USE_API_CONFIG));
0057     });
0058 
0059     it('follows a changed backend URL and drops a trailing slash', () => {
0060       const service = createService();
0061       useBackend('http://customserver:1234/');
0062       expect(service.serverAddress()).toBe('http://customserver:1234');
0063     });
0064 
0065     it('takes the backend from a deep link (?config.server.useApi=true) before anything declared it', () => {
0066       config.applySessionValue('server.useApi', 'true');
0067       config.applySessionValue('server.url', 'http://linked:5454');
0068       const service = createService();
0069       expect(service.isBackendAvailable()).toBe(true);
0070       expect(service.serverAddress()).toBe('http://linked:5454');
0071       expect(localStorage.getItem('server.useApi')).toBeNull();
0072     });
0073 
0074     it('keeps a saved choice across sessions', () => {
0075       localStorage.setItem('server.useApi', 'true');
0076       localStorage.setItem('server.url', 'http://saved:5454');
0077       const service = createService();
0078       expect(service.serverAddress()).toBe('http://saved:5454');
0079     });
0080 
0081     it('prefers the serving pyrobird over a configured backend, once its config arrives', () => {
0082       const service = createService();
0083       useBackend('http://other:1234');
0084       serverConfig.set({ ...defaultFirebirdConfig, servedByPyrobird: true, apiAvailable: true, apiBaseUrl: 'http://served:5454' });
0085       expect(service.isBackendAvailable()).toBe(true);
0086       expect(service.serverAddress()).toBe('http://served:5454');
0087     });
0088 
0089     it('ignores a blob: backend URL', () => {
0090       localStorage.setItem('server.useApi', 'true');
0091       localStorage.setItem('server.url', 'blob:http://localhost/5b1c');
0092       const service = createService();
0093       expect(service.serverAddress()).toBe(BACKEND_URL_CONFIG.default);
0094     });
0095   });
0096 
0097   describe('resolveDownloadUrl', () => {
0098     it('uses the download endpoint for a plain path when a backend is configured (Case 1.2)', () => {
0099       const service = createService();
0100       useBackend();
0101       expect(service.resolveDownloadUrl('/path/to/file.root'))
0102         .toBe('http://localhost:5454/api/v1/download?f=%2Fpath%2Fto%2Ffile.root');
0103     });
0104 
0105     it('resolves local:// through the download endpoint (Case 1.2)', () => {
0106       const service = createService();
0107       useBackend();
0108       expect(service.resolveDownloadUrl('local://subdir/file.root'))
0109         .toBe('http://localhost:5454/api/v1/download?f=subdir%2Ffile.root');
0110     });
0111 
0112     it('passes a local:// path through unresolved when no backend is available', () => {
0113       const service = createService();
0114       expect(service.resolveDownloadUrl('local://file.root')).toBe('file.root');
0115     });
0116 
0117     it('encodes the input URL in the download endpoint', () => {
0118       const service = createService();
0119       useBackend();
0120       expect(service.resolveDownloadUrl('/path with spaces/file.root'))
0121         .toBe('http://localhost:5454/api/v1/download?f=%2Fpath%20with%20spaces%2Ffile.root');
0122     });
0123 
0124     it('leaves absolute URLs as they are (Case 1.1)', () => {
0125       const service = createService();
0126       useBackend();
0127       expect(service.resolveDownloadUrl('https://example.com/file.root')).toBe('https://example.com/file.root');
0128     });
0129   });
0130 
0131   describe('resolveConvertUrl', () => {
0132     it('builds the convert URL when a backend is configured', () => {
0133       const service = createService();
0134       useBackend();
0135       const inputUrl = 'https://example.com/file.root';
0136       expect(service.resolveConvertUrl(inputUrl, 'edm4eic', 'all'))
0137         .toBe(`http://localhost:5454/api/v1/convert/edm4eic/all?f=${encodeURIComponent(inputUrl)}`);
0138     });
0139 
0140     it('resolves asset:// before converting', () => {
0141       const service = createService();
0142       useBackend();
0143       const baseUri = document.baseURI.endsWith('/') ? document.baseURI : `${document.baseURI}/`;
0144       const resolvedAssetUrl = `${baseUri}assets/data/sample.dat`;
0145       expect(service.resolveConvertUrl('asset://data/sample.dat', 'edm4eic', 'all'))
0146         .toBe(`http://localhost:5454/api/v1/convert/edm4eic/all?f=${encodeURIComponent(resolvedAssetUrl)}`);
0147     });
0148 
0149     it('resolves local:// before converting', () => {
0150       const service = createService();
0151       useBackend();
0152       expect(service.resolveConvertUrl('local://sim.edm4eic.root', 'edm4eic', '0'))
0153         .toBe('http://localhost:5454/api/v1/convert/edm4eic/0?f=sim.edm4eic.root');
0154     });
0155 
0156     it('resolves a pack alias before converting', () => {
0157       const service = createService();
0158       useBackend();
0159       const resolvedAliasUrl = 'https://data.example.org/artifacts/some/path/file.root';
0160       expect(service.resolveConvertUrl('exp://some/path/file.root', 'edm4eic', 'all'))
0161         .toBe(`http://localhost:5454/api/v1/convert/edm4eic/all?f=${encodeURIComponent(resolvedAliasUrl)}`);
0162     });
0163 
0164     it('adds the collection groups', () => {
0165       const service = createService();
0166       useBackend();
0167       expect(service.resolveConvertUrl('local://a.root', 'auto', '0', ['tracks', 'mc_particles']))
0168         .toBe('http://localhost:5454/api/v1/convert/auto/0?f=a.root&collections=tracks%2Cmc_particles');
0169     });
0170 
0171     it('throws when no backend is available', () => {
0172       const service = createService();
0173       expect(() => service.resolveConvertUrl('local://a.root', 'auto', '0')).toThrowError(/Backend is not available/);
0174     });
0175   });
0176 });