blob: 064f2f16d9997933a73a44a0db5dd97a71efe0e4 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert' show utf8;
import 'package:fidl/fidl.dart';
import 'package:fidl_fuchsia_io/fidl_async.dart';
import 'package:fuchsia_vfs/vfs.dart';
import 'package:test/test.dart';
import 'package:zircon/zircon.dart';
void main() {
group('remote dir: ', () {
late PseudoDir _externalDirectory;
late PseudoDir _localDirectory;
late Channel _remoteDirHandle;
setUp(() {
final channelPair = ChannelPair();
_externalDirectory = PseudoDir()
..addNode('file1.txt', PseudoFile.readOnlyStr(() => 'foo'))
..addNode(
'bar',
PseudoDir()
..addNode('file2.txt', PseudoFile.readOnlyStr(() => 'bar')))
..serve(InterfaceRequest<Node>(channelPair.first!));
_remoteDirHandle = channelPair.second!;
_localDirectory = PseudoDir();
});
tearDown(() {
_externalDirectory.close();
_localDirectory.close();
});
test('inode number', () {
final dir = RemoteDir(_remoteDirHandle);
expect(dir.inodeNumber(), inoUnknown);
});
test('type', () {
final dir = RemoteDir(_remoteDirHandle);
expect(dir.type(), DirentType.directory);
});
test('add remote after serve', () async {
final proxy = _serveLocal(_localDirectory);
_localDirectory.addNode('subdir', RemoteDir(_remoteDirHandle));
final contents =
await _readFileContentsInRemoteDir(proxy, 'subdir', 'file1.txt');
expect(contents, 'foo');
proxy.ctrl.close();
});
test('add remote before serve', () async {
_localDirectory.addNode('subdir', RemoteDir(_remoteDirHandle));
final proxy = _serveLocal(_localDirectory);
final contents =
await _readFileContentsInRemoteDir(proxy, 'subdir', 'file1.txt');
expect(contents, 'foo');
proxy.ctrl.close();
});
test('can open with trailing slash', () async {
_localDirectory.addNode('subdir', RemoteDir(_remoteDirHandle));
final proxy = _serveLocal(_localDirectory);
final contents =
await _readFileContentsInRemoteDir(proxy, 'subdir/', 'file1.txt');
expect(contents, 'foo');
proxy.ctrl.close();
});
test('can open subdir of remote', () async {
_localDirectory.addNode('subdir', RemoteDir(_remoteDirHandle));
final proxy = _serveLocal(_localDirectory);
final contents =
await _readFileContentsInRemoteDir(proxy, 'subdir', 'bar/file2.txt');
expect(contents, 'bar');
proxy.ctrl.close();
});
test('can open file when remote is not at root', () async {
_localDirectory.addNode(
'dir1', PseudoDir()..addNode('dir2', RemoteDir(_remoteDirHandle)));
final proxy = _serveLocal(_localDirectory);
final contents =
await _readFileContentsInRemoteDir(proxy, 'dir1/dir2', 'file1.txt');
expect(contents, 'foo');
proxy.ctrl.close();
});
test('can open nested file when remote is not at root', () async {
_localDirectory.addNode(
'dir1', PseudoDir()..addNode('dir2', RemoteDir(_remoteDirHandle)));
final proxy = _serveLocal(_localDirectory);
final contents = await _readFileContentsInRemoteDir(
proxy, 'dir1/dir2', 'bar/file2.txt');
expect(contents, 'bar');
proxy.ctrl.close();
});
test('Can open paths through the remote dir', () async {
_localDirectory.addNode('subdir', RemoteDir(_remoteDirHandle));
final proxy = _serveLocal(_localDirectory);
expect(await _readFileContents(proxy, 'subdir/bar/file2.txt'), 'bar');
expect(await _readFileContents(proxy, 'subdir/file1.txt'), 'foo');
expect(await _readFileContents(proxy, 'subdir/./file1.txt'), 'foo');
proxy.ctrl.close();
});
test('open with invalid flags', () async {
_localDirectory.addNode('subdir', RemoteDir(_remoteDirHandle));
final dir = _serveLocal(_localDirectory);
// flags and statuses need to be kept in sync
final flags = [OpenFlags.notDirectory];
final statuses = [ZX.ERR_NOT_SUPPORTED];
expect(flags.length, statuses.length);
for (int i = 0; i < flags.length; i++) {
DirectoryProxy proxy = DirectoryProxy();
await dir.open(OpenFlags.describe | flags[i], 0, 'subdir',
InterfaceRequest(proxy.ctrl.request().passChannel()));
await proxy.onOpen.first.then((response) {
expect(response.s, statuses[i]);
}).catchError((err) async {
fail(err.toString());
});
proxy.ctrl.close();
}
dir.ctrl.close();
});
test('connect with invalid flags', () async {
final dir = RemoteDir(_remoteDirHandle);
// flags and statuses need to be kept in sync
final flags = [OpenFlags.notDirectory];
final statuses = [ZX.ERR_NOT_SUPPORTED];
expect(flags.length, statuses.length);
for (int i = 0; i < flags.length; i++) {
DirectoryProxy proxy = DirectoryProxy();
dir.connect(OpenFlags.describe | flags[i], 0,
InterfaceRequest(proxy.ctrl.request().passChannel()));
await proxy.onOpen.first.then((response) {
expect(response.s, statuses[i]);
}).catchError((err) async {
fail(err.toString());
});
proxy.ctrl.close();
}
dir.close();
});
test('open after close fails', () async {
_localDirectory.addNode('subdir', RemoteDir(_remoteDirHandle)..close());
final dir = _serveLocal(_localDirectory);
DirectoryProxy proxy = DirectoryProxy();
await dir.open(OpenFlags.describe, 0, 'subdir',
InterfaceRequest(proxy.ctrl.request().passChannel()));
await proxy.onOpen.first.then((response) {
expect(response.s, ZX.ERR_NOT_SUPPORTED);
}).catchError((err) async {
fail(err.toString());
});
proxy.ctrl.close();
dir.ctrl.close();
});
test('connect after close failse', () async {
final dir = RemoteDir(_remoteDirHandle)..close();
DirectoryProxy proxy = DirectoryProxy();
dir.connect(OpenFlags.describe, 0,
InterfaceRequest(proxy.ctrl.request().passChannel()));
await proxy.onOpen.first.then((response) {
expect(response.s, ZX.ERR_NOT_SUPPORTED);
}).catchError((err) async {
fail(err.toString());
});
proxy.ctrl.close();
});
});
}
DirectoryProxy _serveLocal(PseudoDir dir) {
DirectoryProxy proxy = DirectoryProxy();
var status = dir.connect(OpenFlags.rightReadable | OpenFlags.rightWritable, 0,
InterfaceRequest(proxy.ctrl.request().passChannel()));
expect(status, ZX.OK);
return proxy;
}
Future<DirectoryProxy> _openDirectory(DirectoryProxy dir, String path,
[flags = OpenFlags.rightReadable]) async {
DirectoryProxy proxy = DirectoryProxy();
await dir.open(
flags, 0, path, InterfaceRequest(proxy.ctrl.request().passChannel()));
return proxy;
}
Future<String> _readFileContents(DirectoryProxy dir, String filename) async {
final proxy = FileProxy();
await dir.open(OpenFlags.rightReadable, modeTypeFile, filename,
InterfaceRequest<Node>(proxy.ctrl.request().passChannel()));
final data = await proxy.read(maxBuf);
proxy.ctrl.close();
return utf8.decode(data);
}
Future<String> _readFileContentsInRemoteDir(
DirectoryProxy dir, String subdir, String filename) async {
final proxy = await _openDirectory(dir, subdir);
final contents = await _readFileContents(proxy, filename);
proxy.ctrl.close();
return contents;
}