Repository: terrapower/armi
Pull request #1713 (2024-05-23 21:13:07)

Adding the MacOS to CI
## What is the change?

Adding the MacOS to CI.

## Why is the change being made?

I recently found out that some of our [users are Mac people](https://github.com/terrapower/armi/issues/1693#issuecomment-2075848836).

## Notes

1. I can not immediately get our unit tests working in Mac in parallel (something about our test temp directory logic breaks). So, this PR only runs the unit tests in series.
2. The Mac Unit Tests take 14 minutes to run. Is that too long?

---

## Checklist

- [X] This PR has only [one purpose or idea](https://terrapower.github.io/armi/developer/tooling.html#one-idea-one-pr).
- [X] [Tests](https://terrapower.github.io/armi/developer/tooling.html#test-it) have been added/updated to verify any new/changed code.

<!-- Check the code quality -->

- [X] The code style follows [good practices](https://terrapower.github.io/armi/developer/standards_and_practices.html).
- [X] The commit message(s) follow [good practices](https://terrapower.github.io/armi/developer/tooling.html).

<!-- Check the project-level cruft -->

- [X] The [release notes](https://terrapower.github.io/armi/developer/tooling.html#add-release-notes) have been updated if necessary.
- [X] The [documentation](https://terrapower.github.io/armi/developer/tooling.html#document-it) is still up-to-date in the `doc` folder.
- [X] The dependencies are still up-to-date in `pyproject.toml`.

john-science: > I've got an old macbook air from grad school lying around if you ever need more mac-specific testing.

I borrowed my wife's Mac. But I'm sure I'd love a second tester. Up to you!

Patch:
diff --git a/armi/bookkeeping/report/reportingUtils.py b/armi/bookkeeping/report/reportingUtils.py
index b1a2291b..c8526cdd 100644
--- a/armi/bookkeeping/report/reportingUtils.py
+++ b/armi/bookkeeping/report/reportingUtils.py
@@ -283,6 +283,31 @@ def _getSystemInfoWindows():
     return subprocess.run(cmd, capture_output=True, text=True, shell=True).stdout
 
 
+def _getSystemInfoMac():
+    """Get system information, assuming the system is MacOS.
+
+    Returns
+    -------
+    str
+        Basic system information: OS name, OS version, basic processor information
+
+    Examples
+    --------
+    Example results:
+
+        System Software Overview:
+
+        System Version: macOS 12.1 (21C52)
+        Kernel Version: Darwin 21.2.0
+        ...
+        Hardware Overview:
+        Model Name: MacBook Pro
+        ...
+    """
+    cmd = "system_profiler SPSoftwareDataType SPHardwareDataType"
+    return subprocess.check_output(cmd, shell=True).decode("utf-8")
+
+
 def _getSystemInfoLinux():
     """Get system information, assuming the system is Linux.
 
@@ -369,10 +394,12 @@ def getSystemInfo():
         return _getSystemInfoWindows()
     elif "linux" in sys.platform:
         return _getSystemInfoLinux()
+    elif "darwin" in sys.platform:
+        return _getSystemInfoMac()
     else:
         runLog.warning(
             f"Cannot get system information for {sys.platform} because ARMI only "
-            + "supports Linux and Windows."
+            + "supports Linux, Windows, and MacOS."
         )
         return ""
 
diff --git a/doc/release/0.3.rst b/doc/release/0.3.rst
index 6ed9df78..8c236a78 100644
--- a/doc/release/0.3.rst
+++ b/doc/release/0.3.rst
@@ -55,6 +55,7 @@ Bug Fixes
 
 Quality Work
 ------------
+#. Supporting MacOS in CI. (`PR#1713 <https://github.com/terrapower/armi/pull/1713>`_)
 #. We now enforce a maximum line length of 120 characters, using ``ruff``. (`PR#1646 <https://github.com/terrapower/armi/pull/1646>`_)
 #. Move ``.coveragerc`` file information into ``pyproject.toml``. (`PR#1692 <https://github.com/terrapower/armi/pull/1692>`_)
 #. TBD
diff --git a/doc/user/inputs.rst b/doc/user/inputs.rst
index 3cc3916a..fda2d072 100644
--- a/doc/user/inputs.rst
+++ b/doc/user/inputs.rst
@@ -478,7 +478,7 @@ The ARMI data model is represented schematically below, and the blueprints are d
     Defines :py:class:`~armi.reactor.components.component.Component` inputs for a
     :py:class:`~armi.reactor.blocks.Block`.
 
-:ref:`asssemblies <assemblies>`:
+:ref:`assemblies <assemblies>`:
     Defines vertical stacks of blocks used to define the axial profile of an
     :py:class:`~armi.reactor.assemblies.Assembly`.
 


Test patch:
diff --git a/.github/workflows/mac_tests.yaml b/.github/workflows/mac_tests.yaml
new file mode 100644
index 00000000..77da1919
--- /dev/null
+++ b/.github/workflows/mac_tests.yaml
@@ -0,0 +1,28 @@
+name: ARMI MacOS Tests
+
+on:
+  push:
+    paths-ignore:
+      - 'doc/**'
+  pull_request:
+    paths-ignore:
+      - 'doc/**'
+
+jobs:
+  build:
+
+    runs-on: macos-14
+
+    steps:
+      - uses: actions/checkout@v2
+      - name: Setup Python
+        uses: actions/setup-python@v2
+        with:
+          python-version: '3.11'
+      - name: Upgrade PIP
+        run: python -m pip install --upgrade pip
+      - name: Run Unit Tests on MacOS
+        run: |
+          brew install openmpi
+          pip install -e .[memprof,mpi,test]
+          pytest armi
diff --git a/armi/bookkeeping/report/tests/test_report.py b/armi/bookkeeping/report/tests/test_report.py
index 87298060..9d70fce6 100644
--- a/armi/bookkeeping/report/tests/test_report.py
+++ b/armi/bookkeeping/report/tests/test_report.py
@@ -16,6 +16,7 @@
 import logging
 import os
 import subprocess
+import sys
 import unittest
 from unittest.mock import patch
 
@@ -24,6 +25,7 @@ from armi.bookkeeping import report
 from armi.bookkeeping.report import data, reportInterface
 from armi.bookkeeping.report.reportingUtils import (
     _getSystemInfoLinux,
+    _getSystemInfoMac,
     _getSystemInfoWindows,
     getNodeName,
     getSystemInfo,
@@ -91,14 +93,36 @@ Processor(s):    1 Processor(s) Installed.
         out = _getSystemInfoWindows()
         self.assertEqual(out, windowsResult)
 
+    @patch("subprocess.run")
+    def test_getSystemInfoMac(self, mockSubprocess):
+        """Test _getSystemInfoMac() on any operating system, by mocking the system call."""
+        macResult = b"""System Software Overview:
+
+        System Version: macOS 12.1 (21C52)
+        Kernel Version: Darwin 21.2.0
+        ...
+        Hardware Overview:
+        Model Name: MacBook Pro
+        ..."""
+
+        mockSubprocess.return_value = _MockReturnResult(macResult)
+
+        out = _getSystemInfoMac()
+        self.assertEqual(out, macResult.decode("utf-8"))
+
     def test_getSystemInfo(self):
         """Basic sanity check of getSystemInfo() running in the wild.
 
         This test should pass if it is run on Window or mainstream Linux distros. But we expect this
         to fail if the test is run on some other OS.
         """
+        if "darwin" in sys.platform:
+            # too comlicated to test MacOS in this method
+            return
+
         out = getSystemInfo()
         substrings = ["OS ", "Processor(s):"]
+
         for sstr in substrings:
             self.assertIn(sstr, out)