import assert from 'node:assert/strict' import { readdir, readFile } from 'node:fs/promises' import path from 'node:path' import test from 'node:test' import { fileURLToPath } from 'node:url' import { ACCESS_MODES, CONTEXTS, IDEMPOTENCY, SYNCHRONOUS_CLIENTS, USER_ENTRIES, graphEdges, longestSimplePaths, stronglyConnectedComponents } from './synchronous-dependency-baseline.mjs' const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') // Discover all active Maven modules; unreviewed clients must fail equality checks. const serviceModules = [...(await readFile(path.join(root, 'pom.xml'), 'utf8')) .matchAll(/([^<]+)<\/module>/g)].map(match => match[1]) const canonicalSource = new Map(serviceModules.map(name => [name, `${name}${name.endsWith('-service') || name.startsWith('common-') || name === 'gateway' || name === 'platform-bom' ? '' : '-service'}`])) const expectedOnlineEdges = [ 'auth-service->iam-service', 'file-service->iam-service', 'file-service->integration-service', 'finance-service->file-service', 'finance-service->firstleg-service', 'finance-service->iam-service', 'finance-service->warehouse-service', 'firstleg-service->file-service', 'firstleg-service->iam-service', 'firstleg-service->lastleg-service', 'firstleg-service->order-service', 'firstleg-service->print-service', 'firstleg-service->warehouse-service', 'iam-service->auth-service', 'iam-service->warehouse-service', 'lastleg-service->file-service', 'lastleg-service->finance-service', 'lastleg-service->firstleg-service', 'lastleg-service->iam-service', 'lastleg-service->order-service', 'lastleg-service->print-service', 'lastleg-service->warehouse-overseas-service', 'lastleg-service->warehouse-service', 'order-service->file-service', 'order-service->finance-service', 'order-service->firstleg-service', 'order-service->iam-service', 'order-service->lastleg-service', 'order-service->warehouse-service', 'warehouse-overseas-service->print-service', 'warehouse-overseas-service->warehouse-service' ] const expectedBackgroundEdges = [ 'integration-service->lastleg-service', 'lastleg-service->integration-service', 'file-service->finance-service', 'file-service->firstleg-service', 'file-service->iam-service', 'file-service->lastleg-service', 'file-service->order-service', 'file-service->warehouse-service', 'finance-service->lastleg-service', 'finance-service->firstleg-service', 'firstleg-service->lastleg-service', 'firstleg-service->finance-service', 'firstleg-service->integration-service', 'firstleg-service->order-service', 'iam-service->firstleg-service', 'lastleg-service->finance-service', 'lastleg-service->firstleg-service', 'order-service->firstleg-service' ].sort() const rawHttpPattern = /\b(?:RestClient|WebClient|HttpClient)\b/ async function javaFiles(directory) { const result = [] async function visit(current) { for (const entry of await readdir(current, { withFileTypes: true })) { const target = path.join(current, entry.name) if (entry.isDirectory()) await visit(target) else if (entry.isFile() && entry.name.endsWith('.java')) result.push(target) } } if (await readdir(directory).catch(error => { if (error.code === 'ENOENT') return null; throw error })) await visit(directory) return result } async function discoverFeignEdges() { const clients = [] for (const module of serviceModules) { const sourceRoot = path.join(root, module, 'src', 'main', 'java') for (const file of await javaFiles(sourceRoot)) { const source = await readFile(file, 'utf8') if (!source.includes('@FeignClient')) continue const annotation = source.match(/@FeignClient\(([\s\S]*?)\)\s*(?:public\s+)?interface/) const target = annotation?.[1].match(/name\s*=\s*"([^"]+)"/)?.[1] assert.ok(target, `cannot resolve Feign target from ${path.relative(root, file)}`) clients.push({ path: path.relative(root, file).replaceAll('\\', '/'), source: canonicalSource.get(module), target }) } } return clients.sort((left, right) => left.path.localeCompare(right.path)) } test('all Feign clients have reviewed context, access and idempotency metadata', async () => { const reviewed = SYNCHRONOUS_CLIENTS.filter(client => client.transport === 'FEIGN') .map(({ path, source, target }) => ({ path, source, target })) .sort((left, right) => left.path.localeCompare(right.path)) assert.equal(reviewed.length, 82) assert.deepEqual(await discoverFeignEdges(), reviewed) }) test('all raw HTTP transports have reviewed context, access and idempotency metadata', async () => { const discovered = [] for (const module of serviceModules) { for (const file of await javaFiles(path.join(root, module, 'src', 'main', 'java'))) { const source = await readFile(file, 'utf8') if (!rawHttpPattern.test(source)) continue if (!/(?:private|final)\s+(?:[\w.]+\.)?(?:RestClient|WebClient|HttpClient)\b|HttpClient\s+client\s*=/.test(source)) continue discovered.push(path.relative(root, file).replaceAll('\\', '/')) } } const reviewed = SYNCHRONOUS_CLIENTS.filter(client => client.transport === 'HTTP') .map(client => client.path).sort() assert.equal(reviewed.length, 32) assert.deepEqual(discovered.sort(), reviewed) }) test('every reviewed synchronous client has a complete and exclusive executable classification', () => { assert.equal(new Set(SYNCHRONOUS_CLIENTS.map(client => client.id)).size, SYNCHRONOUS_CLIENTS.length) for (const client of SYNCHRONOUS_CLIENTS) { assert.ok(client.path && client.source && client.target && client.note, `${client.id} metadata is incomplete`) assert.ok(client.contexts.length > 0, `${client.id} has no execution context`) assert.equal(new Set(client.contexts).size, client.contexts.length, `${client.id} repeats a context`) for (const context of client.contexts) assert.ok(CONTEXTS.includes(context), `${client.id} has invalid context ${context}`) assert.ok(ACCESS_MODES.includes(client.access), `${client.id} has invalid access ${client.access}`) assert.ok(IDEMPOTENCY.includes(client.idempotency), `${client.id} has invalid idempotency ${client.idempotency}`) } }) test('owned business photos use bounded File transport with no automatic upload retry', async () => { const file = 'lastleg-service/src/main/java/com/baiyue/lastleg/fleet/ownedbusiness/gateway/HttpOwnedBusinessFileGateway.java' const reviewed = SYNCHRONOUS_CLIENTS.find(client => client.path === file) assert.equal(reviewed?.target, 'file-service') assert.equal(reviewed?.access, 'READ_WRITE') assert.equal(reviewed?.idempotency, 'MIXED') assert.deepEqual(reviewed?.contexts, ['REQUEST']) const source = await readFile(path.join(root, file), 'utf8') assert.match(source, /factory\.build\(builder,baseUrl,properties\.getCustomerVisitFile\(\)\)/) assert.match(source, /\/internal\/file\/v1\/business-files\/0\/\{type\}\/\{dispatch\}/) assert.doesNotMatch(source, /RetryTemplate|Retryer|@Retryable|\.retry\(|fallbackFactory|fallback\s*=/i) }) test('IAM customer dimension Feign is reachable only from the background relay', async () => { const references = [] for (const file of await javaFiles(path.join(root, 'iam', 'src', 'main', 'java'))) { const source = await readFile(file, 'utf8') if (source.includes('CustomerDimensionRuleClient')) { references.push(path.relative(root, file).replaceAll('\\', '/')) } } assert.deepEqual(references.sort(), [ 'iam/src/main/java/com/baiyue/iam/client/CustomerDimensionRuleClient.java', 'iam/src/main/java/com/baiyue/iam/service/CustomerDimensionInitializationRelay.java' ]) }) test('all six Lastleg RestClient gateways use explicit bounded transports', async () => { const clients = new Map([ ['lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/gateway/HttpUnloadPhotoFileGateway.java', 'getUnloadPhotoFile'], ['lastleg-service/src/main/java/com/baiyue/lastleg/relabel/pda/gateway/HttpRelabelPhotoFileGateway.java', 'getRelabelPhotoFile'], ['lastleg-service/src/main/java/com/baiyue/lastleg/customervisit/gateway/HttpCustomerVisitFileGateway.java', 'getCustomerVisitFile'], ['lastleg-service/src/main/java/com/baiyue/lastleg/procurement/gateway/HttpProcurementFileGateway.java', 'getProcurementFile'], ['lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/gateway/HttpWarehouseResourceGateway.java', 'getWarehouseResource'], ['lastleg-service/src/main/java/com/baiyue/lastleg/palletops/gateway/HttpPalletPhysicalGateway.java', 'getPalletPhysical'] ]) for (const [file, propertyAccessor] of clients) { const source = await readFile(path.join(root, file), 'utf8') assert.match(source, /restClientFactory\.build\(restClientBuilder, baseUrl,/) assert.match(source, new RegExp(`restClientProperties\\.${propertyAccessor}\\(\\)`)) assert.doesNotMatch(source, /RetryTemplate|Retryer|@Retryable|\.retry\(|fallbackFactory|fallback\s*=/i) } const factory = await readFile(path.join(root, 'lastleg-service/src/main/java/com/baiyue/lastleg/config/LastlegRestClientFactory.java'), 'utf8') assert.match(factory, /connectTimeout\(timeouts\.getConnectTimeout\(\)\)/) assert.match(factory, /setReadTimeout\(timeouts\.getReadTimeout\(\)\)/) assert.doesNotMatch(factory, /RetryTemplate|Retryer|@Retryable|\.retry\(|fallbackFactory|fallback\s*=/i) for (const configFile of [ 'lastleg-service/src/main/resources/application.yml', 'config/nacos/test/lastleg-service.yml' ]) { const source = await readFile(path.join(root, configFile), 'utf8') for (const key of ['unload-photo-file', 'relabel-photo-file', 'customer-visit-file', 'procurement-file', 'warehouse-resource', 'pallet-physical']) { assert.match(source, new RegExp( `${key}:\\s*\\n\\s+connect-timeout:\\s*\\$\\{[^}]+:[1-9][0-9]*(?:ms|s)\\}` + `\\s*\\n\\s+read-timeout:\\s*\\$\\{[^}]+:[1-9][0-9]*(?:ms|s)\\}`)) } } }) test('REQUEST, BACKGROUND and full graphs remain separate executable baselines', () => { assert.deepEqual(graphEdges('REQUEST'), expectedOnlineEdges) assert.deepEqual(graphEdges('BACKGROUND'), expectedBackgroundEdges) assert.deepEqual(graphEdges('INFRASTRUCTURE'), [ 'common-audit->audit-service', 'common-security->auth-service', 'gateway->auth-service' ]) assert.deepEqual(stronglyConnectedComponents(graphEdges('REQUEST')), [ ['auth-service', 'iam-service'], ['finance-service', 'firstleg-service', 'lastleg-service', 'order-service'] ]) assert.deepEqual(stronglyConnectedComponents(graphEdges('BACKGROUND')), [[ 'finance-service', 'firstleg-service', 'integration-service', 'lastleg-service', 'order-service' ]]) assert.deepEqual(stronglyConnectedComponents(graphEdges('ALL')), [[ 'auth-service', 'file-service', 'finance-service', 'firstleg-service', 'iam-service', 'integration-service', 'lastleg-service', 'order-service' ]]) }) test('unified authority checks remain infrastructure edges and direct events remain background', () => { assert.ok(graphEdges('INFRASTRUCTURE').includes('gateway->auth-service')) assert.ok(graphEdges('INFRASTRUCTURE').includes('common-security->auth-service')) assert.ok(graphEdges('BACKGROUND').includes('lastleg-service->finance-service')) const financeReads = SYNCHRONOUS_CLIENTS.filter(client => client.source === 'lastleg-service' && client.target === 'finance-service' && client.contexts.includes('REQUEST')) assert.deepEqual(financeReads.map(client => [client.path, client.access, client.idempotency]) .sort((left, right) => left[0].localeCompare(right[0])), [[ 'lastleg-service/src/main/java/com/baiyue/lastleg/client/FinanceFeeCoverageClient.java', 'READ', 'SAFE_READ' ], [ 'lastleg-service/src/main/java/com/baiyue/lastleg/fleet/maintenance/VehicleCareFinanceClient.java', 'READ', 'SAFE_READ' ], [ 'lastleg-service/src/main/java/com/baiyue/lastleg/fleet/reporting/TripFinanceClient.java', 'READ', 'SAFE_READ' ]]) assert.ok(!SYNCHRONOUS_CLIENTS.some(client => ['event-bridge-service','gateway-overseas'].includes(client.source) || ['event-bridge-service','gateway-overseas'].includes(client.target))) }) test('Order, Firstleg, Finance and Lastleg form the reviewed REQUEST SCC', () => { const requestClients = SYNCHRONOUS_CLIENTS.filter(client => client.contexts.includes('REQUEST')) const orderToFirstleg = requestClients.filter(client => client.source === 'order-service' && client.target === 'firstleg-service') const firstlegToOrder = requestClients.filter(client => client.source === 'firstleg-service' && client.target === 'order-service') assert.deepEqual(orderToFirstleg.map(client => client.path).sort(), [ 'order/src/main/java/com/baiyue/order/client/FirstlegColoadGroupClient.java', 'order/src/main/java/com/baiyue/order/client/FirstlegInboundClient.java', 'order/src/main/java/com/baiyue/order/client/FirstlegPricingClient.java', 'order/src/main/java/com/baiyue/order/client/FirstlegUnifiedOrderClient.java', 'order/src/main/java/com/baiyue/order/client/LegacyImportPricingClient.java', 'order/src/main/java/com/baiyue/order/client/MerchantPricingCatalogClient.java' ]) assert.deepEqual(firstlegToOrder.map(client => client.path).sort(), [ 'firstleg/src/main/java/com/baiyue/firstleg/client/OrderCargoClient.java', 'firstleg/src/main/java/com/baiyue/firstleg/client/OrderFulfillmentSplitClient.java', 'firstleg/src/main/java/com/baiyue/firstleg/client/PendingReviewOrderClient.java', 'firstleg/src/main/java/com/baiyue/firstleg/client/PrintableOrderInboundClient.java' ]) assert.ok(stronglyConnectedComponents(graphEdges('REQUEST')).some(component => component.includes('firstleg-service') && component.includes('order-service') && component.includes('finance-service'))) }) test('known user entries expose every longest simple REQUEST path over the two-hop budget', () => { const summary = Object.fromEntries(USER_ENTRIES.map(entry => { const paths = longestSimplePaths(entry.service) return [entry.service, { hops: paths[0].length - 1, paths: paths.map(path => path.join('->')) }] })) assert.deepEqual(summary, { 'auth-service': { hops: 2, paths: [ 'auth-service->iam-service->warehouse-service' ] }, 'iam-service': { hops: 1, paths: [ 'iam-service->auth-service', 'iam-service->warehouse-service' ] }, 'order-service': { hops: 6, paths: [ 'order-service->finance-service->firstleg-service->lastleg-service->file-service->iam-service->auth-service', 'order-service->finance-service->firstleg-service->lastleg-service->file-service->iam-service->warehouse-service', 'order-service->firstleg-service->lastleg-service->finance-service->file-service->iam-service->auth-service', 'order-service->firstleg-service->lastleg-service->finance-service->file-service->iam-service->warehouse-service', 'order-service->lastleg-service->finance-service->firstleg-service->file-service->iam-service->auth-service', 'order-service->lastleg-service->finance-service->firstleg-service->file-service->iam-service->warehouse-service' ] }, 'firstleg-service': { hops: 6, paths: [ 'firstleg-service->lastleg-service->order-service->finance-service->file-service->iam-service->auth-service', 'firstleg-service->lastleg-service->order-service->finance-service->file-service->iam-service->warehouse-service', 'firstleg-service->order-service->lastleg-service->finance-service->file-service->iam-service->auth-service', 'firstleg-service->order-service->lastleg-service->finance-service->file-service->iam-service->warehouse-service' ] }, 'finance-service': { hops: 6, paths: [ 'finance-service->firstleg-service->lastleg-service->order-service->file-service->iam-service->auth-service', 'finance-service->firstleg-service->lastleg-service->order-service->file-service->iam-service->warehouse-service', 'finance-service->firstleg-service->order-service->lastleg-service->file-service->iam-service->auth-service', 'finance-service->firstleg-service->order-service->lastleg-service->file-service->iam-service->warehouse-service' ] }, 'file-service': { hops: 2, paths: [ 'file-service->iam-service->auth-service', 'file-service->iam-service->warehouse-service' ] }, 'lastleg-service': { hops: 6, paths: [ 'lastleg-service->finance-service->firstleg-service->order-service->file-service->iam-service->auth-service', 'lastleg-service->finance-service->firstleg-service->order-service->file-service->iam-service->warehouse-service', 'lastleg-service->firstleg-service->order-service->finance-service->file-service->iam-service->auth-service', 'lastleg-service->firstleg-service->order-service->finance-service->file-service->iam-service->warehouse-service', 'lastleg-service->order-service->finance-service->firstleg-service->file-service->iam-service->auth-service', 'lastleg-service->order-service->finance-service->firstleg-service->file-service->iam-service->warehouse-service' ] }, 'warehouse-service': { hops: 0, paths: ['warehouse-service'] }, 'warehouse-overseas-service': { hops: 1, paths: [ 'warehouse-overseas-service->print-service', 'warehouse-overseas-service->warehouse-service' ] } }) for (const entry of USER_ENTRIES) { const result = summary[entry.service] if (result.hops > 2) assert.ok(result.paths.every(path => path.split('->').length > 3)) } }) test('self-operated collection and quota callbacks stay outside the REQUEST graph', async () => { const find = suffix => SYNCHRONOUS_CLIENTS.find(client => client.path.endsWith(suffix)) const collection = find('/selfoperated/analytics/client/RestLingxingAnalyticsClient.java') const authority = find('/provider/lingxing/LingxingHttpBudgetAuthority.java') const supplier = find('/provider/lingxing/LingxingWmsClient.java') assert.deepEqual([collection.contexts, collection.access, collection.idempotency], [['BACKGROUND'], 'READ', 'NONE']) assert.deepEqual([authority.contexts, authority.access, authority.idempotency], [['BACKGROUND'], 'READ_WRITE', 'MIXED']) assert.deepEqual([supplier.contexts, supplier.access, supplier.idempotency], [['EXTERNAL'], 'READ', 'NONE']) assert.equal(graphEdges('REQUEST').includes('lastleg-service->integration-service'), false) assert.equal(graphEdges('REQUEST').includes('integration-service->lastleg-service'), false) // The background service graph is bidirectional; the permit callback must not re-enter collection. const egress = await readFile(path.join(root, 'lastleg-service/src/main/java/com/baiyue/lastleg/selfoperated/analytics/request/SelfopEgressService.java'), 'utf8') assert.doesNotMatch(egress, /RestLingxingAnalyticsClient|LingxingAnalyticsClient|SelfopExecutionService/) const callback = await readFile(path.join(root, authority.path), 'utf8') assert.match(callback, /followRedirects\(HttpClient\.Redirect\.NEVER\)/) assert.match(callback, /timeout\(Duration\.ofSeconds\(5\)\)/) assert.doesNotMatch(callback, /RetryTemplate|Retryer|@Retryable|\.retry\(/) }) test('new domain reference clients are exact readonly internal dependencies', async () => { const reviewed = [ ['lastleg-service/src/main/java/com/baiyue/lastleg/appointmentplanning/AppointmentForecastClient.java', 'firstleg-service', '/internal/firstleg/appointment-forecasts/batch'], ['lastleg-service/src/main/java/com/baiyue/lastleg/appointmentplanning/AppointmentWarehouseClient.java', 'warehouse-service', '/internal/warehouses/order-catalog'], ['lastleg-service/src/main/java/com/baiyue/lastleg/service/reference/ReturnCustomerReferenceClient.java', 'iam-service', '/internal/iam/finance-customers'], ['lastleg-service/src/main/java/com/baiyue/lastleg/transfer/gateway/TransferWarehouseCatalogClient.java', 'warehouse-service', '/internal/warehouses/order-catalog'], ['order/src/main/java/com/baiyue/order/client/LastlegOrderProgressClient.java', 'lastleg-service', '/internal/lastleg/v1/customer-order-progress'] ] for (const [file, target, endpoint] of reviewed) { const client = SYNCHRONOUS_CLIENTS.find(row => row.path === file) assert.deepEqual([client.target, client.contexts, client.access, client.idempotency], [target, ['REQUEST'], 'READ', 'SAFE_READ']) const source = await readFile(path.join(root, file), 'utf8') assert.ok(source.includes(endpoint)) assert.ok(source.includes('X-Internal-Service-Token')) assert.doesNotMatch(source, /@(?:PutMapping|DeleteMapping|PatchMapping)/) } }) test('delivery fee coverage is a single readonly Finance hop and cannot write financial state', async () => { const client = await readFile(path.join(root, 'lastleg-service/src/main/java/com/baiyue/lastleg/client/FinanceFeeCoverageClient.java'), 'utf8') const service = await readFile(path.join(root, 'finance/src/main/java/com/baiyue/finance/service/DeliveryFeeCoverageQueryService.java'), 'utf8') assert.equal([...client.matchAll(/@(?:Get|Post|Put|Delete|Patch)Mapping/g)].length, 1) assert.ok(client.includes('/internal/finance/v1/delivery-fee-coverage/sources')) assert.ok(service.includes('@Transactional(readOnly = true)')) assert.ok(!/\.client\.|Feign|RestClient|WebClient|HttpClient|jdbc\.update|\.execute\(/.test(service)) assert.ok(service.includes("f.customer_id=:customerId AND f.inbound_id IN (:inboundIds)")) }) test('shared Feign timeout defaults and long-running export overrides do not drift silently', async () => { for (const profile of ['test']) { const source = await readFile(path.join(root, 'config', 'nacos', profile, 'baiyue-common.yml'), 'utf8') assert.match(source, /connect-timeout:\s*3000/) assert.match(source, /read-timeout:\s*5000/) } const fileConfig = await readFile(path.join(root, 'file', 'src', 'main', 'resources', 'application.yml'), 'utf8') assert.equal((fileConfig.match(/read-timeout:\s*15000/g) ?? []).length, 6) assert.match(fileConfig, /lastlegExportProviderClient:\s+connect-timeout:\s*3000\s+read-timeout:\s*15000/) })