"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const Storage_1 = require("../../../Storage");
const cdmStatusLevel_1 = require("../../../Cdm/cdmStatusLevel");
const cdmObjectType_1 = require("../../../Enums/cdmObjectType");
const Persistence_1 = require("../../../Persistence");
const resolveContext_1 = require("../../../Utilities/resolveContext");
const testHelper_1 = require("../../testHelper");
// tslint:disable-next-line: max-func-body-length
describe('Cdm/DataPartitionPattern/DataPartitionPattern', () => {
    /**
     * The path between TestDataPath and TestName.
     */
    const testsSubpath = 'Cdm/DataPartitionPattern';
    /**
     * Tests refreshing files that match the regular expression
     */
    it('TestRefreshDataPartitionPatterns', (done) => __awaiter(void 0, void 0, void 0, function* () {
        const cdmCorpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestRefreshDataPartitionPatterns');
        const cdmManifest = yield cdmCorpus.fetchObjectAsync('local:/patternManifest.manifest.cdm.json');
        const partitionEntity = cdmManifest.entities.allItems[1];
        expect(partitionEntity.dataPartitions.length)
            .toBe(1);
        const timeBeforeLoad = new Date();
        yield cdmManifest.fileStatusCheckAsync();
        // file status check should check patterns and add two more partitions that match the pattern
        // should not re-add already existing partitions
        expect(partitionEntity.dataPartitions.length)
            .toBe(8);
        const partitionFromPattern = partitionEntity.dataPartitions.allItems[2];
        expect(partitionFromPattern.location)
            .toBe('partitions/someSubFolder/someSubPartition.csv');
        expect(partitionFromPattern.specializedSchema)
            .toBe('test special schema');
        expect(partitionFromPattern.lastFileStatusCheckTime >= timeBeforeLoad)
            .toBe(true);
        // inherits the exhibited traits from pattern
        expect(partitionFromPattern.exhibitsTraits.length)
            .toBe(1);
        expect(partitionFromPattern.exhibitsTraits.allItems[0].namedReference)
            .toBe('is');
        expect(partitionFromPattern.arguments.size)
            .toBe(1);
        expect(partitionFromPattern.arguments.has('testParam1'))
            .toBeTruthy();
        expect(partitionFromPattern.arguments.get('testParam1').length)
            .toBe(1);
        expect(partitionFromPattern.arguments.get('testParam1')[0])
            .toEqual('/someSubFolder/someSub');
        // captures pattern in folder
        const folderCapturePartition = partitionEntity.dataPartitions.allItems[3];
        expect(folderCapturePartition.location)
            .toBe('partitions/2018/folderCapture.csv');
        expect(folderCapturePartition.arguments.size)
            .toBe(1);
        expect(folderCapturePartition.arguments.get('year')[0])
            .toEqual('2018');
        // multiple capture groups in folder
        const multipleCapturePartition = partitionEntity.dataPartitions.allItems[4];
        expect(multipleCapturePartition.location)
            .toBe('partitions/2018/8/15/folderCapture.csv');
        expect(multipleCapturePartition.arguments.size)
            .toBe(3);
        expect(multipleCapturePartition.arguments.get('year')[0])
            .toEqual('2018');
        expect(multipleCapturePartition.arguments.get('month')[0])
            .toEqual('8');
        expect(multipleCapturePartition.arguments.get('day')[0])
            .toEqual('15');
        // multiple captures in the same capture group
        const multipleCaptureSameGroup = partitionEntity.dataPartitions.allItems[5];
        expect(multipleCaptureSameGroup.location)
            .toBe('partitions/2018/8/15/folderCaptureRepeatedGroup.csv');
        expect(multipleCaptureSameGroup.arguments.size)
            .toBe(1);
        expect(multipleCaptureSameGroup.arguments.get('day')[0])
            .toEqual('15');
        // tests where there are more captures than parameters
        const tooFewPartition = partitionEntity.dataPartitions.allItems[6];
        expect(tooFewPartition.location)
            .toBe('partitions/testTooFew.csv');
        expect(tooFewPartition.arguments.size)
            .toBe(0);
        // tests where there are fewer captures than parameters
        const tooManyPartition = partitionEntity.dataPartitions.allItems[7];
        expect(tooManyPartition.location)
            .toBe('partitions/testTooMany.csv');
        expect(tooManyPartition.arguments.size)
            .toBe(0);
        done();
    }));
    /**
     * Testing that error is handled when partition pattern contains a folder that does not exist
     */
    it('TestPatternWithNonExistingFolder', (done) => __awaiter(void 0, void 0, void 0, function* () {
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestPatternWithNonExistingFolder');
        const content = testHelper_1.testHelper.getInputFileContent(testsSubpath, 'TestPatternWithNonExistingFolder', 'entities.manifest.cdm.json');
        const cdmManifest = Persistence_1.CdmFolder.ManifestPersistence.fromObject(new resolveContext_1.resolveContext(corpus, undefined), 'entities', 'local', '/', JSON.parse(content));
        let errorLogged = 0;
        corpus.setEventCallback((statusLevel, message) => {
            if (message.indexOf('Failed to fetch all files in the folder location \'local:/testLocation\' described by a partition pattern. Exception') !== -1) {
                errorLogged++;
            }
        }, cdmStatusLevel_1.cdmStatusLevel.warning);
        yield cdmManifest.fileStatusCheckAsync();
        expect(errorLogged)
            .toBe(1);
        expect(cdmManifest.entities.allItems[0].dataPartitions.length)
            .toBe(0);
        // make sure the last check time is still being set
        expect(cdmManifest.entities.allItems[0].dataPartitionPatterns.allItems[0].lastFileStatusCheckTime)
            .not
            .toBeUndefined();
        done();
    }));
    /**
     * Testing that partition is correctly found when namespace of pattern differs from namespace of the manifest
     */
    it('TestPatternWithDifferentNamespace', (done) => __awaiter(void 0, void 0, void 0, function* () {
        const testName = 'TestPatternWithDifferentNamespace';
        const cdmCorpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, testName);
        const localAdapter = cdmCorpus.storage.fetchAdapter('local');
        const localPath = localAdapter.fullRoot;
        cdmCorpus.storage.mount('other', new Storage_1.LocalAdapter(path.join(localPath, 'other')));
        var cdmManifest = yield cdmCorpus.fetchObjectAsync('local:/patternManifest.manifest.cdm.json');
        yield cdmManifest.fileStatusCheckAsync();
        expect(cdmManifest.entities.allItems[0].dataPartitions.length)
            .toBe(1);
        done();
    }));
    /**
     * Testing that patterns behave correctly with variations to rootLocation
     */
    it('TestVariationsInRootLocation', (done) => __awaiter(void 0, void 0, void 0, function* () {
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestVariationsInRootLocation');
        const manifest = yield corpus.fetchObjectAsync('pattern.manifest.cdm.json');
        yield manifest.fileStatusCheckAsync();
        const startsWithSlash = manifest.entities.allItems[0];
        expect(startsWithSlash.dataPartitionPatterns.allItems[0].regularExpression)
            .toBe('.*testfile.csv');
        expect(startsWithSlash.dataPartitions.length)
            .toBe(1);
        expect(startsWithSlash.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        const endsWithSlash = manifest.entities.allItems[1];
        expect(endsWithSlash.dataPartitionPatterns.allItems[0].regularExpression)
            .toBe('.*testfile.csv');
        expect(endsWithSlash.dataPartitions.length)
            .toBe(1);
        expect(endsWithSlash.dataPartitions.allItems[0].location)
            .toBe('partitions/testfile.csv');
        const noSlash = manifest.entities.allItems[2];
        expect(noSlash.dataPartitionPatterns.allItems[0].regularExpression)
            .toBe('.*testfile.csv');
        expect(noSlash.dataPartitions.length)
            .toBe(1);
        expect(noSlash.dataPartitions.allItems[0].location)
            .toBe('partitions/testfile.csv');
        done();
    }));
    /**
     * Testing data partition patterns that use glob patterns
     */
    it('TestPartitionPatternWithGlob', (done) => __awaiter(void 0, void 0, void 0, function* () {
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestPartitionPatternWithGlob');
        let patternsWithGlobAndRegex = 0;
        corpus.setEventCallback((level, msg) => {
            if (msg.indexOf('CdmDataPartitionPatternDefinition | The Data Partition Pattern contains both a glob pattern (/testfile.csv) and a regular expression (/subFolder/testSubFile.csv) set, the glob pattern will be used. | fileStatusCheckAsync') != -1) {
                patternsWithGlobAndRegex++;
            }
        }, cdmStatusLevel_1.cdmStatusLevel.warning);
        const manifest = yield corpus.fetchObjectAsync('pattern.manifest.cdm.json');
        yield manifest.fileStatusCheckAsync();
        // one pattern object contains both glob and regex
        expect(patternsWithGlobAndRegex)
            .toBe(1);
        let index = 0;
        // make sure '.' in glob is not converted to '.' in regex
        const dotIsEscaped = manifest.entities.allItems[index];
        expect(dotIsEscaped.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('test.ile.csv');
        expect(dotIsEscaped.dataPartitions.length)
            .toBe(0);
        index++;
        // star pattern should match anything in the root folder
        const onlyStar = manifest.entities.allItems[index];
        expect(onlyStar.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('*');
        expect(onlyStar.dataPartitions.length)
            .toBe(1);
        expect(onlyStar.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        index++;
        // star can match nothing
        const starNoMatch = manifest.entities.allItems[index];
        expect(starNoMatch.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('/testfile*.csv');
        expect(starNoMatch.dataPartitions.length)
            .toBe(1);
        expect(starNoMatch.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        index++;
        // star at root level
        // this should match any files at root level, none in subfolders
        const starAtRoot = manifest.entities.allItems[index];
        expect(starAtRoot.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('/*.csv');
        expect(starAtRoot.dataPartitions.length)
            .toBe(1);
        expect(starAtRoot.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        index++;
        // star at deeper level
        const starAtDeeperLevel = manifest.entities.allItems[index];
        expect(starAtDeeperLevel.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('/*/*.csv');
        expect(starAtDeeperLevel.dataPartitions.length)
            .toBe(1);
        expect(starAtDeeperLevel.dataPartitions.allItems[0].location)
            .toBe('/partitions/subFolder/testSubFile.csv');
        index++;
        // pattern that ends with star
        const endsWithStar = manifest.entities.allItems[index];
        expect(endsWithStar.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('/testfile*');
        expect(endsWithStar.dataPartitions.length)
            .toBe(1);
        expect(endsWithStar.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        index++;
        // globstar (**) on its own matches
        const globStar = manifest.entities.allItems[index];
        expect(globStar.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('**');
        expect(globStar.dataPartitions.length)
            .toBe(2);
        expect(globStar.dataPartitions.allItems.filter((x) => x.location === '/partitions/testfile.csv').length)
            .toBe(1);
        expect(globStar.dataPartitions.allItems.filter((x) => x.location === '/partitions/subFolder/testSubFile.csv').length)
            .toBe(1);
        index++;
        // globstar at the beginning of the pattern
        const beginsWithGlobstar = manifest.entities.allItems[index];
        expect(beginsWithGlobstar.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('/**.csv');
        expect(beginsWithGlobstar.dataPartitions.length)
            .toBe(1);
        expect(beginsWithGlobstar.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        index++;
        // globstar at the end of the pattern
        const endsWithGlobstar = manifest.entities.allItems[index];
        expect(endsWithGlobstar.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('/**');
        expect(endsWithGlobstar.dataPartitions.length)
            .toBe(2);
        expect(endsWithGlobstar.dataPartitions.allItems.filter((x) => x.location === '/partitions/testfile.csv').length)
            .toBe(1);
        expect(endsWithGlobstar.dataPartitions.allItems.filter((x) => x.location === '/partitions/subFolder/testSubFile.csv').length)
            .toBe(1);
        index++;
        // globstar matches zero or more folders
        const zeroOrMoreFolders = manifest.entities.allItems[index];
        expect(zeroOrMoreFolders.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('/**/*.csv');
        expect(zeroOrMoreFolders.dataPartitions.length)
            .toBe(2);
        expect(zeroOrMoreFolders.dataPartitions.allItems.filter((x) => x.location === '/partitions/testfile.csv').length)
            .toBe(1);
        expect(zeroOrMoreFolders.dataPartitions.allItems.filter((x) => x.location === '/partitions/subFolder/testSubFile.csv').length)
            .toBe(1);
        index++;
        // globstar matches zero or more folders without starting slash
        const zeroOrMoreNoStartingSlash = manifest.entities.allItems[index];
        expect(zeroOrMoreNoStartingSlash.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('/**/*.csv');
        expect(zeroOrMoreNoStartingSlash.dataPartitions.length)
            .toBe(2);
        expect(zeroOrMoreNoStartingSlash.dataPartitions.allItems.filter((x) => x.location === '/partitions/testfile.csv').length)
            .toBe(1);
        expect(zeroOrMoreNoStartingSlash.dataPartitions.allItems.filter((x) => x.location === '/partitions/subFolder/testSubFile.csv').length)
            .toBe(1);
        index++;
        // question mark in the middle of a pattern
        const questionMark = manifest.entities.allItems[index];
        expect(questionMark.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('/test?ile.csv');
        expect(questionMark.dataPartitions.length)
            .toBe(1);
        expect(questionMark.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        index++;
        // question mark at the beginning of a pattern
        const beginsWithQuestionMark = manifest.entities.allItems[index];
        expect(beginsWithQuestionMark.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('/?estfile.csv');
        expect(beginsWithQuestionMark.dataPartitions.length)
            .toBe(1);
        expect(beginsWithQuestionMark.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        index++;
        // question mark at the end of a pattern
        const endsWithQuestionMark = manifest.entities.allItems[index];
        expect(endsWithQuestionMark.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('/testfile.cs?');
        expect(endsWithQuestionMark.dataPartitions.length)
            .toBe(1);
        expect(endsWithQuestionMark.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        index++;
        // backslash in glob can match slash
        const backslashInPattern = manifest.entities.allItems[index];
        expect(backslashInPattern.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('\\testfile.csv');
        expect(backslashInPattern.dataPartitions.length)
            .toBe(1);
        expect(backslashInPattern.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        index++;
        // pattern object includes glob pattern and regular expression
        const globAndRegex = manifest.entities.allItems[index];
        expect(globAndRegex.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('/testfile.csv');
        expect(globAndRegex.dataPartitionPatterns.allItems[0].regularExpression)
            .toBe('/subFolder/testSubFile.csv');
        expect(globAndRegex.dataPartitions.length)
            .toBe(1);
        // matching this file means the glob pattern was (correctly) used
        expect(globAndRegex.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        done();
    }));
    /**
     * Testing data partition patterns that use glob patterns with variations in path style
     */
    it('TestGlobPathVariation', (done) => __awaiter(void 0, void 0, void 0, function* () {
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestGlobPathVariation');
        const manifest = yield corpus.fetchObjectAsync('pattern.manifest.cdm.json');
        yield manifest.fileStatusCheckAsync();
        let index = 0;
        const noSlash = manifest.entities.allItems[index];
        expect(noSlash.dataPartitionPatterns.allItems[0].rootLocation)
            .toBe('/partitions');
        expect(noSlash.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('*.csv');
        expect(noSlash.dataPartitions.length)
            .toBe(1);
        expect(noSlash.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        index++;
        const rootLocationSlash = manifest.entities.allItems[index];
        expect(rootLocationSlash.dataPartitionPatterns.allItems[0].rootLocation)
            .toBe('/partitions/');
        expect(rootLocationSlash.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('*.csv');
        expect(rootLocationSlash.dataPartitions.length)
            .toBe(1);
        expect(rootLocationSlash.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        index++;
        const globPatternSlash = manifest.entities.allItems[index];
        expect(globPatternSlash.dataPartitionPatterns.allItems[0].rootLocation)
            .toBe('/partitions');
        expect(globPatternSlash.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('/*.csv');
        expect(globPatternSlash.dataPartitions.length)
            .toBe(1);
        expect(globPatternSlash.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        index++;
        const bothSlash = manifest.entities.allItems[index];
        expect(bothSlash.dataPartitionPatterns.allItems[0].rootLocation)
            .toBe('/partitions/');
        expect(bothSlash.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('/*.csv');
        expect(bothSlash.dataPartitions.length)
            .toBe(1);
        expect(bothSlash.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        index++;
        const noSlashOrStarAtStart = manifest.entities.allItems[index];
        expect(noSlashOrStarAtStart.dataPartitionPatterns.allItems[0].rootLocation)
            .toBe('/partitions/');
        expect(noSlashOrStarAtStart.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('t*.csv');
        expect(noSlashOrStarAtStart.dataPartitions.length)
            .toBe(1);
        expect(noSlashOrStarAtStart.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        index++;
        const noSlashOrStarAndRootLocation = manifest.entities.allItems[index];
        expect(noSlashOrStarAndRootLocation.dataPartitionPatterns.allItems[0].rootLocation)
            .toBe('/partitions');
        expect(noSlashOrStarAndRootLocation.dataPartitionPatterns.allItems[0].globPattern)
            .toBe('t*.csv');
        expect(noSlashOrStarAndRootLocation.dataPartitions.length)
            .toBe(1);
        expect(noSlashOrStarAndRootLocation.dataPartitions.allItems[0].location)
            .toBe('/partitions/testfile.csv');
        done();
    }));
    /**
     *  Verifies that performing file status check on manifest with a partition with
     * null location is gracefully handled.
     */
    it('TestFileStatusCheckOnNullLocation', () => __awaiter(void 0, void 0, void 0, function* () {
        const corpus = testHelper_1.testHelper.getLocalCorpus(testsSubpath, 'TestFileStatusCheckOnNullLocation');
        corpus.setEventCallback((level, message) => {
            if (level != cdmStatusLevel_1.cdmStatusLevel.error) {
                fail(new Error('Error level message should have been reported'));
            }
            if (message.indexOf('StorageManager | The object path cannot be null or empty. | createAbsoluteCorpusPath') == -1 &&
                message.indexOf('CdmCorpusDefinition | The object path cannot be null or empty. | getLastModifiedTimeFromPartitionPathAsync') == -1) {
                fail(new Error('Unexpected error message received'));
            }
        }, cdmStatusLevel_1.cdmStatusLevel.warning);
        // Create manifest
        var manifest = corpus.MakeObject(cdmObjectType_1.cdmObjectType.manifestDef, 'TestModel');
        corpus.storage.fetchRootFolder('local').documents.push(manifest);
        // Create entity
        var entDoc = corpus.storage.fetchRootFolder('local').documents.push('MyEntityDoc.cdm.json');
        var entDef = corpus.MakeObject(cdmObjectType_1.cdmObjectType.entityDef, 'MyEntity');
        entDoc.definitions.push(entDef);
        var entDecl = manifest.entities.push(entDef);
        // Create partition
        var part = corpus.MakeObject(cdmObjectType_1.cdmObjectType.dataPartitionDef, 'MyPartition');
        entDecl.dataPartitions.push(part);
        // This should not throw exception
        yield manifest.fileStatusCheckAsync();
    }));
});
//# sourceMappingURL=DataPartitionPattern.test.js.map