From a508a1e5282a6453d01d804f13f041790412a856 Mon Sep 17 00:00:00 2001 From: Eivind Jahren Date: Fri, 13 Sep 2024 10:10:30 +0200 Subject: [PATCH] Move interaction focused gui tests to ui_tests --- tests/performance_tests/test_snapshot.py | 5 +- .../test_histogram_log_scale-empty.png | Bin .../test_histogram_log_scale-float.png | Bin .../test_histogram_no_ensembles-empty.png | Bin ...est_histogram_no_log_scale-categorical.png | Bin .../test_histogram_no_log_scale-empty.png | Bin .../test_histogram_no_log_scale-float.png | Bin ...ations_matches_snapshot_plot_figure0-0.png | Bin ...isations_matches_snapshot_plot_figure0.png | Bin ...ations_matches_snapshot_plot_figure1-0.png | Bin ...isations_matches_snapshot_plot_figure1.png | Bin ...ations_matches_snapshot_plot_figure2-0.png | Bin ...isations_matches_snapshot_plot_figure2.png | Bin ...ations_matches_snapshot_plot_figure3-0.png | Bin ...isations_matches_snapshot_plot_figure3.png | Bin ...ations_matches_snapshot_plot_figure4-0.png | Bin ...isations_matches_snapshot_plot_figure4.png | Bin ...ations_matches_snapshot_plot_figure5-0.png | Bin ...isations_matches_snapshot_plot_figure5.png | Bin ...ations_matches_snapshot_plot_figure6-0.png | Bin ...isations_matches_snapshot_plot_figure6.png | Bin tests/ui_tests/gui/conftest.py | 427 +++++++++++++++++ .../gui/test_csv_export.py | 0 .../gui/test_full_manual_update_workflow.py | 0 .../gui}/test_load_results_manually.py | 2 +- .../gui/test_main_window.py | 0 .../gui}/test_plotting_of_snake_oil.py | 3 +- .../gui/test_restart_ensemble_experiment.py | 0 .../gui/test_restart_esmda.py | 0 ...est_restart_no_responses_and_parameters.py | 0 .../gui/test_rft_export_plugin.py | 0 .../gui/test_single_test_run.py | 0 .../gui}/test_workflow_tool.py | 2 +- tests/unit_tests/gui/conftest.py | 446 +----------------- .../test_plot_case_selection_widget.py | 3 +- .../test_evaluate_ensemble_panel.py | 2 +- .../gui/simulation/test_run_dialog.py | 3 +- .../gui/simulation/view/test_legend.py | 2 +- .../gui/simulation/view/test_realization.py | 31 ++ 39 files changed, 469 insertions(+), 457 deletions(-) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_histogram_log_scale-empty.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_histogram_log_scale-float.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_histogram_no_ensembles-empty.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_histogram_no_log_scale-categorical.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_histogram_no_log_scale-empty.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_histogram_no_log_scale-float.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure0-0.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure0.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure1-0.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure1.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure2-0.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure2.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure3-0.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure3.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure4-0.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure4.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure5-0.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure5.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure6-0.png (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure6.png (100%) create mode 100644 tests/ui_tests/gui/conftest.py rename tests/{unit_tests => ui_tests}/gui/test_csv_export.py (100%) rename tests/{unit_tests => ui_tests}/gui/test_full_manual_update_workflow.py (100%) rename tests/{unit_tests/gui/tools => ui_tests/gui}/test_load_results_manually.py (98%) rename tests/{unit_tests => ui_tests}/gui/test_main_window.py (100%) rename tests/{unit_tests/gui/plottery => ui_tests/gui}/test_plotting_of_snake_oil.py (99%) rename tests/{unit_tests => ui_tests}/gui/test_restart_ensemble_experiment.py (100%) rename tests/{unit_tests => ui_tests}/gui/test_restart_esmda.py (100%) rename tests/{unit_tests => ui_tests}/gui/test_restart_no_responses_and_parameters.py (100%) rename tests/{unit_tests => ui_tests}/gui/test_rft_export_plugin.py (100%) rename tests/{unit_tests => ui_tests}/gui/test_single_test_run.py (100%) rename tests/{unit_tests/gui/tools => ui_tests/gui}/test_workflow_tool.py (98%) diff --git a/tests/performance_tests/test_snapshot.py b/tests/performance_tests/test_snapshot.py index 7bd0f7620e1..86f38c5d0f6 100644 --- a/tests/performance_tests/test_snapshot.py +++ b/tests/performance_tests/test_snapshot.py @@ -14,12 +14,11 @@ FMStepSnapshot, RealizationSnapshot, ) - -from ..unit_tests.gui.conftest import ( # noqa: F401 +from tests.ui_tests.gui.conftest import ( # noqa: F401 active_realizations_fixture, large_snapshot, ) -from ..unit_tests.gui.simulation.test_run_dialog import ( # noqa: F401 +from tests.unit_tests.gui.simulation.test_run_dialog import ( # noqa: F401 event_queue, notifier, run_dialog, diff --git a/tests/unit_tests/gui/plottery/baseline/test_histogram_log_scale-empty.png b/tests/ui_tests/gui/baseline/test_histogram_log_scale-empty.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_histogram_log_scale-empty.png rename to tests/ui_tests/gui/baseline/test_histogram_log_scale-empty.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_histogram_log_scale-float.png b/tests/ui_tests/gui/baseline/test_histogram_log_scale-float.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_histogram_log_scale-float.png rename to tests/ui_tests/gui/baseline/test_histogram_log_scale-float.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_histogram_no_ensembles-empty.png b/tests/ui_tests/gui/baseline/test_histogram_no_ensembles-empty.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_histogram_no_ensembles-empty.png rename to tests/ui_tests/gui/baseline/test_histogram_no_ensembles-empty.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_histogram_no_log_scale-categorical.png b/tests/ui_tests/gui/baseline/test_histogram_no_log_scale-categorical.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_histogram_no_log_scale-categorical.png rename to tests/ui_tests/gui/baseline/test_histogram_no_log_scale-categorical.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_histogram_no_log_scale-empty.png b/tests/ui_tests/gui/baseline/test_histogram_no_log_scale-empty.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_histogram_no_log_scale-empty.png rename to tests/ui_tests/gui/baseline/test_histogram_no_log_scale-empty.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_histogram_no_log_scale-float.png b/tests/ui_tests/gui/baseline/test_histogram_no_log_scale-float.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_histogram_no_log_scale-float.png rename to tests/ui_tests/gui/baseline/test_histogram_no_log_scale-float.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure0-0.png b/tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure0-0.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure0-0.png rename to tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure0-0.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure0.png b/tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure0.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure0.png rename to tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure0.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure1-0.png b/tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure1-0.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure1-0.png rename to tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure1-0.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure1.png b/tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure1.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure1.png rename to tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure1.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure2-0.png b/tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure2-0.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure2-0.png rename to tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure2-0.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure2.png b/tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure2.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure2.png rename to tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure2.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure3-0.png b/tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure3-0.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure3-0.png rename to tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure3-0.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure3.png b/tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure3.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure3.png rename to tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure3.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure4-0.png b/tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure4-0.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure4-0.png rename to tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure4-0.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure4.png b/tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure4.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure4.png rename to tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure4.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure5-0.png b/tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure5-0.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure5-0.png rename to tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure5-0.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure5.png b/tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure5.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure5.png rename to tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure5.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure6-0.png b/tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure6-0.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure6-0.png rename to tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure6-0.png diff --git a/tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure6.png b/tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure6.png similarity index 100% rename from tests/unit_tests/gui/plottery/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure6.png rename to tests/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure6.png diff --git a/tests/ui_tests/gui/conftest.py b/tests/ui_tests/gui/conftest.py new file mode 100644 index 00000000000..7df7518ccbb --- /dev/null +++ b/tests/ui_tests/gui/conftest.py @@ -0,0 +1,427 @@ +import contextlib +import fileinput +import os +import os.path +import shutil +import stat +import time +from contextlib import contextmanager +from pathlib import Path +from textwrap import dedent +from typing import Generator, List, Tuple, Type, TypeVar +from unittest.mock import MagicMock, Mock + +import pytest +from pytestqt.qtbot import QtBot +from qtpy.QtCore import Qt, QTimer +from qtpy.QtWidgets import QApplication, QComboBox, QMessageBox, QPushButton, QWidget + +from ert.config import ErtConfig +from ert.gui.ertwidgets import ClosableDialog +from ert.gui.ertwidgets.create_experiment_dialog import CreateExperimentDialog +from ert.gui.ertwidgets.ensembleselector import EnsembleSelector +from ert.gui.main import ErtMainWindow, _setup_main_window, add_gui_log_handler +from ert.gui.simulation.experiment_panel import ExperimentPanel +from ert.gui.simulation.run_dialog import RunDialog +from ert.gui.simulation.view import RealizationWidget +from ert.gui.tools.load_results.load_results_panel import LoadResultsPanel +from ert.gui.tools.manage_experiments.manage_experiments_tool import ( + ManageExperimentsTool, +) +from ert.gui.tools.manage_experiments.storage_widget import AddWidget, StorageWidget +from ert.plugins import ErtPluginContext +from ert.run_models import EnsembleExperiment, MultipleDataAssimilation +from ert.services import StorageService +from ert.storage import Storage, open_storage +from tests.unit_tests.gui.simulation.test_run_path_dialog import handle_run_path_dialog + + +@pytest.fixture +def opened_main_window( + source_root, tmp_path, monkeypatch +) -> Generator[ErtMainWindow, None, None]: + monkeypatch.chdir(tmp_path) + _new_poly_example(source_root, tmp_path) + with _open_main_window(tmp_path / "poly.ert") as ( + gui, + _, + config, + ), StorageService.init_service( + project=os.path.abspath(config.ens_path), + ): + yield gui + + +def _new_poly_example(source_root, destination, num_realizations: int = 20): + shutil.copytree( + os.path.join(source_root, "test-data", "poly_example"), + destination, + dirs_exist_ok=True, + ) + + with fileinput.input(destination / "poly.ert", inplace=True) as fin: + for line in fin: + if "NUM_REALIZATIONS" in line: + # Decrease the number of realizations to speed up the test, + # if there is flakyness, this can be increased. + print(f"NUM_REALIZATIONS {num_realizations}", end="\n") + else: + print(line, end="") + + +@contextmanager +def _open_main_window( + path, +) -> Generator[Tuple[ErtMainWindow, Storage, ErtConfig], None, None]: + args_mock = Mock() + args_mock.config = str(path) + with ErtPluginContext(): + config = ErtConfig.with_plugins().from_file(path) + with open_storage( + config.ens_path, mode="w" + ) as storage, add_gui_log_handler() as log_handler: + gui = _setup_main_window(config, args_mock, log_handler, storage) + yield gui, storage, config + gui.close() + + +@pytest.fixture +def opened_main_window_clean(source_root, tmp_path, monkeypatch): + monkeypatch.chdir(tmp_path) + _new_poly_example(source_root, tmp_path) + with _open_main_window(tmp_path / "poly.ert") as ( + gui, + _, + config, + ), StorageService.init_service( + project=os.path.abspath(config.ens_path), + ): + yield gui + + +@pytest.fixture +def opened_main_window_minimal_realizations(source_root, tmp_path, monkeypatch): + monkeypatch.chdir(tmp_path) + _new_poly_example(source_root, tmp_path, 2) + with _open_main_window(tmp_path / "poly.ert") as ( + gui, + _, + config, + ), StorageService.init_service( + project=os.path.abspath(config.ens_path), + ): + yield gui + + +@pytest.fixture +def opened_main_window_snake_oil(snake_oil_case_storage): + with _open_main_window(Path("./snake_oil.ert")) as ( + gui, + _, + config, + ), StorageService.init_service( + project=os.path.abspath(config.ens_path), + ): + yield gui + + +@pytest.fixture(scope="module") +def _esmda_run(run_experiment, source_root, tmp_path_factory): + path = tmp_path_factory.mktemp("test-data") + _new_poly_example(source_root, path) + with pytest.MonkeyPatch.context() as mp, _open_main_window(path / "poly.ert") as ( + gui, + _, + config, + ): + mp.chdir(path) + run_experiment(MultipleDataAssimilation, gui) + # Check that we produce update log + log_paths = list(Path(config.analysis_config.log_path).iterdir()) + assert log_paths + assert (log_paths[0] / "Report.report").exists() + assert (log_paths[0] / "Report.csv").exists() + + return path + + +def _ensemble_experiment_run( + run_experiment, source_root, tmp_path_factory, failing_reals +): + path = tmp_path_factory.mktemp("test-data") + _new_poly_example(source_root, path) + with pytest.MonkeyPatch.context() as mp, _open_main_window(path / "poly.ert") as ( + gui, + _, + _, + ): + mp.chdir(path) + if failing_reals: + with open("poly_eval.py", "w", encoding="utf-8") as f: + f.write( + dedent( + """\ + #!/usr/bin/env python3 + import os + import sys + import json + + def _load_coeffs(filename): + with open(filename, encoding="utf-8") as f: + return json.load(f)["COEFFS"] + + def _evaluate(coeffs, x): + return coeffs["a"] * x**2 + coeffs["b"] * x + coeffs["c"] + + if __name__ == "__main__": + if int(os.getenv("_ERT_REALIZATION_NUMBER")) % 2 == 0: + sys.exit(1) + coeffs = _load_coeffs("parameters.json") + output = [_evaluate(coeffs, x) for x in range(10)] + with open("poly.out", "w", encoding="utf-8") as f: + f.write("\\n".join(map(str, output))) + """ + ) + ) + os.chmod( + "poly_eval.py", + os.stat("poly_eval.py").st_mode + | stat.S_IXUSR + | stat.S_IXGRP + | stat.S_IXOTH, + ) + run_experiment(EnsembleExperiment, gui) + + return path + + +@pytest.fixture +def esmda_has_run(_esmda_run, tmp_path, monkeypatch): + monkeypatch.chdir(tmp_path) + shutil.copytree(_esmda_run, tmp_path, dirs_exist_ok=True) + with _open_main_window(tmp_path / "poly.ert") as ( + gui, + _, + config, + ), StorageService.init_service( + project=os.path.abspath(config.ens_path), + ): + yield gui + + +@pytest.fixture +def ensemble_experiment_has_run( + tmp_path, monkeypatch, run_experiment, source_root, tmp_path_factory +): + monkeypatch.chdir(tmp_path) + test_files = _ensemble_experiment_run( + run_experiment, source_root, tmp_path_factory, True + ) + shutil.copytree(test_files, tmp_path, dirs_exist_ok=True) + with _open_main_window(tmp_path / "poly.ert") as ( + gui, + _, + config, + ), StorageService.init_service( + project=os.path.abspath(config.ens_path), + ): + yield gui + + +@pytest.fixture +def ensemble_experiment_has_run_no_failure( + tmp_path, monkeypatch, run_experiment, source_root, tmp_path_factory +): + monkeypatch.chdir(tmp_path) + test_files = _ensemble_experiment_run( + run_experiment, source_root, tmp_path_factory, False + ) + shutil.copytree(test_files, tmp_path, dirs_exist_ok=True) + with _open_main_window(tmp_path / "poly.ert") as ( + gui, + _, + config, + ), StorageService.init_service( + project=os.path.abspath(config.ens_path), + ): + yield gui + + +@pytest.fixture(name="run_experiment", scope="module") +def run_experiment_fixture(request): + def func(experiment_mode, gui): + qtbot = QtBot(request) + with contextlib.suppress(FileNotFoundError): + shutil.rmtree("poly_out") + # Select correct experiment in the simulation panel + experiment_panel = gui.findChild(ExperimentPanel) + assert isinstance(experiment_panel, ExperimentPanel) + simulation_mode_combo = experiment_panel.findChild(QComboBox) + assert isinstance(simulation_mode_combo, QComboBox) + simulation_mode_combo.setCurrentText(experiment_mode.name()) + simulation_settings = experiment_panel._experiment_widgets[ + experiment_panel.get_current_experiment_type() + ] + if hasattr(simulation_settings, "_ensemble_name_field"): + simulation_settings._ensemble_name_field.setText("iter-0") + + # Click start simulation and agree to the message + run_experiment = experiment_panel.findChild(QWidget, name="run_experiment") + + def handle_dialog(): + QTimer.singleShot( + 500, + lambda: handle_run_path_dialog(gui, qtbot, delete_run_path=False), + ) + + if not experiment_mode.name() in ( + "Ensemble experiment", + "Evaluate ensemble", + ): + QTimer.singleShot(500, handle_dialog) + qtbot.mouseClick(run_experiment, Qt.LeftButton) + + # The Run dialog opens, click show details and wait until done appears + # then click it + qtbot.waitUntil(lambda: gui.findChild(RunDialog) is not None) + run_dialog = gui.findChild(RunDialog) + + qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=200000) + qtbot.waitUntil(lambda: run_dialog._tab_widget.currentWidget() is not None) + + # Assert that the number of boxes in the detailed view is + # equal to the number of realizations + realization_widget = run_dialog._tab_widget.currentWidget() + assert isinstance(realization_widget, RealizationWidget) + list_model = realization_widget._real_view.model() + assert ( + list_model.rowCount() + == experiment_panel.config.model_config.num_realizations + ) + + qtbot.mouseClick(run_dialog.done_button, Qt.LeftButton) + + return func + + +@pytest.fixture(name="active_realizations") +def active_realizations_fixture() -> Mock: + active_reals = MagicMock() + active_reals.count = Mock(return_value=10) + active_reals.__iter__.return_value = [True] * 10 + return active_reals + + +@pytest.fixture +def runmodel(active_realizations) -> Mock: + brm = Mock() + brm.get_runtime = Mock(return_value=100) + brm.format_error = Mock(return_value="") + brm.support_restart = True + brm.simulation_arguments = {"active_realizations": active_realizations} + brm.has_failed_realizations = lambda: False + return brm + + +class MockTracker: + def __init__(self, events) -> None: + self._events = events + self._is_running = True + + def track(self): + for event in self._events: + if not self._is_running: + break + time.sleep(0.1) + yield event + + def reset(self): + pass + + def request_termination(self): + self._is_running = False + + +@pytest.fixture +def mock_tracker(): + def _make_mock_tracker(events): + return MockTracker(events) + + return _make_mock_tracker + + +def load_results_manually(qtbot, gui, ensemble_name="default"): + def handle_load_results_dialog(): + dialog = wait_for_child(gui, qtbot, ClosableDialog) + panel = get_child(dialog, LoadResultsPanel) + + ensemble_selector = get_child(panel, EnsembleSelector) + index = ensemble_selector.findText(ensemble_name, Qt.MatchFlag.MatchContains) + assert index != -1 + ensemble_selector.setCurrentIndex(index) + + # click on "Load" + load_button = get_child(panel.parent(), QPushButton, name="Load") + + # Verify that the messagebox is the success kind + def handle_popup_dialog(): + messagebox = QApplication.activeModalWidget() + assert isinstance(messagebox, QMessageBox) + assert messagebox.text() == "Successfully loaded all realisations" + ok_button = messagebox.button(QMessageBox.Ok) + qtbot.mouseClick(ok_button, Qt.LeftButton) + + QTimer.singleShot(2000, handle_popup_dialog) + qtbot.mouseClick(load_button, Qt.LeftButton) + dialog.close() + + QTimer.singleShot(1000, handle_load_results_dialog) + load_results_tool = gui.tools["Load results manually"] + load_results_tool.trigger() + + +def add_experiment_manually( + qtbot, gui, experiment_name="My experiment", ensemble_name="default" +): + manage_tool = gui.tools["Manage experiments"] + manage_tool.trigger() + + assert isinstance(manage_tool, ManageExperimentsTool) + experiments_panel = manage_tool._manage_experiments_panel + + # Open the create new experiment tab + experiments_panel.setCurrentIndex(0) + current_tab = experiments_panel.currentWidget() + assert current_tab.objectName() == "create_new_ensemble_tab" + storage_widget = get_child(current_tab, StorageWidget) + + def handle_add_dialog(): + dialog = wait_for_child(current_tab, qtbot, CreateExperimentDialog) + dialog._experiment_edit.setText(experiment_name) + dialog._ensemble_edit.setText(ensemble_name) + qtbot.mouseClick(dialog._ok_button, Qt.MouseButton.LeftButton) + + QTimer.singleShot(1000, handle_add_dialog) + add_widget = get_child(storage_widget, AddWidget) + qtbot.mouseClick(add_widget.addButton, Qt.MouseButton.LeftButton) + + experiments_panel.close() + + +V = TypeVar("V") + + +def wait_for_child(gui, qtbot: QtBot, typ: Type[V], *args, **kwargs) -> V: + qtbot.waitUntil(lambda: gui.findChild(typ, *args, **kwargs) is not None) + return get_child(gui, typ, *args, **kwargs) + + +def get_child(gui: QWidget, typ: Type[V], *args, **kwargs) -> V: + child = gui.findChild(typ, *args, **kwargs) + assert isinstance(child, typ) + return child + + +def get_children(gui: QWidget, typ: Type[V], *args, **kwargs) -> List[V]: + children: List[typ] = gui.findChildren(typ, *args, **kwargs) + return children diff --git a/tests/unit_tests/gui/test_csv_export.py b/tests/ui_tests/gui/test_csv_export.py similarity index 100% rename from tests/unit_tests/gui/test_csv_export.py rename to tests/ui_tests/gui/test_csv_export.py diff --git a/tests/unit_tests/gui/test_full_manual_update_workflow.py b/tests/ui_tests/gui/test_full_manual_update_workflow.py similarity index 100% rename from tests/unit_tests/gui/test_full_manual_update_workflow.py rename to tests/ui_tests/gui/test_full_manual_update_workflow.py diff --git a/tests/unit_tests/gui/tools/test_load_results_manually.py b/tests/ui_tests/gui/test_load_results_manually.py similarity index 98% rename from tests/unit_tests/gui/tools/test_load_results_manually.py rename to tests/ui_tests/gui/test_load_results_manually.py index 6c67daf5d62..6dcc06cd688 100644 --- a/tests/unit_tests/gui/tools/test_load_results_manually.py +++ b/tests/ui_tests/gui/test_load_results_manually.py @@ -5,7 +5,7 @@ from ert.gui.ertwidgets.ensembleselector import EnsembleSelector from ert.gui.tools.load_results import LoadResultsPanel -from ..conftest import ( +from .conftest import ( get_child, wait_for_child, ) diff --git a/tests/unit_tests/gui/test_main_window.py b/tests/ui_tests/gui/test_main_window.py similarity index 100% rename from tests/unit_tests/gui/test_main_window.py rename to tests/ui_tests/gui/test_main_window.py diff --git a/tests/unit_tests/gui/plottery/test_plotting_of_snake_oil.py b/tests/ui_tests/gui/test_plotting_of_snake_oil.py similarity index 99% rename from tests/unit_tests/gui/plottery/test_plotting_of_snake_oil.py rename to tests/ui_tests/gui/test_plotting_of_snake_oil.py index 02c554afa90..d6cf08dcd60 100644 --- a/tests/unit_tests/gui/plottery/test_plotting_of_snake_oil.py +++ b/tests/ui_tests/gui/test_plotting_of_snake_oil.py @@ -22,7 +22,8 @@ ) from ert.services import StorageService from ert.storage import open_storage -from tests.unit_tests.gui.conftest import ( + +from .conftest import ( get_child, wait_for_child, ) diff --git a/tests/unit_tests/gui/test_restart_ensemble_experiment.py b/tests/ui_tests/gui/test_restart_ensemble_experiment.py similarity index 100% rename from tests/unit_tests/gui/test_restart_ensemble_experiment.py rename to tests/ui_tests/gui/test_restart_ensemble_experiment.py diff --git a/tests/unit_tests/gui/test_restart_esmda.py b/tests/ui_tests/gui/test_restart_esmda.py similarity index 100% rename from tests/unit_tests/gui/test_restart_esmda.py rename to tests/ui_tests/gui/test_restart_esmda.py diff --git a/tests/unit_tests/gui/test_restart_no_responses_and_parameters.py b/tests/ui_tests/gui/test_restart_no_responses_and_parameters.py similarity index 100% rename from tests/unit_tests/gui/test_restart_no_responses_and_parameters.py rename to tests/ui_tests/gui/test_restart_no_responses_and_parameters.py diff --git a/tests/unit_tests/gui/test_rft_export_plugin.py b/tests/ui_tests/gui/test_rft_export_plugin.py similarity index 100% rename from tests/unit_tests/gui/test_rft_export_plugin.py rename to tests/ui_tests/gui/test_rft_export_plugin.py diff --git a/tests/unit_tests/gui/test_single_test_run.py b/tests/ui_tests/gui/test_single_test_run.py similarity index 100% rename from tests/unit_tests/gui/test_single_test_run.py rename to tests/ui_tests/gui/test_single_test_run.py diff --git a/tests/unit_tests/gui/tools/test_workflow_tool.py b/tests/ui_tests/gui/test_workflow_tool.py similarity index 98% rename from tests/unit_tests/gui/tools/test_workflow_tool.py rename to tests/ui_tests/gui/test_workflow_tool.py index f2a794b00ac..0946e2949cb 100644 --- a/tests/unit_tests/gui/tools/test_workflow_tool.py +++ b/tests/ui_tests/gui/test_workflow_tool.py @@ -18,7 +18,7 @@ from ert.services import StorageService from ert.storage import Storage, open_storage -from ..conftest import get_child, wait_for_child +from .conftest import get_child, wait_for_child @contextmanager diff --git a/tests/unit_tests/gui/conftest.py b/tests/unit_tests/gui/conftest.py index 17eafc7a0c6..19fa1babddf 100644 --- a/tests/unit_tests/gui/conftest.py +++ b/tests/unit_tests/gui/conftest.py @@ -1,24 +1,8 @@ -import contextlib import copy -import fileinput -import os -import os.path -import shutil -import stat -import time -from contextlib import contextmanager from datetime import datetime as dt -from pathlib import Path -from textwrap import dedent -from typing import Generator, List, Tuple, Type, TypeVar -from unittest.mock import MagicMock, Mock import pytest -from pytestqt.qtbot import QtBot -from qtpy.QtCore import Qt, QTimer -from qtpy.QtWidgets import QApplication, QComboBox, QMessageBox, QPushButton, QWidget -from ert.config import ErtConfig from ert.ensemble_evaluator.snapshot import ( EnsembleSnapshot, FMStepSnapshot, @@ -32,295 +16,10 @@ REALIZATION_STATE_RUNNING, REALIZATION_STATE_UNKNOWN, ) -from ert.gui.ertwidgets import ClosableDialog -from ert.gui.ertwidgets.create_experiment_dialog import CreateExperimentDialog -from ert.gui.ertwidgets.ensembleselector import EnsembleSelector -from ert.gui.main import ErtMainWindow, _setup_main_window, add_gui_log_handler -from ert.gui.simulation.experiment_panel import ExperimentPanel -from ert.gui.simulation.run_dialog import RunDialog -from ert.gui.simulation.view import RealizationWidget -from ert.gui.tools.load_results.load_results_panel import LoadResultsPanel -from ert.gui.tools.manage_experiments.manage_experiments_tool import ( - ManageExperimentsTool, -) -from ert.gui.tools.manage_experiments.storage_widget import AddWidget, StorageWidget -from ert.plugins import ErtPluginContext -from ert.run_models import EnsembleExperiment, MultipleDataAssimilation -from ert.services import StorageService -from ert.storage import Storage, open_storage from tests import SnapshotBuilder -from tests.unit_tests.gui.simulation.test_run_path_dialog import handle_run_path_dialog - - -@pytest.fixture -def opened_main_window( - source_root, tmp_path, monkeypatch -) -> Generator[ErtMainWindow, None, None]: - monkeypatch.chdir(tmp_path) - _new_poly_example(source_root, tmp_path) - with _open_main_window(tmp_path / "poly.ert") as ( - gui, - _, - config, - ), StorageService.init_service( - project=os.path.abspath(config.ens_path), - ): - yield gui - - -def _new_poly_example(source_root, destination, num_realizations: int = 20): - shutil.copytree( - os.path.join(source_root, "test-data", "poly_example"), - destination, - dirs_exist_ok=True, - ) - - with fileinput.input(destination / "poly.ert", inplace=True) as fin: - for line in fin: - if "NUM_REALIZATIONS" in line: - # Decrease the number of realizations to speed up the test, - # if there is flakyness, this can be increased. - print(f"NUM_REALIZATIONS {num_realizations}", end="\n") - else: - print(line, end="") - - -@contextmanager -def _open_main_window( - path, -) -> Generator[Tuple[ErtMainWindow, Storage, ErtConfig], None, None]: - args_mock = Mock() - args_mock.config = str(path) - with ErtPluginContext(): - config = ErtConfig.with_plugins().from_file(path) - with open_storage( - config.ens_path, mode="w" - ) as storage, add_gui_log_handler() as log_handler: - gui = _setup_main_window(config, args_mock, log_handler, storage) - yield gui, storage, config - gui.close() - - -@pytest.fixture -def opened_main_window_clean(source_root, tmp_path, monkeypatch): - monkeypatch.chdir(tmp_path) - _new_poly_example(source_root, tmp_path) - with _open_main_window(tmp_path / "poly.ert") as ( - gui, - _, - config, - ), StorageService.init_service( - project=os.path.abspath(config.ens_path), - ): - yield gui - - -@pytest.fixture -def opened_main_window_minimal_realizations(source_root, tmp_path, monkeypatch): - monkeypatch.chdir(tmp_path) - _new_poly_example(source_root, tmp_path, 2) - with _open_main_window(tmp_path / "poly.ert") as ( - gui, - _, - config, - ), StorageService.init_service( - project=os.path.abspath(config.ens_path), - ): - yield gui - - -@pytest.fixture -def opened_main_window_snake_oil(snake_oil_case_storage): - with _open_main_window(Path("./snake_oil.ert")) as ( - gui, - _, - config, - ), StorageService.init_service( - project=os.path.abspath(config.ens_path), - ): - yield gui - - -@pytest.fixture(scope="module") -def _esmda_run(run_experiment, source_root, tmp_path_factory): - path = tmp_path_factory.mktemp("test-data") - _new_poly_example(source_root, path) - with pytest.MonkeyPatch.context() as mp, _open_main_window(path / "poly.ert") as ( - gui, - _, - config, - ): - mp.chdir(path) - run_experiment(MultipleDataAssimilation, gui) - # Check that we produce update log - log_paths = list(Path(config.analysis_config.log_path).iterdir()) - assert log_paths - assert (log_paths[0] / "Report.report").exists() - assert (log_paths[0] / "Report.csv").exists() - - return path - - -def _ensemble_experiment_run( - run_experiment, source_root, tmp_path_factory, failing_reals -): - path = tmp_path_factory.mktemp("test-data") - _new_poly_example(source_root, path) - with pytest.MonkeyPatch.context() as mp, _open_main_window(path / "poly.ert") as ( - gui, - _, - _, - ): - mp.chdir(path) - if failing_reals: - with open("poly_eval.py", "w", encoding="utf-8") as f: - f.write( - dedent( - """\ - #!/usr/bin/env python3 - import os - import sys - import json - - def _load_coeffs(filename): - with open(filename, encoding="utf-8") as f: - return json.load(f)["COEFFS"] - - def _evaluate(coeffs, x): - return coeffs["a"] * x**2 + coeffs["b"] * x + coeffs["c"] - - if __name__ == "__main__": - if int(os.getenv("_ERT_REALIZATION_NUMBER")) % 2 == 0: - sys.exit(1) - coeffs = _load_coeffs("parameters.json") - output = [_evaluate(coeffs, x) for x in range(10)] - with open("poly.out", "w", encoding="utf-8") as f: - f.write("\\n".join(map(str, output))) - """ - ) - ) - os.chmod( - "poly_eval.py", - os.stat("poly_eval.py").st_mode - | stat.S_IXUSR - | stat.S_IXGRP - | stat.S_IXOTH, - ) - run_experiment(EnsembleExperiment, gui) - - return path - - -@pytest.fixture -def esmda_has_run(_esmda_run, tmp_path, monkeypatch): - monkeypatch.chdir(tmp_path) - shutil.copytree(_esmda_run, tmp_path, dirs_exist_ok=True) - with _open_main_window(tmp_path / "poly.ert") as ( - gui, - _, - config, - ), StorageService.init_service( - project=os.path.abspath(config.ens_path), - ): - yield gui - - -@pytest.fixture -def ensemble_experiment_has_run( - tmp_path, monkeypatch, run_experiment, source_root, tmp_path_factory -): - monkeypatch.chdir(tmp_path) - test_files = _ensemble_experiment_run( - run_experiment, source_root, tmp_path_factory, True - ) - shutil.copytree(test_files, tmp_path, dirs_exist_ok=True) - with _open_main_window(tmp_path / "poly.ert") as ( - gui, - _, - config, - ), StorageService.init_service( - project=os.path.abspath(config.ens_path), - ): - yield gui @pytest.fixture -def ensemble_experiment_has_run_no_failure( - tmp_path, monkeypatch, run_experiment, source_root, tmp_path_factory -): - monkeypatch.chdir(tmp_path) - test_files = _ensemble_experiment_run( - run_experiment, source_root, tmp_path_factory, False - ) - shutil.copytree(test_files, tmp_path, dirs_exist_ok=True) - with _open_main_window(tmp_path / "poly.ert") as ( - gui, - _, - config, - ), StorageService.init_service( - project=os.path.abspath(config.ens_path), - ): - yield gui - - -@pytest.fixture(name="run_experiment", scope="module") -def run_experiment_fixture(request): - def func(experiment_mode, gui): - qtbot = QtBot(request) - with contextlib.suppress(FileNotFoundError): - shutil.rmtree("poly_out") - # Select correct experiment in the simulation panel - experiment_panel = gui.findChild(ExperimentPanel) - assert isinstance(experiment_panel, ExperimentPanel) - simulation_mode_combo = experiment_panel.findChild(QComboBox) - assert isinstance(simulation_mode_combo, QComboBox) - simulation_mode_combo.setCurrentText(experiment_mode.name()) - simulation_settings = experiment_panel._experiment_widgets[ - experiment_panel.get_current_experiment_type() - ] - if hasattr(simulation_settings, "_ensemble_name_field"): - simulation_settings._ensemble_name_field.setText("iter-0") - - # Click start simulation and agree to the message - run_experiment = experiment_panel.findChild(QWidget, name="run_experiment") - - def handle_dialog(): - QTimer.singleShot( - 500, - lambda: handle_run_path_dialog(gui, qtbot, delete_run_path=False), - ) - - if not experiment_mode.name() in ( - "Ensemble experiment", - "Evaluate ensemble", - ): - QTimer.singleShot(500, handle_dialog) - qtbot.mouseClick(run_experiment, Qt.LeftButton) - - # The Run dialog opens, click show details and wait until done appears - # then click it - qtbot.waitUntil(lambda: gui.findChild(RunDialog) is not None) - run_dialog = gui.findChild(RunDialog) - - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=200000) - qtbot.waitUntil(lambda: run_dialog._tab_widget.currentWidget() is not None) - - # Assert that the number of boxes in the detailed view is - # equal to the number of realizations - realization_widget = run_dialog._tab_widget.currentWidget() - assert isinstance(realization_widget, RealizationWidget) - list_model = realization_widget._real_view.model() - assert ( - list_model.rowCount() - == experiment_panel.config.model_config.num_realizations - ) - - qtbot.mouseClick(run_dialog.done_button, Qt.LeftButton) - - return func - - -@pytest.fixture() def full_snapshot() -> EnsembleSnapshot: real = RealizationSnapshot( status=REALIZATION_STATE_RUNNING, @@ -383,7 +82,7 @@ def full_snapshot() -> EnsembleSnapshot: return snapshot -@pytest.fixture() +@pytest.fixture def fail_snapshot() -> EnsembleSnapshot: real = RealizationSnapshot( status=REALIZATION_STATE_FAILED, @@ -430,146 +129,3 @@ def large_snapshot() -> EnsembleSnapshot: ) real_ids = [str(i) for i in range(0, 150)] return builder.build(real_ids, REALIZATION_STATE_UNKNOWN) - - -@pytest.fixture() -def small_snapshot() -> EnsembleSnapshot: - builder = SnapshotBuilder() - for i in range(0, 2): - builder.add_fm_step( - fm_step_id=str(i), - index=str(i), - name=f"job_{i}", - current_memory_usage="500", - max_memory_usage="1000", - status=FORWARD_MODEL_STATE_START, - stdout=f"job_{i}.stdout", - stderr=f"job_{i}.stderr", - start_time=dt(1999, 1, 1), - end_time=dt(2019, 1, 1), - ) - real_ids = [str(i) for i in range(0, 5)] - return builder.build(real_ids, REALIZATION_STATE_UNKNOWN) - - -@pytest.fixture(name="active_realizations") -def active_realizations_fixture() -> Mock: - active_reals = MagicMock() - active_reals.count = Mock(return_value=10) - active_reals.__iter__.return_value = [True] * 10 - return active_reals - - -@pytest.fixture -def runmodel(active_realizations) -> Mock: - brm = Mock() - brm.get_runtime = Mock(return_value=100) - brm.format_error = Mock(return_value="") - brm.support_restart = True - brm.simulation_arguments = {"active_realizations": active_realizations} - brm.has_failed_realizations = lambda: False - return brm - - -class MockTracker: - def __init__(self, events) -> None: - self._events = events - self._is_running = True - - def track(self): - for event in self._events: - if not self._is_running: - break - time.sleep(0.1) - yield event - - def reset(self): - pass - - def request_termination(self): - self._is_running = False - - -@pytest.fixture -def mock_tracker(): - def _make_mock_tracker(events): - return MockTracker(events) - - return _make_mock_tracker - - -def load_results_manually(qtbot, gui, ensemble_name="default"): - def handle_load_results_dialog(): - dialog = wait_for_child(gui, qtbot, ClosableDialog) - panel = get_child(dialog, LoadResultsPanel) - - ensemble_selector = get_child(panel, EnsembleSelector) - index = ensemble_selector.findText(ensemble_name, Qt.MatchFlag.MatchContains) - assert index != -1 - ensemble_selector.setCurrentIndex(index) - - # click on "Load" - load_button = get_child(panel.parent(), QPushButton, name="Load") - - # Verify that the messagebox is the success kind - def handle_popup_dialog(): - messagebox = QApplication.activeModalWidget() - assert isinstance(messagebox, QMessageBox) - assert messagebox.text() == "Successfully loaded all realisations" - ok_button = messagebox.button(QMessageBox.Ok) - qtbot.mouseClick(ok_button, Qt.LeftButton) - - QTimer.singleShot(2000, handle_popup_dialog) - qtbot.mouseClick(load_button, Qt.LeftButton) - dialog.close() - - QTimer.singleShot(1000, handle_load_results_dialog) - load_results_tool = gui.tools["Load results manually"] - load_results_tool.trigger() - - -def add_experiment_manually( - qtbot, gui, experiment_name="My experiment", ensemble_name="default" -): - manage_tool = gui.tools["Manage experiments"] - manage_tool.trigger() - - assert isinstance(manage_tool, ManageExperimentsTool) - experiments_panel = manage_tool._manage_experiments_panel - - # Open the create new experiment tab - experiments_panel.setCurrentIndex(0) - current_tab = experiments_panel.currentWidget() - assert current_tab.objectName() == "create_new_ensemble_tab" - storage_widget = get_child(current_tab, StorageWidget) - - def handle_add_dialog(): - dialog = wait_for_child(current_tab, qtbot, CreateExperimentDialog) - dialog._experiment_edit.setText(experiment_name) - dialog._ensemble_edit.setText(ensemble_name) - qtbot.mouseClick(dialog._ok_button, Qt.MouseButton.LeftButton) - - QTimer.singleShot(1000, handle_add_dialog) - add_widget = get_child(storage_widget, AddWidget) - qtbot.mouseClick(add_widget.addButton, Qt.MouseButton.LeftButton) - - experiments_panel.close() - - -V = TypeVar("V") - - -def wait_for_child(gui, qtbot: QtBot, typ: Type[V], *args, **kwargs) -> V: - qtbot.waitUntil(lambda: gui.findChild(typ, *args, **kwargs) is not None) - return get_child(gui, typ, *args, **kwargs) - - -def get_child(gui: QWidget, typ: Type[V], *args, **kwargs) -> V: - child = gui.findChild(typ, *args, **kwargs) - assert isinstance(child, typ) - return child - - -def get_children(gui: QWidget, typ: Type[V], *args, **kwargs) -> List[V]: - children: List[typ] = gui.findChildren(typ, *args, **kwargs) - return children diff --git a/tests/unit_tests/gui/ertwidgets/test_plot_case_selection_widget.py b/tests/unit_tests/gui/ertwidgets/test_plot_case_selection_widget.py index cd78b5bfdab..75611a2c234 100644 --- a/tests/unit_tests/gui/ertwidgets/test_plot_case_selection_widget.py +++ b/tests/unit_tests/gui/ertwidgets/test_plot_case_selection_widget.py @@ -6,8 +6,7 @@ EnsembleSelectionWidget, EnsembleSelectListWidget, ) - -from ..conftest import get_child +from tests.ui_tests.gui.conftest import get_child def test_ensemble_selection_widget_max_min_selection(qtbot: QtBot): diff --git a/tests/unit_tests/gui/simulation/test_evaluate_ensemble_panel.py b/tests/unit_tests/gui/simulation/test_evaluate_ensemble_panel.py index 5976c34ab2c..e6954250be5 100644 --- a/tests/unit_tests/gui/simulation/test_evaluate_ensemble_panel.py +++ b/tests/unit_tests/gui/simulation/test_evaluate_ensemble_panel.py @@ -6,7 +6,7 @@ from ert.gui.main import GUILogHandler from ert.gui.simulation.evaluate_ensemble_panel import EvaluateEnsemblePanel from ert.gui.simulation.experiment_panel import ExperimentPanel -from tests.unit_tests.gui.conftest import get_child +from tests.ui_tests.gui.conftest import get_child @pytest.mark.usefixtures("copy_poly_case") diff --git a/tests/unit_tests/gui/simulation/test_run_dialog.py b/tests/unit_tests/gui/simulation/test_run_dialog.py index 230502bf366..1dea3a17fba 100644 --- a/tests/unit_tests/gui/simulation/test_run_dialog.py +++ b/tests/unit_tests/gui/simulation/test_run_dialog.py @@ -28,10 +28,9 @@ from ert.services import StorageService from ert.storage import open_storage from tests import SnapshotBuilder +from tests.ui_tests.gui.conftest import wait_for_child from tests.unit_tests.gui.simulation.test_run_path_dialog import handle_run_path_dialog -from ..conftest import wait_for_child - @pytest.fixture def run_model(): diff --git a/tests/unit_tests/gui/simulation/view/test_legend.py b/tests/unit_tests/gui/simulation/view/test_legend.py index 604eeb9e9f5..ee3d2e88dc7 100644 --- a/tests/unit_tests/gui/simulation/view/test_legend.py +++ b/tests/unit_tests/gui/simulation/view/test_legend.py @@ -7,7 +7,7 @@ from ert.ensemble_evaluator.state import REAL_STATE_TO_COLOR from ert.gui.simulation.view import ProgressWidget -from tests.unit_tests.gui.conftest import get_child +from tests.ui_tests.gui.conftest import get_child @given( diff --git a/tests/unit_tests/gui/simulation/view/test_realization.py b/tests/unit_tests/gui/simulation/view/test_realization.py index 44ce864ae9a..049a1f79ae8 100644 --- a/tests/unit_tests/gui/simulation/view/test_realization.py +++ b/tests/unit_tests/gui/simulation/view/test_realization.py @@ -1,10 +1,41 @@ +from datetime import datetime as dt + +import pytest from qtpy import QtCore from qtpy.QtCore import QModelIndex, QSize from qtpy.QtWidgets import QStyledItemDelegate, QStyleOptionViewItem +from ert.ensemble_evaluator.snapshot import ( + EnsembleSnapshot, +) +from ert.ensemble_evaluator.state import ( + FORWARD_MODEL_STATE_START, + REALIZATION_STATE_UNKNOWN, +) from ert.gui.model.node import _Node from ert.gui.model.snapshot import SnapshotModel from ert.gui.simulation.view.realization import RealizationWidget +from tests import SnapshotBuilder + + +@pytest.fixture +def small_snapshot() -> EnsembleSnapshot: + builder = SnapshotBuilder() + for i in range(0, 2): + builder.add_fm_step( + fm_step_id=str(i), + index=str(i), + name=f"job_{i}", + current_memory_usage="500", + max_memory_usage="1000", + status=FORWARD_MODEL_STATE_START, + stdout=f"job_{i}.stdout", + stderr=f"job_{i}.stderr", + start_time=dt(1999, 1, 1), + end_time=dt(2019, 1, 1), + ) + real_ids = [str(i) for i in range(0, 5)] + return builder.build(real_ids, REALIZATION_STATE_UNKNOWN) class MockDelegate(QStyledItemDelegate):