Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make tests robust and independent #543

Merged
merged 28 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2102c83
Use request.node.name for make_dantzig scenarios
glatterf42 Mar 12, 2024
c625e12
Fix typo in docstring
glatterf42 Mar 12, 2024
31d7a44
Group tutorials that depend on each other
glatterf42 Mar 12, 2024
d68f757
Give every platform a test-specific name
glatterf42 Mar 12, 2024
6a8bd54
Use test-specific name for scenarios
glatterf42 Mar 12, 2024
c7d94ef
Use test-specific name for platforms
glatterf42 Mar 12, 2024
38ac174
Revert temporary fix from #510
glatterf42 Mar 12, 2024
b955aab
Copy model["dantzig"] properly
glatterf42 Mar 12, 2024
3b62932
Avoid searching for to-be-created test-specific platforms
glatterf42 Mar 18, 2024
540d613
Search for correct new scenario name
glatterf42 Mar 18, 2024
4127f57
Increase default cell runtime on GHA
glatterf42 Mar 18, 2024
6c111d8
Use more test-specific platforms
glatterf42 Mar 18, 2024
9f6afa3
Make call to to-be-tested function explicit
glatterf42 Mar 18, 2024
4a67769
Rename expected data files for individual tests
glatterf42 Mar 18, 2024
f3615ce
Call Scenario deletion function explicitly
glatterf42 Mar 22, 2024
6216c02
Call TimeSeries deletion function explicitly
glatterf42 Mar 22, 2024
12bfcc3
Add type hint for correct specific backend type
glatterf42 Mar 22, 2024
12464ed
Remove timeseries from jindex explicitly
glatterf42 Mar 22, 2024
d469fd3
Discard tmp_path directories after each test
glatterf42 Sep 11, 2024
bb48e78
Drop workaround for jupyter/nbclient#85
glatterf42 Sep 11, 2024
918298f
Make second R tutorial independent with helper function
glatterf42 Sep 11, 2024
34f0595
Mark first tutorial tests as flaky on Windows
glatterf42 Sep 12, 2024
6a50d32
Mark test_del_ts as flaky on Windows
glatterf42 Sep 12, 2024
5b30a63
Remove xfail marker for consistently xpassing test
glatterf42 Sep 12, 2024
fc76fab
Distinguish platforms for more stability
glatterf42 Sep 12, 2024
61b40cb
Expand typing in .testing.data
khaeru Sep 12, 2024
97f1121
Remove editor-specific notebook metadata
glatterf42 Sep 12, 2024
749709e
Address review comments
glatterf42 Sep 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,12 @@ jobs:
shell: Rscript {0}

- name: Run test suite using pytest
# FIXME: Use --numprocesses=auto once flaky tests are fixed
run: |
pytest ixmp \
-m "not performance" \
--color=yes -rA --verbose \
--cov-report=xml \
--numprocesses=1
--numprocesses=auto --dist=loadgroup
shell: bash

- name: Upload test coverage to Codecov.io
Expand Down
1 change: 1 addition & 0 deletions ixmp/backend/jdbc.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,7 @@ def del_ts(self, ts):

# Aggressively free memory
self.gc()
self.jindex.pop(ts, None)

def check_out(self, ts, timeseries_only):
with _handle_jexception():
Expand Down
1 change: 1 addition & 0 deletions ixmp/core/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ def export_timeseries_data(
- subannual
- year
- value

default : bool, optional
:obj:`True` to include only TimeSeries versions marked as default.
model: str, optional
Expand Down
62 changes: 47 additions & 15 deletions ixmp/testing/data.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,42 @@
# Methods are in alphabetical order
from itertools import product
from math import ceil
from typing import Any, List
from typing import TYPE_CHECKING, Any, Dict, List, Optional

import genno
import numpy as np
import pandas as pd
import pint
import pytest

from ixmp import Platform, Scenario, TimeSeries
from ixmp.backend import IAMC_IDX

if TYPE_CHECKING:
from typing import TypedDict

class ScenarioIdentifiers(TypedDict):
"""Identifiers of a Scenario.

Used only for type checking in this file, so version is omitted.
"""

model: str
scenario: str

class ScenarioKwargs(TypedDict, total=False):
"""Keyword arguments to Scenario.__init__()."""

model: str
scenario: str
version: str
scheme: str
annotation: str
with_data: Optional[bool]


#: Common (model name, scenario name) pairs for testing.
SCEN = {
SCEN: Dict[str, "ScenarioIdentifiers"] = {
"dantzig": dict(model="canning problem", scenario="standard"),
"h2g2": dict(model="Douglas Adams", scenario="Hitchhiker"),
}
Expand Down Expand Up @@ -158,7 +182,12 @@ def add_test_data(scen: Scenario):
return t, t_foo, t_bar, x


def make_dantzig(mp: Platform, solve: bool = False, quiet: bool = False) -> Scenario:
def make_dantzig(
mp: Platform,
solve: bool = False,
quiet: bool = False,
request: Optional["pytest.FixtureRequest"] = None,
) -> Scenario:
"""Return :class:`ixmp.Scenario` of Dantzig's canning/transport problem.

Parameters
Expand All @@ -169,6 +198,8 @@ def make_dantzig(mp: Platform, solve: bool = False, quiet: bool = False) -> Scen
If :obj:`True`. then solve the scenario before returning. Default :obj:`False`.
quiet : bool, optional
If :obj:`True`, suppress console output when solving.
request : :class:`pytest.FixtureRequest`, optional
If present, use for a distinct scenario name for each test.

Returns
-------
Expand All @@ -178,38 +209,39 @@ def make_dantzig(mp: Platform, solve: bool = False, quiet: bool = False) -> Scen
--------
.DantzigModel
"""
# add custom units and region for timeseries data
# Add custom units and region for time series data
try:
mp.add_unit("USD/km")
except Exception:
# Unit already exists. Pending bugfix from zikolach
pass
mp.add_region("DantzigLand", "country")

# Initialize a new Scenario, and use the DantzigModel class' initialize()
# method to populate it
annot = "Dantzig's transportation problem for illustration and testing"
scen = Scenario(
mp,
**models["dantzig"], # type: ignore [arg-type]
# Initialize a new Scenario, and use the DantzigModel class' initialize() method to
# populate it
args: "ScenarioKwargs" = dict(
**models["dantzig"],
version="new",
annotation=annot,
annotation="Dantzig's transportation problem for illustration and testing",
scheme="dantzig",
with_data=True,
)
# Use a distinct scenario name for a particular test
args.update({"scenario": request.node.name} if request else {})

scen = Scenario(mp, **args)

# commit the scenario
# Commit the scenario
scen.commit("Import Dantzig's transport problem for testing.")

# set this new scenario as the default version for the model/scenario name
# Set this new scenario as the default version for the model/scenario name
scen.set_as_default()

if solve:
# Solve the model using the GAMS code provided in the `tests` folder
scen.solve(model="dantzig", case="transport_standard", quiet=quiet)

# add timeseries data for testing `clone(keep_solution=False)`
# and `remove_solution()`
# Add time series data for testing clone(keep_solution=False) and remove_solution()
scen.check_out(timeseries_only=True)
scen.add_timeseries(HIST_DF, meta=True)
scen.add_timeseries(INP_DF)
Expand Down
10 changes: 0 additions & 10 deletions ixmp/testing/jupyter.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,6 @@ def run_notebook(nb_path, tmp_path, env=None, **kwargs):
import nbformat
from nbclient import NotebookClient

# Workaround for https://github.com/jupyter/nbclient/issues/85
if (
sys.version_info[0] == 3
and sys.version_info[1] >= 8
and sys.platform.startswith("win")
):
import asyncio

asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

# Read the notebook
nb = nbformat.read(nb_path, as_version=4)

Expand Down
8 changes: 4 additions & 4 deletions ixmp/tests/backend/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,14 @@ def test_cache_invalidate(self, test_mp):

backend.cache_invalidate(ts, "par", "baz", dict(x=["x1", "x2"], y=["y1", "y2"]))

def test_del_ts(self, test_mp):
def test_del_ts(self, test_mp, request):
"""Test CachingBackend.del_ts()."""
# Since CachingBackend is an abstract class, test it via JDBCBackend
backend = test_mp._backend
backend: CachingBackend = test_mp._backend # type: ignore
cache_size_pre = len(backend._cache)

# Load data, thereby adding to the cache
s = make_dantzig(test_mp)
s = make_dantzig(test_mp, request=request)
s.par("d")

# Cache size has increased
Expand All @@ -155,7 +155,7 @@ def test_del_ts(self, test_mp):
s.__del__() # Force deletion of cached objects associated with `s`

# Delete the object; associated cache is freed
del s
backend.del_ts(s)

# Objects were invalidated/removed from cache
assert cache_size_pre == len(backend._cache)
Loading
Loading