2016-09-19 22:48:09 +03:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
#
|
2017-01-21 09:02:33 +03:00
|
|
|
# Copyright (c) 2016-present, Facebook, Inc.
|
2016-09-19 22:48:09 +03:00
|
|
|
# All rights reserved.
|
|
|
|
#
|
|
|
|
# This source code is licensed under the BSD-style license found in the
|
|
|
|
# LICENSE file in the root directory of this source tree. An additional grant
|
|
|
|
# of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
|
2016-09-19 22:48:15 +03:00
|
|
|
import errno
|
2016-09-19 22:48:09 +03:00
|
|
|
import os
|
2017-04-04 01:47:54 +03:00
|
|
|
import stat
|
2018-04-05 03:31:28 +03:00
|
|
|
from typing import Dict
|
|
|
|
|
2016-09-19 22:48:15 +03:00
|
|
|
from facebook.eden import EdenService
|
2016-09-20 00:08:47 +03:00
|
|
|
from facebook.eden.ttypes import FileInformationOrError
|
2016-09-19 22:48:09 +03:00
|
|
|
|
2018-05-10 07:33:49 +03:00
|
|
|
from .lib import testcase
|
|
|
|
|
2017-01-24 05:02:39 +03:00
|
|
|
|
2018-11-08 02:18:40 +03:00
|
|
|
INITIAL_SEQ = 6
|
2017-04-06 23:10:54 +03:00
|
|
|
|
2018-04-18 22:27:18 +03:00
|
|
|
|
2016-09-19 22:48:09 +03:00
|
|
|
@testcase.eden_repo_test
|
2018-04-05 03:31:25 +03:00
|
|
|
class MaterializedQueryTest(testcase.EdenRepoTest):
|
2018-05-10 07:33:49 +03:00
|
|
|
"""Check that materialization is represented correctly."""
|
2016-09-19 22:48:09 +03:00
|
|
|
|
2018-04-05 03:31:28 +03:00
|
|
|
def populate_repo(self) -> None:
|
2018-05-10 07:33:49 +03:00
|
|
|
self.repo.write_file("hello", "hola\n")
|
|
|
|
self.repo.write_file("adir/file", "foo!\n")
|
|
|
|
self.repo.write_file("bdir/test.sh", "#!/bin/bash\necho test\n", mode=0o755)
|
|
|
|
self.repo.write_file("bdir/noexec.sh", "#!/bin/bash\necho test\n")
|
|
|
|
self.repo.symlink("slink", "hello")
|
|
|
|
self.repo.commit("Initial commit.")
|
2016-09-19 22:48:09 +03:00
|
|
|
|
2018-04-05 03:31:28 +03:00
|
|
|
def edenfs_logging_settings(self) -> Dict[str, str]:
|
2018-05-10 07:33:49 +03:00
|
|
|
return {"eden.fs.fuse.RequestData": "DBG5"}
|
2017-04-01 04:13:29 +03:00
|
|
|
|
2018-04-05 03:31:28 +03:00
|
|
|
def setUp(self) -> None:
|
2016-09-19 22:48:09 +03:00
|
|
|
super().setUp()
|
|
|
|
self.client = self.get_thrift_client()
|
|
|
|
self.client.open()
|
2018-03-29 08:10:44 +03:00
|
|
|
self.addCleanup(self.client.close)
|
2016-09-19 22:48:09 +03:00
|
|
|
|
2018-04-05 03:31:28 +03:00
|
|
|
def test_noEntries(self) -> None:
|
2018-08-11 11:34:44 +03:00
|
|
|
pos = self.client.getCurrentJournalPosition(self.mount_path_bytes)
|
2017-03-25 08:52:33 +03:00
|
|
|
# setting up the .eden dir bumps the sequence number
|
2017-04-06 23:10:54 +03:00
|
|
|
self.assertEqual(INITIAL_SEQ, pos.sequenceNumber)
|
2016-09-19 22:48:14 +03:00
|
|
|
self.assertNotEqual(0, pos.mountGeneration)
|
|
|
|
|
2018-08-11 11:34:44 +03:00
|
|
|
changed = self.client.getFilesChangedSince(self.mount_path_bytes, pos)
|
2017-08-11 22:51:51 +03:00
|
|
|
self.assertEqual(set(), set(changed.changedPaths))
|
|
|
|
self.assertEqual(set(), set(changed.createdPaths))
|
|
|
|
self.assertEqual(set(), set(changed.removedPaths))
|
2016-09-19 22:48:15 +03:00
|
|
|
self.assertEqual(pos, changed.fromPosition)
|
|
|
|
self.assertEqual(pos, changed.toPosition)
|
|
|
|
|
2018-04-05 03:31:28 +03:00
|
|
|
def test_getFileInformation(self) -> None:
|
2016-09-20 00:08:47 +03:00
|
|
|
""" verify that getFileInformation is consistent with the VFS """
|
|
|
|
|
2018-08-11 11:34:44 +03:00
|
|
|
paths = [
|
|
|
|
b"",
|
|
|
|
b"not-exist",
|
|
|
|
b"hello",
|
|
|
|
b"adir",
|
|
|
|
b"adir/file",
|
|
|
|
b"bdir/test.sh",
|
|
|
|
b"slink",
|
|
|
|
]
|
|
|
|
info_list = self.client.getFileInformation(self.mount_path_bytes, paths)
|
2016-09-20 00:08:47 +03:00
|
|
|
self.assertEqual(len(paths), len(info_list))
|
|
|
|
|
|
|
|
for idx, path in enumerate(paths):
|
|
|
|
try:
|
2018-08-11 11:34:44 +03:00
|
|
|
st = os.lstat(os.path.join(self.mount, os.fsdecode(path)))
|
2018-05-10 07:33:49 +03:00
|
|
|
self.assertEqual(
|
|
|
|
FileInformationOrError.INFO,
|
|
|
|
info_list[idx].getType(),
|
2018-08-11 11:34:44 +03:00
|
|
|
msg="have non-error result for " + repr(path),
|
2018-05-10 07:33:49 +03:00
|
|
|
)
|
2016-09-20 00:08:47 +03:00
|
|
|
info = info_list[idx].get_info()
|
2018-08-11 11:34:44 +03:00
|
|
|
self.assertEqual(
|
|
|
|
st.st_mode, info.mode, msg="mode matches for " + repr(path)
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
st.st_size, info.size, msg="size matches for " + repr(path)
|
|
|
|
)
|
2017-04-04 01:47:54 +03:00
|
|
|
self.assertEqual(int(st.st_mtime), info.mtime.seconds)
|
|
|
|
if not stat.S_ISDIR(st.st_mode):
|
|
|
|
self.assertNotEqual(0, st.st_mtime)
|
|
|
|
self.assertNotEqual(0, st.st_ctime)
|
|
|
|
self.assertNotEqual(0, st.st_atime)
|
2016-09-20 00:08:47 +03:00
|
|
|
except OSError as e:
|
2018-05-10 07:33:49 +03:00
|
|
|
self.assertEqual(
|
|
|
|
FileInformationOrError.ERROR,
|
|
|
|
info_list[idx].getType(),
|
2018-08-11 11:34:44 +03:00
|
|
|
msg="have error result for " + repr(path),
|
2018-05-10 07:33:49 +03:00
|
|
|
)
|
2016-09-20 00:08:47 +03:00
|
|
|
err = info_list[idx].get_error()
|
2018-05-10 07:33:49 +03:00
|
|
|
self.assertEqual(
|
2018-08-11 11:34:44 +03:00
|
|
|
e.errno, err.errorCode, msg="error code matches for " + repr(path)
|
2018-05-10 07:33:49 +03:00
|
|
|
)
|
2016-09-20 00:08:47 +03:00
|
|
|
|
2018-04-05 03:31:28 +03:00
|
|
|
def test_invalidProcessGeneration(self) -> None:
|
2016-09-19 22:48:15 +03:00
|
|
|
# Get a candidate position
|
2018-08-11 11:34:44 +03:00
|
|
|
pos = self.client.getCurrentJournalPosition(self.mount_path_bytes)
|
2016-09-19 22:48:15 +03:00
|
|
|
|
|
|
|
# poke the generation to a value that will never manifest in practice
|
|
|
|
pos.mountGeneration = 0
|
|
|
|
|
|
|
|
with self.assertRaises(EdenService.EdenError) as context:
|
2018-08-11 11:34:44 +03:00
|
|
|
self.client.getFilesChangedSince(self.mount_path_bytes, pos)
|
2018-05-10 07:33:49 +03:00
|
|
|
self.assertEqual(
|
|
|
|
errno.ERANGE, context.exception.errorCode, msg="Must return ERANGE"
|
|
|
|
)
|
2016-09-19 22:48:15 +03:00
|
|
|
|
2018-04-05 03:31:28 +03:00
|
|
|
def test_removeFile(self) -> None:
|
2018-08-11 11:34:44 +03:00
|
|
|
initial_pos = self.client.getCurrentJournalPosition(self.mount_path_bytes)
|
2017-08-11 22:51:51 +03:00
|
|
|
self.assertEqual(INITIAL_SEQ, initial_pos.sequenceNumber)
|
|
|
|
|
2018-05-10 07:33:49 +03:00
|
|
|
os.unlink(os.path.join(self.mount, "adir", "file"))
|
2018-08-11 11:34:44 +03:00
|
|
|
changed = self.client.getFilesChangedSince(self.mount_path_bytes, initial_pos)
|
2017-08-11 22:51:51 +03:00
|
|
|
self.assertEqual(set(), set(changed.createdPaths))
|
2018-08-16 00:43:28 +03:00
|
|
|
self.assertEqual({b"adir/file"}, set(changed.changedPaths))
|
|
|
|
self.assertEqual(set(), set(changed.removedPaths))
|
2017-08-11 22:51:51 +03:00
|
|
|
|
2018-04-05 03:31:28 +03:00
|
|
|
def test_renameFile(self) -> None:
|
2018-08-11 11:34:44 +03:00
|
|
|
initial_pos = self.client.getCurrentJournalPosition(self.mount_path_bytes)
|
2017-08-11 22:51:51 +03:00
|
|
|
self.assertEqual(INITIAL_SEQ, initial_pos.sequenceNumber)
|
|
|
|
|
2018-05-10 07:33:49 +03:00
|
|
|
os.rename(os.path.join(self.mount, "hello"), os.path.join(self.mount, "bye"))
|
2018-08-11 11:34:44 +03:00
|
|
|
changed = self.client.getFilesChangedSince(self.mount_path_bytes, initial_pos)
|
|
|
|
self.assertEqual({b"bye"}, set(changed.createdPaths))
|
2018-08-16 00:43:28 +03:00
|
|
|
self.assertEqual({b"hello"}, set(changed.changedPaths))
|
|
|
|
self.assertEqual(set(), set(changed.removedPaths))
|
2017-08-11 22:51:51 +03:00
|
|
|
|
2018-04-05 03:31:28 +03:00
|
|
|
def test_addFile(self) -> None:
|
2018-08-11 11:34:44 +03:00
|
|
|
initial_pos = self.client.getCurrentJournalPosition(self.mount_path_bytes)
|
2017-04-06 23:10:54 +03:00
|
|
|
self.assertEqual(INITIAL_SEQ, initial_pos.sequenceNumber)
|
2016-09-19 22:48:14 +03:00
|
|
|
|
2018-05-10 07:33:49 +03:00
|
|
|
name = os.path.join(self.mount, "overlaid")
|
|
|
|
with open(name, "w+") as f:
|
2018-08-11 11:34:44 +03:00
|
|
|
pos = self.client.getCurrentJournalPosition(self.mount_path_bytes)
|
2018-05-10 07:33:49 +03:00
|
|
|
self.assertEqual(
|
|
|
|
INITIAL_SEQ + 1,
|
|
|
|
pos.sequenceNumber,
|
|
|
|
msg="creating a file bumps the journal",
|
|
|
|
)
|
2016-09-19 22:48:14 +03:00
|
|
|
|
2018-08-11 11:34:44 +03:00
|
|
|
changed = self.client.getFilesChangedSince(
|
|
|
|
self.mount_path_bytes, initial_pos
|
|
|
|
)
|
|
|
|
self.assertEqual({b"overlaid"}, set(changed.createdPaths))
|
2017-08-11 22:51:51 +03:00
|
|
|
self.assertEqual(set(), set(changed.changedPaths))
|
|
|
|
self.assertEqual(set(), set(changed.removedPaths))
|
2018-05-10 07:33:49 +03:00
|
|
|
self.assertEqual(
|
|
|
|
initial_pos.sequenceNumber + 1,
|
|
|
|
changed.fromPosition.sequenceNumber,
|
|
|
|
msg="changes start AFTER initial_pos",
|
|
|
|
)
|
2016-09-19 22:48:15 +03:00
|
|
|
|
2018-05-10 07:33:49 +03:00
|
|
|
f.write("NAME!\n")
|
2016-09-19 22:48:09 +03:00
|
|
|
|
2018-08-11 11:34:44 +03:00
|
|
|
pos_after_overlaid = self.client.getCurrentJournalPosition(
|
|
|
|
self.mount_path_bytes
|
|
|
|
)
|
2018-05-10 07:33:49 +03:00
|
|
|
self.assertEqual(
|
|
|
|
INITIAL_SEQ + 2,
|
|
|
|
pos_after_overlaid.sequenceNumber,
|
|
|
|
msg="writing bumps the journal",
|
|
|
|
)
|
2018-08-11 11:34:44 +03:00
|
|
|
changed = self.client.getFilesChangedSince(self.mount_path_bytes, initial_pos)
|
|
|
|
self.assertEqual({b"overlaid"}, set(changed.createdPaths))
|
2017-08-11 22:51:51 +03:00
|
|
|
self.assertEqual(set(), set(changed.changedPaths))
|
|
|
|
self.assertEqual(set(), set(changed.removedPaths))
|
2018-05-10 07:33:49 +03:00
|
|
|
self.assertEqual(
|
|
|
|
initial_pos.sequenceNumber + 1,
|
|
|
|
changed.fromPosition.sequenceNumber,
|
|
|
|
msg="changes start AFTER initial_pos",
|
|
|
|
)
|
|
|
|
|
|
|
|
name = os.path.join(self.mount, "adir", "file")
|
|
|
|
with open(name, "a") as f:
|
2018-08-11 11:34:44 +03:00
|
|
|
pos = self.client.getCurrentJournalPosition(self.mount_path_bytes)
|
2018-05-10 07:33:49 +03:00
|
|
|
self.assertEqual(
|
|
|
|
INITIAL_SEQ + 2,
|
|
|
|
pos.sequenceNumber,
|
|
|
|
msg="journal still in same place for append",
|
|
|
|
)
|
|
|
|
f.write("more stuff on the end\n")
|
2016-09-19 22:48:09 +03:00
|
|
|
|
2018-08-11 11:34:44 +03:00
|
|
|
pos = self.client.getCurrentJournalPosition(self.mount_path_bytes)
|
2018-05-10 07:33:49 +03:00
|
|
|
self.assertEqual(
|
|
|
|
INITIAL_SEQ + 3, pos.sequenceNumber, msg="appending bumps the journal"
|
|
|
|
)
|
2016-09-19 22:48:14 +03:00
|
|
|
|
2018-08-11 11:34:44 +03:00
|
|
|
changed = self.client.getFilesChangedSince(
|
|
|
|
self.mount_path_bytes, pos_after_overlaid
|
|
|
|
)
|
|
|
|
self.assertEqual({b"adir/file"}, set(changed.changedPaths))
|
2017-08-11 22:51:51 +03:00
|
|
|
self.assertEqual(set(), set(changed.createdPaths))
|
|
|
|
self.assertEqual(set(), set(changed.removedPaths))
|
2018-05-10 07:33:49 +03:00
|
|
|
self.assertEqual(
|
|
|
|
pos_after_overlaid.sequenceNumber + 1,
|
|
|
|
changed.fromPosition.sequenceNumber,
|
|
|
|
msg="changes start AFTER pos_after_overlaid",
|
|
|
|
)
|