优化
This commit is contained in:
@@ -21,7 +21,7 @@ function departedRecoveryFixture() {
|
||||
departure:{action:'LOADING_COMPLETE',dispatchNo:'OWN',status:'ACTIVE',stage:'DELIVERING',recordVersion:'31',result:{loadingCompletionHash:'HASH',loadingCompletedAt:snapshotTrip.departedAt,confirmedLoad:{manifestHash:'a'.repeat(64)}}}}
|
||||
const trip={marker:'RUN',tripNo:'TR-OWN',dispatchNo:'OWN',warehouseId:'W1',confirmedLoad:{manifestHash:'a'.repeat(64),pallets:measured},costAcceptance:{marker:'RUN',status:'FAILED',costs:[],departure,
|
||||
requests:[{method:'GET',status:'RESPONDED',http:200,code:'200',requestId:'r',traceId:'t'}]},externalReceipt:{status:'VERIFIED',bookingNo:'BK',warehousePalletId:'P2'},externalDispatch:{dispatchNo:'OWN',deliveryNo:'DL-EXT'}}
|
||||
const report={success:false,steps:[{name:'独立预期覆盖全部实物且没有重叠托盘',passed:false},{name:'模块执行',passed:false}],createdResources:{fleetAcceptance:proof,fleetTrips:[trip],fleetCostActors:{status:'DISABLED'},fleetFeeCoverageCases:[{mode:'PARTIAL',dispatchNo:'OWN',proof:{deliveryNos:['DL-OWN','DL-EXT']}}]}}
|
||||
const report={success:false,steps:[{name:'独立预期覆盖全部实物且没有重叠托盘',passed:false},{name:'模块执行',passed:false}],createdResources:{fleetAcceptance:proof,fleetTrips:[trip],fleetCostActors:{status:'SESSIONS_CLOSED'},fleetFeeCoverageCases:[{mode:'PARTIAL',dispatchNo:'OWN',proof:{deliveryNos:['DL-OWN','DL-EXT']}}]}}
|
||||
const base='/api/platform/v1/last-leg/fleet/trips/TR-OWN'
|
||||
const responses=new Map([[base,{trip:structuredClone(snapshotTrip),dispatches:[{dispatchNo:'OWN'}]}],
|
||||
[base+'/history?page=1&size=100',{total:1,records:[structuredClone(departure)]}],
|
||||
@@ -514,58 +514,31 @@ test('cost actor journal removes credential keys while retaining IDs, roles and
|
||||
assert.equal(source.nested.accessToken, 'actual-session')
|
||||
})
|
||||
|
||||
for (const failLogin of [false, true]) test(`cost actors create exact isolated roles and disable only owned accounts; login failure=${failLogin}`, async () => {
|
||||
const calls = [], saved = [], roles = [], users = []
|
||||
const context = { marker: 'RUN', token: 'admin-secret', createdResources: {}, async findAvailablePhone() { return '19900000000' },
|
||||
for (const failLogin of [false, true]) test(`cost actors reuse configured roles and only logout owned sessions: failure=${failLogin}`, async () => {
|
||||
const calls = [], saved = []
|
||||
const actors = Object.fromEntries(['reader', 'denied'].map((kind, index) => [`fleet-cost.${kind}`, { membershipId: String(10 + index), roleId: String(20 + index), roleCode: kind, username: kind, password: `fixed-secret-${kind}` }]))
|
||||
const context = { marker: 'RUN', token: 'admin-secret', options: { fixedActors: actors }, createdResources: {},
|
||||
async checkpoint() { saved.push(structuredClone(context.createdResources)) },
|
||||
async request(method, path, body, token) {
|
||||
if (method === 'GET' && (path.startsWith('/api/platform/v1/iam/users?') || path.includes('/administrator-phone-availability?')))
|
||||
return { http: 200, body: { code: '200', data: path.includes('/administrator-phone-availability?') ? true : { records: [], total: 0 } }, requestId: 'r', traceId: 't' }
|
||||
const pending = saved.at(-1).fleetCostActors.requests.at(-1)
|
||||
assert.equal(pending.status, 'SENDING'); assert.equal(pending.path, path)
|
||||
calls.push({ method, path, body, token })
|
||||
let data
|
||||
if (path.endsWith('/authorization/permissions')) data = token === 'session-1' ? ['platform:fleet:trip:list'] : []
|
||||
else if (path.endsWith('/permissions') && method === 'GET') data = [{ id: '7', permissionCode: 'platform:fleet:trip:list', status: 'ACTIVE' }]
|
||||
else if (path.endsWith('/roles') && method === 'POST') { data = { ...body, id: String(roles.length + 1), roleType: 'CUSTOM' }; roles.push(data) }
|
||||
else if (path.endsWith('/roles/permissions')) data = body
|
||||
else if (path.endsWith('/users') && method === 'POST') { data = { ...body, membershipId: String(users.length + 10) }; users.push(data) }
|
||||
else if (path === '/api/auth/login') { if (failLogin) throw Error('login unavailable'); data = { accessToken: `session-${users.length}` } }
|
||||
else if (path.endsWith('/status')) data = body
|
||||
calls.push({ method, path, body, token }); let data
|
||||
if (path.endsWith('/roles')) data = Object.values(actors).map(a => ({ id: a.roleId, roleCode: a.roleCode, status: 'ACTIVE' }))
|
||||
else if (path.includes('/users?')) data = { page: 1, size: 100, total: 2, records: Object.values(actors).map(a => ({ membershipId: a.membershipId, username: a.username, tenantId: '0', roleIds: [a.roleId], status: 'ACTIVE' })) }
|
||||
else if (path.endsWith('/login')) { if (failLogin) throw Error('login unavailable'); data = { accessToken: `session-${body.loginId}`, refreshToken: `refresh-${body.loginId}` } }
|
||||
else if (path.endsWith('/authorization/permissions')) data = token === 'session-reader' ? ['platform:fleet:trip:list'] : []
|
||||
else if (path.endsWith('/logout')) data = null
|
||||
else assert.fail(path)
|
||||
return { http: 200, body: { code: '200', data }, requestId: 'request', traceId: 'trace' }
|
||||
} }
|
||||
if (failLogin) await assert.rejects(prepareFleetCostActors(context), /login unavailable/)
|
||||
else {
|
||||
const actors = await prepareFleetCostActors(context)
|
||||
assert.equal(actors.listOnlyToken, 'session-1'); assert.equal(actors.deniedToken, 'session-2')
|
||||
assert.equal(calls.filter(row => row.path.endsWith('/roles/permissions'))[1].body.permissionIds.length, 0)
|
||||
await actors.close()
|
||||
const count = calls.length; await actors.close(); assert.equal(calls.length, count)
|
||||
const actor = await prepareFleetCostActors(context)
|
||||
assert.equal(actor.listOnlyToken, 'session-reader'); assert.equal(actor.deniedToken, 'session-denied')
|
||||
await actor.close(); const count = calls.length; await actor.close(); assert.equal(calls.length, count)
|
||||
}
|
||||
assert.equal(context.createdResources.fleetCostActors.status, 'DISABLED')
|
||||
assert.equal(calls.filter(row => /\/users\/\d+\/status$/.test(row.path)).length, users.length)
|
||||
assert.equal(calls.filter(row => /\/roles\/\d+\/status$/.test(row.path)).length, roles.length)
|
||||
assert.equal(context.createdResources.fleetCostActors.status, 'SESSIONS_CLOSED')
|
||||
assert.ok(calls.every(call => call.method === 'GET' || call.path.startsWith('/api/auth/')))
|
||||
const evidence = JSON.stringify(saved)
|
||||
assert.ok(!evidence.includes('session-1')); assert.ok(!evidence.includes('admin-secret'))
|
||||
for (const user of users) assert.ok(!evidence.includes(user.password))
|
||||
assert.ok(!calls.some(row => row.method === 'DELETE'))
|
||||
})
|
||||
|
||||
test('fresh cost actor phones avoid existing platform users and use an independent namespace under the same original marker', async () => {
|
||||
const phones = [], ctx = { marker: 'ORIGINAL-RUN', async request(method, path) {
|
||||
assert.equal(method, 'GET')
|
||||
let data
|
||||
if (path.includes('/users?')) {
|
||||
const phone = new URL('https://test.invalid' + path).searchParams.get('keyword'); phones.push(phone)
|
||||
data = { records: phones.length === 1 ? [{ phone }] : [], total: phones.length === 1 ? 1 : 0 }
|
||||
} else data = true
|
||||
return { http: 200, body: { code: '200', data }, requestId: 'r', traceId: 't' }
|
||||
} }
|
||||
const first = await findFleetActorPhone(ctx, 'a'.repeat(16))
|
||||
assert.notEqual(first, phones[0]); assert.match(first, /^18\d{9}$/)
|
||||
const second = await findFleetActorPhone(ctx, 'b'.repeat(16))
|
||||
assert.notEqual(first, second)
|
||||
for (const secret of ['session-reader', 'admin-secret', 'fixed-secret-reader', 'fixed-secret-denied']) assert.ok(!evidence.includes(secret))
|
||||
})
|
||||
|
||||
test('phone lookup failure stops without any user creation or guessing', async () => {
|
||||
|
||||
Reference in New Issue
Block a user