mirror of
1
0
Fork 0
ultimate-vim/sources_non_forked/coc.nvim/src/__tests__/core/fileSystemWatcher.test.ts

381 lines
11 KiB
TypeScript

import bser from 'bser'
import fs from 'fs'
import net from 'net'
import os from 'os'
import path from 'path'
import Watchman, { FileChangeItem, isValidWatchRoot } from '../../core/watchman'
import helper from '../helper'
import { Disposable } from 'vscode-languageserver-protocol'
import Configurations from '../../configuration/index'
import WorkspaceFolderController from '../../core/workspaceFolder'
import { FileSystemWatcherManager, FileSystemWatcher } from '../../core/fileSystemWatcher'
import { disposeAll } from '../../util'
import { URI } from 'vscode-uri'
let server: net.Server
let client: net.Socket
const cwd = process.cwd()
const sockPath = path.join(os.tmpdir(), `watchman-fake-${process.pid}`)
process.env.WATCHMAN_SOCK = sockPath
let workspaceFolder: WorkspaceFolderController
let watcherManager: FileSystemWatcherManager
let configurations: Configurations
let disposables: Disposable[] = []
function wait(ms: number): Promise<any> {
return new Promise(resolve => {
setTimeout(() => {
resolve(undefined)
}, ms)
})
}
function createFileChange(file: string, isNew = true, exists = true): FileChangeItem {
return {
size: 1,
name: file,
exists,
new: isNew,
type: 'f',
mtime_ms: Date.now()
}
}
function sendResponse(data: any): void {
client.write(bser.dumpToBuffer(data))
}
function sendSubscription(uid: string, root: string, files: FileChangeItem[]): void {
client.write(bser.dumpToBuffer({
subscription: uid,
root,
files
}))
}
let capabilities: any
let watchResponse: any
beforeAll(done => {
let userConfigFile = path.join(process.env.COC_VIMCONFIG, 'coc-settings.json')
configurations = new Configurations(userConfigFile, {
$removeConfigurationOption: () => {},
$updateConfigurationOption: () => {}
})
workspaceFolder = new WorkspaceFolderController(configurations)
watcherManager = new FileSystemWatcherManager(workspaceFolder, '')
watcherManager.attach(helper.createNullChannel())
// create a mock sever for watchman
server = net.createServer(c => {
client = c
c.on('data', data => {
let obj = bser.loadFromBuffer(data)
if (obj[0] == 'watch-project') {
sendResponse(watchResponse || { watch: obj[1], warning: 'warning' })
} else if (obj[0] == 'unsubscribe') {
sendResponse({ path: obj[1] })
} else if (obj[0] == 'clock') {
sendResponse({ clock: 'clock' })
} else if (obj[0] == 'version') {
let { optional, required } = obj[1]
let res = {}
for (let key of optional) {
res[key] = true
}
for (let key of required) {
res[key] = true
}
sendResponse({ capabilities: capabilities || res })
} else if (obj[0] == 'subscribe') {
sendResponse({ subscribe: obj[2] })
} else {
sendResponse({})
}
})
})
server.on('error', err => {
throw err
})
server.listen(sockPath, () => {
done()
})
})
afterEach(async () => {
disposeAll(disposables)
capabilities = undefined
watchResponse = undefined
})
afterAll(async () => {
watcherManager.dispose()
server.removeAllListeners()
server.close()
if (fs.existsSync(sockPath)) {
fs.unlinkSync(sockPath)
}
})
describe('watchman', () => {
it('should throw error when not watching', async () => {
let client = new Watchman(null)
disposables.push(client)
let fn = async () => {
await client.subscribe('**/*', () => {})
}
await expect(fn()).rejects.toThrow(/not watching/)
})
it('should checkCapability', async () => {
let client = new Watchman(null)
let res = await client.checkCapability()
expect(res).toBe(true)
capabilities = { relative_root: false }
res = await client.checkCapability()
expect(res).toBe(false)
client.dispose()
})
it('should watchProject', async () => {
let client = new Watchman(null)
disposables.push(client)
let res = await client.watchProject(__dirname)
expect(res).toBe(true)
client.dispose()
})
it('should unsubscribe', async () => {
let client = new Watchman(null)
disposables.push(client)
await client.watchProject(cwd)
let fn = jest.fn()
let disposable = await client.subscribe(`${cwd}/*`, fn)
disposable.dispose()
client.dispose()
})
})
describe('Watchman#subscribe', () => {
it('should subscribe file change', async () => {
let client = new Watchman(null, helper.createNullChannel())
disposables.push(client)
await client.watchProject(cwd)
let fn = jest.fn()
let disposable = await client.subscribe(`${cwd}/*`, fn)
let changes: FileChangeItem[] = [createFileChange(`${cwd}/a`)]
sendSubscription(disposable.subscribe, cwd, changes)
await wait(30)
expect(fn).toBeCalled()
let call = fn.mock.calls[0][0]
disposable.dispose()
expect(call.root).toBe(cwd)
client.dispose()
})
it('should subscribe with relative_path', async () => {
let client = new Watchman(null, helper.createNullChannel())
watchResponse = { watch: cwd, relative_path: 'foo' }
await client.watchProject(cwd)
let fn = jest.fn()
let disposable = await client.subscribe(`${cwd}/*`, fn)
let changes: FileChangeItem[] = [createFileChange(`${cwd}/a`)]
sendSubscription(disposable.subscribe, cwd, changes)
await wait(30)
expect(fn).toBeCalled()
let call = fn.mock.calls[0][0]
disposable.dispose()
expect(call.root).toBe(path.join(cwd, 'foo'))
client.dispose()
})
it('should not subscribe invalid response', async () => {
let c = new Watchman(null, helper.createNullChannel())
disposables.push(c)
watchResponse = { watch: cwd, relative_path: 'foo' }
await c.watchProject(cwd)
let fn = jest.fn()
let disposable = await c.subscribe(`${cwd}/*`, fn)
let changes: FileChangeItem[] = [createFileChange(`${cwd}/a`)]
sendSubscription('uuid', cwd, changes)
await wait(10)
sendSubscription(disposable.subscribe, cwd, [])
await wait(10)
client.write(bser.dumpToBuffer({
subscription: disposable.subscribe,
root: cwd
}))
await wait(10)
expect(fn).toBeCalledTimes(0)
})
})
describe('Watchman#createClient', () => {
it('should not create client when capabilities not match', async () => {
capabilities = { relative_root: false }
let client = await Watchman.createClient(null, cwd)
expect(client).toBe(null)
})
it('should not create when watch failed', async () => {
watchResponse = {}
let client = await Watchman.createClient(null, cwd)
expect(client).toBe(null)
})
it('should create client', async () => {
let client = await Watchman.createClient(null, cwd)
disposables.push(client)
expect(client).toBeDefined()
})
it('should not create client for root', async () => {
let client = await Watchman.createClient(null, '/')
expect(client).toBeNull()
})
})
describe('isValidWatchRoot()', () => {
it('should check valid root', async () => {
expect(isValidWatchRoot('/')).toBe(false)
expect(isValidWatchRoot(os.homedir())).toBe(false)
expect(isValidWatchRoot('/tmp/a/b/c')).toBe(false)
expect(isValidWatchRoot(os.tmpdir())).toBe(false)
})
})
describe('fileSystemWatcher', () => {
function createWatcher(pattern: string, ignoreCreateEvents = false, ignoreChangeEvents = false, ignoreDeleteEvents = false): FileSystemWatcher {
let watcher = watcherManager.createFileSystemWatcher(
pattern,
ignoreCreateEvents,
ignoreChangeEvents,
ignoreDeleteEvents
)
disposables.push(watcher)
return watcher
}
beforeAll(async () => {
workspaceFolder.addWorkspaceFolder(cwd, true)
await watcherManager.waitClient(cwd)
})
it('should watch for file create', async () => {
let watcher = createWatcher('**/*', false, true, true)
let fn = jest.fn()
watcher.onDidCreate(fn)
await helper.wait(50)
let changes: FileChangeItem[] = [createFileChange(`a`)]
sendSubscription(watcher.subscribe, cwd, changes)
await helper.wait(50)
expect(fn).toBeCalled()
})
it('should watch for file delete', async () => {
let watcher = createWatcher('**/*', true, true, false)
let fn = jest.fn()
watcher.onDidDelete(fn)
await helper.wait(50)
let changes: FileChangeItem[] = [createFileChange(`a`, false, false)]
sendSubscription(watcher.subscribe, cwd, changes)
await helper.wait(50)
expect(fn).toBeCalled()
})
it('should watch for file change', async () => {
let watcher = createWatcher('**/*', false, false, false)
let fn = jest.fn()
watcher.onDidChange(fn)
await helper.wait(50)
let changes: FileChangeItem[] = [createFileChange(`a`, false, true)]
sendSubscription(watcher.subscribe, cwd, changes)
await helper.wait(50)
expect(fn).toBeCalled()
})
it('should watch for file rename', async () => {
let watcher = createWatcher('**/*', false, false, false)
let fn = jest.fn()
watcher.onDidRename(fn)
await helper.wait(50)
let changes: FileChangeItem[] = [
createFileChange(`a`, false, false),
createFileChange(`b`, true, true),
]
sendSubscription(watcher.subscribe, cwd, changes)
await helper.wait(50)
expect(fn).toBeCalled()
})
it('should not watch for events', async () => {
let watcher = createWatcher('**/*', true, true, true)
let called = false
let onChange = () => { called = true }
watcher.onDidCreate(onChange)
watcher.onDidChange(onChange)
watcher.onDidDelete(onChange)
await helper.wait(50)
let changes: FileChangeItem[] = [
createFileChange(`a`, false, false),
createFileChange(`b`, true, true),
createFileChange(`c`, false, true),
]
sendSubscription(watcher.subscribe, cwd, changes)
await helper.wait(50)
expect(called).toBe(false)
})
it('should watch for folder rename', async () => {
let watcher = createWatcher('**/*')
let newFiles: string[] = []
let count = 0
watcher.onDidRename(e => {
count++
newFiles.push(e.newUri.fsPath)
})
await helper.wait(50)
let changes: FileChangeItem[] = [
createFileChange(`a/1`, false, false),
createFileChange(`a/2`, false, false),
createFileChange(`b/1`, true, true),
createFileChange(`b/2`, true, true),
]
sendSubscription(watcher.subscribe, cwd, changes)
await helper.waitValue(() => {
return count
}, 2)
})
it('should watch for new folder', async () => {
let watcher = createWatcher('**/*')
expect(watcher).toBeDefined()
workspaceFolder.renameWorkspaceFolder(cwd, __dirname)
await helper.wait(50)
let uri: URI
watcher.onDidCreate(e => {
uri = e
})
await helper.wait(50)
let changes: FileChangeItem[] = [createFileChange(`a`)]
sendSubscription(watcher.subscribe, __dirname, changes)
await helper.wait(50)
expect(uri.fsPath).toEqual(path.join(__dirname, 'a'))
})
})
describe('create FileSystemWatcherManager', () => {
it('should attach to existing workspace folder', async () => {
let workspaceFolder = new WorkspaceFolderController(configurations)
workspaceFolder.addWorkspaceFolder(cwd, false)
let watcherManager = new FileSystemWatcherManager(workspaceFolder, '')
watcherManager.attach(helper.createNullChannel())
await helper.wait(100)
await watcherManager.createClient(os.tmpdir())
await watcherManager.createClient(cwd)
await watcherManager.waitClient(cwd)
watcherManager.dispose()
})
})