-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add vertical streak detection controls (#5549)
* fix(ballot-interpreter): correct JS argument marshaling If `options` was given as `{ scoreWriteIns: undefined }`, the interpreter would fail to coerce the value as a `bool` but would ignore the error until some point in the future when interacting with the JavaScript context. This is because the `get::<JsBoolean>` call would put the context into a throwing state, but would not then bubble that `Throw` up to the caller. As a result, subsequent calls to the context would also yield `Throw` for operations that should have succeeded. In this case the error would be "failed to downcast any to boolean". To fix this we need to not trigger throws when we don't intend to bubble them up. In particular, instead of `get::<JsBoolean>` we now `get_value()?.downcast::<JsBoolean>` so that we can bubble possible errors from the getter but then handle a mismatched type in Rust appopriately. * feat(scan): allow disabling streak detection Closes #5538 Adds a system setting that disables streak detection for an election. We might want this in case of a ballot design that triggers false positives when looking for streaks. Because we support taking someone else's AccuVote-style ballot, we may not be able to ensure no streaks are naturally present in the original image. This is unlikely, but this gives us an escape hatch. * refactor(scan): access system settings directly * fix(ballot-interpreter): pass `disableVerticalStreakDetection` Ensures that the `disableVerticalStreakDetection` system setting is passed through from the CLI. Also adds a CLI option to disable streak detection. * test(scan): ensure disabling streak detection works
- Loading branch information
1 parent
5800d86
commit 9801fad
Showing
20 changed files
with
481 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import { electionGridLayoutNewHampshireTestBallotFixtures } from '@votingworks/fixtures'; | ||
import { DEFAULT_SYSTEM_SETTINGS } from '@votingworks/types'; | ||
import { | ||
BooleanEnvironmentVariableName, | ||
getFeatureFlagMock, | ||
} from '@votingworks/utils'; | ||
import { simulateScan, withApp } from '../test/helpers/pdi_helpers'; | ||
import { configureApp, waitForStatus } from '../test/helpers/shared_helpers'; | ||
import { delays } from './scanners/pdi/state_machine'; | ||
|
||
const mockFeatureFlagger = getFeatureFlagMock(); | ||
|
||
jest.mock('@votingworks/utils', (): typeof import('@votingworks/utils') => { | ||
return { | ||
...jest.requireActual('@votingworks/utils'), | ||
isFeatureFlagEnabled: (flag) => mockFeatureFlagger.isEnabled(flag), | ||
}; | ||
}); | ||
|
||
beforeEach(() => { | ||
mockFeatureFlagger.resetFeatureFlags(); | ||
mockFeatureFlagger.enableFeatureFlag( | ||
BooleanEnvironmentVariableName.SKIP_ELECTION_PACKAGE_AUTHENTICATION | ||
); | ||
}); | ||
|
||
test('scanBatch with streaked page', async () => { | ||
const { scanMarkedFront, scanMarkedBack } = | ||
electionGridLayoutNewHampshireTestBallotFixtures; | ||
|
||
const frontImageData = await scanMarkedFront.asImageData(); | ||
const backImageData = await scanMarkedBack.asImageData(); | ||
|
||
// add a vertical streak | ||
for ( | ||
let offset = 500; | ||
offset < frontImageData.data.length; | ||
offset += frontImageData.width * 4 | ||
) { | ||
frontImageData.data[offset] = 0; | ||
frontImageData.data[offset + 1] = 0; | ||
frontImageData.data[offset + 2] = 0; | ||
frontImageData.data[offset + 3] = 255; | ||
} | ||
|
||
// try with vertical streak detection enabled | ||
await withApp( | ||
async ({ | ||
apiClient, | ||
clock, | ||
mockAuth, | ||
mockScanner, | ||
mockUsbDrive, | ||
workspace, | ||
}) => { | ||
await configureApp(apiClient, mockAuth, mockUsbDrive, { | ||
electionPackage: | ||
electionGridLayoutNewHampshireTestBallotFixtures.electionJson.toElectionPackage(), | ||
testMode: true, | ||
}); | ||
|
||
workspace.store.setSystemSettings({ | ||
...DEFAULT_SYSTEM_SETTINGS, | ||
// enable vertical streak detection | ||
disableVerticalStreakDetection: false, | ||
}); | ||
|
||
clock.increment(delays.DELAY_SCANNING_ENABLED_POLLING_INTERVAL); | ||
await waitForStatus(apiClient, { state: 'no_paper' }); | ||
expect(mockScanner.client.enableScanning).toHaveBeenCalledWith({ | ||
doubleFeedDetectionEnabled: true, | ||
paperLengthInches: 11, | ||
}); | ||
|
||
await simulateScan(apiClient, mockScanner, [ | ||
frontImageData, | ||
backImageData, | ||
]); | ||
|
||
await waitForStatus(apiClient, { | ||
state: 'rejecting', | ||
interpretation: { | ||
type: 'InvalidSheet', | ||
reason: 'vertical_streaks_detected', | ||
}, | ||
}); | ||
} | ||
); | ||
|
||
// try again with vertical streak detection disabled | ||
await withApp( | ||
async ({ | ||
apiClient, | ||
clock, | ||
mockAuth, | ||
mockScanner, | ||
mockUsbDrive, | ||
workspace, | ||
}) => { | ||
await configureApp(apiClient, mockAuth, mockUsbDrive, { | ||
electionPackage: | ||
electionGridLayoutNewHampshireTestBallotFixtures.electionJson.toElectionPackage(), | ||
testMode: true, | ||
}); | ||
|
||
workspace.store.setSystemSettings({ | ||
...DEFAULT_SYSTEM_SETTINGS, | ||
// disable vertical streak detection | ||
disableVerticalStreakDetection: true, | ||
}); | ||
|
||
clock.increment(delays.DELAY_SCANNING_ENABLED_POLLING_INTERVAL); | ||
await waitForStatus(apiClient, { state: 'no_paper' }); | ||
expect(mockScanner.client.enableScanning).toHaveBeenCalledWith({ | ||
doubleFeedDetectionEnabled: true, | ||
paperLengthInches: 11, | ||
}); | ||
|
||
await simulateScan(apiClient, mockScanner, [ | ||
frontImageData, | ||
backImageData, | ||
]); | ||
|
||
await waitForStatus(apiClient, { | ||
state: 'accepting', | ||
interpretation: { | ||
type: 'ValidSheet', | ||
}, | ||
}); | ||
} | ||
); | ||
}); |
Oops, something went wrong.