Nine findings from review, all taken. Row reads (getdata): - approversForTable reads every column through field(): the security and group rows are seeded with UPPERCASE keys and an edited row comes back lower-cased, so a direct property read compared undefined with 'UNDEFINED' and found no grant - silently falling back to the admin group for every table. - tx_to is handled by rowInForce(): epoch seconds, which is what Date.now()/1000 assumes, with an ISO string accepted; a blank, absent or unparseable end date is open-ended rather than expired, so a rule or a grant that omits it is no longer dropped as NaN. The dqrules filter reads rule_active/base_lib/base_ds through field() for the same reason. Rows and the text that describes them (getdata): - the current-rows clause in FILTER_TEXT is now applied to the selection: the grid no longer shows expired rows while telling the user they were excluded. - the primary-key sort resolves each key to the column's own casing, so a lowercase DDL sorts on real values instead of comparing undefined. Settings (getdata, viewlibs): - dcLibref falls back to 'DC_JSLIB' like dcAdminGroup already did: a deploy that has not run makedata has no settings.js, and viewlibs must still list the control library. Wording that had gone stale: - the parity README's Status paragraph now states the invariant (every scenario is gated; gated:false is advisory) instead of counts and a list of differences that were fixed, and the scenarios.json notes say what each scenario pins now. - viewdata's comment states the contract rather than the behaviour it replaced, and the synthetic no-data row writes the same space for a blank character cell as the data rows do. Tests: getdata-rules.test.js covers an uppercase-keyed APPROVE grant and an open-ended rule (both fail on the previous code); viewdata.test.js covers the numeric missing and the empty-table row.
81 lines
2.3 KiB
JavaScript
81 lines
2.3 KiB
JavaScript
/**
|
|
* Two reads in getdata go through the control library's own rows, and both have
|
|
* a case that looks like an empty answer rather than a bug:
|
|
*
|
|
* - the security and group rows are seeded with UPPERCASE keys (`SAS_GROUP`)
|
|
* while a row that has been through the edit flow comes back lower-cased, so
|
|
* a direct property read compares against undefined and finds no approver;
|
|
* - a `tx_to` that is blank or absent is an open-ended row, not an expired
|
|
* one, and reading it as NaN drops the rule or the grant with no signal.
|
|
*/
|
|
const test = require('node:test')
|
|
const assert = require('node:assert')
|
|
|
|
const { seededEstate, runService, readTable, writeTable } = require('./harness')
|
|
|
|
function getdata(estate, libds) {
|
|
return JSON.parse(
|
|
runService(estate, 'editors/getdata', {
|
|
tableName: 'SASControlTable',
|
|
rows: [{ LIBDS: libds, FILTER_RK: -1 }]
|
|
})
|
|
)
|
|
}
|
|
|
|
test('an APPROVE grant whose keys are upper case still yields its group', () => {
|
|
const estate = seededEstate({ demo: false })
|
|
const security = readTable(estate, 'MPE_SECURITY')
|
|
writeTable(
|
|
estate,
|
|
'MPE_SECURITY',
|
|
security.concat([
|
|
{
|
|
TX_FROM: 0,
|
|
TX_TO: 127490111999,
|
|
LIBREF: 'DC_JSLIB',
|
|
DSN: 'MPE_TABLES',
|
|
ACCESS_LEVEL: 'APPROVE',
|
|
SAS_GROUP: 'dc-admin'
|
|
}
|
|
])
|
|
)
|
|
|
|
const body = getdata(estate, 'DC_JSLIB.MPE_TABLES')
|
|
|
|
assert.equal(body.sasjsAbort, undefined)
|
|
const users = body.approvers.map((row) => row.USERID).sort()
|
|
assert.deepEqual(
|
|
users,
|
|
['allbow', 'dctestuser1', 'mihmed'],
|
|
'the grant is found and its group expanded, rather than falling back'
|
|
)
|
|
})
|
|
|
|
test('a rule with no end date is in force, not dropped', () => {
|
|
const estate = seededEstate({ demo: false })
|
|
const validations = readTable(estate, 'MPE_VALIDATIONS')
|
|
writeTable(
|
|
estate,
|
|
'MPE_VALIDATIONS',
|
|
validations.concat([
|
|
{
|
|
tx_from: 0,
|
|
TX_TO: ' ',
|
|
BASE_LIB: 'DC_JSLIB',
|
|
BASE_DS: 'MPE_TABLES',
|
|
BASE_COL: 'LOADTYPE',
|
|
RULE_TYPE: 'NOTNULL',
|
|
RULE_VALUE: ' ',
|
|
RULE_ACTIVE: 1
|
|
}
|
|
])
|
|
)
|
|
|
|
const body = getdata(estate, 'DC_JSLIB.MPE_TABLES')
|
|
const rule = body.dqrules.find(
|
|
(row) => row.BASE_COL === 'LOADTYPE' && row.RULE_TYPE === 'NOTNULL'
|
|
)
|
|
|
|
assert.ok(rule, 'a blank end date means open-ended, so the rule is returned')
|
|
})
|