spiegel-keyman/developer/src/kmc/test/test-infrastructureMessages.ts
Marc Durdin fa19eea873 chore(developer): improve kmc sentry reporting on fatal build errors
kmc already reported unhandled exceptions, but any handled fatal errors
were captured and only reported to the user. It is better to report
these to Sentry as these are still unexpected.

I have refactored all the fatal exception messages in various kmc
modules to use a common mechanism, keeping all the Sentry integration in
kmc, now passing exception data up in the `CompilerEvent.exceptionVar`
property.

* I took the opportunity to rename messages.ts to
  infrastructureMessages.ts

* @types/chai was missing which gave intellisense errors in vscode

* normal exit of kmc now provides an opportunity for error reports to
  Sentry to be finalized

* Added a unit test for fatal errors in kmc

* Added a manual test pathway with `SENTRY_CLIENT_TEST_BUILD_EXCEPTION`
  env var to trip the build fatal error mechanism and verify that it
  looks ok; the following shows test runs demonstrate how fatal build
  errors are reported:

```
mcdurdin@THARK MINGW64 /c/Projects/keyman/app/developer/src/kmc (chore/developer/report-fatal-compiler-errors-to-sentry)
$ SENTRY_CLIENT_TEST_BUILD_EXCEPTION=1 node . --error-reporting build
fatal KM05001: Unexpected exception: Error: Test exception from SENTRY_CLIENT_TEST_BUILD_EXCEPTION

Call stack:
Error: Test exception from SENTRY_CLIENT_TEST_BUILD_EXCEPTION
    at build (file:///C:/Projects/keyman/app/developer/src/kmc/build/src/commands/build.js:78:19)
    at Command.<anonymous> (file:///C:/Projects/keyman/app/developer/src/kmc/build/src/commands/build.js:66:24)
    at Command.listener [as _actionHandler] (C:\Projects\keyman\app\node_modules\commander\lib\command.js:482:17)
    at C:\Projects\keyman\app\node_modules\commander\lib\command.js:1283:65
    at Command._chainOrCall (C:\Projects\keyman\app\node_modules\commander\lib\command.js:1177:12)
    at Command._parseCommand (C:\Projects\keyman\app\node_modules\commander\lib\command.js:1283:27)
    at C:\Projects\keyman\app\node_modules\commander\lib\command.js:1081:27
    at Command._chainOrCall (C:\Projects\keyman\app\node_modules\commander\lib\command.js:1177:12)
    at Command._dispatchSubcommand (C:\Projects\keyman\app\node_modules\commander\lib\command.js:1077:23)
    at Command._parseCommand (C:\Projects\keyman\app\node_modules\commander\lib\command.js:1248:19)

    This error has been automatically reported to the Keyman team.
      Identifier:  6f0fca1a26694c22b03f02b2463d39c5
      Application: Keyman Developer
      Reported at: https://sentry.io/organizations/keyman/projects/keyman-developer/events/6f0fca1a26694c22b03f02b2463d39c5/

mcdurdin@THARK MINGW64 /c/Projects/keyman/app/developer/src/kmc (chore/developer/report-fatal-compiler-errors-to-sentry)
$ SENTRY_CLIENT_TEST_BUILD_EXCEPTION=1 node . --no-error-reporting build
fatal KM05001: Unexpected exception: Error: Test exception from SENTRY_CLIENT_TEST_BUILD_EXCEPTION

Call stack:
Error: Test exception from SENTRY_CLIENT_TEST_BUILD_EXCEPTION
    at build (file:///C:/Projects/keyman/app/developer/src/kmc/build/src/commands/build.js:78:19)
    at Command.<anonymous> (file:///C:/Projects/keyman/app/developer/src/kmc/build/src/commands/build.js:66:24)
    at Command.listener [as _actionHandler] (C:\Projects\keyman\app\node_modules\commander\lib\command.js:482:17)
    at C:\Projects\keyman\app\node_modules\commander\lib\command.js:1283:65
    at Command._chainOrCall (C:\Projects\keyman\app\node_modules\commander\lib\command.js:1177:12)
    at Command._parseCommand (C:\Projects\keyman\app\node_modules\commander\lib\command.js:1283:27)
    at C:\Projects\keyman\app\node_modules\commander\lib\command.js:1081:27
    at Command._chainOrCall (C:\Projects\keyman\app\node_modules\commander\lib\command.js:1177:12)
    at Command._dispatchSubcommand (C:\Projects\keyman\app\node_modules\commander\lib\command.js:1077:23)
    at Command._parseCommand (C:\Projects\keyman\app\node_modules\commander\lib\command.js:1248:19)
```
2023-08-09 09:34:44 +07:00

68 lines
3.1 KiB
TypeScript

import 'mocha';
import { assert } from 'chai';
import { InfrastructureMessages } from '../src/messages/infrastructureMessages.js';
import { verifyCompilerMessagesObject } from '@keymanapp/developer-test-helpers';
import { makePathToFixture } from './helpers/index.js';
import { NodeCompilerCallbacks } from '../src/util/NodeCompilerCallbacks.js';
import { CompilerErrorNamespace } from '@keymanapp/common-types';
import { unitTestEndpoints } from '../src/commands/build.js';
describe('InfrastructureMessages', function () {
it('should have a valid InfrastructureMessages object', function() {
return verifyCompilerMessagesObject(InfrastructureMessages, CompilerErrorNamespace.Infrastructure);
});
//
// Message tests
//
// FATAL_UnexpectedException
it('should generate FATAL_UnexpectedException if an exception is raised', async function() {
const ncb = new NodeCompilerCallbacks({logLevel: 'silent'});
process.env.SENTRY_CLIENT_TEST_BUILD_EXCEPTION = '1';
await unitTestEndpoints.build(null, ncb, {});
delete process.env.SENTRY_CLIENT_TEST_BUILD_EXCEPTION;
assert.isTrue(ncb.hasMessage(InfrastructureMessages.FATAL_UnexpectedException),
`FATAL_UnexpectedException not generated, instead got: `+JSON.stringify(ncb.messages,null,2));
assert.lengthOf(ncb.messages, 1);
assert.instanceOf<Error>(ncb.messages[0].exceptionVar, Error);
});
/*
// ERROR_FileDoesNotExist
it('should generate ERROR_FileDoesNotExist if a file does not exist', async function() {
await testForMessage(this, ['invalid-keyboards', 'error_file_does_not_exist.kmn'], CompilerMessages.ERROR_FileDoesNotExist);
});
// ERROR_FileTypeNotRecognized
it('should generate ERROR_FileTypeNotRecognized if a file is not a recognized type', async function() {
await testForMessage(this, ['invalid-keyboards', 'error_file_type_not_recognized.xxx'], CompilerMessages.ERROR_FileTypeNotRecognized);
});
// ERROR_OutFileNotValidForProjects
it('should generate ERROR_OutFileNotValidForProjects if an output file is specified for a project build', async function() {
await testForMessage(this, ['invalid-keyboards', 'error_out_file_not_valid_for_projects.kpj'], CompilerMessages.ERROR_OutFileNotValidForProjects);
});
// ERROR_InvalidProjectFile
it('should generate ERROR_InvalidProjectFile if a project file is invalid', async function() {
await testForMessage(this, ['invalid-keyboards', 'error_invalid_project_file.kpj'], CompilerMessages.ERROR_InvalidProjectFile);
});
*/
// HINT_FilenameHasDifferingCase
it('should generate HINT_FilenameHasDifferingCase if a referenced file has differing case', async function() {
// This message is generated by NodeCompilerCallbacks, because that's where the filesystem is visible,
// so we can't use our usual testForMessage pattern.
const ncb = new NodeCompilerCallbacks({logLevel: 'silent'});
ncb.loadFile(makePathToFixture('invalid-keyboards', 'Hint_Filename_Has_Differing_Case.kmn'));
assert.isTrue(ncb.hasMessage(InfrastructureMessages.HINT_FilenameHasDifferingCase),
`HINT_FilenameHasDifferingCase not generated, instead got: `+JSON.stringify(ncb.messages,null,2));
});
});