Source code for armi.cli.tests.test_runEntryPoint

# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Test for run cli entry point."""
from shutil import copyfile
import os
import sys
import unittest

from armi.__main__ import main
from armi.bookkeeping.visualization.entryPoint import VisFileEntryPoint
from armi.cli.checkInputs import CheckInputEntryPoint, ExpandBlueprints
from armi.cli.clone import CloneArmiRunCommandBatch, CloneSuiteCommand
from armi.cli.compareCases import CompareCases, CompareSuites
from armi.cli.database import ExtractInputs, InjectInputs
from armi.cli.entryPoint import EntryPoint
from armi.cli.migrateInputs import MigrateInputs
from armi.cli.modify import ModifyCaseSettingsCommand
from armi.cli.reportsEntryPoint import ReportsEntryPoint
from armi.cli.run import RunEntryPoint
from armi.cli.runSuite import RunSuiteCommand
from armi.physics.neutronics.diffIsotxs import CompareIsotxsLibraries
from armi.tests import mockRunLogs, TEST_ROOT, ARMI_RUN_PATH
from armi.utils.directoryChangers import TemporaryDirectoryChanger
from armi.utils.dynamicImporter import getEntireFamilyTree


[docs]class TestInitializationEntryPoints(unittest.TestCase):
[docs] def test_entryPointInitialization(self): """Tests the initialization of all subclasses of `EntryPoint`. .. test:: Test initialization of many basic CLIs. :id: T_ARMI_CLI_GEN0 :tests: R_ARMI_CLI_GEN """ entryPoints = getEntireFamilyTree(EntryPoint) # Comparing to a minimum number of entry points, in case more are added. self.assertGreater(len(entryPoints), 15) for e in entryPoints: entryPoint = e() entryPoint.addOptions() settingsArg = None if entryPoint.settingsArgument is not None: for a in entryPoint.parser._actions: if "settings_file" in a.dest: settingsArg = a break self.assertIsNotNone( settingsArg, msg=( f"A settings file argument was expected for {entryPoint}, " "but does not exist. This is a error in the EntryPoint " "implementation." ), )
[docs]class TestCheckInputEntryPoint(unittest.TestCase):
[docs] def test_checkInputEntryPointBasics(self): ci = CheckInputEntryPoint() ci.addOptions() ci.parse_args(["/path/to/fake.yaml", "-C"]) self.assertEqual(ci.name, "check-input") self.assertEqual(ci.args.patterns, ["/path/to/fake.yaml"]) self.assertEqual(ci.args.skip_checks, True) self.assertEqual(ci.args.generate_design_summary, False)
[docs] def test_checkInputEntryPointInvoke(self): """Test the "check inputs" entry point. .. test:: A working CLI child class, to validate inputs. :id: T_ARMI_CLI_GEN1 :tests: R_ARMI_CLI_GEN """ ci = CheckInputEntryPoint() ci.addOptions() ci.parse_args([ARMI_RUN_PATH]) with mockRunLogs.BufferLog() as mock: self.assertEqual("", mock.getStdout()) ci.invoke() self.assertIn(ARMI_RUN_PATH, mock.getStdout()) self.assertIn("input is self consistent", mock.getStdout())
[docs]class TestCloneArmiRunCommandBatch(unittest.TestCase):
[docs] def test_cloneArmiRunCommandBatchBasics(self): ca = CloneArmiRunCommandBatch() ca.addOptions() ca.parse_args( [ ARMI_RUN_PATH, "--additional-files", "test", "--settingsWriteStyle", "full", ] ) self.assertEqual(ca.name, "clone-batch") self.assertEqual(ca.settingsArgument, "required") self.assertEqual(ca.args.additional_files, ["test"]) self.assertEqual(ca.args.settingsWriteStyle, "full")
[docs] def test_cloneArmiRunCommandBatchInvokeShort(self): # Test short write style ca = CloneArmiRunCommandBatch() ca.addOptions() ca.parse_args([ARMI_RUN_PATH]) with TemporaryDirectoryChanger(): ca.invoke() self.assertEqual(ca.settingsArgument, "required") self.assertEqual(ca.args.settingsWriteStyle, "short") clonedYaml = "armiRun.yaml" self.assertTrue(os.path.exists(clonedYaml)) # validate a setting that has a default value was removed txt = open(clonedYaml, "r").read() self.assertNotIn("availabilityFactor", txt)
[docs] def test_cloneArmiRunCommandBatchInvokeMedium(self): """Test the "clone armi run" batch entry point, on medium detail. .. test:: A working CLI child class, to clone a run. :id: T_ARMI_CLI_GEN2 :tests: R_ARMI_CLI_GEN """ # Test medium write style ca = CloneArmiRunCommandBatch() ca.addOptions() ca.parse_args([ARMI_RUN_PATH, "--settingsWriteStyle", "medium"]) with TemporaryDirectoryChanger(): ca.invoke() self.assertEqual(ca.settingsArgument, "required") self.assertEqual(ca.args.settingsWriteStyle, "medium") clonedYaml = "armiRun.yaml" self.assertTrue(os.path.exists(clonedYaml)) # validate a setting that has a default value is still there txt = open(clonedYaml, "r").read() self.assertIn("availabilityFactor", txt)
[docs]class TestCloneSuiteCommand(unittest.TestCase):
[docs] def test_cloneSuiteCommandBasics(self): cs = CloneSuiteCommand() cs.addOptions() cs.parse_args(["-d", "test", "--settingsWriteStyle", "medium"]) self.assertEqual(cs.name, "clone-suite") self.assertEqual(cs.args.directory, "test") self.assertEqual(cs.args.settingsWriteStyle, "medium")
[docs]class TestCompareCases(unittest.TestCase):
[docs] def test_compareCasesBasics(self): cc = CompareCases() cc.addOptions() cc.parse_args(["/path/to/fake1.h5", "/path/to/fake2.h5"]) self.assertEqual(cc.name, "compare") self.assertIsNone(cc.args.timestepCompare) self.assertIsNone(cc.args.weights)
[docs]class TestCompareSuites(unittest.TestCase):
[docs] def test_compareSuitesBasics(self): cs = CompareSuites() cs.addOptions() cs.parse_args(["/path/to/fake1.h5", "/path/to/fake2.h5"]) self.assertEqual(cs.name, "compare-suites") self.assertEqual(cs.args.reference, "/path/to/fake1.h5") self.assertIsNone(cs.args.weights)
[docs]class TestExpandBlueprints(unittest.TestCase):
[docs] def test_expandBlueprintsBasics(self): ebp = ExpandBlueprints() ebp.addOptions() ebp.parse_args(["/path/to/fake.yaml"]) self.assertEqual(ebp.name, "expand-bp") self.assertEqual(ebp.args.blueprints, "/path/to/fake.yaml") # Since the file is fake, invoke() should exit early. with mockRunLogs.BufferLog() as mock: self.assertEqual("", mock.getStdout()) ebp.invoke() self.assertIn("does not exist", mock.getStdout())
[docs]class TestExtractInputs(unittest.TestCase):
[docs] def test_extractInputsBasics(self): ei = ExtractInputs() ei.addOptions() ei.parse_args(["/path/to/fake"]) self.assertEqual(ei.name, "extract-inputs") self.assertEqual(ei.args.output_base, "/path/to/fake") with mockRunLogs.BufferLog() as mock: self.assertEqual("", mock.getStdout()) with self.assertRaises(FileNotFoundError): # The "fake" file doesn't exist, so this should fail. ei.invoke()
[docs]class TestInjectInputs(unittest.TestCase):
[docs] def test_injectInputsBasics(self): ii = InjectInputs() ii.addOptions() ii.parse_args(["/path/to/fake.h5"]) self.assertEqual(ii.name, "inject-inputs") self.assertIsNone(ii.args.blueprints)
[docs] def test_injectInputsInvokeIgnore(self): ii = InjectInputs() ii.addOptions() ii.parse_args(["/path/to/fake.h5"]) with mockRunLogs.BufferLog() as mock: self.assertEqual("", mock.getStdout()) ii.invoke() self.assertIn("No settings", mock.getStdout())
[docs] def test_injectInputsInvokeNoData(self): with TemporaryDirectoryChanger(): # init CLI ii = InjectInputs() ii.addOptions() bp = os.path.join(TEST_ROOT, "refSmallReactor.yaml") ii.parse_args(["/path/to/fake.h5", "--blueprints", bp]) # invoke and check log with mockRunLogs.BufferLog() as mock: self.assertEqual("", mock.getStdout()) with self.assertRaises(FileNotFoundError): # The "fake.h5" doesn't exist, so this should fail. ii.invoke()
[docs]class TestMigrateInputs(unittest.TestCase):
[docs] def test_migrateInputsBasics(self): mi = MigrateInputs() mi.addOptions() mi.parse_args(["--settings-path", "cs_path"]) self.assertEqual(mi.name, "migrate-inputs") self.assertEqual(mi.args.settings_path, "cs_path")
[docs]class TestModifyCaseSettingsCommand(unittest.TestCase):
[docs] def test_modifyCaseSettingsCommandBasics(self): mcs = ModifyCaseSettingsCommand() mcs.addOptions() mcs.parse_args( ["--rootDir", "/path/to/", "--settingsWriteStyle", "medium", "fake.yaml"] ) self.assertEqual(mcs.name, "modify") self.assertEqual(mcs.args.rootDir, "/path/to/") self.assertEqual(mcs.args.settingsWriteStyle, "medium") self.assertEqual(mcs.args.patterns, ["fake.yaml"])
[docs] def test_modifyCaseSettingsCommandInvoke(self): mcs = ModifyCaseSettingsCommand() mcs.addOptions() with TemporaryDirectoryChanger(): # copy over settings files for fileName in ["armiRun.yaml", "refSmallReactor.yaml"]: copyfile(os.path.join(TEST_ROOT, fileName), fileName) # pass in --numProcessors=333 mcs.parse_args(["--numProcessors=333", "--rootDir", ".", "armiRun.yaml"]) # invoke the CLI mcs.invoke() # validate the change to numProcessors was made txt = open("armiRun.yaml", "r").read() self.assertIn("numProcessors: 333", txt)
[docs]class TestReportsEntryPoint(unittest.TestCase):
[docs] def test_reportsEntryPointBasics(self): rep = ReportsEntryPoint() rep.addOptions() rep.parse_args(["-h5db", "/path/to/fake.h5"]) self.assertEqual(rep.name, "report") self.assertEqual(rep.settingsArgument, "optional") with mockRunLogs.BufferLog() as mock: self.assertEqual("", mock.getStdout()) with self.assertRaises(ValueError): # The "fake.h5" doesn't exist, so this should fail. rep.invoke()
[docs]class TestCompareIsotxsLibsEntryPoint(unittest.TestCase):
[docs] def test_compareIsotxsLibsBasics(self): com = CompareIsotxsLibraries() com.addOptions() com.parse_args( ["--fluxFile", "/path/to/fluxfile.txt", "reference", "comparisonFiles"] ) self.assertEqual(com.name, "diff-isotxs") self.assertIsNone(com.settingsArgument)
[docs]class TestRunEntryPoint(unittest.TestCase):
[docs] def test_runEntryPointBasics(self): rep = RunEntryPoint() rep.addOptions() rep.parse_args([ARMI_RUN_PATH]) self.assertEqual(rep.name, "run") self.assertEqual(rep.settingsArgument, "required")
[docs] def test_runCommandHelp(self): """Ensure main entry point with no args completes.""" with self.assertRaises(SystemExit) as excinfo: # have to override the pytest args sys.argv = [""] main() self.assertEqual(excinfo.exception.code, 0)
[docs] def test_executeCommand(self): """Use executeCommand to call run. But we expect it to fail because we provide a fictional settings YAML. """ with self.assertRaises(SystemExit) as excinfo: # override the pytest args sys.argv = ["run", "path/to/fake.yaml"] main() self.assertEqual(excinfo.exception.code, 1)
[docs]class TestRunSuiteCommand(unittest.TestCase):
[docs] def test_runSuiteCommandBasics(self): rs = RunSuiteCommand() rs.addOptions() rs.parse_args(["/path/to/fake.yaml"]) self.assertEqual(rs.name, "run-suite") self.assertIsNone(rs.settingsArgument)
[docs]class TestVisFileEntryPointCommand(unittest.TestCase):
[docs] def test_visFileEntryPointBasics(self): vf = VisFileEntryPoint() vf.addOptions() vf.parse_args(["/path/to/fake.h5"]) self.assertEqual(vf.name, "vis-file") self.assertIsNone(vf.settingsArgument)