From 1c901e31377eaba4c4b088ebfef4ddcfdc4c3146 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 8 Nov 2022 14:01:06 +0000 Subject: [PATCH] Fix Node 19 compatibility and run CI against it (#2842) --- .github/workflows/tests.yml | 21 ++++++++++++++++--- spec/browserify/setupTests.ts | 21 +++++++++++++++++++ spec/browserify/sync-browserify.spec.ts | 17 ++------------- spec/setupTests.ts | 6 ++++++ spec/unit/crypto/verification/request.spec.ts | 7 +------ spec/unit/crypto/verification/sas.spec.ts | 7 +------ .../verification/secret_request.spec.ts | 14 +++++-------- spec/unit/crypto/verification/util.ts | 15 ------------- .../verification/verification_request.spec.ts | 9 -------- spec/unit/http-api/utils.spec.ts | 2 ++ src/sync.ts | 1 + 11 files changed, 57 insertions(+), 63 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b149d2e18..13b289e1c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,25 +8,40 @@ concurrency: cancel-in-progress: true jobs: jest: - name: Jest + name: 'Jest [${{ matrix.specs }}] (Node ${{ matrix.node }})' runs-on: ubuntu-latest + timeout-minutes: 10 + strategy: + matrix: + specs: [browserify, integ, unit] + node: [16, 18, latest] steps: - name: Checkout code uses: actions/checkout@v3 - - name: Yarn cache + - name: Setup Node uses: actions/setup-node@v3 with: cache: 'yarn' + node-version: ${{ matrix.node }} - name: Install dependencies run: "yarn install" - name: Build + if: matrix.specs == 'browserify' run: "yarn build" + - name: Get number of CPU cores + id: cpu-cores + uses: SimenB/github-actions-cpu-cores@v1 + - name: Run tests with coverage - run: "yarn coverage --ci --reporters github-actions" + run: | + yarn coverage --ci --reporters github-actions --max-workers ${{ steps.cpu-cores.outputs.count }} ./spec/${{ matrix.specs }} + mv coverage/lcov.info coverage/${{ matrix.node }}-${{ matrix.specs }}.lcov.info + env: + JEST_SONAR_UNIQUE_OUTPUT_NAME: true - name: Upload Artifact uses: actions/upload-artifact@v3 diff --git a/spec/browserify/setupTests.ts b/spec/browserify/setupTests.ts index 833d8591c..a92a70e23 100644 --- a/spec/browserify/setupTests.ts +++ b/spec/browserify/setupTests.ts @@ -14,6 +14,21 @@ See the License for the specific language governing permissions and limitations under the License. */ +import "../../dist/browser-matrix"; // uses browser-matrix instead of the src +import type { MatrixClient, ClientEvent } from "../../src"; + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace NodeJS { + interface Global { + matrixcs: { + MatrixClient: typeof MatrixClient; + ClientEvent: typeof ClientEvent; + }; + } + } +} + // stub for browser-matrix browserify tests // @ts-ignore global.XMLHttpRequest = jest.fn(); @@ -23,3 +38,9 @@ afterAll(() => { // @ts-ignore global.XMLHttpRequest = undefined; }); + +// Akin to spec/setupTests.ts - but that won't affect the browser-matrix bundle +global.matrixcs = { + ...global.matrixcs, + timeoutSignal: () => new AbortController().signal, +}; diff --git a/spec/browserify/sync-browserify.spec.ts b/spec/browserify/sync-browserify.spec.ts index 648a72dc4..172cb0c47 100644 --- a/spec/browserify/sync-browserify.spec.ts +++ b/spec/browserify/sync-browserify.spec.ts @@ -16,27 +16,14 @@ limitations under the License. import HttpBackend from "matrix-mock-request"; -import "./setupTests"; -import "../../dist/browser-matrix"; // uses browser-matrix instead of the src -import type { MatrixClient, ClientEvent } from "../../src"; +import "./setupTests";// uses browser-matrix instead of the src +import type { MatrixClient } from "../../src"; const USER_ID = "@user:test.server"; const DEVICE_ID = "device_id"; const ACCESS_TOKEN = "access_token"; const ROOM_ID = "!room_id:server.test"; -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace NodeJS { - interface Global { - matrixcs: { - MatrixClient: typeof MatrixClient; - ClientEvent: typeof ClientEvent; - }; - } - } -} - describe("Browserify Test", function() { let client: MatrixClient; let httpBackend: HttpBackend; diff --git a/spec/setupTests.ts b/spec/setupTests.ts index bbd70fe3d..2557be755 100644 --- a/spec/setupTests.ts +++ b/spec/setupTests.ts @@ -17,3 +17,9 @@ limitations under the License. import DOMException from "domexception"; global.DOMException = DOMException; + +jest.mock("../src/http-api/utils", () => ({ + ...jest.requireActual("../src/http-api/utils"), + // We mock timeoutSignal otherwise it causes tests to leave timers running + timeoutSignal: () => new AbortController().signal, +})); diff --git a/spec/unit/crypto/verification/request.spec.ts b/spec/unit/crypto/verification/request.spec.ts index cd32ce264..be957989a 100644 --- a/spec/unit/crypto/verification/request.spec.ts +++ b/spec/unit/crypto/verification/request.spec.ts @@ -18,7 +18,7 @@ import "../../../olm-loader"; import { CryptoEvent, verificationMethods } from "../../../../src/crypto"; import { logger } from "../../../../src/logger"; import { SAS } from "../../../../src/crypto/verification/SAS"; -import { makeTestClients, setupWebcrypto, teardownWebcrypto } from './util'; +import { makeTestClients } from './util'; const Olm = global.Olm; @@ -31,14 +31,9 @@ describe("verification request integration tests with crypto layer", function() } beforeAll(function() { - setupWebcrypto(); return Olm.init(); }); - afterAll(() => { - teardownWebcrypto(); - }); - it("should request and accept a verification", async function() { const [[alice, bob], clearTestClientTimeouts] = await makeTestClients( [ diff --git a/spec/unit/crypto/verification/sas.spec.ts b/spec/unit/crypto/verification/sas.spec.ts index 559ecf351..ee058c7f0 100644 --- a/spec/unit/crypto/verification/sas.spec.ts +++ b/spec/unit/crypto/verification/sas.spec.ts @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ import "../../../olm-loader"; -import { makeTestClients, setupWebcrypto, teardownWebcrypto } from './util'; +import { makeTestClients } from './util'; import { MatrixEvent } from "../../../../src/models/event"; import { ISasEvent, SAS, SasEvent } from "../../../../src/crypto/verification/SAS"; import { DeviceInfo } from "../../../../src/crypto/deviceinfo"; @@ -41,14 +41,9 @@ describe("SAS verification", function() { } beforeAll(function() { - setupWebcrypto(); return Olm.init(); }); - afterAll(() => { - teardownWebcrypto(); - }); - it("should error on an unexpected event", async function() { //channel, baseApis, userId, deviceId, startEvent, request const request = { diff --git a/spec/unit/crypto/verification/secret_request.spec.ts b/spec/unit/crypto/verification/secret_request.spec.ts index 1c0a7410a..2f9fafb5d 100644 --- a/spec/unit/crypto/verification/secret_request.spec.ts +++ b/spec/unit/crypto/verification/secret_request.spec.ts @@ -14,13 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { CrossSigningInfo } from '../../../../src/crypto/CrossSigning'; +import '../../../olm-loader'; +import { MatrixClient, MatrixEvent } from '../../../../src/matrix'; import { encodeBase64 } from "../../../../src/crypto/olmlib"; -import { setupWebcrypto, teardownWebcrypto } from './util'; -import { VerificationBase } from '../../../../src/crypto/verification/Base'; -import { MatrixClient, MatrixEvent } from '../../../../src'; +import "../../../../src/crypto"; // import this to cycle-break +import { CrossSigningInfo } from '../../../../src/crypto/CrossSigning'; import { VerificationRequest } from '../../../../src/crypto/verification/request/VerificationRequest'; import { IVerificationChannel } from '../../../../src/crypto/verification/request/Channel'; +import { VerificationBase } from '../../../../src/crypto/verification/Base'; jest.useFakeTimers(); @@ -35,14 +36,9 @@ const testKeyPub = "nqOvzeuGWT/sRx3h7+MHoInYj3Uk2LD/unI9kDYcHwk"; describe("self-verifications", () => { beforeAll(function() { - setupWebcrypto(); return global.Olm.init(); }); - afterAll(() => { - teardownWebcrypto(); - }); - it("triggers a request for key sharing upon completion", async () => { const userId = "@test:localhost"; diff --git a/spec/unit/crypto/verification/util.ts b/spec/unit/crypto/verification/util.ts index 7c19e8926..5efbe4ed5 100644 --- a/spec/unit/crypto/verification/util.ts +++ b/spec/unit/crypto/verification/util.ts @@ -15,8 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import nodeCrypto from "crypto"; - import { TestClient } from '../../../TestClient'; import { MatrixEvent } from "../../../../src/models/event"; import { IRoomTimelineData } from "../../../../src/models/event-timeline-set"; @@ -118,16 +116,3 @@ export async function makeTestClients(userInfos, options): Promise<[TestClient[] return [clients, destroy]; } - -export function setupWebcrypto() { - global.crypto = { - getRandomValues: (buf) => { - return nodeCrypto.randomFillSync(buf as any); - }, - } as unknown as Crypto; -} - -export function teardownWebcrypto() { - // @ts-ignore undefined != Crypto - global.crypto = undefined; -} diff --git a/spec/unit/crypto/verification/verification_request.spec.ts b/spec/unit/crypto/verification/verification_request.spec.ts index 913fec1de..6549c3af7 100644 --- a/spec/unit/crypto/verification/verification_request.spec.ts +++ b/spec/unit/crypto/verification/verification_request.spec.ts @@ -20,7 +20,6 @@ import { ToDeviceChannel } from "../../../../src/crypto/verification/request/ToDeviceChannel"; import { MatrixEvent } from "../../../../src/models/event"; import { MatrixClient } from "../../../../src/client"; -import { setupWebcrypto, teardownWebcrypto } from "./util"; import { IVerificationChannel } from "../../../../src/crypto/verification/request/Channel"; import { VerificationBase } from "../../../../src/crypto/verification/Base"; @@ -147,14 +146,6 @@ async function distributeEvent( jest.useFakeTimers(); describe("verification request unit tests", function() { - beforeAll(function() { - setupWebcrypto(); - }); - - afterAll(() => { - teardownWebcrypto(); - }); - it("transition from UNSENT to DONE through happy path", async function() { const alice = makeMockClient("@alice:matrix.tld", "device1"); const bob = makeMockClient("@bob:matrix.tld", "device1"); diff --git a/spec/unit/http-api/utils.spec.ts b/spec/unit/http-api/utils.spec.ts index b3d4e6848..108ba306f 100644 --- a/spec/unit/http-api/utils.spec.ts +++ b/spec/unit/http-api/utils.spec.ts @@ -28,6 +28,8 @@ import { import { sleep } from "../../../src/utils"; jest.mock("../../../src/utils"); +// setupTests mocks `timeoutSignal` due to hanging timers +jest.unmock("../../../src/http-api/utils"); describe("timeoutSignal", () => { jest.useFakeTimers(); diff --git a/src/sync.ts b/src/sync.ts index 59798c9e0..d85bfc4cb 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -1536,6 +1536,7 @@ export class SyncApi { { prefix: '', localTimeoutMs: 15 * 1000, + abortSignal: this.abortController?.signal, }, ).then(() => { success();