Skip to content

Commit

Permalink
Add a test to cover pantsbuild#6331 and pantsbuild#6301.
Browse files Browse the repository at this point in the history
  • Loading branch information
stuhood committed Aug 12, 2018
1 parent 99211ab commit b4beed6
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 56 deletions.
11 changes: 7 additions & 4 deletions tests/python/pants_test/pants_run_integration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,13 @@ def setUp(self):
# Some integration tests rely on clean subsystem state (e.g., to set up a DistributionLocator).
Subsystem.reset()

def temporary_workdir(self, cleanup=True):
def temporary_workdir(self, cleanup=True, rootdir=None):
rootdir = rootdir or get_buildroot()
# We can hard-code '.pants.d' here because we know that will always be its value
# in the pantsbuild/pants repo (e.g., that's what we .gitignore in that repo).
# Grabbing the pants_workdir config would require this pants's config object,
# which we don't have a reference to here.
root = os.path.join(get_buildroot(), '.pants.d', 'tmp')
root = os.path.join(rootdir, '.pants.d', 'tmp')
safe_mkdir(root)
return temporary_dir(root_dir=root, cleanup=cleanup, suffix='.pants.d')

Expand Down Expand Up @@ -464,7 +465,7 @@ def temporary_file_content(self, path, content, binary_mode=True):
os.unlink(path)

@contextmanager
def mock_buildroot(self, dirs_to_copy=None):
def mock_buildroot(self, dirs_to_copy=None, root_dir=None):
"""Construct a mock buildroot and return a helper object for interacting with it."""
class Manager(datatype(['write_file', 'pushd', 'new_buildroot'])): pass
# N.B. BUILD.tools, contrib, 3rdparty needs to be copied vs symlinked to avoid
Expand All @@ -480,7 +481,9 @@ class Manager(datatype(['write_file', 'pushd', 'new_buildroot'])): pass
'src')
dirs_to_copy = ('3rdparty', 'contrib') + tuple(dirs_to_copy or [])

with self.temporary_workdir() as tmp_dir:
root_dir = root_dir or get_buildroot()

with temporary_dir(root_dir=root_dir) as tmp_dir:
for filename in files_to_copy:
shutil.copy(os.path.join(get_buildroot(), filename), os.path.join(tmp_dir, filename))

Expand Down
1 change: 1 addition & 0 deletions tests/python/pants_test/python/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ python_tests(
'tests/python/pants_test:int-test',
],
tags = {'integration'},
timeout = 360,
)
2 changes: 1 addition & 1 deletion tests/python/pants_test/tasks/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ python_tests(
'tests/python/pants_test/testutils:git_util',
],
tags = {'integration'},
timeout=120,
timeout=600,
)

python_tests(
Expand Down
169 changes: 118 additions & 51 deletions tests/python/pants_test/tasks/test_changed_target_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,70 +10,91 @@

from pants.base.build_environment import get_buildroot
from pants.util.contextutil import temporary_dir
from pants.util.dirutil import safe_open
from pants.util.dirutil import fast_relpath, safe_file_dump, safe_mkdir, safe_open
from pants_test.pants_run_integration_test import PantsRunIntegrationTest
from pants_test.testutils.git_util import initialize_repo


class ChangedTargetGoalsIntegrationTest(PantsRunIntegrationTest):
@contextmanager
def known_commits(self):
"""Creates an anonymous git repository under the buildroot."""
with temporary_dir(root_dir=get_buildroot()) as worktree:
with safe_open(os.path.join(worktree, 'README'), 'w') as fp:
fp.write('Just a test tree.')
rel_buildroot = fast_relpath(worktree, get_buildroot())
with self.known_commits_in(worktree):
yield worktree

with initialize_repo(worktree=worktree, gitdir=os.path.join(worktree, '.git')) as git:
src_file = os.path.join(worktree, 'src/java/org/pantsbuild/Class.java')
with safe_open(src_file, 'w') as fp:
fp.write(dedent("""
package org.pantsbuild;
class Class {
static final int MEANING_OF_LIFE = 42;
@contextmanager
def known_commits_in(self, worktree, prefix=None):
"""Creates a git repository in the given target git root directory.
If prefix is specified, it represents a tuple of a relative buildroot, and a relative source
dir under that buildroot.
"""
gitdir = os.path.join(worktree, '.git')
if os.path.exists(gitdir):
raise Exception('`known_commits_in` should not be used with an existing git repository.')

buildroot = os.path.join(worktree, prefix[0]) if prefix else get_buildroot()
sourcedir = os.path.join(worktree, prefix[0], prefix[1]) if prefix else worktree
safe_mkdir(sourcedir)

with safe_open(os.path.join(sourcedir, 'README'), 'w') as fp:
fp.write('Just a test tree.')

with initialize_repo(worktree=worktree, gitdir=gitdir) as git:
src_file = os.path.join(sourcedir, 'src/java/org/pantsbuild/Class.java')
with safe_open(src_file, 'w') as fp:
fp.write(dedent("""
package org.pantsbuild;
class Class {
static final int MEANING_OF_LIFE = 42;
}
"""))

src_build_file = os.path.join(sourcedir, 'src/java/org/pantsbuild/BUILD')
src_address = fast_relpath(os.path.dirname(src_build_file), buildroot)
with safe_open(src_build_file, 'w') as fp:
fp.write("java_library(name='pantsbuild', sources=['Class.java'])")

git.add(src_file, src_build_file)
git.commit('Introduce Class.')

test_file = os.path.join(sourcedir, 'tests/java/org/pantsbuild/ClassTest.java')
with safe_open(test_file, 'w') as fp:
fp.write(dedent("""
package org.pantsbuild;
import org.junit.Assert;
import org.junit.Test;
public class ClassTest {
@Test public void test() {
Assert.assertEquals(42, Class.MEANING_OF_LIFE);
}
"""))

src_build_file = os.path.join(worktree, 'src/java/org/pantsbuild/BUILD')
with safe_open(src_build_file, 'w') as fp:
fp.write("java_library(name='pantsbuild', sources=['Class.java'])")
}
"""))

git.add(src_file, src_build_file)
git.commit('Introduce Class.')
test_build_file = os.path.join(sourcedir, 'tests/java/org/pantsbuild/BUILD')
with safe_open(test_build_file, 'w') as fp:
fp.write(dedent("""
jar_library(name='junit', jars=[jar('junit', 'junit', '4.12')])
test_file = os.path.join(worktree, 'tests/java/org/pantsbuild/ClassTest.java')
with safe_open(test_file, 'w') as fp:
fp.write(dedent("""
package org.pantsbuild;
import org.junit.Assert;
import org.junit.Test;
public class ClassTest {
@Test public void test() {
Assert.assertEquals(42, Class.MEANING_OF_LIFE);
}
}
"""))

test_build_file = os.path.join(worktree, 'tests/java/org/pantsbuild/BUILD')
with safe_open(test_build_file, 'w') as fp:
fp.write(dedent("""
jar_library(name='junit', jars=[jar('junit', 'junit', '4.12')])
junit_tests(
name='pantsbuild',
sources=['ClassTest.java'],
dependencies=[
':junit',
'{}'
]
)
""").format(os.path.relpath(os.path.dirname(src_build_file), get_buildroot())))
junit_tests(
name='pantsbuild',
sources=['ClassTest.java'],
dependencies=[
':junit',
'{}'
]
)
""").format(src_address))

git.add(test_file, test_build_file)
git.commit('Introduce ClassTest.')
git.add(test_file, test_build_file)
git.commit('Introduce ClassTest.')

yield
yield worktree

_PACKAGE_PATH_PREFIX = os.sep + os.path.join('classes', 'org', 'pantsbuild')

Expand Down Expand Up @@ -119,7 +140,7 @@ def test_compile_changed(self):
self.assertIsNotNone(self.find_classfile(workdir, 'ClassTest.class'))

def test_test_changed(self):
with self.known_commits(), self.temporary_workdir() as workdir:
with self.known_commits() as worktree, self.temporary_workdir(rootdir=worktree) as workdir:
cmd = ['--changed-diffspec=HEAD~2..HEAD~1', 'test']
junit_out = os.path.join(get_buildroot(), 'dist', 'test', 'junit',
'org.pantsbuild.ClassTest.out.txt')
Expand All @@ -135,3 +156,49 @@ def test_test_changed(self):
self.assert_success(run)

self.assertTrue(os.path.exists(junit_out))

def test_list_changed(self):
with self.known_commits() as worktree, self.temporary_workdir(rootdir=worktree) as workdir:
rel_buildroot = fast_relpath(worktree, get_buildroot())
cmd = ['--changed-diffspec=HEAD~2..HEAD~1', 'list']
run = self.run_pants_with_workdir(cmd, workdir)
self.assert_success(run)
self.assertEquals(
{os.path.join(rel_buildroot, 'src/java/org/pantsbuild:pantsbuild')},
set(run.stdout_data.splitlines()),
)

def test_list_changed_with_buildroot_ne_gitroot(self):
# Create a temporary directory, create a mock buildroot in a subdirectory, and then
# initialize a git repository _above_ the buildroot in the original temp directory.
with temporary_dir(root_dir=get_buildroot()) as worktree, \
self.mock_buildroot(root_dir=worktree) as mock_buildroot:
# The mock buildroot will have all the same contents as the "real" buildroot, so we
# create commits under it in a non-colliding directory name.
# TODO: Could maybe make another temp directory here.
rel_sources_dir = 'changed-sources'
rel_buildroot = fast_relpath(mock_buildroot.new_buildroot, worktree)
with self.known_commits_in(worktree, prefix=(rel_buildroot, rel_sources_dir)), \
mock_buildroot.pushd():

# Add untracked files both inside and outside of the buildroot to cover the case described in #6301.
safe_file_dump(os.path.join(mock_buildroot.new_buildroot, rel_sources_dir, 'this-is-untracked-inside-the-buildroot'), '')
safe_file_dump(os.path.join(worktree, 'this-is-untracked-outside-the-buildroot'), '')

# `--changed-parent` uses a separate codepath from `--changed-diffspec`, so cover it
# independently.
for cmd in (['--changed-diffspec=HEAD~1..HEAD', 'list'], ['--changed-parent=HEAD~1', 'list']):
run = self.run_pants_with_workdir(
cmd,
workdir=os.path.join(mock_buildroot.new_buildroot, '.pants.d'),
build_root=mock_buildroot.new_buildroot,
)

self.assert_success(run)
self.assertEquals(
{
os.path.join(rel_sources_dir, 'tests/java/org/pantsbuild:pantsbuild'),
os.path.join(rel_sources_dir, 'tests/java/org/pantsbuild:junit'),
},
set(run.stdout_data.splitlines()),
)

0 comments on commit b4beed6

Please sign in to comment.