Skip to content

Commit

Permalink
reduce update with limit_output tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mirpedrol committed Jul 16, 2024
1 parent d4196e1 commit 7b3d985
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 194 deletions.
119 changes: 21 additions & 98 deletions tests/modules/update.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import io
import logging
import re
import shutil
import tempfile
from pathlib import Path
Expand Down Expand Up @@ -73,15 +71,9 @@ def test_install_at_hash_and_update(self):
@mock.patch.object(questionary.Question, "unsafe_ask", return_value=True)
def test_install_at_hash_and_update_limit_output(self, mock_prompt):
"""Installs an old version of a module in the pipeline and updates it with limited output reporting"""
self.caplog.set_level(logging.INFO)
assert self.mods_install_old.install("trimgalore")

# Capture the logger output
log_capture = io.StringIO()
ch = logging.StreamHandler(log_capture)
logger = logging.getLogger()
logger.addHandler(ch)
logger.setLevel(logging.INFO)

update_obj = ModuleUpdate(
self.pipeline_dir,
show_diff=True,
Expand All @@ -90,61 +82,15 @@ def test_install_at_hash_and_update_limit_output(self, mock_prompt):
branch=OLD_TRIMGALORE_BRANCH,
limit_output=True,
)
assert update_obj.update("trimgalore")

# Copy the module files and check that they are affected by the update
tmpdir = Path(tempfile.TemporaryDirectory().name)
trimgalore_tmpdir = tmpdir / "trimgalore"
trimgalore_path = Path(self.pipeline_dir, "modules", GITLAB_REPO, "trimgalore")
shutil.copytree(trimgalore_path, trimgalore_tmpdir)

assert update_obj.update("trimgalore") is True
assert cmp_component(trimgalore_tmpdir, trimgalore_path) is False

# Check that the modules.json is correctly updated
mod_json = ModulesJson(self.pipeline_dir).get_modules_json()
# Get the up-to-date git_sha for the module from the ModuleRepo object
correct_git_sha = update_obj.modules_repo.get_latest_component_version("trimgalore", "modules")
current_git_sha = mod_json["repos"][GITLAB_URL]["modules"][GITLAB_REPO]["trimgalore"]["git_sha"]
assert correct_git_sha == current_git_sha

# Get the captured log output
log_output = log_capture.getvalue()
log_lines = log_output.split("\n")

# Check for various scenarios
nf_changes_shown = False
for line in log_lines:
if (
re.match(r"'.+' is unchanged", line)
or re.match(r"'.+' was created", line)
or re.match(r"'.+' was removed", line)
):
# Unchanged, created, and removed files should be reported for both .nf and non-.nf files
assert True
elif re.match(r"Changes in '.+' but not shown", line):
# Changes not shown should only be for non-.nf files
match = re.search(r"'(.+)'", line)
if match:
file_path = match.group(1)
else:
raise AssertionError("Changes not shown message did not contain a file path")
assert Path(file_path).suffix != ".nf", f"Changes in .nf file were not shown: {line}"
elif re.match(r"Changes in '.+':$", line):
# Changes shown should only be for .nf files
match = re.search(r"'(.+)'", line)
if match:
file_path = match.group(1)
else:
raise AssertionError("Changes shown message did not contain a file path")
assert Path(file_path).suffix == ".nf", f"Changes in non-.nf file were shown: {line}"
nf_changes_shown = True

# Ensure that changes in at least one .nf file were shown
assert nf_changes_shown, "No changes in .nf files were shown"

# Clean up
logger.removeHandler(ch)
log_capture.close()
# Check changes not shown for non-.nf files
assert "Changes in 'trimgalore/meta.yml' but not shown" in self.caplog.text
# Check changes shown for .nf files
assert "Changes in 'trimgalore/main.nf'" in self.caplog.text
for line in self.caplog.text.split("\n"):
if line.startswith("---"):
assert line.endswith("main.nf")


def test_install_at_hash_and_update_and_save_diff_to_file(self):
Expand Down Expand Up @@ -173,55 +119,32 @@ def test_install_at_hash_and_update_and_save_diff_to_file(self):

def test_install_at_hash_and_update_and_save_diff_to_file_limit_output(self):
"""Installs an old version of a module in the pipeline and updates it"""
# Install old version of trimgalore
self.mods_install_old.install("trimgalore")
patch_path = Path(self.pipeline_dir, "trimgalore.patch")
# Update saving the differences to a patch file and with `limit_output`
update_obj = ModuleUpdate(
self.pipeline_dir,
save_diff_fn=patch_path,
sha=OLD_TRIMGALORE_SHA,
remote_url=GITLAB_URL,
branch=OLD_TRIMGALORE_BRANCH,
limit_output=True,
)

# Copy the module files and check that they are affected by the update
tmpdir = Path(tempfile.TemporaryDirectory().name)
trimgalore_tmpdir = tmpdir / "trimgalore"
trimgalore_path = Path(self.pipeline_dir, "modules", GITLAB_REPO, "trimgalore")
shutil.copytree(trimgalore_path, trimgalore_tmpdir)

assert update_obj.update("trimgalore") is True
assert cmp_component(trimgalore_tmpdir, trimgalore_path) is True
assert update_obj.update("trimgalore")

# Check that the patch file was created
assert patch_path.exists(), f"Patch file was not created at {patch_path}"

# Read the contents of the patch file
with open(patch_path) as f:
patch_content = f.read()

# Check the content of the patch file
patch_lines = patch_content.split("\n")
for line in patch_lines:
if re.match(r"'.+' is unchanged", line):
# Unchanged files should be reported for both .nf and non-.nf files
assert True
elif re.match(r"Changes in '.+' but not shown", line):
# Changes not shown should only be for non-.nf files
match = re.search(r"'(.+)'", line)
if match:
file_path = match.group(1)
else:
raise AssertionError("Changes not shown message did not contain a file path.")
assert Path(file_path).suffix != ".nf", f"Changes in .nf file were not shown: {line}"
elif re.match("diff --git", line):
# Diff should only be shown for .nf files
match = re.search(r"'(.+)'", line)
if match:
file_path = match.group(1)
else:
raise AssertionError("Changes shown message did not contain a file path.")
assert Path(file_path).suffix == ".nf", f"Diff shown for non-.nf file: {line}"
with open(patch_path) as fh:
patch_content = fh.read()
# Check changes not shown for non-.nf files
assert "Changes in 'trimgalore/meta.yml' but not shown" in patch_content
# Check changes only shown for main.nf
assert "Changes in 'trimgalore/main.nf'" in patch_content
for line in patch_content:
if line.startswith("---"):
assert line.endswith("main.nf")


def test_update_all(self):
Expand Down
123 changes: 27 additions & 96 deletions tests/subworkflows/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,71 +64,23 @@ def test_install_at_hash_and_update(self):
@mock.patch.object(questionary.Question, "unsafe_ask", return_value=True)
def test_install_at_hash_and_update_limit_output(self, mock_prompt):
"""Installs an old version of a subworkflow in the pipeline and updates it with limit_output=True"""
self.caplog.set_level(logging.INFO)
assert self.subworkflow_install_old.install("fastq_align_bowtie2")

# Capture the logger output
log_capture = io.StringIO()
ch = logging.StreamHandler(log_capture)
logger = logging.getLogger()
logger.addHandler(ch)
logger.setLevel(logging.INFO)

update_obj = SubworkflowUpdate(self.pipeline_dir, show_diff=True, update_deps=True, limit_output=True)
old_mod_json = ModulesJson(self.pipeline_dir).get_modules_json()

# Copy the subworkflow files and check that they are affected by the update
tmpdir = Path(tempfile.TemporaryDirectory().name)
sw_path = Path(self.pipeline_dir, "subworkflows", NF_CORE_MODULES_NAME, "fastq_align_bowtie2")
shutil.copytree(sw_path, tmpdir)

assert update_obj.update("fastq_align_bowtie2") is True
assert cmp_component(tmpdir, sw_path) is False

# Check that the modules.json is correctly updated
mod_json = ModulesJson(self.pipeline_dir).get_modules_json()
assert (
old_mod_json["repos"][NF_CORE_MODULES_REMOTE]["subworkflows"][NF_CORE_MODULES_NAME]["fastq_align_bowtie2"][
"git_sha"
]
!= mod_json["repos"][NF_CORE_MODULES_REMOTE]["subworkflows"][NF_CORE_MODULES_NAME]["fastq_align_bowtie2"][
"git_sha"
]
)
assert update_obj.update("fastq_align_bowtie2")

# Get the captured log output
log_output = log_capture.getvalue()
log_lines = log_output.split("\n")

# Check for various scenarios
nf_changes_shown = False
for line in log_lines:
if (
re.match(r"'.+' is unchanged", line)
or re.match(r"'.+' was created", line)
or re.match(r"'.+' was removed", line)
):
# Unchanged, created, and removed files should be reported for both .nf and non-.nf files
assert True
elif re.match(r"Changes in '.+' but not shown", line):
# Changes not shown should only be for non-.nf files
match = re.search(r"'(.+)'", line)
if match:
file_path = match.group(1)
else:
raise AssertionError("Changes not shown message did not contain a file path")
assert Path(file_path).suffix != ".nf", f"Changes in .nf file were not shown: {line}"
elif re.match(r"Changes in '.+':$", line):
# Changes shown should only be for .nf files
file_path = re.search(r"'(.+)'", line).group(1)
assert Path(file_path).suffix == ".nf", f"Changes in non-.nf file were shown: {line}"
nf_changes_shown = True

# Ensure that changes in at least one .nf file were shown
assert nf_changes_shown, "No changes in .nf files were shown"

# Clean up
logger.removeHandler(ch)
log_capture.close()
# Check changes not shown for non-.nf files
assert "Changes in 'fastq_align_bowtie2/meta.yml' but not shown" in self.caplog.text
assert "Changes in 'bam_sort_stats_samtools/meta.yml' but not shown" in self.caplog.text
assert "Changes in 'bam_stats_samtools/meta.yml' but not shown" in self.caplog.text
assert "Changes in 'samtools/flagstat/meta.yml' but not shown" in self.caplog.text
# Check changes only shown for main.nf files
assert "Changes in 'fastq_align_bowtie2/main.nf'" in self.caplog.text
for line in self.caplog.text.split("\n"):
if line.startswith("---"):
assert line.endswith("main.nf")


def test_install_at_hash_and_update_and_save_diff_to_file(self):
Expand All @@ -155,50 +107,29 @@ def test_install_at_hash_and_update_and_save_diff_to_file(self):

def test_install_at_hash_and_update_and_save_diff_limit_output(self):
"""Installs an old version of a sw in the pipeline and updates it. Save differences to a file."""
assert self.subworkflow_install_old.install("fastq_align_bowtie2")
# Install old version of fastq_align_bowtie2
self.subworkflow_install_old.install("fastq_align_bowtie2")
patch_path = Path(self.pipeline_dir, "fastq_align_bowtie2.patch")
# Update saving the differences to a patch file and with `limit_output`
update_obj = SubworkflowUpdate(self.pipeline_dir, save_diff_fn=patch_path, update_deps=True, limit_output=True)

# Copy the sw files and check that they are affected by the update
tmpdir = Path(tempfile.TemporaryDirectory().name)
sw_path = Path(self.pipeline_dir, "subworkflows", NF_CORE_MODULES_NAME, "fastq_align_bowtie2")
shutil.copytree(sw_path, tmpdir)

assert update_obj.update("fastq_align_bowtie2") is True
assert cmp_component(tmpdir, sw_path) is True
assert update_obj.update("fastq_align_bowtie2")

# Check that the patch file was created
assert patch_path.exists(), f"Patch file was not created at {patch_path}"

nf_changes_shown = False
non_nf_changes_not_shown = False

# Read the contents of the patch file
with open(patch_path) as fh:
content = fh.read()

# Check the first line
assert re.match(
r"Changes in module 'nf-core/fastq_align_bowtie2' between \([a-f0-9]+\) and \([a-f0-9]+\)",
content.split("\n")[0],
), "Unexpected first line in patch file"

# Check for .nf file changes shown
nf_changes_shown = bool(re.search(r"Changes in '.*\.nf':\n", content))

# Check for non-.nf file changes not shown
non_nf_changes_not_shown = bool(re.search(r"Changes in '.*[^.nf]' but not shown", content))

# Check that diff content is only for .nf files
diff_lines = re.findall(r"diff --git.*", content)
for line in diff_lines:
assert re.search(r"\.nf$", line), f"Diff shown for non-.nf file: {line}"

# Ensure that changes in .nf files were shown and non-.nf files were not shown
assert nf_changes_shown, "No changes in .nf files were shown in the patch file"
assert non_nf_changes_not_shown, "Changes in non-.nf files were not properly limited in the patch file"

# Clean up
patch_path.unlink()
# Check changes not shown for non-.nf files
assert "Changes in 'fastq_align_bowtie2/meta.yml' but not shown" in content
assert "Changes in 'bam_sort_stats_samtools/meta.yml' but not shown" in content
assert "Changes in 'bam_stats_samtools/meta.yml' but not shown" in content
assert "Changes in 'samtools/flagstat/meta.yml' but not shown" in content
# Check changes only shown for main.nf files
assert "Changes in 'fastq_align_bowtie2/main.nf'" in content
for line in content:
if line.startswith("---"):
assert line.endswith("main.nf")


def test_update_all(self):
Expand Down
5 changes: 5 additions & 0 deletions tests/test_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import shutil
import unittest
from pathlib import Path
import pytest

import requests_cache
import responses
Expand Down Expand Up @@ -156,6 +157,10 @@ def test_modulesrepo_class(self):
assert modrepo.repo_path == "nf-core"
assert modrepo.branch == "master"

@pytest.fixture(autouse=True)
def _use_caplog(self, caplog):
self.caplog = caplog

############################################
# Test of the individual modules commands. #
############################################
Expand Down
5 changes: 5 additions & 0 deletions tests/test_subworkflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import shutil
import unittest
from pathlib import Path
import pytest

import nf_core.modules
import nf_core.pipelines.create.create
Expand Down Expand Up @@ -113,6 +114,10 @@ def tearDown(self):
if os.path.exists(self.tmp_dir):
shutil.rmtree(self.tmp_dir)

@pytest.fixture(autouse=True)
def _use_caplog(self, caplog):
self.caplog = caplog

################################################
# Test of the individual subworkflow commands. #
################################################
Expand Down

0 comments on commit 7b3d985

Please sign in to comment.