import { DbResponseStatus } from "@itwin/core-common";
import { expect } from "chai";
import { ConcurrentQuery } from "../../ConcurrentQuery";
import { SnapshotDb } from "../../IModelDb";
import { _nativeDb } from "../../core-backend";
import { IModelTestUtils } from "../IModelTestUtils";
async function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}
describe("ConcurrentQuery", () => {
    it("default config", () => {
        const testFile = IModelTestUtils.resolveAssetFile("test.bim");
        const db = SnapshotDb.openFile(testFile);
        const defaultConfig = {
            autoShutdownWhenIdleForSeconds: 1800,
            doNotUsePrimaryConnToPrepare: false,
            globalQuota: { time: 60, memory: 8388608 },
            ignoreDelay: true,
            ignorePriority: false,
            memoryMapFileSize: 0,
            monitorPollInterval: 5000,
            progressOpCount: 5000,
            requestQueueSize: 2000,
            statementCacheSizePerWorker: 40,
            workerThreads: 4,
        };
        const config = ConcurrentQuery.resetConfig(db[_nativeDb], {});
        expect(config).deep.eq(defaultConfig);
        db.close();
    });
    it("modify config", () => {
        const testFile = IModelTestUtils.resolveAssetFile("test.bim");
        const db = SnapshotDb.openFile(testFile);
        const modifiedConfig = {
            autoShutdownWhenIdleForSeconds: 100,
            doNotUsePrimaryConnToPrepare: true,
            globalQuota: { time: 10, memory: 1000000 },
            ignoreDelay: false,
            ignorePriority: true,
            memoryMapFileSize: 100,
            monitorPollInterval: 2000,
            progressOpCount: 6000,
            requestQueueSize: 1000,
            statementCacheSizePerWorker: 20,
            workerThreads: 3,
        };
        const config = ConcurrentQuery.resetConfig(db[_nativeDb], modifiedConfig);
        expect(config).deep.eq(modifiedConfig);
        db.close();
    });
    it("time limit check", async () => {
        const testFile = IModelTestUtils.resolveAssetFile("test.bim");
        const db = SnapshotDb.openFile(testFile);
        ConcurrentQuery.resetConfig(db[_nativeDb], { globalQuota: { time: 1, memory: 100000 }, progressOpCount: 1000 });
        // await runSingleRequest(db, `SELECT 1`);
        const req = {
            query: `WITH sequence(n,k) AS (
                SELECT  1,1 UNION ALL SELECT n + 1, random() FROM sequence WHERE n < 10000000
              ) SELECT COUNT(*) FROM sequence s`
        };
        const resp = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], req);
        expect(resp.status).equals(DbResponseStatus.Partial);
        expect(resp.stats.timeLimit).equals(1000);
        expect(resp.stats.memLimit).equals(100000);
        expect(resp.stats.cpuTime).to.be.closeTo(1000970, 500000);
        expect(resp.stats.totalTime).to.be.closeTo(1001, 100);
        expect(resp.stats.memUsed).to.be.closeTo(2, 3);
        expect(resp.stats.prepareTime).to.be.closeTo(0, 2);
        db.close();
    });
    it("memory limit check", async () => {
        const testFile = IModelTestUtils.resolveAssetFile("test.bim");
        const db = SnapshotDb.openFile(testFile);
        ConcurrentQuery.resetConfig(db[_nativeDb], { globalQuota: { time: 60, memory: 1000 }, progressOpCount: 1000 });
        // await runSingleRequest(db, `SELECT 1`);
        const req = {
            query: `WITH sequence(n) AS (
                SELECT  1
                UNION ALL
                SELECT n + 1 FROM sequence WHERE n < 10000000
              )
              SELECT 'xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx' FROM sequence s`
        };
        const resp = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], req);
        expect(resp.status).equals(DbResponseStatus.Partial);
        expect(resp.stats.timeLimit).equals(60000);
        expect(resp.stats.memLimit).equals(1000);
        expect(resp.stats.memUsed).to.be.closeTo(1037, 100);
        db.close();
    });
    it("prepare error", async () => {
        const testFile = IModelTestUtils.resolveAssetFile("test.bim");
        const db = SnapshotDb.openFile(testFile);
        const req = {
            query: `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
        };
        const resp = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], req);
        expect(resp.status).equals(DbResponseStatus.Error_ECSql_PreparedFailed);
        db.close();
    });
    it("restart query", async () => {
        const testFile = IModelTestUtils.resolveAssetFile("test.bim");
        const db = SnapshotDb.openFile(testFile);
        ConcurrentQuery.resetConfig(db[_nativeDb], { globalQuota: { time: 60, memory: 10000000 }, progressOpCount: 1000 });
        const req0 = {
            query: `WITH sequence(n) AS (
                SELECT  1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 10000000
              ) SELECT n FROM sequence s`,
            restartToken: "Blah",
        };
        const req1 = {
            query: `WITH sequence(n) AS (
                SELECT  1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 1000
              ) SELECT n FROM sequence s`,
            restartToken: "Blah",
        };
        const resp1 = ConcurrentQuery.executeQueryRequest(db[_nativeDb], req0);
        await delay(1);
        const resp2 = ConcurrentQuery.executeQueryRequest(db[_nativeDb], req1);
        const resp = await Promise.all([resp1, resp2]);
        expect(resp[0].status).equals(DbResponseStatus.Cancel);
        expect(resp[1].status).equals(DbResponseStatus.Done);
        db.close();
    });
    it("queue limit check", async () => {
        const testFile = IModelTestUtils.resolveAssetFile("test.bim");
        const db = SnapshotDb.openFile(testFile);
        ConcurrentQuery.resetConfig(db[_nativeDb], { requestQueueSize: 40, globalQuota: { time: 5, memory: 100000 } });
        const req = {
            query: `WITH sequence(n) AS (
                SELECT  1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 10000000
              ) SELECT n FROM sequence s`,
        };
        const responsePromises = [];
        for (let i = 0; i < 60; ++i) {
            responsePromises.push(ConcurrentQuery.executeQueryRequest(db[_nativeDb], req));
        }
        const responses = await Promise.all(responsePromises);
        const queueResponses = Array.from(responses.filter((x) => x.status === DbResponseStatus.QueueFull));
        expect(queueResponses.length).to.be.greaterThanOrEqual(10);
        db.close();
    });
    it("timeout check", async () => {
        const testFile = IModelTestUtils.resolveAssetFile("test.bim");
        const db = SnapshotDb.openFile(testFile);
        ConcurrentQuery.resetConfig(db[_nativeDb], { monitorPollInterval: 1, globalQuota: { time: 5, memory: 10000000 } });
        const req = {
            query: `WITH sequence(n) AS (
                SELECT  1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 10000000
              ) SELECT n FROM sequence s`,
        };
        const responsePromises = [];
        for (let i = 0; i < 100; ++i) {
            responsePromises.push(ConcurrentQuery.executeQueryRequest(db[_nativeDb], req));
        }
        const responses = await Promise.all(responsePromises);
        const queueResponses = Array.from(responses.filter((x) => x.status === DbResponseStatus.Timeout));
        expect(queueResponses.length).to.be.greaterThanOrEqual(10);
        db.close();
    });
});
//# sourceMappingURL=ConcurrentQuery.test.js.map