"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const Utils_1 = __importDefault(require("../Utils"));
const Datastore_1 = __importDefault(require("../../src/common/Datastore"));
const DealPreparationWorker_1 = __importDefault(require("../../src/deal-preparation/DealPreparationWorker"));
const Scanner_1 = __importDefault(require("../../src/deal-preparation/Scanner"));
const fs = __importStar(require("fs/promises"));
describe('DealPreparationWorker', () => {
    let worker;
    beforeAll(async () => {
        await Utils_1.default.initDatabase();
        worker = new DealPreparationWorker_1.default();
    });
    beforeEach(async () => {
        await Datastore_1.default.ScanningRequestModel.remove();
        await Datastore_1.default.GenerationRequestModel.remove();
        await Datastore_1.default.InputFileListModel.remove();
        await Datastore_1.default.OutputFileListModel.remove();
    });
    afterAll(async () => {
        for (const file of await fs.readdir('.')) {
            if (file.endsWith('.car')) {
                await fs.rm(file);
            }
        }
    });
    describe('startPollWork', () => {
        it('should immediately start next job if Scan work finishes', async () => {
            const spy = spyOn(global, 'setTimeout');
            const spyScanning = spyOn(worker, 'pollScanningWork').and.resolveTo(true);
            const spyGeneration = spyOn(worker, 'pollGenerationWork').and.resolveTo(false);
            await worker['startPollWork']();
            expect(spyScanning).toHaveBeenCalled();
            expect(spyGeneration).not.toHaveBeenCalled();
            expect(spy).toHaveBeenCalledWith(jasmine.anything(), worker['ImmediatePollInterval']);
        });
        it('should immediately start next job if Generation work finishes', async () => {
            const spy = spyOn(global, 'setTimeout');
            const spyScanning = spyOn(worker, 'pollScanningWork').and.resolveTo(false);
            const spyGeneration = spyOn(worker, 'pollGenerationWork').and.resolveTo(true);
            await worker['startPollWork']();
            expect(spyScanning).toHaveBeenCalled();
            expect(spyGeneration).toHaveBeenCalled();
            expect(spy).toHaveBeenCalledWith(jasmine.anything(), worker['ImmediatePollInterval']);
        });
        it('should poll for next job after 5s if no work found', async () => {
            const spy = spyOn(global, 'setTimeout');
            const spyScanning = spyOn(worker, 'pollScanningWork').and.resolveTo(false);
            const spyGeneration = spyOn(worker, 'pollGenerationWork').and.resolveTo(false);
            await worker['startPollWork']();
            expect(spyScanning).toHaveBeenCalled();
            expect(spyGeneration).toHaveBeenCalled();
            expect(spy).toHaveBeenCalledWith(jasmine.anything(), worker['PollInterval']);
        });
    });
    describe('healthCheck', () => {
        it('should create an entry in HealthCheck table', async () => {
            await worker['healthCheck']();
            const found = await Datastore_1.default.HealthCheckModel.findOne({ workerId: worker['workerId'] });
            expect(found).not.toBeNull();
            expect(found.workerId).toEqual(worker['workerId']);
            expect(found.updatedAt).not.toBeNull();
        });
    });
    describe('pollWork', () => {
        it('should update with error if file no longer exists', async () => {
            const created = await Datastore_1.default.GenerationRequestModel.create({
                datasetId: 'id',
                datasetName: 'name',
                path: 'tests/test_folder',
                index: 0,
                status: 'active',
                outDir: '.',
            });
            await Datastore_1.default.InputFileListModel.create({
                generationId: created.id,
                index: 0,
                fileList: [
                    {
                        path: 'tests/test_folder/not_exists.txt',
                        size: 3,
                        start: 0,
                        end: 0
                    }
                ]
            });
            await worker['pollWork']();
            const found = await Datastore_1.default.GenerationRequestModel.findById(created.id);
            expect(found).toEqual(jasmine.objectContaining({
                status: 'error',
                errorMessage: jasmine.stringMatching(/no such file or directory|cannot find the file/)
            }));
        });
        it('should generate commp, car files', async () => {
            const created = await Datastore_1.default.GenerationRequestModel.create({
                datasetId: 'id',
                datasetName: 'name',
                path: 'tests/test_folder',
                index: 0,
                status: 'active',
                outDir: '.',
                tmpDir: './tmpdir'
            });
            await Datastore_1.default.InputFileListModel.create({
                generationId: created.id,
                index: 0,
                fileList: [
                    {
                        path: 'tests/test_folder/a/1.txt',
                        size: 3,
                    },
                    {
                        path: 'tests/test_folder/b/2.txt',
                        size: 27,
                        start: 0,
                        end: 9,
                    }
                ]
            });
            await worker['pollWork']();
            const found = await Datastore_1.default.GenerationRequestModel.findById(created.id);
            expect(found).toEqual(jasmine.objectContaining({
                status: 'completed',
                dataCid: 'bafybeih2nwd66s7rstnbj4grzjw7re4lyhmx3auvphibbz7nalo4ygfypq',
                pieceCid: 'baga6ea4seaqoqixvkneyg6tzwfoqsmw33xdva3aywkawp6n5jd5tffjdmqrn6gy',
                pieceSize: 512,
            }));
            const generatedFileList = await Datastore_1.default.OutputFileListModel.findOne({
                generatedId: created.id
            });
            expect(generatedFileList).toEqual(jasmine.objectContaining({
                index: 0,
                generatedFileList: [
                    jasmine.objectContaining({
                        path: '',
                        dir: true,
                        cid: 'bafybeih2nwd66s7rstnbj4grzjw7re4lyhmx3auvphibbz7nalo4ygfypq',
                        selector: []
                    }),
                    jasmine.objectContaining({
                        path: 'a',
                        dir: true,
                        cid: 'bafybeifd34zco7545dzqflv7djpi3q2l2egi4l4coohgftgjssn4zoeu2y',
                        selector: [0]
                    }),
                    jasmine.objectContaining({
                        path: path_1.default.join('a', '1.txt'),
                        size: 3,
                        dir: false,
                        cid: 'bafkreiey5jxe6ilpf62lnh77tm5ejbbmhbugzjuf6p2v3remlu73ced34q',
                        selector: [0, 0],
                    }),
                    jasmine.objectContaining({
                        path: 'b',
                        dir: true,
                        cid: 'bafybeif7zaqg45xk5zvwybbfgeiotkzvjmd4bpjasb4aevne57dpt67com',
                        selector: [1]
                    }),
                    jasmine.objectContaining({
                        path: path_1.default.join('b', '2.txt'),
                        size: 27,
                        start: 0,
                        end: 9,
                        dir: false,
                        cid: 'bafkreiblmv6wzk3grdk7u5a7u5zqh5vez3zatwuk3ptparw45unujqxysi',
                        selector: [1, 0]
                    }),
                ]
            }));
        });
        it('should insert the database with fileLists', async () => {
            const created = await Datastore_1.default.ScanningRequestModel.create({
                name: 'name',
                path: 'tests/test_folder',
                minSize: 12,
                maxSize: 16,
                status: 'active'
            });
            expect(await worker['pollWork']()).toEqual(true);
            const found = await Datastore_1.default.ScanningRequestModel.findById(created.id);
            expect(found.status).toEqual('completed');
            expect(await Datastore_1.default.GenerationRequestModel.find({ datasetId: created.id })).toHaveSize(4);
        });
        it('should update the database with error message if it counter any error', async () => {
            const created = await Datastore_1.default.ScanningRequestModel.create({
                name: 'name',
                path: '/home/shane/test_folder_not_exist',
                minSize: 12,
                maxSize: 16,
                status: 'active'
            });
            expect(await worker['pollWork']()).toEqual(true);
            expect(await Datastore_1.default.ScanningRequestModel.findById(created.id)).toEqual(jasmine.objectContaining({
                status: 'error',
                errorMessage: jasmine.stringContaining('ENOENT')
            }));
        });
    });
    describe('scan', () => {
        it('should work with >1000 fileList', async () => {
            let fileList = Array(5000).fill(null).map((_, i) => ({
                path: `tests/test_folder/folder/${i}.txt`,
                size: 100,
                selector: [],
                start: 0,
                end: 0,
                dir: false
            }));
            const f = async function* () {
                yield fileList;
            };
            spyOn(Scanner_1.default, 'scan').and.returnValue(f());
            await worker['scan']({
                id: '507f1f77bcf86cd799439011',
                name: 'name',
                path: 'tests/test_folder',
                minSize: 12,
                maxSize: 16,
                status: 'active',
                outDir: '.'
            });
            const requests = await Datastore_1.default.GenerationRequestModel.find({}, null, { sort: { index: 1 } });
            expect(requests.length).toEqual(1);
            const list = await Datastore_1.default.InputFileListModel.find({ generationId: requests[0].id }, null, { sort: { index: 1 } });
            expect(list.length).toEqual(5);
            expect(list[0].fileList.length).toEqual(1000);
            expect(list[0].fileList[0].path).toEqual('tests/test_folder/folder/0.txt');
            expect(list[4].index).toEqual(4);
            expect(list[4].fileList[999].path).toEqual('tests/test_folder/folder/4999.txt');
        });
        it('should get the correct fileList', async () => {
            await worker['scan']({
                id: '507f191e810c19729de860ea',
                name: 'name',
                path: path_1.default.join('tests', 'test_folder'),
                minSize: 12,
                maxSize: 16,
                status: 'active',
                outDir: '.',
                tmpDir: './tmpdir'
            });
            const requests = await Datastore_1.default.GenerationRequestModel.find({}, null, { sort: { index: 1 } });
            /**
             * a/1.txt -> 3 bytes
             * b/2.txt -> 27 bytes
             * c/3.txt -> 9 bytes
             * d.txt   -> 9 bytes (symlink)
             * 0. a/1.txt (3) + b/2.txt (9) = 12
             * 1. b/2.txt(12) = 12
             * 2. b/2.txt(6) + c/3.txt(9) = 15
             * 3. d.txt(9) = 9
             */
            expect(requests.length).toEqual(4);
            expect(requests[0]).toEqual(jasmine.objectContaining({
                datasetId: '507f191e810c19729de860ea',
                datasetName: 'name',
                path: path_1.default.join('tests', 'test_folder'),
                index: 0,
                status: 'active',
                outDir: '.',
                tmpDir: './tmpdir'
            }));
            expect(await Datastore_1.default.InputFileListModel.findOne({ generationId: requests[0].id })).toEqual(jasmine.objectContaining({
                fileList: [jasmine.objectContaining({
                        path: path_1.default.join('tests', 'test_folder', 'a', '1.txt'),
                        size: 3,
                    }), jasmine.objectContaining({
                        path: path_1.default.join('tests', 'test_folder', 'b', '2.txt'),
                        size: 27,
                        start: 0,
                        end: 9,
                    })],
            }));
            expect(requests[1]).toEqual(jasmine.objectContaining({
                datasetId: '507f191e810c19729de860ea',
                datasetName: 'name',
                path: path_1.default.join('tests', 'test_folder'),
                index: 1,
                status: 'active',
                outDir: '.',
                tmpDir: './tmpdir'
            }));
            expect(await Datastore_1.default.InputFileListModel.findOne({ generationId: requests[1].id })).toEqual(jasmine.objectContaining({
                fileList: [jasmine.objectContaining({
                        path: path_1.default.join('tests', 'test_folder', 'b', '2.txt'),
                        size: 27,
                        start: 9,
                        end: 21,
                    })],
            }));
            expect(requests[2]).toEqual(jasmine.objectContaining({
                datasetId: '507f191e810c19729de860ea',
                datasetName: 'name',
                path: path_1.default.join('tests', 'test_folder'),
                index: 2,
                status: 'active',
                outDir: '.',
                tmpDir: './tmpdir'
            }));
            expect(await Datastore_1.default.InputFileListModel.findOne({ generationId: requests[2].id })).toEqual(jasmine.objectContaining({
                fileList: [jasmine.objectContaining({
                        path: path_1.default.join('tests', 'test_folder', 'b', '2.txt'),
                        size: 27,
                        start: 21,
                        end: 27,
                    }), jasmine.objectContaining({
                        path: path_1.default.join('tests', 'test_folder', 'c', '3.txt'),
                        size: 9,
                    })],
            }));
            // windows does not support symbolic link
            const dtxtsize = process.platform === 'win32' ? 7 : 9;
            expect(requests[3]).toEqual(jasmine.objectContaining({
                datasetId: '507f191e810c19729de860ea',
                datasetName: 'name',
                path: path_1.default.join('tests', 'test_folder'),
                index: 3,
                status: 'active',
                outDir: '.',
                tmpDir: './tmpdir'
            }));
            expect(await Datastore_1.default.InputFileListModel.findOne({ generationId: requests[3].id })).toEqual(jasmine.objectContaining({
                fileList: [jasmine.objectContaining({
                        path: path_1.default.join('tests', 'test_folder', 'd.txt'),
                        size: dtxtsize,
                    })]
            }));
        });
    });
});
//# sourceMappingURL=DealPreparationWorker.spec.js.map