From 5724700de6ad92fe0171fc8f7ec96a833ddad885 Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Wed, 23 Oct 2024 11:42:55 -0400 Subject: [PATCH 1/5] update expected values for transit tests In b4805ed61b8925720b71cfd7a9f64d4e43f7a2e4, the NTD intensities were adjusted. Thus, the expected values in all tests that perform transit calculations must be updated. I noticed that the second argument of Jest's `toBeCloseTo` is supposed to be a # of decimal places, not a delta as we were using before. So I changed our `expectAlmostEqual` wrapper to use `places` rather than `delta`. This ensures consistent pass/fail conditions whether the test is running in python or JS. --- test/__testing.py | 8 +++++--- test/metrics/test_egrid.py | 4 ++-- test/metrics/test_footprint_calculations.py | 16 ++++++++-------- test/metrics/test_transit.js | 14 +++++++------- test/metrics/test_transit.py | 14 +++++++------- 5 files changed, 29 insertions(+), 27 deletions(-) diff --git a/test/__testing.py b/test/__testing.py index 941db0b..7b88627 100644 --- a/test/__testing.py +++ b/test/__testing.py @@ -12,11 +12,13 @@ def expectEqual(a, b): ?''' -def expectAlmostEqual(a, b, delta=0.001): - assert abs(a - b) < delta # __: skip +# __pragma__('kwargs') +def expectAlmostEqual(a, b, places=3): + assert abs(a - b) < (.5 / 10 ** places) # __: skip '''? - expect(a).toBeCloseTo(b, delta) + expect(a).toBeCloseTo(b, places) ?''' +# __pragma__('nokwargs') def jest_test(test): diff --git a/test/metrics/test_egrid.py b/test/metrics/test_egrid.py index faefea4..3c7c7d7 100644 --- a/test/metrics/test_egrid.py +++ b/test/metrics/test_egrid.py @@ -29,7 +29,7 @@ async def test_egrid_intensity_cincinnati_2022(): "requested_coords": coords, "egrid_region": "RFCW", } - expectAlmostEqual(kg_per_kwh, expected_kg_per_kwh, delta=0.01) + expectAlmostEqual(kg_per_kwh, expected_kg_per_kwh, places=2) for key in expected_metadata.keys(): expectEqual(metadata[key], expected_metadata[key]) @@ -51,7 +51,7 @@ async def test_egrid_intensity_eagle_point_2023(): "requested_coords": coords, "egrid_region": "NWPP", } - expectAlmostEqual(kg_per_kwh, expected_kg_per_kwh, delta=0.01) + expectAlmostEqual(kg_per_kwh, expected_kg_per_kwh, places=2) for key in expected_metadata.keys(): expectEqual(metadata[key], expected_metadata[key]) diff --git a/test/metrics/test_footprint_calculations.py b/test/metrics/test_footprint_calculations.py index 1d62b6c..e36594e 100644 --- a/test/metrics/test_footprint_calculations.py +++ b/test/metrics/test_footprint_calculations.py @@ -26,7 +26,7 @@ async def test_car_footprint(): expected_footprint = {'kwh': 0.899, 'kg_co2': 0.291} for key in expected_footprint.keys(): - expectAlmostEqual(footprint[key], expected_footprint[key], delta=0.001) + expectAlmostEqual(footprint[key], expected_footprint[key], places=3) # with 2 passengers, the footprint should be halved fake_label_options['MODE'][0]['passengers'] = 2 @@ -35,7 +35,7 @@ async def test_car_footprint(): expected_footprint = {'kwh': 0.899 / 2, 'kg_co2': 0.291 / 2} for key in expected_footprint.keys(): - expectAlmostEqual(footprint[key], expected_footprint[key], delta=0.001) + expectAlmostEqual(footprint[key], expected_footprint[key], places=3) @jest_test @@ -60,7 +60,7 @@ async def test_ebike_footprint(): expected_footprint = {'kwh': 0.014, 'kg_co2': 0.006} for key in expected_footprint.keys(): - expectAlmostEqual(footprint[key], expected_footprint[key], delta=0.001) + expectAlmostEqual(footprint[key], expected_footprint[key], places=3) @jest_test @@ -88,7 +88,7 @@ async def test_custom_car_footprint(): 'kg_co2': (0.1 / 1000) * emcmfu.FUELS_KG_CO2_PER_MWH['gasoline'] } for key in expected_footprint.keys(): - expectAlmostEqual(footprint[key], expected_footprint[key], delta=0.01) + expectAlmostEqual(footprint[key], expected_footprint[key], places=2) @jest_test @@ -111,7 +111,7 @@ async def test_nyc_bus_footprint(): (footprint, metadata) = await emcmff.calc_footprint_for_trip(fake_trip, fake_label_options) - expected_footprint = {'kwh': 12.93, 'kg_co2': 2.80} + expected_footprint = {'kwh': 12.82, 'kg_co2': 2.78} expected_metadata = { "data_sources": ["ntd2022", "egrid2022"], "is_provisional": False, @@ -120,7 +120,7 @@ async def test_nyc_bus_footprint(): "ntd_modes": ["MB", "RB", "CB"], } for key in expected_footprint.keys(): - expectAlmostEqual(footprint[key], expected_footprint[key], delta=0.01) + expectAlmostEqual(footprint[key], expected_footprint[key], places=2) for key in expected_metadata.keys(): expectEqual(metadata[key], expected_metadata[key]) @@ -156,8 +156,8 @@ async def test_impact_of_ebike_replacing_car(): kwh_saved = replaced_mode_footprint['kwh'] - mode_footprint['kwh'] kg_co2_saved = replaced_mode_footprint['kg_co2'] - mode_footprint['kg_co2'] - expectAlmostEqual(kwh_saved, 0.885, delta=0.001) - expectAlmostEqual(kg_co2_saved, 0.285, delta=0.001) + expectAlmostEqual(kwh_saved, 0.885, places=3) + expectAlmostEqual(kg_co2_saved, 0.285, places=3) jest_describe("test_footprint_calculations") diff --git a/test/metrics/test_transit.js b/test/metrics/test_transit.js index 2d146cc..ba94143 100644 --- a/test/metrics/test_transit.js +++ b/test/metrics/test_transit.js @@ -21,43 +21,43 @@ describe('TestTransit', () => { it('test_bus_nyc', async () => { const [intensities, metadata] = await emcft.get_transit_intensities_for_uace(2022, NYC_UACE_CODE, BUS_MODES); - expect(intensities['overall']['wh_per_km']).toBeCloseTo(646.80, 2); + expect(intensities['overall']['wh_per_km']).toBeCloseTo(641.24, 2); expect(metadata['ntd_ids'].length).toEqual(22); }); it('test_bus_chicago', async () => { const [intensities, metadata] = await emcft.get_transit_intensities_for_uace(2022, CHICAGO_UACE_CODE, BUS_MODES); - expect(intensities['overall']['wh_per_km']).toBeCloseTo(1048.12, 2); + expect(intensities['overall']['wh_per_km']).toBeCloseTo(1039.10, 2); expect(metadata['ntd_ids'].length).toEqual(2); }); it('test_bus_nationwide', async () => { const [intensities, metadata] = await emcft.get_transit_intensities_for_uace(2022, null, BUS_MODES); - expect(intensities['overall']['wh_per_km']).toBeCloseTo(811.85, 2); + expect(intensities['overall']['wh_per_km']).toBeCloseTo(804.91, 2); expect(metadata['ntd_ids'].length).toEqual(410); }); it('test_train_nyc', async () => { const [intensities, metadata] = await emcft.get_transit_intensities_for_uace(2022, NYC_UACE_CODE, TRAIN_MODES); - expect(intensities['overall']['wh_per_km']).toBeCloseTo(24.79, 2); + expect(intensities['overall']['wh_per_km']).toBeCloseTo(24.75, 2); expect(metadata['ntd_ids'].length).toEqual(6); }); it('test_train_chicago', async () => { const [intensities, metadata] = await emcft.get_transit_intensities_for_uace(2022, CHICAGO_UACE_CODE, TRAIN_MODES); - expect(intensities['overall']['wh_per_km']).toBeCloseTo(159.04, 2); + expect(intensities['overall']['wh_per_km']).toBeCloseTo(158.14, 2); expect(metadata['ntd_ids'].length).toEqual(3); }); it('test_train_nationwide', async () => { const [intensities, metadata] = await emcft.get_transit_intensities_for_uace(2022, null, TRAIN_MODES); - expect(intensities['overall']['wh_per_km']).toBeCloseTo(68.06, 2); + expect(intensities['overall']['wh_per_km']).toBeCloseTo(67.87, 2); expect(metadata['ntd_ids'].length).toEqual(49); }); it('test_all_modes_nationwide', async () => { const [intensities, metadata] = await emcft.get_transit_intensities_for_uace(2022, null, null); - expect(intensities['overall']['wh_per_km']).toBeCloseTo(486.96, 2); + expect(intensities['overall']['wh_per_km']).toBeCloseTo(483.04, 2); expect(metadata['ntd_ids'].length).toEqual(517); }); }); diff --git a/test/metrics/test_transit.py b/test/metrics/test_transit.py index bc9e2bc..5bcd95d 100644 --- a/test/metrics/test_transit.py +++ b/test/metrics/test_transit.py @@ -19,38 +19,38 @@ async def test_get_uace_by_coords(self): async def test_bus_nyc(self): (intensities, metadata) = await emcmft.get_transit_intensities_for_uace(2022, NYC_UACE_CODE, BUS_MODES) - self.assertAlmostEqual(intensities['overall']['wh_per_km'], 646.80, places=2) + self.assertAlmostEqual(intensities['overall']['wh_per_km'], 641.24, places=2) self.assertEqual(len(metadata['ntd_ids']), 22) async def test_bus_chicago(self): (intensities, metadata) = await emcmft.get_transit_intensities_for_uace(2022, CHICAGO_UACE_CODE, BUS_MODES) - self.assertAlmostEqual(intensities['overall']['wh_per_km'], 1048.12, places=2) + self.assertAlmostEqual(intensities['overall']['wh_per_km'], 1039.10, places=2) self.assertEqual(len(metadata['ntd_ids']), 2) async def test_bus_nationwide(self): (intensities, metadata) = await emcmft.get_transit_intensities_for_uace(2022, None, BUS_MODES) - self.assertAlmostEqual(intensities['overall']['wh_per_km'], 811.85, places=2) + self.assertAlmostEqual(intensities['overall']['wh_per_km'], 804.91, places=2) self.assertEqual(len(metadata['ntd_ids']), 410) async def test_train_nyc(self): (intensities, metadata) = await emcmft.get_transit_intensities_for_uace(2022, NYC_UACE_CODE, TRAIN_MODES) - self.assertAlmostEqual(intensities['overall']['wh_per_km'], 24.79, places=2) + self.assertAlmostEqual(intensities['overall']['wh_per_km'], 24.75, places=2) self.assertEqual(len(metadata['ntd_ids']), 6) async def test_train_chicago(self): (intensities, metadata) = await emcmft.get_transit_intensities_for_uace(2022, CHICAGO_UACE_CODE, TRAIN_MODES) - self.assertAlmostEqual(intensities['overall']['wh_per_km'], 159.04, places=2) + self.assertAlmostEqual(intensities['overall']['wh_per_km'], 158.14, places=2) # 3 passenger rail systems in Chicago - "the L", Metra, and South Shore Line self.assertEqual(len(metadata['ntd_ids']), 3) async def test_train_nationwide(self): (intensities, metadata) = await emcmft.get_transit_intensities_for_uace(2022, None, TRAIN_MODES) - self.assertAlmostEqual(intensities['overall']['wh_per_km'], 68.06, places=2) + self.assertAlmostEqual(intensities['overall']['wh_per_km'], 67.87, places=2) self.assertEqual(len(metadata['ntd_ids']), 49) async def test_all_modes_nationwide(self): (intensities, metadata) = await emcmft.get_transit_intensities_for_uace(2022, None, None) - self.assertAlmostEqual(intensities['overall']['wh_per_km'], 486.96, places=2) + self.assertAlmostEqual(intensities['overall']['wh_per_km'], 483.04, places=2) self.assertEqual(len(metadata['ntd_ids']), 517) From 863161e0f6c72353887d94e7262d87247fdba720 Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Wed, 23 Oct 2024 11:48:56 -0400 Subject: [PATCH 2/5] add unit-tests.yml (experimenting with GH actions) --- .github/workflows/unit-tests.yml | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/workflows/unit-tests.yml diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 0000000..3691eca --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,48 @@ +# taken from https://github.com/e-mission/e-mission-server/blob/master/.github/workflows/test-with-manual-install.yml + +name: unit-tests + +# Controls when the action will run. Triggers the workflow on push or pull request +on: + push: + pull_request: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + test-pytest: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Run setup.sh + shell: bash -l {0} + run: | + source bin/setup.sh + + - name: Run pytest + shell: bash -l {0} + run: | + source bin/run_pytest.sh + + test-jest: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '20' + + - name: Run setup.sh + shell: bash -l {0} + run: | + source bin/setup.sh + + - name: Run jest tests + shell: bash -l {0} + run: | + source bin/run_jest.sh From 0f958780b8c3510ebd1df8e445b1e813faa8fa38 Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Wed, 23 Oct 2024 11:55:38 -0400 Subject: [PATCH 3/5] fix TARGET_PLATFORM in setup.sh The setup_conda.sh script expects "Linux-x86_64" or "MacOSX-x86_64", not "linux" or "mac" --- bin/setup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/setup.sh b/bin/setup.sh index d451d47..754218e 100644 --- a/bin/setup.sh +++ b/bin/setup.sh @@ -11,9 +11,9 @@ rm -rf e-mission-server # determine platform if [[ "$OSTYPE" == "linux-gnu"* ]]; then - TARGET_PLATFORM="linux" + TARGET_PLATFORM="Linux-x86_64" elif [[ "$OSTYPE" == "darwin"* ]]; then - TARGET_PLATFORM="mac" + TARGET_PLATFORM="MacOSX-x86_64" else echo "Unsupported platform $OSTYPE" exit 1 From a9fdffd816c860b657c7e46377184d4f790238b1 Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Wed, 23 Oct 2024 12:24:25 -0400 Subject: [PATCH 4/5] remove unit-tests.yml experiment --- .github/workflows/unit-tests.yml | 48 -------------------------------- 1 file changed, 48 deletions(-) delete mode 100644 .github/workflows/unit-tests.yml diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml deleted file mode 100644 index 3691eca..0000000 --- a/.github/workflows/unit-tests.yml +++ /dev/null @@ -1,48 +0,0 @@ -# taken from https://github.com/e-mission/e-mission-server/blob/master/.github/workflows/test-with-manual-install.yml - -name: unit-tests - -# Controls when the action will run. Triggers the workflow on push or pull request -on: - push: - pull_request: - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - test-pytest: - # The type of runner that the job will run on - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Run setup.sh - shell: bash -l {0} - run: | - source bin/setup.sh - - - name: Run pytest - shell: bash -l {0} - run: | - source bin/run_pytest.sh - - test-jest: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Set up Node.js - uses: actions/setup-node@v2 - with: - node-version: '20' - - - name: Run setup.sh - shell: bash -l {0} - run: | - source bin/setup.sh - - - name: Run jest tests - shell: bash -l {0} - run: | - source bin/run_jest.sh From e8ae9dc2ef6dd264a67533db22ce1b1bf12428d6 Mon Sep 17 00:00:00 2001 From: jpfleischer <70083705+jpfleischer@users.noreply.github.com> Date: Wed, 23 Oct 2024 12:41:53 -0400 Subject: [PATCH 5/5] add unit-tests workflow; auto run tests with both `jest` + `pytest` * Adds an automated unit-tests workflow with GitHub Actions -- This workflow has 2 tasks that run in parallel. Both start by setting up an environment with `setup.sh`. Then, one runs `run_pytest.sh` and the other runs `run_jest.sh`. * Adds execute permissions to all *.sh files in `bin` Co-authored-by: Jack Greenlee --- .github/workflows/unit-tests.yml | 48 ++++++++++++++++++++++++++++++++ README.md | 6 +++- bin/compile_to_js.sh | 0 bin/run_jest.sh | 0 bin/run_pytest.sh | 0 bin/setup.sh | 0 6 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/unit-tests.yml mode change 100644 => 100755 bin/compile_to_js.sh mode change 100644 => 100755 bin/run_jest.sh mode change 100644 => 100755 bin/run_pytest.sh mode change 100644 => 100755 bin/setup.sh diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 0000000..3691eca --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,48 @@ +# taken from https://github.com/e-mission/e-mission-server/blob/master/.github/workflows/test-with-manual-install.yml + +name: unit-tests + +# Controls when the action will run. Triggers the workflow on push or pull request +on: + push: + pull_request: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + test-pytest: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Run setup.sh + shell: bash -l {0} + run: | + source bin/setup.sh + + - name: Run pytest + shell: bash -l {0} + run: | + source bin/run_pytest.sh + + test-jest: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '20' + + - name: Run setup.sh + shell: bash -l {0} + run: | + source bin/setup.sh + + - name: Run jest tests + shell: bash -l {0} + run: | + source bin/run_jest.sh diff --git a/README.md b/README.md index 4dc3ab1..b1f891d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This repository uses the [Transcrypt](https://www.transcrypt.org/) library to co ## Setup -``` +```bash . bin/setup.sh ``` @@ -126,3 +126,7 @@ There may be testing scenarios that must significantly diverge between Python an ```bash . bin/run_jest.sh ``` + +### GitHub Actions + +The unit tests also run via an Actions workflow, which executes both `run_pytest.sh` and `run_jest.sh` on each commit or PR to `master`. diff --git a/bin/compile_to_js.sh b/bin/compile_to_js.sh old mode 100644 new mode 100755 diff --git a/bin/run_jest.sh b/bin/run_jest.sh old mode 100644 new mode 100755 diff --git a/bin/run_pytest.sh b/bin/run_pytest.sh old mode 100644 new mode 100755 diff --git a/bin/setup.sh b/bin/setup.sh old mode 100644 new mode 100755