1 | import {EventEmitter} from 'eventemitter3';
|
2 | import {InternalEventsEmitter} from '../src/utils';
|
3 | import * as Promise from 'bluebird';
|
4 | import {expect} from 'chai';
|
5 | import {EventsMatcher} from '../test-kit/drivers/events-matcher';
|
6 | import {SlowFs} from '../test-kit/drivers/slow-fs';
|
7 |
|
8 | import {
|
9 | FileSystem,
|
10 | fileSystemEventNames,
|
11 | CacheFileSystem,
|
12 | MemoryFileSystem
|
13 | } from '../src/universal';
|
14 |
|
15 | import {
|
16 | assertFileSystemContract,
|
17 | ignoredDir,
|
18 | ignoredFile,
|
19 | fileName,
|
20 | dirName,
|
21 | content
|
22 | } from './implementation-suite';
|
23 |
|
24 | describe(`the cache file system implementation`, () => {
|
25 |
|
26 | const eventMatcherOptions: EventsMatcher.Options = {
|
27 | interval: 1,
|
28 | noExtraEventsGrace: 10,
|
29 | timeout: 30
|
30 | };
|
31 |
|
32 | assertFileSystemContract(
|
33 | () => Promise.resolve(new CacheFileSystem(new MemoryFileSystem(undefined, [ignoredDir, ignoredFile]))),
|
34 | eventMatcherOptions
|
35 | );
|
36 |
|
37 | describe(`using slow FileSystem`, () => {
|
38 | const timeout = 200;
|
39 |
|
40 | let timer;
|
41 | let fs: FileSystem;
|
42 | let slow: FileSystem;
|
43 | let startTimestamp: number;
|
44 | let matcher: EventsMatcher;
|
45 |
|
46 | beforeEach(() => {
|
47 | startTimestamp = Date.now();
|
48 | slow = new SlowFs(timeout)
|
49 | fs = new CacheFileSystem(slow)
|
50 | matcher = new EventsMatcher(eventMatcherOptions);
|
51 | matcher.track(fs.events as any as EventEmitter, ...fileSystemEventNames)
|
52 | });
|
53 |
|
54 |
|
55 | it('loads file faster after it has been saved', () => {
|
56 | return fs.saveFile(fileName, content)
|
57 | .then(() => fs.loadTextFile(fileName))
|
58 | .then(() => expect(Date.now() - startTimestamp).to.be.lessThan(timeout * 2));
|
59 | })
|
60 |
|
61 | it('loads file faster after it has been saved from outside', () => {
|
62 | const onFileCreated = new Promise((resolve, reject) => {
|
63 | fs.events.once('fileCreated', () => {
|
64 | fs.loadTextFile(fileName)
|
65 | .then(() => resolve(Date.now() - startTimestamp))
|
66 | })
|
67 | })
|
68 |
|
69 | slow.saveFile(fileName, content)
|
70 | return expect(onFileCreated).to.be.eventually.lessThan(timeout * 2)
|
71 |
|
72 | })
|
73 |
|
74 | it('loads tree faster after it has been loaded before', () => {
|
75 | return fs.loadDirectoryTree()
|
76 | .then(() => fs.loadDirectoryTree())
|
77 | .then(() => expect(Date.now() - startTimestamp).to.be.lessThan(timeout * 2))
|
78 | })
|
79 | });
|
80 |
|
81 | describe(`unexpected error behaviour`, () => {
|
82 | let fs: FileSystem;
|
83 | let original: FileSystem;
|
84 | let matcher: EventsMatcher;
|
85 |
|
86 | beforeEach(() => {
|
87 | original = new MemoryFileSystem();
|
88 | fs = new CacheFileSystem(original);
|
89 | matcher = new EventsMatcher({
|
90 | interval: 2,
|
91 | noExtraEventsGrace: 150,
|
92 | timeout: 300
|
93 | });
|
94 | matcher.track(fs.events as any as EventEmitter, ...fileSystemEventNames)
|
95 | });
|
96 |
|
97 | it('emits `fileCreated` if there is not cached file after error', () => {
|
98 | original.events.removeAllListeners('fileCreated')
|
99 | return original.saveFile(fileName, content)
|
100 | .then(() => matcher.expect([]))
|
101 | .then(() => (original.events as InternalEventsEmitter).emit('unexpectedError', {type: 'unexpectedError'}))
|
102 | .then(() => matcher.expect([{type: 'fileCreated', fullPath: fileName, newContent: content}]))
|
103 | })
|
104 |
|
105 | it('emits `directoryCreated` if there is not cached dir after error', () => {
|
106 | original.events.removeAllListeners('directoryCreated');
|
107 | return original.ensureDirectory(dirName)
|
108 | .then(() => matcher.expect([]))
|
109 | .then(() => (original.events as InternalEventsEmitter).emit('unexpectedError', {type: 'unexpectedError'}))
|
110 | .then(() => matcher.expect([{type: 'directoryCreated', fullPath: dirName}]))
|
111 | })
|
112 |
|
113 | it('emits `fileDeleted` if there is cached file and no real file after error', () => {
|
114 | return fs.saveFile(fileName, content).then(() => {
|
115 | original.events.removeAllListeners('fileDeleted');
|
116 | return original.deleteFile(fileName)
|
117 | .then(() => matcher.expect([{type: 'fileCreated', fullPath: fileName}]))
|
118 | .then(() => (original.events as InternalEventsEmitter).emit('unexpectedError', {type: 'unexpectedError'}))
|
119 | .then(() => matcher.expect([{type: 'fileDeleted', fullPath: fileName}]))
|
120 |
|
121 | })
|
122 | })
|
123 |
|
124 | it('emits `directoryDeleted` if there is cached dir and no real dir after error', () => {
|
125 | return fs.ensureDirectory(dirName).then(() => {
|
126 | original.events.removeAllListeners('directoryDeleted');
|
127 | return original.deleteDirectory(dirName)
|
128 | .then(() => matcher.expect([{type: 'directoryCreated', fullPath: dirName}]))
|
129 | .then(() => (original.events as InternalEventsEmitter).emit('unexpectedError', {type: 'unexpectedError'}))
|
130 | .then(() => matcher.expect([{type: 'directoryDeleted', fullPath: dirName}]))
|
131 | })
|
132 | })
|
133 |
|
134 | it('emits `unexpectedError` if cache created with `rescanOnError = false` flag', () => {
|
135 | const fs = new CacheFileSystem(original, false);
|
136 | const matcher = new EventsMatcher(eventMatcherOptions);
|
137 | matcher.track(fs.events as any as EventEmitter, ...fileSystemEventNames);
|
138 | (original.events as InternalEventsEmitter).emit('unexpectedError', {type: 'unexpectedError'});
|
139 | return matcher.expect([{type: 'unexpectedError'}]);
|
140 | })
|
141 | });
|
142 | });
|