Skip to content

Commit

Permalink
test: clean up test dirs (iterative#1904)
Browse files Browse the repository at this point in the history
* test: clean up test dirs

Closes iterative#1770. Partially does iterative#1888.

* dvc: close anything opened

* test: finalize git repo explicitly to remove test dir later

This was previously an issue on Windows.
  • Loading branch information
Suor authored and efiop committed Apr 25, 2019
1 parent c0104e2 commit 7478e7d
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 70 deletions.
21 changes: 6 additions & 15 deletions dvc/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,22 +102,13 @@ def _reflink_linux(src, dst):

FICLONE = 0x40049409

s = open(src, "r")
d = open(dst, "w+")

try:
ret = fcntl.ioctl(d.fileno(), FICLONE, s.fileno())
except IOError:
s.close()
d.close()
os.unlink(dst)
raise

s.close()
d.close()

if ret != 0:
os.unlink(dst)
ret = 255
with open(src, "r") as s, open(dst, "w+") as d:
ret = fcntl.ioctl(d.fileno(), FICLONE, s.fileno())
finally:
if ret != 0:
os.unlink(dst)

return ret

Expand Down
28 changes: 11 additions & 17 deletions dvc/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,28 +119,22 @@ def copyfile(src, dest, no_progress_bar=False, name=None):
name = name if name else os.path.basename(dest)
total = os.stat(src).st_size

fsrc = open(src, "rb")

if os.path.isdir(dest):
fdest = open(os.path.join(dest, os.path.basename(src)), "wb+")
else:
fdest = open(dest, "wb+")

while True:
buf = fsrc.read(LOCAL_CHUNK_SIZE)
if not buf:
break
fdest.write(buf)
copied += len(buf)
if not no_progress_bar:
progress.update_target(name, copied, total)
dest = os.path.join(dest, os.path.basename(src))

with open(src, "rb") as fsrc, open(dest, "wb+") as fdest:
while True:
buf = fsrc.read(LOCAL_CHUNK_SIZE)
if not buf:
break
fdest.write(buf)
copied += len(buf)
if not no_progress_bar:
progress.update_target(name, copied, total)

if not no_progress_bar:
progress.finish_target(name)

fsrc.close()
fdest.close()


def move(src, dst):
dst = os.path.abspath(dst)
Expand Down
28 changes: 27 additions & 1 deletion tests/basic_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import uuid
import tempfile
import logging
import warnings

from git import Repo
from git.exc import GitCommandNotFound
Expand Down Expand Up @@ -60,7 +61,8 @@ def __init__(self, root_dir=None):
self._root_dir = os.path.realpath(root_dir)

def _pushd(self, d):
self._saved_dir = os.path.realpath(os.curdir)
if not hasattr(self, "_saved_dir"):
self._saved_dir = os.path.realpath(os.curdir)
os.chdir(d)

def _popd(self):
Expand Down Expand Up @@ -98,6 +100,21 @@ def setUp(self):

def tearDown(self):
self._popd()
try:
shutil.rmtree(self._root_dir)
except OSError as exc:
# We ignore this under Windows with a warning because it happened
# to be really hard to trace all not properly closed files.
#
# Best guess so far is that gitpython is the culprit:
# it opens files and uses __del__ to close them, which can happen
# late in current pythons. TestGitFixture and TestDvcFixture try
# to close that and it works on most of the tests, but not all.
# Repos and thus git repos are created all over the dvc ;)
if os.name == "nt" and exc.winerror == 32:
warnings.warn("Failed to remove test dir: " + str(exc))
else:
raise


class TestGitFixture(TestDirFixture):
Expand All @@ -122,6 +139,9 @@ def setUp(self):
self.git.index.add([self.CODE])
self.git.index.commit("add code")

def tearDown(self):
self.git.close()


class TestGitSubmoduleFixture(TestGitFixture):
def __init__(self, root_dir=None):
Expand All @@ -145,6 +165,9 @@ def setUp(self):
self.dvc.scm.commit("init dvc")
logger.setLevel("DEBUG")

def tearDown(self):
self.dvc.scm.git.close()


class TestDvcGitInitializedFixture(TestDvcFixture):
def __init__(self, root_dir=None):
Expand Down Expand Up @@ -196,6 +219,9 @@ class MockConfig:
)
self.git.index.commit("Hello world commit")

# Return to the dir we started to not confuse parent fixture
os.chdir(self._saved_dir)


# NOTE: Inheritance order in the classes below is important.

Expand Down
18 changes: 12 additions & 6 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,19 @@ def git(repo_dir):
continue
break

git.index.add([repo_dir.CODE])
git.index.commit("add code")
return git
try:
git.index.add([repo_dir.CODE])
git.index.commit("add code")
yield git
finally:
git.close()


@pytest.fixture
def dvc(repo_dir, git):
dvc = DvcRepo.init(repo_dir._root_dir)
dvc.scm.commit("init dvc")
return dvc
try:
dvc = DvcRepo.init(repo_dir._root_dir)
dvc.scm.commit("init dvc")
yield dvc
finally:
dvc.scm.git.close()
5 changes: 2 additions & 3 deletions tests/func/test_checkout.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,8 @@ def commit_data_file(self, fname, content="random text"):
self.dvc.scm.commit("adding " + fname)

def read_ignored(self):
return list(
map(lambda s: s.strip("\n"), open(self.GIT_IGNORE).readlines())
)
with open(self.GIT_IGNORE) as f:
return [s.strip("\n") for s in f.readlines()]

def outs_info(self, stage):
FileInfo = collections.namedtuple("FileInfo", "path inode")
Expand Down
3 changes: 2 additions & 1 deletion tests/func/test_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ def test(self):
ret = main(["import", tmpfile])
self.assertEqual(ret, 0)
self.assertTrue(os.path.exists(filename))
self.assertEqual(open(filename).read(), "content")
with open(filename) as fd:
self.assertEqual(fd.read(), "content")


class TestFailedImportMessage(TestDvc):
Expand Down
24 changes: 16 additions & 8 deletions tests/func/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,8 @@ def test(self):
)
self.assertEqual(ret, 0)
self.assertFalse(os.access(self.FOO, os.W_OK))
self.assertEqual(open(self.FOO, "r").read(), "foo")
with open(self.FOO, "r") as fd:
self.assertEqual(fd.read(), "foo")

ret = main(
[
Expand All @@ -399,7 +400,8 @@ def test(self):
)
self.assertEqual(ret, 0)
self.assertFalse(os.access(self.FOO, os.W_OK))
self.assertEqual(open(self.FOO, "r").read(), "foo")
with open(self.FOO, "r") as fd:
self.assertEqual(fd.read(), "foo")


class TestRunUnprotectOutsSymlink(TestDvc):
Expand Down Expand Up @@ -432,7 +434,8 @@ def test(self):
self.assertEqual(ret, 0)
self.assertFalse(os.access(self.FOO, os.W_OK))
self.assertTrue(System.is_symlink(self.FOO))
self.assertEqual(open(self.FOO, "r").read(), "foo")
with open(self.FOO, "r") as fd:
self.assertEqual(fd.read(), "foo")

ret = main(
[
Expand All @@ -451,7 +454,8 @@ def test(self):
self.assertEqual(ret, 0)
self.assertFalse(os.access(self.FOO, os.W_OK))
self.assertTrue(System.is_symlink(self.FOO))
self.assertEqual(open(self.FOO, "r").read(), "foo")
with open(self.FOO, "r") as fd:
self.assertEqual(fd.read(), "foo")


class TestRunUnprotectOutsHardlink(TestDvc):
Expand Down Expand Up @@ -484,7 +488,8 @@ def test(self):
self.assertEqual(ret, 0)
self.assertFalse(os.access(self.FOO, os.W_OK))
self.assertTrue(System.is_hardlink(self.FOO))
self.assertEqual(open(self.FOO, "r").read(), "foo")
with open(self.FOO, "r") as fd:
self.assertEqual(fd.read(), "foo")

ret = main(
[
Expand All @@ -503,7 +508,8 @@ def test(self):
self.assertEqual(ret, 0)
self.assertFalse(os.access(self.FOO, os.W_OK))
self.assertTrue(System.is_hardlink(self.FOO))
self.assertEqual(open(self.FOO, "r").read(), "foo")
with open(self.FOO, "r") as fd:
self.assertEqual(fd.read(), "foo")


class TestCmdRunOverwrite(TestDvc):
Expand Down Expand Up @@ -603,12 +609,14 @@ class TestCmdRunCliMetrics(TestDvc):
def test_cached(self):
ret = main(["run", "-m", "metrics.txt", "echo test > metrics.txt"])
self.assertEqual(ret, 0)
self.assertEqual(open("metrics.txt", "r").read().rstrip(), "test")
with open("metrics.txt", "r") as fd:
self.assertEqual(fd.read().rstrip(), "test")

def test_not_cached(self):
ret = main(["run", "-M", "metrics.txt", "echo test > metrics.txt"])
self.assertEqual(ret, 0)
self.assertEqual(open("metrics.txt", "r").read().rstrip(), "test")
with open("metrics.txt", "r") as fd:
self.assertEqual(fd.read().rstrip(), "test")


class TestCmdRunWorkingDirectory(TestDvc):
Expand Down
19 changes: 8 additions & 11 deletions tests/func/test_system.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
import os
import pytest

from dvc.system import System
from tests.basic_env import TestDir


class TestSystem(TestDir):
def test_getdirinfo(self):
if os.name != "nt":
return

# simulate someone holding an exclussive access
locked = "locked"
fd = os.open(locked, os.O_WRONLY | os.O_CREAT | os.O_EXCL)

@pytest.mark.skipif(os.name != "nt", reason="Windows specific")
def test_getdirinfo(tmp_path):
# simulate someone holding an exclussive access
locked = str(tmp_path / "locked")
fd = os.open(locked, os.O_WRONLY | os.O_CREAT | os.O_EXCL)
try:
# should not raise WinError
System.getdirinfo(locked)

finally:
os.close(fd)
16 changes: 8 additions & 8 deletions tests/func/test_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ def setUp(self):
self.tree = WorkingTree()

def test_open(self):
self.assertEqual(self.tree.open(self.FOO).read(), self.FOO_CONTENTS)
self.assertEqual(
self.tree.open(self.UNICODE).read(), self.UNICODE_CONTENTS
)
with self.tree.open(self.FOO) as fd:
self.assertEqual(fd.read(), self.FOO_CONTENTS)
with self.tree.open(self.UNICODE) as fd:
self.assertEqual(fd.read(), self.UNICODE_CONTENTS)

def test_exists(self):
self.assertTrue(self.tree.exists(self.FOO))
Expand All @@ -47,10 +47,10 @@ def setUp(self):
def test_open(self):
self.scm.add([self.FOO, self.UNICODE, self.DATA_DIR])
self.scm.commit("add")
self.assertEqual(self.tree.open(self.FOO).read(), self.FOO_CONTENTS)
self.assertEqual(
self.tree.open(self.UNICODE).read(), self.UNICODE_CONTENTS
)
with self.tree.open(self.FOO) as fd:
self.assertEqual(fd.read(), self.FOO_CONTENTS)
with self.tree.open(self.UNICODE) as fd:
self.assertEqual(fd.read(), self.UNICODE_CONTENTS)
with self.assertRaises(IOError):
self.tree.open("not-existing-file")
with self.assertRaises(IOError):
Expand Down

0 comments on commit 7478e7d

Please sign in to comment.