idmtools-platform-container 0.0.0.dev0__py3-none-any.whl → 0.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- docker_image/BASE_VERSION +1 -0
- docker_image/Dockerfile +48 -0
- docker_image/Dockerfile_buildenv +46 -0
- docker_image/ImageName +1 -0
- docker_image/README.md +78 -0
- docker_image/__init__.py +6 -0
- docker_image/build_docker_image.py +145 -0
- docker_image/debian/BASE_VERSION +1 -0
- docker_image/debian/Dockerfile +40 -0
- docker_image/debian/ImageName +1 -0
- docker_image/debian/README.md +48 -0
- docker_image/debian/pip.conf +3 -0
- docker_image/debian/requirements.txt +1 -0
- docker_image/docker_image_history.py +101 -0
- docker_image/pip.conf +3 -0
- docker_image/push_docker_image.py +62 -0
- docker_image/requirements.txt +1 -0
- docker_image/rocky_meta_runtime.txt +37 -0
- idmtools_platform_container/__init__.py +18 -8
- idmtools_platform_container/cli/__init__.py +5 -0
- idmtools_platform_container/cli/container.py +682 -0
- idmtools_platform_container/container_operations/__init__.py +5 -0
- idmtools_platform_container/container_operations/docker_operations.py +593 -0
- idmtools_platform_container/container_platform.py +375 -0
- idmtools_platform_container/platform_operations/__init__.py +5 -0
- idmtools_platform_container/platform_operations/experiment_operations.py +112 -0
- idmtools_platform_container/platform_operations/simulation_operations.py +58 -0
- idmtools_platform_container/plugin_info.py +79 -0
- idmtools_platform_container/utils/__init__.py +5 -0
- idmtools_platform_container/utils/general.py +136 -0
- idmtools_platform_container/utils/status.py +130 -0
- idmtools_platform_container-0.0.3.dist-info/METADATA +212 -0
- idmtools_platform_container-0.0.3.dist-info/RECORD +69 -0
- idmtools_platform_container-0.0.3.dist-info/entry_points.txt +5 -0
- idmtools_platform_container-0.0.3.dist-info/licenses/LICENSE.TXT +3 -0
- {idmtools_platform_container-0.0.0.dev0.dist-info → idmtools_platform_container-0.0.3.dist-info}/top_level.txt +2 -0
- tests/inputs/Assets/MyLib/functions.py +2 -0
- tests/inputs/__init__.py +0 -0
- tests/inputs/model.py +28 -0
- tests/inputs/model1.py +31 -0
- tests/inputs/model3.py +21 -0
- tests/inputs/model_file.py +18 -0
- tests/inputs/run.sh +1 -0
- tests/inputs/sleep.py +9 -0
- tests/test_container_cli/__init__.py +0 -0
- tests/test_container_cli/helper.py +57 -0
- tests/test_container_cli/test_base.py +14 -0
- tests/test_container_cli/test_cancel.py +96 -0
- tests/test_container_cli/test_clear_results.py +54 -0
- tests/test_container_cli/test_container.py +72 -0
- tests/test_container_cli/test_file_container_cli.py +121 -0
- tests/test_container_cli/test_get_detail.py +60 -0
- tests/test_container_cli/test_history.py +136 -0
- tests/test_container_cli/test_history_count.py +53 -0
- tests/test_container_cli/test_inspect.py +53 -0
- tests/test_container_cli/test_install.py +48 -0
- tests/test_container_cli/test_is_running.py +69 -0
- tests/test_container_cli/test_jobs.py +138 -0
- tests/test_container_cli/test_list_containers.py +99 -0
- tests/test_container_cli/test_packages.py +41 -0
- tests/test_container_cli/test_path.py +96 -0
- tests/test_container_cli/test_ps.py +47 -0
- tests/test_container_cli/test_remove_container.py +78 -0
- tests/test_container_cli/test_status.py +149 -0
- tests/test_container_cli/test_stop_container.py +71 -0
- tests/test_container_cli/test_sync_history.py +98 -0
- tests/test_container_cli/test_verify_docker.py +28 -0
- tests/test_container_cli/test_volume.py +28 -0
- idmtools_platform_container-0.0.0.dev0.dist-info/METADATA +0 -41
- idmtools_platform_container-0.0.0.dev0.dist-info/RECORD +0 -5
- {idmtools_platform_container-0.0.0.dev0.dist-info → idmtools_platform_container-0.0.3.dist-info}/WHEEL +0 -0
tests/inputs/run.sh
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
python3 -m pip list
|
tests/inputs/sleep.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from rich.table import Table
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_actual_rich_table_values(mock_console):
|
|
7
|
+
"""
|
|
8
|
+
Get actual table values from the mock console
|
|
9
|
+
Args:
|
|
10
|
+
mock_console: rich.console.Console
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
list for actual table values
|
|
14
|
+
"""
|
|
15
|
+
actual_table = []
|
|
16
|
+
head = []
|
|
17
|
+
for call in mock_console.call_args_list:
|
|
18
|
+
args, _ = call
|
|
19
|
+
|
|
20
|
+
for arg in args:
|
|
21
|
+
if isinstance(arg, Table):
|
|
22
|
+
actual_rows = []
|
|
23
|
+
if len(head) == 0:
|
|
24
|
+
head = [column.header for column in arg.columns]
|
|
25
|
+
actual_table.append(head)
|
|
26
|
+
for c in arg.columns:
|
|
27
|
+
actual_rows.append(c._cells[0])
|
|
28
|
+
actual_table.append(actual_rows)
|
|
29
|
+
return actual_table
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def found_job_id_by_experiment(actual_jobs_table, experiment_id=None):
|
|
33
|
+
"""
|
|
34
|
+
Find job id by experiment id
|
|
35
|
+
Args:
|
|
36
|
+
actual_jobs_table: the actual jobs table from 'idmtools container jobs' cli command
|
|
37
|
+
experiment_id:
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
job_id, container_id
|
|
41
|
+
"""
|
|
42
|
+
for row in actual_jobs_table:
|
|
43
|
+
if row[1] == experiment_id:
|
|
44
|
+
return row[2], row[3]
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def cleaned_str(input_string):
|
|
49
|
+
"""
|
|
50
|
+
Remove all substrings enclosed in brackets, leading spaces, and newlines
|
|
51
|
+
Args:
|
|
52
|
+
input_string: str
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
cleaned string
|
|
56
|
+
"""
|
|
57
|
+
return re.sub(r'^\s+|\[.*?\]|\n', '', input_string)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import os
|
|
3
|
+
import pytest
|
|
4
|
+
from click.testing import CliRunner
|
|
5
|
+
from idmtools.core.platform_factory import Platform
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestContainerPlatformCliBase(unittest.TestCase):
|
|
9
|
+
|
|
10
|
+
@classmethod
|
|
11
|
+
def setUpClass(cls):
|
|
12
|
+
cls.runner = CliRunner()
|
|
13
|
+
cls.job_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), "DEST")
|
|
14
|
+
cls.platform = Platform("Container", job_directory=cls.job_directory)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
from time import sleep
|
|
4
|
+
import unittest
|
|
5
|
+
from unittest.mock import patch
|
|
6
|
+
import pytest
|
|
7
|
+
from idmtools.entities.command_task import CommandTask
|
|
8
|
+
from idmtools.entities.experiment import Experiment
|
|
9
|
+
import idmtools_platform_container.cli.container as container_cli
|
|
10
|
+
|
|
11
|
+
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
12
|
+
sys.path.append(script_dir)
|
|
13
|
+
from test_base import TestContainerPlatformCliBase
|
|
14
|
+
from helper import found_job_id_by_experiment, get_actual_rich_table_values
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.mark.serial
|
|
18
|
+
class TestContainerPlatformCancelCli(TestContainerPlatformCliBase):
|
|
19
|
+
@patch('rich.console.Console.print')
|
|
20
|
+
def test_cancel_with_experiment_id(self, mock_console):
|
|
21
|
+
command = "sleep 100"
|
|
22
|
+
task = CommandTask(command=command)
|
|
23
|
+
experiment = Experiment.from_task(task, name="run_command")
|
|
24
|
+
experiment.run(wait_until_done=False)
|
|
25
|
+
sleep(1)
|
|
26
|
+
# test cancel with experiment id
|
|
27
|
+
result = self.runner.invoke(container_cli.container, ['cancel', experiment.id])
|
|
28
|
+
self.assertEqual(result.exit_code, 0)
|
|
29
|
+
self.assertIn('Successfully killed EXPERIMENT', mock_console.call_args_list[0].args[0])
|
|
30
|
+
|
|
31
|
+
@patch('rich.console.Console.print')
|
|
32
|
+
def test_cancel_with_simulation_id(self, mock_console1):
|
|
33
|
+
command = "python3 Assets/sleep.py"
|
|
34
|
+
task = CommandTask(command=command)
|
|
35
|
+
task.common_assets.add_asset(os.path.join(script_dir, "..", "inputs", "sleep.py"))
|
|
36
|
+
experiment = Experiment.from_task(task, name="run_command")
|
|
37
|
+
experiment.run(wait_until_done=False)
|
|
38
|
+
sleep(1)
|
|
39
|
+
# test cancel with simulation id
|
|
40
|
+
result = self.runner.invoke(container_cli.container, ['cancel', experiment.simulations[0].id])
|
|
41
|
+
self.assertEqual(result.exit_code, 0)
|
|
42
|
+
self.assertIn('Successfully killed SIMULATION', mock_console1.call_args_list[0].args[0])
|
|
43
|
+
|
|
44
|
+
@patch('rich.console.Console.print')
|
|
45
|
+
def test_cancel_with_experiment_job_id_and_container_id(self, mock_console):
|
|
46
|
+
command = "sleep 100"
|
|
47
|
+
task = CommandTask(command=command)
|
|
48
|
+
experiment = Experiment.from_task(task, name="run_command")
|
|
49
|
+
experiment.run(wait_until_done=False)
|
|
50
|
+
sleep(1)
|
|
51
|
+
result = self.runner.invoke(container_cli.container, ['jobs'])
|
|
52
|
+
self.assertEqual(result.exit_code, 0)
|
|
53
|
+
actual_table = get_actual_rich_table_values(mock_console)
|
|
54
|
+
job_id, container_id = found_job_id_by_experiment(actual_table[1:], experiment.id)
|
|
55
|
+
# test cancel with job_id and container_id
|
|
56
|
+
result = self.runner.invoke(container_cli.container, ['cancel', job_id, '-c', container_id])
|
|
57
|
+
self.assertTrue(f'Successfully killed EXPERIMENT {job_id}', mock_console.call_args[0][0])
|
|
58
|
+
self.assertEqual(result.exit_code, 0)
|
|
59
|
+
|
|
60
|
+
@patch('rich.console.Console.print')
|
|
61
|
+
def test_cancel_with_job_id_only(self, mock_console):
|
|
62
|
+
command = "sleep 100"
|
|
63
|
+
task = CommandTask(command=command)
|
|
64
|
+
experiment = Experiment.from_task(task, name="run_command")
|
|
65
|
+
experiment.run(wait_until_done=False)
|
|
66
|
+
sleep(1)
|
|
67
|
+
result = self.runner.invoke(container_cli.container, ['jobs'])
|
|
68
|
+
self.assertEqual(result.exit_code, 0)
|
|
69
|
+
actual_table = get_actual_rich_table_values(mock_console)
|
|
70
|
+
job_id, container_id = found_job_id_by_experiment(actual_table[1:], experiment.id)
|
|
71
|
+
# test cancel with job_id and container_id
|
|
72
|
+
result = self.runner.invoke(container_cli.container, ['cancel', job_id])
|
|
73
|
+
self.assertTrue(f'Successfully killed EXPERIMENT {job_id}', mock_console.call_args[0][0])
|
|
74
|
+
self.assertEqual(result.exit_code, 0)
|
|
75
|
+
|
|
76
|
+
def test_cancel_help(self):
|
|
77
|
+
result = self.runner.invoke(container_cli.container, ['cancel', "--help"])
|
|
78
|
+
expected_help = (
|
|
79
|
+
"Usage: container cancel [OPTIONS] ITEM_ID\n"
|
|
80
|
+
"\n"
|
|
81
|
+
" Cancel an Experiment/Simulation job.\n"
|
|
82
|
+
"\n"
|
|
83
|
+
" Arguments:\n"
|
|
84
|
+
"\n"
|
|
85
|
+
" ITEM_ID: Experiment/Simulation ID or Job ID\n"
|
|
86
|
+
"\n"
|
|
87
|
+
"Options:\n"
|
|
88
|
+
" -c, --container_id TEXT Container Id\n"
|
|
89
|
+
" --help Show this message and exit.\n"
|
|
90
|
+
)
|
|
91
|
+
self.assertEqual(result.exit_code, 0)
|
|
92
|
+
self.assertEqual(result.output, expected_help)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
if __name__ == '__main__':
|
|
96
|
+
unittest.main()
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import pytest
|
|
4
|
+
import idmtools_platform_container.cli.container as container_cli
|
|
5
|
+
from idmtools.entities.command_task import CommandTask
|
|
6
|
+
from idmtools.entities.experiment import Experiment
|
|
7
|
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
|
8
|
+
from test_base import TestContainerPlatformCliBase
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.mark.serial
|
|
12
|
+
class TestContainerPlatformClearResultsCli(TestContainerPlatformCliBase):
|
|
13
|
+
|
|
14
|
+
def test_clear_results(self):
|
|
15
|
+
command = "sleep 100"
|
|
16
|
+
task = CommandTask(command=command)
|
|
17
|
+
experiment = Experiment.from_task(task, name="run_command")
|
|
18
|
+
experiment.run(wait_until_done=False)
|
|
19
|
+
result = self.runner.invoke(container_cli.container, ['clear-results', experiment.id])
|
|
20
|
+
self.assertEqual(result.exit_code, 0)
|
|
21
|
+
# check if the EXPERIMENT_FILES are removed
|
|
22
|
+
for f in container_cli.EXPERIMENT_FILES:
|
|
23
|
+
self.assertFalse(os.path.exists(os.path.join(self.job_directory, experiment.id, f)))
|
|
24
|
+
# check if the SIMULATION_FILES are removed
|
|
25
|
+
for f in container_cli.SIMULATION_FILES:
|
|
26
|
+
self.assertFalse(os.path.exists(
|
|
27
|
+
os.path.join(self.job_directory,experiment.id, experiment.simulations[0].id, f)))
|
|
28
|
+
# clear-results Assets for simulation extra folder
|
|
29
|
+
result = self.runner.invoke(container_cli.container, ['clear-results', experiment.id, '-r',
|
|
30
|
+
os.path.join(self.job_directory,
|
|
31
|
+
experiment.id, experiment.simulations[0].id,
|
|
32
|
+
"Assets")])
|
|
33
|
+
self.assertFalse(os.path.exists(
|
|
34
|
+
os.path.join(self.job_directory, experiment.id, experiment.simulations[0].id,
|
|
35
|
+
"Assets")))
|
|
36
|
+
# clean up container
|
|
37
|
+
result = self.runner.invoke(container_cli.container, ['stop-container', self.platform.container_id], '--remove')
|
|
38
|
+
self.assertEqual(result.exit_code, 0)
|
|
39
|
+
|
|
40
|
+
def test_clear_results_help(self):
|
|
41
|
+
result = self.runner.invoke(container_cli.container, ['clear-results', "--help"])
|
|
42
|
+
expected_help = ('Usage: container clear-results [OPTIONS] ITEM_ID\n'
|
|
43
|
+
'\n'
|
|
44
|
+
' Clear job results files and folders.\n'
|
|
45
|
+
'\n'
|
|
46
|
+
' Arguments:\n'
|
|
47
|
+
'\n'
|
|
48
|
+
' ITEM_ID: Experiment/Simulation ID\n'
|
|
49
|
+
'\n'
|
|
50
|
+
'Options:\n'
|
|
51
|
+
' -r, --remove TEXT Extra files/folders to be removed from simulation\n'
|
|
52
|
+
' --help Show this message and exit.\n')
|
|
53
|
+
self.assertEqual(result.exit_code, 0)
|
|
54
|
+
self.assertEqual(result.output, expected_help)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import pytest
|
|
4
|
+
import idmtools_platform_container.cli.container as container_cli
|
|
5
|
+
|
|
6
|
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
|
7
|
+
from test_base import TestContainerPlatformCliBase
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestContainerPlatformCliContainer(TestContainerPlatformCliBase):
|
|
11
|
+
|
|
12
|
+
def test_container_help(self):
|
|
13
|
+
result = self.runner.invoke(container_cli.container, ["--help"])
|
|
14
|
+
expected_help = ('Usage: container [OPTIONS] COMMAND [ARGS]...\n'
|
|
15
|
+
'\n'
|
|
16
|
+
' Container Platform CLI commands.\n'
|
|
17
|
+
'\n'
|
|
18
|
+
' Args: all: Bool, show all commands\n'
|
|
19
|
+
'\n'
|
|
20
|
+
' Returns: None\n'
|
|
21
|
+
'\n'
|
|
22
|
+
'Options:\n'
|
|
23
|
+
' --all Show all commands\n'
|
|
24
|
+
' --help Show this message and exit.\n'
|
|
25
|
+
'\n'
|
|
26
|
+
'Commands:\n'
|
|
27
|
+
' cancel Cancel an Experiment/Simulation job.\n'
|
|
28
|
+
' history View the job history.\n'
|
|
29
|
+
' jobs List running Experiment/Simulation jobs.\n'
|
|
30
|
+
' status Check the status of an Experiment/Simulation.\n'
|
|
31
|
+
)
|
|
32
|
+
self.assertEqual(result.exit_code, 0)
|
|
33
|
+
self.assertEqual(result.output, expected_help)
|
|
34
|
+
|
|
35
|
+
def test_container_help_all(self):
|
|
36
|
+
result = self.runner.invoke(container_cli.container, ["--all", "--help"])
|
|
37
|
+
expected_help_all = ('Usage: container [OPTIONS] COMMAND [ARGS]...\n'
|
|
38
|
+
'\n'
|
|
39
|
+
' Container Platform CLI commands.\n'
|
|
40
|
+
'\n'
|
|
41
|
+
' Args: all: Bool, show all commands\n'
|
|
42
|
+
'\n'
|
|
43
|
+
' Returns: None\n'
|
|
44
|
+
'\n'
|
|
45
|
+
'Options:\n'
|
|
46
|
+
' --all Show all commands\n'
|
|
47
|
+
' --help Show this message and exit.\n'
|
|
48
|
+
'\n'
|
|
49
|
+
'Commands:\n'
|
|
50
|
+
' cancel Cancel an Experiment/Simulation job.\n'
|
|
51
|
+
' clear-history Clear the job history.\n'
|
|
52
|
+
' clear-results Clear job results files and folders.\n'
|
|
53
|
+
' get-detail Retrieve Experiment history.\n'
|
|
54
|
+
' history View the job history.\n'
|
|
55
|
+
' history-count Get the count of count histories.\n'
|
|
56
|
+
' inspect Inspect a container.\n'
|
|
57
|
+
' install pip install a package on a container.\n'
|
|
58
|
+
' is-running Check if an Experiment/Simulation is running.\n'
|
|
59
|
+
' jobs List running Experiment/Simulation jobs.\n'
|
|
60
|
+
' list-containers List all available containers.\n'
|
|
61
|
+
' packages List packages installed on a container.\n'
|
|
62
|
+
' path Locate Suite/Experiment/Simulation file directory.\n'
|
|
63
|
+
' ps List running processes in a container.\n'
|
|
64
|
+
' remove-container Remove stopped containers.\n'
|
|
65
|
+
' status Check the status of an Experiment/Simulation.\n'
|
|
66
|
+
' stop-container Stop running container(s).\n'
|
|
67
|
+
' sync-history Sync the file system with job history.\n'
|
|
68
|
+
' verify-docker Verify the Docker environment.\n'
|
|
69
|
+
' volume Check the history volume.\n'
|
|
70
|
+
)
|
|
71
|
+
self.assertEqual(result.exit_code, 0)
|
|
72
|
+
self.assertEqual(result.output, expected_help_all)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import shutil
|
|
4
|
+
import unittest
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from unittest.mock import patch
|
|
7
|
+
import pytest
|
|
8
|
+
from click.testing import CliRunner
|
|
9
|
+
import idmtools_platform_file.cli.file as file_cli
|
|
10
|
+
from idmtools.core import EntityStatus, ItemType
|
|
11
|
+
from idmtools.core.platform_factory import Platform
|
|
12
|
+
from idmtools.entities.command_task import CommandTask
|
|
13
|
+
from idmtools.entities.experiment import Experiment
|
|
14
|
+
from idmtools_platform_container.container_operations.docker_operations import stop_container
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.mark.serial
|
|
18
|
+
@pytest.mark.cli
|
|
19
|
+
class TestFileContainerPlatformCli(unittest.TestCase):
|
|
20
|
+
@classmethod
|
|
21
|
+
def setUpClass(cls):
|
|
22
|
+
cls.runner = CliRunner()
|
|
23
|
+
cls.job_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), "DEST")
|
|
24
|
+
cls.platform = Platform("Container", job_directory=cls.job_directory)
|
|
25
|
+
command = "ls -lat"
|
|
26
|
+
task = CommandTask(command=command)
|
|
27
|
+
cls.experiment = Experiment.from_task(task, name="run_command")
|
|
28
|
+
cls.experiment.run(wait_until_done=True)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def tearDownClass(cls) -> None:
|
|
33
|
+
try:
|
|
34
|
+
stop_container(cls.platform.container_id, remove=True)
|
|
35
|
+
except Exception as e:
|
|
36
|
+
pass
|
|
37
|
+
shutil.rmtree(os.path.join(os.path.dirname(os.path.abspath(__file__)), "DEST"))
|
|
38
|
+
|
|
39
|
+
# Test cli: test status
|
|
40
|
+
# idmtools file DEST status-report --exp-id <exp_id>
|
|
41
|
+
@patch('idmtools_platform_file.tools.status_report.status_report.user_logger')
|
|
42
|
+
def test_status_report(self, mock_user_logger):
|
|
43
|
+
result = self.runner.invoke(file_cli.file,
|
|
44
|
+
[self.job_directory, 'status-report', '--exp-id', self.experiment.id])
|
|
45
|
+
self.assertEqual(result.exit_code, 0)
|
|
46
|
+
actual_messages = [call[0][0] for call in mock_user_logger.info.call_args_list]
|
|
47
|
+
|
|
48
|
+
# verify there are total 18 lines for this cli command
|
|
49
|
+
self.assertEqual(mock_user_logger.info.call_count, 17)
|
|
50
|
+
|
|
51
|
+
# verify first 2 lines as expected messages
|
|
52
|
+
expected_messages_first_2_lines = [
|
|
53
|
+
f"{'experiment: '.ljust(20)} {self.experiment.id}",
|
|
54
|
+
f"{'job directory: '.ljust(20)} {self.job_directory}",
|
|
55
|
+
]
|
|
56
|
+
self.assertEqual(actual_messages[:2], expected_messages_first_2_lines)
|
|
57
|
+
|
|
58
|
+
# verify last 8 lines as expected messages
|
|
59
|
+
expected_messages_last_few_lines = [
|
|
60
|
+
f"{'status filter: '.ljust(20)} ('0', '-1', '100')",
|
|
61
|
+
f"{'sim filter: '.ljust(20)} None",
|
|
62
|
+
f"{'verbose: '.ljust(20)} True",
|
|
63
|
+
f"{'display: '.ljust(20)} True",
|
|
64
|
+
f"{'Simulation Count: '.ljust(20)} {self.experiment.simulation_count}",
|
|
65
|
+
f"{'Match Count: '.ljust(20)} 1 ({{'0': 1}})",
|
|
66
|
+
f"{'Not Running Count: '.ljust(20)} 0",
|
|
67
|
+
"\nExperiment Status: SUCCEEDED"
|
|
68
|
+
]
|
|
69
|
+
self.assertEqual(actual_messages[-8:], expected_messages_last_few_lines)
|
|
70
|
+
|
|
71
|
+
# Test cli: get latest experiment info
|
|
72
|
+
# idmtools file job_directory get-latest
|
|
73
|
+
@patch('idmtools_platform_file.cli.file.user_logger')
|
|
74
|
+
def test_get_latest(self, mock_user_logger):
|
|
75
|
+
result = self.runner.invoke(file_cli.file, [self.job_directory, 'get-latest'])
|
|
76
|
+
self.assertEqual(result.exit_code, 0)
|
|
77
|
+
exp_dir = str(self.platform.get_directory_by_id(self.experiment.id, ItemType.EXPERIMENT))
|
|
78
|
+
expected_dict = dict(experiment_id=Path(exp_dir).name,
|
|
79
|
+
experiment_directory=exp_dir,
|
|
80
|
+
job_directory=self.job_directory)
|
|
81
|
+
actual_messages = [call[0][0] for call in mock_user_logger.info.call_args_list]
|
|
82
|
+
self.assertEqual(actual_messages[0], json.dumps(expected_dict, indent=3))
|
|
83
|
+
|
|
84
|
+
# Test cli: Get simulation/experiment's status
|
|
85
|
+
# idmtools file job_directory status --exp-id <exp_id>
|
|
86
|
+
@patch('idmtools_platform_file.tools.status_report.utils.user_logger')
|
|
87
|
+
def test_status(self, mock_user_logger):
|
|
88
|
+
result = self.runner.invoke(file_cli.file, [self.job_directory, 'status', '--exp-id', self.experiment.id])
|
|
89
|
+
self.assertEqual(result.exit_code, 0)
|
|
90
|
+
actual_messages = [call[0][0] for call in mock_user_logger.info.call_args_list]
|
|
91
|
+
exp_dir = str(self.platform.get_directory_by_id(self.experiment.id, ItemType.EXPERIMENT))
|
|
92
|
+
expected_messages = [
|
|
93
|
+
f"\nExperiment Directory: \n{exp_dir}",
|
|
94
|
+
"\nSimulation Count: 1\n",
|
|
95
|
+
"SUCCEEDED (1)",
|
|
96
|
+
"FAILED (0)",
|
|
97
|
+
"RUNNING (0)",
|
|
98
|
+
"PENDING (0)",
|
|
99
|
+
f"\nExperiment Status: SUCCEEDED\n"]
|
|
100
|
+
self.assertEqual(actual_messages, expected_messages)
|
|
101
|
+
|
|
102
|
+
# Test cli: get status of experiment/simulation
|
|
103
|
+
# idmtools file job_directory get-status --exp-id <exp_id>
|
|
104
|
+
@patch('idmtools_platform_file.cli.file.user_logger')
|
|
105
|
+
def test_get_status(self, mock_user_logger):
|
|
106
|
+
result = self.runner.invoke(file_cli.file, [self.job_directory, 'get-status', '--exp-id', self.experiment.id])
|
|
107
|
+
self.assertEqual(result.exit_code, 0)
|
|
108
|
+
mock_user_logger.info.assert_called_with("SUCCEEDED")
|
|
109
|
+
|
|
110
|
+
# Test cli: get path of experiment/simulation
|
|
111
|
+
# idmtools file job_directory get-path --exp-id <exp_id>
|
|
112
|
+
@patch('idmtools_platform_file.cli.file.user_logger')
|
|
113
|
+
def test_get_path(self, mock_user_logger):
|
|
114
|
+
result = self.runner.invoke(file_cli.file, [self.job_directory, 'get-path', '--exp-id', self.experiment.id])
|
|
115
|
+
self.assertEqual(result.exit_code, 0)
|
|
116
|
+
exp_dir = str(self.platform.get_directory_by_id(self.experiment.id, ItemType.EXPERIMENT))
|
|
117
|
+
mock_user_logger.info.assert_called_with(Path(exp_dir))
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
if __name__ == '__main__':
|
|
121
|
+
unittest.main()
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
from time import sleep
|
|
4
|
+
from unittest.mock import patch
|
|
5
|
+
import pytest
|
|
6
|
+
import idmtools_platform_container.cli.container as container_cli
|
|
7
|
+
from idmtools.core import ItemType
|
|
8
|
+
from idmtools.entities.command_task import CommandTask
|
|
9
|
+
from idmtools.entities.experiment import Experiment
|
|
10
|
+
from idmtools_platform_container.utils.general import normalize_path
|
|
11
|
+
|
|
12
|
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
|
13
|
+
from test_base import TestContainerPlatformCliBase
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.mark.serial
|
|
17
|
+
@pytest.mark.cli
|
|
18
|
+
class TestContainerPlatformGetDetailCli(TestContainerPlatformCliBase):
|
|
19
|
+
|
|
20
|
+
@patch('rich.console.Console.print')
|
|
21
|
+
def test_get_details(self, mock_console):
|
|
22
|
+
command = "sleep 100"
|
|
23
|
+
task = CommandTask(command=command)
|
|
24
|
+
experiment = Experiment.from_task(task, name="run_command")
|
|
25
|
+
experiment.run(wait_until_done=False)
|
|
26
|
+
sleep(1)
|
|
27
|
+
result = self.runner.invoke(container_cli.container, ['get-detail', experiment.id])
|
|
28
|
+
self.assertEqual(result.exit_code, 0)
|
|
29
|
+
self.assertIn(f'"JOB_DIRECTORY": "{normalize_path(self.job_directory)}",',
|
|
30
|
+
mock_console.call_args_list[0].args[0].text)
|
|
31
|
+
exp_dir = self.platform.get_directory_by_id(experiment.id, ItemType.EXPERIMENT)
|
|
32
|
+
self.assertIn(
|
|
33
|
+
f'"EXPERIMENT_DIR": "{normalize_path(exp_dir)}",',
|
|
34
|
+
mock_console.call_args_list[0].args[0].text)
|
|
35
|
+
self.assertIn(f'"EXPERIMENT_NAME": "run_command",',
|
|
36
|
+
mock_console.call_args_list[0].args[0].text)
|
|
37
|
+
self.assertIn(f'"EXPERIMENT_ID": "{experiment.id}",',
|
|
38
|
+
mock_console.call_args_list[0].args[0].text)
|
|
39
|
+
self.assertIn(f'"CONTAINER": "{self.platform.container_id}",',
|
|
40
|
+
mock_console.call_args_list[0].args[0].text)
|
|
41
|
+
self.assertIn(f'"CREATED": ',
|
|
42
|
+
mock_console.call_args_list[0].args[0].text)
|
|
43
|
+
# clean up container
|
|
44
|
+
result = self.runner.invoke(container_cli.container, ['stop-container', self.platform.container_id], '--remove')
|
|
45
|
+
self.assertEqual(result.exit_code, 0)
|
|
46
|
+
|
|
47
|
+
def test_get_detail_help(self):
|
|
48
|
+
result = self.runner.invoke(container_cli.container, ['get-detail', "--help"])
|
|
49
|
+
expected_help = ('Usage: container get-detail [OPTIONS] EXP_ID\n'
|
|
50
|
+
'\n'
|
|
51
|
+
' Retrieve Experiment history.\n'
|
|
52
|
+
'\n'
|
|
53
|
+
' Arguments:\n'
|
|
54
|
+
'\n'
|
|
55
|
+
' EXP_ID: Experiment ID\n'
|
|
56
|
+
'\n'
|
|
57
|
+
'Options:\n'
|
|
58
|
+
' --help Show this message and exit.\n')
|
|
59
|
+
self.assertEqual(result.exit_code, 0)
|
|
60
|
+
self.assertEqual(result.output, expected_help)
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
import sys
|
|
4
|
+
import unittest
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from unittest.mock import patch
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from idmtools.entities import Suite
|
|
10
|
+
from idmtools.entities.command_task import CommandTask
|
|
11
|
+
from idmtools.entities.experiment import Experiment
|
|
12
|
+
import idmtools_platform_container.cli.container as container_cli
|
|
13
|
+
from idmtools_platform_container.container_platform import ContainerPlatform
|
|
14
|
+
from idmtools_platform_container.utils.general import normalize_path
|
|
15
|
+
|
|
16
|
+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
|
17
|
+
from test_base import TestContainerPlatformCliBase
|
|
18
|
+
from helper import cleaned_str
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.mark.serial
|
|
22
|
+
@pytest.mark.cli
|
|
23
|
+
class TestContainerPlatformHistoryCli(TestContainerPlatformCliBase):
|
|
24
|
+
@patch('rich.console.Console.print')
|
|
25
|
+
def test_history(self, mock_console):
|
|
26
|
+
# first clear the history
|
|
27
|
+
result = self.runner.invoke(container_cli.container, ['clear-history'])
|
|
28
|
+
self.assertEqual(result.exit_code, 0)
|
|
29
|
+
command = "sleep 100"
|
|
30
|
+
platform = ContainerPlatform(job_directory=self.job_directory, new_container=True)
|
|
31
|
+
task = CommandTask(command=command)
|
|
32
|
+
experiment = Experiment.from_task(task, name="run_command")
|
|
33
|
+
experiment.run(wait_until_done=False, platform=platform)
|
|
34
|
+
# test history
|
|
35
|
+
result = self.runner.invoke(container_cli.container, ['history'])
|
|
36
|
+
self.assertEqual(result.exit_code, 0)
|
|
37
|
+
self.assertEqual('There are 1 Experiment cache in history.', mock_console.call_args_list[0].args[0])
|
|
38
|
+
self.assertIn(normalize_path(f"{platform.job_directory}"),
|
|
39
|
+
mock_console.call_args_list[2].args[0])
|
|
40
|
+
self.assertEqual('EXPERIMENT_NAME : run_command', cleaned_str(mock_console.call_args_list[3][0][0]))
|
|
41
|
+
self.assertEqual(f'EXPERIMENT_ID : {experiment.id}', cleaned_str(mock_console.call_args_list[4][0][0]))
|
|
42
|
+
self.assertEqual(f'CONTAINER : {platform.container_id}',
|
|
43
|
+
cleaned_str(mock_console.call_args_list[5][0][0]))
|
|
44
|
+
match_created_time = re.match(r'^CREATED : \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$',
|
|
45
|
+
cleaned_str(mock_console.call_args_list[6][0][0]))
|
|
46
|
+
self.assertTrue(match_created_time)
|
|
47
|
+
# Verify history path:
|
|
48
|
+
JOB_HISTORY_DIR = "idmtools_experiment_history"
|
|
49
|
+
history_path = Path.home().joinpath(".idmtools").joinpath(JOB_HISTORY_DIR)
|
|
50
|
+
self.assertTrue(history_path.is_dir())
|
|
51
|
+
self.assertTrue(any(history_path.iterdir())) # verify history path has some files
|
|
52
|
+
|
|
53
|
+
# clean up container
|
|
54
|
+
result = self.runner.invoke(container_cli.container, ['stop-container', platform.container_id, '--remove'])
|
|
55
|
+
self.assertEqual(result.exit_code, 0)
|
|
56
|
+
|
|
57
|
+
@patch('rich.console.Console.print')
|
|
58
|
+
def test_history_with_container(self, mock_console):
|
|
59
|
+
# first clear the history
|
|
60
|
+
result = self.runner.invoke(container_cli.container, ['clear-history'])
|
|
61
|
+
self.assertEqual(result.exit_code, 0)
|
|
62
|
+
command = "sleep 100"
|
|
63
|
+
task = CommandTask(command=command)
|
|
64
|
+
platform = ContainerPlatform(job_directory=self.job_directory, new_container=True)
|
|
65
|
+
experiment = Experiment.from_task(task, name="run_command")
|
|
66
|
+
experiment.run(wait_until_done=False, platform=platform)
|
|
67
|
+
# test history
|
|
68
|
+
result = self.runner.invoke(container_cli.container, ['history', platform.container_id])
|
|
69
|
+
self.assertEqual(result.exit_code, 0)
|
|
70
|
+
self.assertEqual('There are 1 Experiment cache in history.', mock_console.call_args_list[0].args[0])
|
|
71
|
+
self.assertIn(normalize_path(f"{platform.job_directory}"),
|
|
72
|
+
mock_console.call_args_list[2].args[0])
|
|
73
|
+
self.assertEqual('EXPERIMENT_NAME : run_command', cleaned_str(mock_console.call_args_list[3][0][0]))
|
|
74
|
+
self.assertEqual(f'EXPERIMENT_ID : {experiment.id}', cleaned_str(mock_console.call_args_list[4][0][0]))
|
|
75
|
+
self.assertEqual(f'CONTAINER : {platform.container_id}',
|
|
76
|
+
cleaned_str(mock_console.call_args_list[5][0][0]))
|
|
77
|
+
match_created_time = re.match(r'^CREATED : \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$',
|
|
78
|
+
cleaned_str(mock_console.call_args_list[6][0][0]))
|
|
79
|
+
self.assertTrue(match_created_time)
|
|
80
|
+
|
|
81
|
+
# clean up container
|
|
82
|
+
result = self.runner.invoke(container_cli.container, ['stop-container', platform.container_id, '--remove'])
|
|
83
|
+
self.assertEqual(result.exit_code, 0)
|
|
84
|
+
|
|
85
|
+
@patch('rich.console.Console.print')
|
|
86
|
+
def test_history_with_container_suite(self, mock_console):
|
|
87
|
+
# first clear the history
|
|
88
|
+
result = self.runner.invoke(container_cli.container, ['clear-history'])
|
|
89
|
+
self.assertEqual(result.exit_code, 0)
|
|
90
|
+
command = "sleep 100"
|
|
91
|
+
platform = ContainerPlatform(job_directory=self.job_directory, new_container=True)
|
|
92
|
+
task = CommandTask(command=command)
|
|
93
|
+
experiment = Experiment.from_task(task, name="run_command")
|
|
94
|
+
suite = Suite(name="suite_name")
|
|
95
|
+
suite.add_experiment(experiment)
|
|
96
|
+
suite.run(wait_until_done=False)
|
|
97
|
+
# test history
|
|
98
|
+
result = self.runner.invoke(container_cli.container, ['history', platform.container_id])
|
|
99
|
+
self.assertEqual(result.exit_code, 0)
|
|
100
|
+
self.assertEqual('There are 1 Experiment cache in history.', mock_console.call_args_list[0].args[0])
|
|
101
|
+
self.assertIn(normalize_path(f"{platform.job_directory}"),
|
|
102
|
+
mock_console.call_args_list[2].args[0])
|
|
103
|
+
self.assertEqual(f'SUITE_NAME : {suite.name}', cleaned_str(mock_console.call_args_list[3][0][0]))
|
|
104
|
+
self.assertEqual(f'SUITE_ID : {suite.id}', cleaned_str(mock_console.call_args_list[4][0][0]))
|
|
105
|
+
self.assertEqual(f'EXPERIMENT_NAME : {experiment.name}', cleaned_str(mock_console.call_args_list[5][0][0]))
|
|
106
|
+
self.assertEqual(f'EXPERIMENT_ID : {experiment.id}', cleaned_str(mock_console.call_args_list[6][0][0]))
|
|
107
|
+
self.assertEqual(f'CONTAINER : {platform.container_id}',
|
|
108
|
+
cleaned_str(mock_console.call_args_list[7][0][0]))
|
|
109
|
+
match_created_time = re.match(r'^CREATED : \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$',
|
|
110
|
+
cleaned_str(mock_console.call_args_list[8][0][0]))
|
|
111
|
+
self.assertTrue(match_created_time)
|
|
112
|
+
|
|
113
|
+
# clean up container
|
|
114
|
+
result = self.runner.invoke(container_cli.container, ['stop-container', platform.container_id, '--remove'])
|
|
115
|
+
self.assertEqual(result.exit_code, 0)
|
|
116
|
+
|
|
117
|
+
def test_history_help(self):
|
|
118
|
+
result = self.runner.invoke(container_cli.container, ['history', "--help"])
|
|
119
|
+
expected_help = ('Usage: container history [OPTIONS] [CONTAINER_ID]\n'
|
|
120
|
+
'\n'
|
|
121
|
+
' View the job history.\n'
|
|
122
|
+
'\n'
|
|
123
|
+
' Arguments:\n'
|
|
124
|
+
'\n'
|
|
125
|
+
' CONTAINER_ID: Container ID\n'
|
|
126
|
+
'\n'
|
|
127
|
+
'Options:\n'
|
|
128
|
+
' -l, --limit INTEGER Max number of jobs to show\n'
|
|
129
|
+
' -n, --next INTEGER Next number of jobs to show\n'
|
|
130
|
+
' --help Show this message and exit.\n')
|
|
131
|
+
self.assertEqual(result.exit_code, 0)
|
|
132
|
+
self.assertEqual(result.output, expected_help)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
if __name__ == '__main__':
|
|
136
|
+
unittest.main()
|