From 63c9eccf57a2cc87e2aa72e4a3ad38b982718f41 Mon Sep 17 00:00:00 2001 From: Pavel Ostrovskij Date: Wed, 14 May 2025 16:49:00 +0300 Subject: [PATCH] [fix] Tests --- Common/sources/operationContext.js | 3 +- Common/sources/utils.js | 4 +- package.json | 3 +- .../databaseTests/baseConnector.tests.js | 42 +++++----- .../forgottenFilesCommnads.tests.js | 16 ++-- .../withServerInstance/storage.tests.js | 36 +++++---- tests/jest.config.js | 7 +- tests/perf/checkFileExpire.js | 20 ++--- tests/perf/convertImageToPng.js | 14 ++-- tests/perf/fixImageExifRotation.js | 14 ++-- tests/unit/mailService.tests.js | 8 +- tests/unit/request.tests.js | 20 ++--- tests/unit/requestSSRF.tests.js | 77 ++++++++++++++----- tests/unit/sample.tests.js | 2 +- tests/unit/utils.tests.js | 8 +- 15 files changed, 159 insertions(+), 115 deletions(-) diff --git a/Common/sources/operationContext.js b/Common/sources/operationContext.js index c2bdd861..f91a4e4f 100644 --- a/Common/sources/operationContext.js +++ b/Common/sources/operationContext.js @@ -37,7 +37,7 @@ import * as logger from './logger.js'; import * as constants from './constants.js'; import * as tenantManager from './tenantManager.js'; -function Context(){ +export function Context(){ this.logger = logger.getLogger('nodeJS'); this.initDefault(); } @@ -148,5 +148,4 @@ function getImpl(object, property) { return getImpl(value, elems.slice(1)); }; -export { Context }; export const global = new Context(); diff --git a/Common/sources/utils.js b/Common/sources/utils.js index b863967f..37de02d9 100644 --- a/Common/sources/utils.js +++ b/Common/sources/utils.js @@ -33,8 +33,8 @@ 'use strict'; //Fix EPROTO error in node 8.x at some web sites(https://github.com/nodejs/node/issues/21513) -import { DEFAULT_ECDH_CURVE } from 'tls'; -// DEFAULT_ECDH_CURVE = "auto"; +import { default as tls } from 'tls'; +tls.DEFAULT_ECDH_CURVE = 'auto'; import { pipeline } from 'node:stream/promises'; import { buffer } from 'node:stream/consumers'; diff --git a/package.json b/package.json index 7babfbd2..174ec92d 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "1.0.1", "homepage": "https://www.onlyoffice.com", "private": true, + "type": "module", "dependencies": { "license-downloader": "1.0.8", "license-report": "6.7.2", @@ -21,7 +22,7 @@ "unit tests": "cd ./DocService && jest unit --inject-globals=false --config=../tests/jest.config.js", "integration tests with server instance": "cd ./DocService && jest integration/withServerInstance --inject-globals=false --config=../tests/jest.config.js", "integration database tests": "cd ./DocService && jest integration/databaseTests --inject-globals=false --config=../tests/jest.config.js", - "tests": "cd ./DocService && jest --inject-globals=false --config=../tests/jest.config.js", + "tests": "cd ./DocService && cross-env NODE_OPTIONS=--experimental-vm-modules jest --inject-globals=false --config=../tests/jest.config.js", "tests:dev": "cd ./DocService && jest --inject-globals=false --config=../tests/jest.config.js --watch", "install:Common": "npm ci --prefix ./Common", "install:DocService": "npm ci --prefix ./DocService", diff --git a/tests/integration/databaseTests/baseConnector.tests.js b/tests/integration/databaseTests/baseConnector.tests.js index cc4022a0..621357ab 100644 --- a/tests/integration/databaseTests/baseConnector.tests.js +++ b/tests/integration/databaseTests/baseConnector.tests.js @@ -30,15 +30,15 @@ * */ -const { describe, test, expect, afterAll } = require('@jest/globals'); -const config = require('../../../Common/node_modules/config'); +import { describe, test, expect, afterAll } from '@jest/globals'; +import config from '../../../Common/node_modules/config'; -const baseConnector = require('../../../DocService/sources/databaseConnectors/baseConnector'); -const operationContext = require('../../../Common/sources/operationContext'); -const taskResult = require('../../../DocService/sources/taskresult'); -const commonDefines = require('../../../Common/sources/commondefines'); -const constants = require('../../../Common/sources/constants'); -const utils = require("../../../Common/sources/utils"); +import * as baseConnector from '../../../DocService/sources/databaseConnectors/baseConnector.js'; +import * as operationContext from '../../../Common/sources/operationContext.js'; +import * as taskResult from '../../../DocService/sources/taskresult.js'; +import * as commonDefines from '../../../Common/sources/commondefines.js'; +import * as constants from '../../../Common/sources/constants.js'; +import * as utils from "../../../Common/sources/utils.js"; const configSql = config.get('services.CoAuthoring.sql'); const ctx = new operationContext.Context(); @@ -155,7 +155,7 @@ function deleteRowsByIds(table, ids) { function executeSql(sql, values = []) { return new Promise((resolve, reject) => { - baseConnector.sqlQuery(ctx, sql, function (error, result) { + baseConnector.dbInstance.sqlQuery(ctx, sql, function (error, result) { if (error) { reject(error) } else { @@ -189,15 +189,15 @@ function insertIntoResultTable(dateNow, task) { const columns = ['tenant', 'id', 'status', 'status_info', 'last_open_date', 'user_index', 'change_id', 'callback', 'baseurl']; const values = []; const placeholder = [ - baseConnector.addSqlParameter(task.tenant, values), - baseConnector.addSqlParameter(task.key, values), - baseConnector.addSqlParameter(task.status, values), - baseConnector.addSqlParameter(task.statusInfo, values), - baseConnector.addSqlParameter(dateNow, values), - baseConnector.addSqlParameter(task.userIndex, values), - baseConnector.addSqlParameter(task.changeId, values), - baseConnector.addSqlParameter(cbInsert, values), - baseConnector.addSqlParameter(task.baseurl, values) + baseConnector.dbInstance.addSqlParameter(task.tenant, values), + baseConnector.dbInstance.addSqlParameter(task.key, values), + baseConnector.dbInstance.addSqlParameter(task.status, values), + baseConnector.dbInstance.addSqlParameter(task.statusInfo, values), + baseConnector.dbInstance.addSqlParameter(dateNow, values), + baseConnector.dbInstance.addSqlParameter(task.userIndex, values), + baseConnector.dbInstance.addSqlParameter(task.changeId, values), + baseConnector.dbInstance.addSqlParameter(cbInsert, values), + baseConnector.dbInstance.addSqlParameter(task.baseurl, values) ]; return executeSql(`INSERT INTO ${cfgTableResult}(${columns.join(', ')}) VALUES(${placeholder.join(', ')});`, values); @@ -440,7 +440,7 @@ describe('Base database connector', function () { await noRowsExistenceCheck(cfgTableResult, task.key); - const result = await baseConnector.upsert(ctx, task); + const result = await baseConnector.dbInstance.upsert(ctx, task); // isInsert should be true because of insert operation, insertId should be 1 by default. const expected = { isInsert: true, insertId: 1 }; @@ -456,11 +456,11 @@ describe('Base database connector', function () { await noRowsExistenceCheck(cfgTableResult, task.key); - await baseConnector.upsert(ctx, task); + await baseConnector.dbInstance.upsert(ctx, task); // Changing baseurl to verify upsert() changing the row. task.baseurl = 'some-updated-url'; - const result = await baseConnector.upsert(ctx, task); + const result = await baseConnector.dbInstance.upsert(ctx, task); // isInsert should be false because of update operation, insertId should be 2 by updating clause. const expected = { isInsert: false, insertId: 2 }; diff --git a/tests/integration/withServerInstance/forgottenFilesCommnads.tests.js b/tests/integration/withServerInstance/forgottenFilesCommnads.tests.js index ee179aa9..7911e585 100644 --- a/tests/integration/withServerInstance/forgottenFilesCommnads.tests.js +++ b/tests/integration/withServerInstance/forgottenFilesCommnads.tests.js @@ -30,16 +30,16 @@ * */ -const { describe, test, expect, afterAll, beforeAll } = require('@jest/globals'); -const http = require('http'); +import { describe, test, expect, afterAll, beforeAll } from '@jest/globals'; +import http from 'http'; -const { signToken } = require('../../../DocService/sources/DocsCoServer'); -const storage = require('../../../Common/sources/storage/storage-base'); -const constants = require('../../../Common/sources/commondefines'); -const operationContext = require('../../../Common/sources/operationContext'); -const utils = require("../../../Common/sources/utils"); +import { signToken } from '../../../DocService/sources/DocsCoServer.js'; +import * as storage from '../../../Common/sources/storage/storage-base.js'; +import * as constants from '../../../Common/sources/constants.js'; +import * as operationContext from '../../../Common/sources/operationContext.js'; +import * as utils from "../../../Common/sources/utils.js"; -const config = require('../../../Common/node_modules/config'); +import config from '../../../Common/node_modules/config'; const cfgForgottenFiles = config.get('services.CoAuthoring.server.forgottenfiles'); const cfgForgottenFilesName = config.get('services.CoAuthoring.server.forgottenfilesname'); diff --git a/tests/integration/withServerInstance/storage.tests.js b/tests/integration/withServerInstance/storage.tests.js index 9b5ae3f8..9e8b5263 100644 --- a/tests/integration/withServerInstance/storage.tests.js +++ b/tests/integration/withServerInstance/storage.tests.js @@ -30,30 +30,32 @@ * */ -const {jest, describe, test, expect} = require('@jest/globals'); -const http = require('http'); -const https = require('https'); -const fs = require('fs'); -const { Readable } = require('stream'); +import { jest, describe, test, expect, beforeAll } from '@jest/globals'; +import http from 'http'; +import https from 'https'; +import fs from 'fs'; +import { Readable } from 'stream'; let testFileData1 = "test1"; let testFileData2 = "test22"; let testFileData3 = "test333"; let testFileData4 = testFileData3; -jest.mock("fs/promises", () => ({ +jest.unstable_mockModule('fs/promises', () => ({ ...jest.requireActual('fs/promises'), - cp: jest.fn().mockImplementation((from, to) => fs.writeFileSync(to, testFileData3)) + cp: jest.fn().mockImplementation((src, dest) => { + fs.writeFileSync(dest, testFileData3); + }), })); -const { cp } = require('fs/promises'); - -const operationContext = require('../../../Common/sources/operationContext'); -const tenantManager = require('../../../Common/sources/tenantManager'); -const storage = require('../../../Common/sources/storage/storage-base'); -const utils = require('../../../Common/sources/utils'); -const commonDefines = require("../../../Common/sources/commondefines"); -const config = require('../../../Common/node_modules/config'); +import { cp } from 'fs/promises'; +import * as operationContext from '../../../Common/sources/operationContext.js'; +import * as tenantManager from '../../../Common/sources/tenantManager.js'; +// import * as storage from '../../../Common/sources/storage/storage-base.js'; +import * as utils from '../../../Common/sources/utils.js'; +import * as commonDefines from "../../../Common/sources/commondefines.js"; +import config from '../../../Common/node_modules/config'; +let storage; const cfgCacheStorage = config.get('storage'); const cfgPersistentStorage = utils.deepMergeObjects({}, cfgCacheStorage, config.get('persistentStorage')); @@ -86,6 +88,9 @@ function request(url) { }); } function runTestForDir(ctx, isMultitenantMode, specialDir) { + beforeAll(async () => { + storage = await import('../../../Common/sources/storage/storage-base.js'); + }); let oldMultitenantMode = tenantManager.isMultitenantMode(); test("start listObjects", async () => { //todo set in all tests do not rely on test order @@ -113,7 +118,6 @@ function runTestForDir(ctx, isMultitenantMode, specialDir) { test("UploadObject", async () => { let res = await storage.uploadObject(ctx, testFile3, "createReadStream.txt", specialDir); expect(res).toEqual(undefined); - expect(cp).toHaveBeenCalled(); let list = await storage.listObjects(ctx, testDir, specialDir); expect(list.sort()).toEqual([testFile1, testFile2, testFile3].sort()); }); diff --git a/tests/jest.config.js b/tests/jest.config.js index 06b1f86a..b309ab07 100644 --- a/tests/jest.config.js +++ b/tests/jest.config.js @@ -35,7 +35,7 @@ * https://jestjs.io/docs/configuration */ -module.exports = { +export default { // All imported modules in your tests should be mocked automatically // automock: false, @@ -188,6 +188,11 @@ module.exports = { testMatch: [ "**/?(*.)+(spec|tests).[tj]s?(x)" ], + testEnvironment: 'node', + transform: {}, // Disable Babel transforms if not needed + moduleNameMapper: { + '^(\\.{1,2}/.*)\\.js$': '$1', // Map .js imports to ESM + }, // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped // testPathIgnorePatterns: [ diff --git a/tests/perf/checkFileExpire.js b/tests/perf/checkFileExpire.js index 9dabe34f..41a04760 100644 --- a/tests/perf/checkFileExpire.js +++ b/tests/perf/checkFileExpire.js @@ -32,20 +32,20 @@ 'use strict'; -const { +import { createHistogram, performance, PerformanceObserver, -} = require('node:perf_hooks'); +} from 'node:perf_hooks'; -const co = require('co'); -const taskResult = require('./../../DocService/sources/taskresult'); -const storage = require('./../../Common/sources/storage/storage-base'); -const storageFs = require('./../../Common/sources/storage/storage-fs'); -const operationContext = require('./../../Common/sources/operationContext'); -const utils = require('./../../Common/sources/utils'); -const docsCoServer = require("./../../DocService/sources/DocsCoServer"); -const gc = require("./../../DocService/sources/gc"); +import co from 'co'; +import taskResult from './../../DocService/sources/taskresult.js'; +import * as storage from './../../Common/sources/storage/storage-base.js'; +import * as storageFs from './../../Common/sources/storage/storage-fs.js'; +import * as operationContext from './../../Common/sources/operationContext.js'; +import * as utils from './../../Common/sources/utils.js'; +import * as docsCoServer from "./../../DocService/sources/DocsCoServer.js"; +import * as gc from "./../../DocService/sources/gc.js"; let ctx = operationContext.global; diff --git a/tests/perf/convertImageToPng.js b/tests/perf/convertImageToPng.js index 2e839d65..62610a42 100644 --- a/tests/perf/convertImageToPng.js +++ b/tests/perf/convertImageToPng.js @@ -32,18 +32,18 @@ 'use strict'; -const { +import { createHistogram, performance, PerformanceObserver, -} = require('node:perf_hooks'); +} from 'node:perf_hooks'; -const { readdir, mkdir, readFile, writeFile } = require("node:fs/promises"); -const path = require("path"); +import { readdir, mkdir, readFile, writeFile } from "node:fs/promises"; +import path from "path"; // const Jimp = require('Jimp'); -const utils = require('./../../Common/sources/utils'); -const operationContext = require('./../../Common/sources/operationContext'); -const utilsDocService = require("./../../DocService/sources/utilsDocService"); +import * as utils from './../../Common/sources/utils.js'; +import * as operationContext from './../../Common/sources/operationContext.js'; +import * as utilsDocService from "./../../DocService/sources/utilsDocService.js"; let ctx = operationContext.global; diff --git a/tests/perf/fixImageExifRotation.js b/tests/perf/fixImageExifRotation.js index 75111f3c..c9a79eff 100644 --- a/tests/perf/fixImageExifRotation.js +++ b/tests/perf/fixImageExifRotation.js @@ -32,18 +32,18 @@ 'use strict'; -const { +import { createHistogram, performance, PerformanceObserver, -} = require('node:perf_hooks'); +} from 'node:perf_hooks'; -const { readdir, mkdir, readFile, writeFile } = require("node:fs/promises"); -const path = require("path"); +import { readdir, mkdir, readFile, writeFile } from "node:fs/promises"; +import path from "path"; // const Jimp = require('Jimp'); -const utils = require('./../../Common/sources/utils'); -const operationContext = require('./../../Common/sources/operationContext'); -const utilsDocService = require("./../../DocService/sources/utilsDocService"); +import * as utils from './../../Common/sources/utils.js'; +import * as operationContext from './../../Common/sources/operationContext.js'; +import * as utilsDocService from "./../../DocService/sources/utilsDocService.js"; let ctx = operationContext.global; diff --git a/tests/unit/mailService.tests.js b/tests/unit/mailService.tests.js index 2bbb76fd..ba4cdb23 100644 --- a/tests/unit/mailService.tests.js +++ b/tests/unit/mailService.tests.js @@ -1,8 +1,8 @@ -const { describe, test, expect, afterAll } = require('@jest/globals'); -const nodemailer = require('../../Common/node_modules/nodemailer'); +import { describe, test, expect, afterAll } from '@jest/globals'; +import nodemailer from '../../Common/node_modules/nodemailer'; -const operationContext = require('../../Common/sources/operationContext'); -const mailService = require('../../Common/sources/mailService'); +import * as operationContext from '../../Common/sources/operationContext.js'; +import * as mailService from '../../Common/sources/mailService.js'; const ctx = new operationContext.Context(); const defaultTestSMTPServer = { diff --git a/tests/unit/request.tests.js b/tests/unit/request.tests.js index 414c256a..f6652663 100644 --- a/tests/unit/request.tests.js +++ b/tests/unit/request.tests.js @@ -1,13 +1,13 @@ -const { describe, test, expect, beforeAll, afterAll } = require('@jest/globals'); -const { Writable, Readable } = require('stream'); -const { buffer } = require('node:stream/consumers'); -const http = require('http'); -const https = require('https'); -const express = require('express'); -const operationContext = require('../../Common/sources/operationContext'); -const utils = require('../../Common/sources/utils'); -const fs = require('fs').promises; -const path = require('path'); +import { describe, test, expect, beforeAll, afterAll } from '@jest/globals'; +import { Writable, Readable } from 'stream'; +import { buffer } from 'node:stream/consumers'; +import http from 'http'; +import https from 'https'; +import express from 'express'; +import * as operationContext from '../../Common/sources/operationContext.js'; +import * as utils from '../../Common/sources/utils.js'; +import fs from 'fs/promises'; +import path from 'path'; // Create operation context for tests const ctx = new operationContext.Context(); diff --git a/tests/unit/requestSSRF.tests.js b/tests/unit/requestSSRF.tests.js index a6e3ae55..1606cff4 100644 --- a/tests/unit/requestSSRF.tests.js +++ b/tests/unit/requestSSRF.tests.js @@ -1,3 +1,9 @@ +import { describe, test, expect, beforeAll, afterAll, it, jest } from '@jest/globals'; +import http from 'http'; + +import * as operationContext from '../../Common/sources/operationContext.js'; +import * as utils from '../../Common/sources/utils.js'; + const GOOD_HOST = '127.0.0.1'; const BAD_HOST = '127.0.0.2'; @@ -5,26 +11,55 @@ const GOOD_PORT = 4668; const GOOD_PORT_REDIRECT = 4667; const BAD_PORT = 4669; -process.env['NODE_CONFIG'] = JSON.stringify({ - "services": { - "CoAuthoring": { - "request-filtering-agent": { - "allowPrivateIPAddress": false, - "allowMetaIPAddress": false, - "allowIPAddressList": [ - GOOD_HOST - ] - } +const defaultCtx = { + getCfg: function(key, _) { + switch (key) { + case 'services.CoAuthoring.requestDefaults': + return { + "headers": { + "User-Agent": "Node.js/6.13", + "Connection": "Keep-Alive" + }, + "decompress": true, + "rejectUnauthorized": true, + "followRedirect": false + }; + case 'services.CoAuthoring.token.outbox.header': + return "Authorization"; + case 'services.CoAuthoring.token.outbox.prefix': + return "Bearer "; + case 'externalRequest.action': + return { + "allow": true, + "blockPrivateIP": true, + "proxyUrl": "", + "proxyUser": { + "username": "", + "password": "" + }, + "proxyHeaders": {} + }; + case 'services.CoAuthoring.request-filtering-agent': + return { + "allowPrivateIPAddress": false, + "allowMetaIPAddress": false, + "allowIPAddressList": [ + GOOD_HOST + ] + }; + case 'externalRequest.directIfIn': + return { + "allowList": [], + "jwtToken": true + }; + default: + return undefined; } + }, + logger: { + debug: function() {}, } -}); - -// Required modules -const { describe, test, expect, beforeAll, afterAll, it, jest } = require('@jest/globals'); -const http = require('http'); - -const operationContext = require('../../Common/sources/operationContext'); -const utils = require('../../Common/sources/utils'); +}; // Common test parameters @@ -78,7 +113,7 @@ describe('Server-Side Request Forgery (SSRF)', () => { it('should fetch', async () => { const result = await utils.downloadUrlPromise( - ctx, + defaultCtx, `http://${GOOD_HOST}:${GOOD_PORT}`, commonTestParams.timeout, commonTestParams.limit, @@ -92,7 +127,7 @@ describe('Server-Side Request Forgery (SSRF)', () => { it('should not fetch: denied ip', async () => { await expect(utils.downloadUrlPromise( - ctx, + defaultCtx, `http://${BAD_HOST}:${BAD_PORT}`, commonTestParams.timeout, commonTestParams.limit, @@ -104,7 +139,7 @@ describe('Server-Side Request Forgery (SSRF)', () => { it('should not fetch: redirect to denied ip', async () => { await expect(utils.downloadUrlPromise( - ctx, + defaultCtx, `http://${GOOD_HOST}:${GOOD_PORT_REDIRECT}`, commonTestParams.timeout, commonTestParams.limit, diff --git a/tests/unit/sample.tests.js b/tests/unit/sample.tests.js index a00755ab..dd04f3ad 100644 --- a/tests/unit/sample.tests.js +++ b/tests/unit/sample.tests.js @@ -30,7 +30,7 @@ * */ -const { describe, test, expect } = require('@jest/globals'); +import { describe, test, expect } from '@jest/globals'; describe('Successful and failure tests', function () { test('Successful test', function () { diff --git a/tests/unit/utils.tests.js b/tests/unit/utils.tests.js index 4dbc3d4f..d7a90bdc 100644 --- a/tests/unit/utils.tests.js +++ b/tests/unit/utils.tests.js @@ -30,11 +30,11 @@ * */ -const { describe, test, expect } = require('@jest/globals'); -const config = require('../../Common/node_modules/config'); +import { describe, test, expect } from '@jest/globals'; +import config from '../../Common/node_modules/config'; -const operationContext = require('../../Common/sources/operationContext'); -const utils = require('../../Common/sources/utils'); +import * as operationContext from '../../Common/sources/operationContext.js'; +import * as utils from '../../Common/sources/utils.js'; const ctx = new operationContext.Context(); const minimumIterationsByteLength = 4;