diff --git a/buildbucket/package.sh b/buildbucket/package.sh index 80e0bd9c684cff0f7ec6ea4b7bcd6935a4d15430..829e5ff22c0306ab5f32c4ce43368949d740ff26 100755 --- a/buildbucket/package.sh +++ b/buildbucket/package.sh @@ -76,7 +76,7 @@ mkdir -p bin libexec/python_runtime cp $GGLM_DIR/PACKAGE_README.md ./README.md cp $GGLM_DIR/PACKAGE_LICENSE ./LICENSE cp $GGLM_DIR/bin/* ./bin/ -cp $GGLM_DIR/libexec/* ./libexec/ +cp -r $GGLM_DIR/libexec/* ./libexec/ # Untar the tarball so we can put things where we want tar -xz -C ./libexec/python_runtime -f ../${conda_tb} # write a conda environment.yml to the python_runtime/ folder so that we can more easily audit what's included in our runtime between builds diff --git a/gridded_glm/bin/cspp-geo-gglm.sh b/gridded_glm/bin/cspp-geo-gglm.sh index fb2bfff30206dd9eb8e5e6908b3c899515944a88..7320b710e66e155952b622f6265e74ca51026c26 100755 --- a/gridded_glm/bin/cspp-geo-gglm.sh +++ b/gridded_glm/bin/cspp-geo-gglm.sh @@ -30,4 +30,4 @@ source $CSPP_GEO_GGLM_HOME/libexec/env.sh # Call the python module to do the processing, passing all arguments export PROG_NAME="${BASH_SOURCE[0]}" -python3 $CSPP_GEO_GGLM_HOME/libexec/_minute_gridder.py "$@" +python3 $CSPP_GEO_GGLM_HOME/libexec/gridded_glm/_minute_gridder.py "$@" diff --git a/gridded_glm/libexec/gridded_glm/__init__.py b/gridded_glm/libexec/gridded_glm/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/gridded_glm/libexec/_minute_gridder.py b/gridded_glm/libexec/gridded_glm/_minute_gridder.py similarity index 93% rename from gridded_glm/libexec/_minute_gridder.py rename to gridded_glm/libexec/gridded_glm/_minute_gridder.py index d43be6a0df2832de437bc0571b28515f7a7382e7..f0969b1d55d07db96e3e627a9b7950d3c1b6d295 100644 --- a/gridded_glm/libexec/_minute_gridder.py +++ b/gridded_glm/libexec/gridded_glm/_minute_gridder.py @@ -158,19 +158,19 @@ def get_start_end(filenames, start_time=None, end_time=None): return start_time, end_time -def get_sector_shortstring(args): - if args.goes_sector == 'full': +def get_sector_shortstring(goes_sector): + if goes_sector == 'full': return 'F' - elif args.goes_sector == 'conus': + elif goes_sector == 'conus': return 'C' - elif args.goes_sector == 'meso' or args.goes_sector == 'meso1': + elif goes_sector == 'meso' or goes_sector == 'meso1': return 'M1' - elif args.goes_sector == 'meso2': + elif goes_sector == 'meso2': return 'M2' else: raise RuntimeError("sector not recognized") -def get_outpath_base(args): +def get_outpath_base(filenames, goes_sector, system_environment_prefix): """create a base outpath string to feed glmtools from glmtools: @@ -181,16 +181,16 @@ def get_outpath_base(args): start_time, end_time: datetimes that can be used with strftime syntax, e.g. './{start_time:%y/%b/%d}/GLM_{start_time:%Y%m%d_%H%M%S}.nc' """ - ordered_filenames = sorted(args.filenames) + ordered_filenames = sorted(filenames) _, _, platform, start_time, _, _ = parse_glm_filename(os.path.basename(ordered_filenames[0])) _, _, _, _, end_time, _ = parse_glm_filename(os.path.basename(ordered_filenames[-1])) - sector_short = get_sector_shortstring(args) + sector_short = get_sector_shortstring(goes_sector) mode = "M3" # FIXME: is GLM always in M3? # example string: OR_GLM-L2-GLMC-M3_G17_s20182750032000_e20182750033000_c20210431923130.nc dsname = "{environment_prefix}_GLM-L2-GLM{sector_short}-{mode}_{platform}_s{start_time}_e{end_time}_c{created_time}.nc".format( - environment_prefix=args.system_environment_prefix, + environment_prefix=system_environment_prefix, sector_short=sector_short, mode=mode, platform=platform, @@ -225,7 +225,7 @@ def grid_setup(glm_files, args, work_dir=os.getcwd()): base_date = datetime(start_time.year, start_time.month, start_time.day) proj_name = 'geos' - outputpath = os.path.join(work_dir, get_outpath_base(args)) # GLMTools expects a template in addition to the path + outputpath = os.path.join(work_dir, get_outpath_base(glm_files, args.goes_sector, args.system_environment_prefix)) # GLMTools expects a template in addition to the path goes_position = get_goes_position(glm_files) @@ -339,8 +339,8 @@ def grid_minute(minute, args): # do we have three input files for this minute? if len(minute_files) != 3: - log.error("Minute {} only has {} input file(s). A gridded file will not be generated.".format(minute, len(minute_files))) - return +# log.error("Minute {} has {} input file(s). We expected 3. A gridded file will not be generated.".format(minute, len(minute_files))) + raise RuntimeError("Minute {} has {} input file(s). We expected 3. A gridded file will not be generated.".format(minute, len(minute_files))) # do the gridding gridder, glm_filenames, start_time, end_time, grid_kwargs = grid_setup(minute_files, args, work_dir=tempdir_path) @@ -403,8 +403,9 @@ def grid_minute(minute, args): # tempdir cleans itself up via atexit, above -if __name__ == '__main__': +def main(): # freeze_support() # nb. I don't think this is needed as we're not making windows execs at this time + errors = False parser = create_parser() args = parser.parse_args() @@ -422,20 +423,21 @@ if __name__ == '__main__': if args.realtime: if len(args.filenames) != 1: log.error("realtime mode only accepts one input file") - exit(1) + return 1 glminfo = parse_glm_filename(os.path.basename(args.filenames[0])) globstring = "{}_{}_{}_s{}*".format(glminfo[0], glminfo[1], glminfo[2], glminfo[3].strftime("%Y%j%H%M")) fileglob = glob(os.path.join(os.path.dirname(args.filenames[0]), globstring)) if len(fileglob) != 3: - log.error("There are not (yet) three GLM files from this minute. This may be expected. Exiting.") - exit(0) + log.error("There are not yet three GLM files from this minute. This may be expected. Exiting.") + # we expect people using realtime mode to run this on every file, so a return code of 0 is expected on a file before the end of the minute + return 0 # this allows a user to use realtime mode to process a large directory of GLM without # creating the same output file multiple times if sorted(fileglob)[-1] != args.filenames[0]: log.error("This is not the last file from this minute. Exiting.") - exit(0) + return 0 args.filenames = fileglob @@ -443,7 +445,7 @@ if __name__ == '__main__': for f in args.filenames: if not os.path.exists(f): log.error("Tried to grid file that does not exist: {}".format(f)) - exit(1) + return 1 # set up output dir os.makedirs(args.output_dir, exist_ok=True) @@ -458,7 +460,16 @@ if __name__ == '__main__': try: grid_minute(m, args) except Exception as e: + errors = True log.error(e) log.debug(traceback.format_exc()) log.error(f"Gridding minute {m} failed.") - continue \ No newline at end of file + continue + + if errors: + return 1 + else: + return 0 + +if __name__ == '__main__': + sys.exit(main()) \ No newline at end of file diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000000000000000000000000000000000000..d09983e307301cd2bad71c1628a7ecb1556866f6 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[tool:pytest] +norecursedirs=tests/lib diff --git a/tests/.gitattributes b/tests/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..9abd2058819fae6e5f68d95ef7ffd1a2abad7650 --- /dev/null +++ b/tests/.gitattributes @@ -0,0 +1 @@ +*.nc filter=lfs diff=lfs merge=lfs -text diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..66c3aba109238f3e0c9625c371cc1b35a2f19f23 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,30 @@ +""" +Shared config for all tests +""" +import sys +import os +sys.path.append(os.path.join(os.path.dirname(__file__), 'lib')) + + + +import pytest +import shutil +import pprint +from glob import glob + +@pytest.fixture(autouse=True) +def run_before_and_after_tests(tmp_path): + """Fixture to execute asserts before and after a test is run""" + # Setup: fill with any logic you want + os.chdir(tmp_path) + print(os.getcwd()) + + yield # this is where the testing happens + + # print the current directory's list of files + pp = pprint.PrettyPrinter() + pp.pprint(glob("*")) + + # Teardown : fill with any logic you want + shutil.rmtree(tmp_path) + diff --git a/tests/test-inputs/.gitignore b/tests/test-inputs/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..0bee393995d9dc961b2f064b033b21a163fc25c3 --- /dev/null +++ b/tests/test-inputs/.gitignore @@ -0,0 +1,2 @@ +# ignore all G18 test files until G18 data can be made public +OR_GLM-L2-LCFA_G18* diff --git a/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc new file mode 100644 index 0000000000000000000000000000000000000000..54394a4f154b3e15bec905ac0a1748be050a36bb --- /dev/null +++ b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aa8371db66811b43030f0e7bfbd36d8979650022b3f241087723a98c63ecea35 +size 407925 diff --git a/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc new file mode 100644 index 0000000000000000000000000000000000000000..25d0659dedb1462c2605a613a5feb86803d8a269 --- /dev/null +++ b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d58219b5995807cee8d12ad668a56b85a6d28691e98aae424fc7b70f9a86c995 +size 379253 diff --git a/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc new file mode 100644 index 0000000000000000000000000000000000000000..4a76c4149963e0ebf3d83ca35e2e3f59908a8dd6 --- /dev/null +++ b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf7d7fb938664e5349b793376e7438b7e8b006314a0481421ae6fc1cc25853e1 +size 358773 diff --git a/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740001000_e20220740001200_c20220740001225.nc b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740001000_e20220740001200_c20220740001225.nc new file mode 100644 index 0000000000000000000000000000000000000000..fad137c751eb19f56c70d2d8ff7f0fc948fd7d84 --- /dev/null +++ b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740001000_e20220740001200_c20220740001225.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5428944ea5f2a566f8c99ee6400ed96a71db07d8ee9f67a987baa8081e418f88 +size 440693 diff --git a/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740001200_e20220740001400_c20220740001419.nc b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740001200_e20220740001400_c20220740001419.nc new file mode 100644 index 0000000000000000000000000000000000000000..d6e835045e59d363dced5e99018e998958b85e98 --- /dev/null +++ b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740001200_e20220740001400_c20220740001419.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:62d2e0857dbf4667230e0dec0686e2301bcbd33cd8214b9a8f035026f8242e03 +size 401781 diff --git a/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740001400_e20220740002000_c20220740002019.nc b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740001400_e20220740002000_c20220740002019.nc new file mode 100644 index 0000000000000000000000000000000000000000..211ec83c088d233322f51f5ccda82510646f5d60 --- /dev/null +++ b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740001400_e20220740002000_c20220740002019.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cc1214302c8df0217ae504ebbc5eeba39dc87910046e90e99b621b6516410b4c +size 375157 diff --git a/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740002000_e20220740002200_c20220740002228.nc b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740002000_e20220740002200_c20220740002228.nc new file mode 100644 index 0000000000000000000000000000000000000000..ef686db0865ba6b4b3a140d4102d6c331ed90faf --- /dev/null +++ b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740002000_e20220740002200_c20220740002228.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d03d3f6dc115fd17325ad4af9b47a9b4d152b028d3a17d96cdc2281a3d7e97d6 +size 385397 diff --git a/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740002200_e20220740002400_c20220740002427.nc b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740002200_e20220740002400_c20220740002427.nc new file mode 100644 index 0000000000000000000000000000000000000000..b2a5032efc461ef156ce975c3d5d0f7722d45008 --- /dev/null +++ b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740002200_e20220740002400_c20220740002427.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e3c40ad0642eb7e5795c1b3e17c9f6ebdacaeb54e56ee4416ac270b6e60627d7 +size 389493 diff --git a/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740002400_e20220740003000_c20220740003018.nc b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740002400_e20220740003000_c20220740003018.nc new file mode 100644 index 0000000000000000000000000000000000000000..6768e3a9dad465e17ee2abee1c3cbcf8ffec73eb --- /dev/null +++ b/tests/test-inputs/OR_GLM-L2-LCFA_G16_s20220740002400_e20220740003000_c20220740003018.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3abf234f7d2b2e3853779bdb20efc29a4a9f5c6981612cff609fb3b0ed941db2 +size 403829 diff --git a/tests/test-inputs/OR_GLM-L2-LCFA_G17_s20222631921000_e20222631921200_c20222631921214.nc b/tests/test-inputs/OR_GLM-L2-LCFA_G17_s20222631921000_e20222631921200_c20222631921214.nc new file mode 100644 index 0000000000000000000000000000000000000000..a96b2f8a4362ae508efee3873c1e074fadeb260c --- /dev/null +++ b/tests/test-inputs/OR_GLM-L2-LCFA_G17_s20222631921000_e20222631921200_c20222631921214.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c6bdb97180067489205cea8b7fcd8640907e0e59c4de74157f2d6e5207bd062f +size 155423 diff --git a/tests/test-inputs/OR_GLM-L2-LCFA_G17_s20222631921200_e20222631921400_c20222631921418.nc b/tests/test-inputs/OR_GLM-L2-LCFA_G17_s20222631921200_e20222631921400_c20222631921418.nc new file mode 100644 index 0000000000000000000000000000000000000000..743991d7f3e8d3348e243d6f8b4562bf396bab03 --- /dev/null +++ b/tests/test-inputs/OR_GLM-L2-LCFA_G17_s20222631921200_e20222631921400_c20222631921418.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dd7509d24f141096d66a579e8a6ea9514022f0f48780c32950a2729829a97b1b +size 157110 diff --git a/tests/test-inputs/OR_GLM-L2-LCFA_G17_s20222631921400_e20222631922000_c20222631922019.nc b/tests/test-inputs/OR_GLM-L2-LCFA_G17_s20222631921400_e20222631922000_c20222631922019.nc new file mode 100644 index 0000000000000000000000000000000000000000..4954ae77d707c4f828b04c8f10417cd9e1aac18c --- /dev/null +++ b/tests/test-inputs/OR_GLM-L2-LCFA_G17_s20222631921400_e20222631922000_c20222631922019.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6b530b9bd17f9096a2093ca9c7d5c685e3b8ed8b1ae79198a872fae0c3a05bcd +size 154428 diff --git a/tests/test_functionality.py b/tests/test_functionality.py new file mode 100644 index 0000000000000000000000000000000000000000..4241ec2106fb29e7990552ccade32b3f04b2d9aa --- /dev/null +++ b/tests/test_functionality.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 +""" +Gridded GLM basic functionality tests +""" + +import subprocess +import os +import warnings + +from testlib.common import TESTDIR, MINUTE_GRIDDER +from testlib.common import check_fileglob + +def test_simple_success(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--goes-sector", "full", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + ]) + assert completed_process.returncode == 0 + assert(check_fileglob("CG_GLM-L2-GLMF-M3_G16_s20220740000000_e20220740001000_c*.nc")) + +# formerly the issue5 realtime success test +def test_realtime(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--goes-sector", "conus", + "--create-tiles", + "--realtime", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740002400_e20220740003000_c20220740003018.nc"), + ]) + assert completed_process.returncode == 0 + assert(check_fileglob("CG_GLM-L2-GLMC-M3_G16_s20220740002000_e20220740003000_c*", 1)) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T08_20220315000300.nc", 1)) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T05_20220315000300.nc", 1)) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T04_20220315000300.nc", 1)) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T07_20220315000300.nc", 1)) + +def test_g16(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--create-tiles", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + ]) + assert completed_process.returncode == 0 + assert(check_fileglob("CG_GLM-L2-GLMF-M3_G16_*.nc", 1)) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMF-M3_G16_T*.nc", 17)) + + assert(check_fileglob('CG_GLM-L2-GLMF-M3_G16_s20220740000000_e20220740001000_c*.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T27_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T41_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T40_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T20_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T46_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T08_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T14_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T42_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T38_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T21_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T47_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T15_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T28_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T34_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T35_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T36_20220315000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G16_T33_20220315000100.nc', 1)) + +def test_g17(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--create-tiles", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G17_s20222631921000_e20222631921200_c20222631921214.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G17_s20222631921200_e20222631921400_c20222631921418.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G17_s20222631921400_e20222631922000_c20222631922019.nc"), + ]) + assert completed_process.returncode == 0 + assert(check_fileglob("CG_GLM-L2-GLMF-M3_G17_*.nc", 1)) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMF-M3_G17_T*.nc", 15)) + + assert(check_fileglob('CG_GLM-L2-GLMF-M3_G17_s20222631921000_e20222631922000_c*.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G17_T49_20220920192200.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G17_T19_20220920192200.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G17_T05_20220920192200.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G17_T18_20220920192200.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G17_T30_20220920192200.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G17_T11_20220920192200.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G17_T43_20220920192200.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G17_T25_20220920192200.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G17_T14_20220920192200.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G17_T08_20220920192200.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G17_T24_20220920192200.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G17_T13_20220920192200.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G17_T41_20220920192200.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G17_T17_20220920192200.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G17_T23_20220920192200.nc', 1)) + +def test_g18(): + inputs = [os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G18_s20222210000000_e20222210000200_c20222210000225.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G18_s20222210000200_e20222210000400_c20222210000424.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G18_s20222210000400_e20222210001000_c20222210001027.nc")] + for i in inputs: + if not os.path.exists(i): + warnings.warn(UserWarning("GOES-18 test files are not available in this environment. GOES-18 functionality has not been tested.")) + return + + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--create-tiles", + inputs[0], + inputs[1], + inputs[2], + ]) + assert completed_process.returncode == 0 + assert(check_fileglob("CG_GLM-L2-GLMF-M3_G18_*.nc", 1)) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMF-M3_G18_T*.nc", 15)) + + assert(check_fileglob("CG_GLM-L2-GLMF-M3_G18_s20222210000000_e20222210001000_c*.nc", 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G18_T04_20220809000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G18_T30_20220809000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G18_T18_20220809000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G18_T29_20220809000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G18_T49_20220809000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G18_T16_20220809000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G18_T27_20220809000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G18_T23_20220809000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G18_T17_20220809000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G18_T20_20220809000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G18_T08_20220809000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G18_T11_20220809000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G18_T21_20220809000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G18_T24_20220809000100.nc', 1)) + assert(check_fileglob('CSPP_OR_GLM-L2-GLMF-M3_G18_T10_20220809000100.nc', 1)) + diff --git a/tests/test_regressions.py b/tests/test_regressions.py new file mode 100644 index 0000000000000000000000000000000000000000..47c77ccdcdd181698bce59a159601f6fa72fdf62 --- /dev/null +++ b/tests/test_regressions.py @@ -0,0 +1,268 @@ +#!/usr/bin/env python3 +""" +Gridded GLM regression tests +""" + +import subprocess +import os +from glob import glob + +import netCDF4 +import numpy as np + +from testlib.common import TESTDIR, MINUTE_GRIDDER +from testlib.common import check_fileglob + + +def test_issue5_fail1_3(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + ]) + assert completed_process.returncode == 1 + assert(check_fileglob("CG_GLM-*.nc", 0)) + assert(check_fileglob("CSPP_OR_GLM-*.nc", 0)) + +def test_issue5_fail2_1and3(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + ]) + assert completed_process.returncode == 1 + assert(check_fileglob("CG_GLM-*.nc", 0)) + assert(check_fileglob("CSPP_OR_GLM-*.nc", 0)) + +def test_issue5_fail2_2and3(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + ]) + assert completed_process.returncode == 1 + assert(check_fileglob("CG_GLM-*.nc", 0)) + assert(check_fileglob("CSPP_OR_GLM-*.nc", 0)) + +def test_issue5_3minutes(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--goes-sector", "conus", + "--create-tiles", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740001000_e20220740001200_c20220740001225.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740001200_e20220740001400_c20220740001419.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740001400_e20220740002000_c20220740002019.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740002000_e20220740002200_c20220740002228.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740002200_e20220740002400_c20220740002427.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740002400_e20220740003000_c20220740003018.nc"), + ]) + assert completed_process.returncode == 0 + assert(check_fileglob("CG_GLM-L2-GLMC-M3_G16_s20220740000000_e20220740001000_c*.nc")) + assert(check_fileglob("CG_GLM-L2-GLMC-M3_G16_s20220740001000_e20220740002000_c*.nc")) + assert(check_fileglob("CG_GLM-L2-GLMC-M3_G16_s20220740002000_e20220740003000_c*.nc")) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T04_20220315000100.nc")) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T04_20220315000200.nc")) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T04_20220315000300.nc")) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T05_20220315000100.nc")) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T05_20220315000200.nc")) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T05_20220315000300.nc")) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T07_20220315000100.nc")) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T07_20220315000200.nc")) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T07_20220315000300.nc")) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T08_20220315000100.nc")) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T08_20220315000200.nc")) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T08_20220315000300.nc")) + +def test_issue5_crossminutes_fail(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--goes-sector", "conus", + "--create-tiles", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740001200_e20220740001400_c20220740001419.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740002400_e20220740003000_c20220740003018.nc"), + ]) + assert completed_process.returncode == 1 + assert(check_fileglob("CG_GLM-*.nc", 0)) + assert(check_fileglob("CSPP_OR_GLM-*.nc", 0)) + +def test_issue5_realtime_early1(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--goes-sector", "conus", + "--create-tiles", + "--realtime", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + ]) + # we expect people using realtime mode to run this on every file, so a return code of 0 is expected on a file before the end of the minute + assert completed_process.returncode == 0 + assert(check_fileglob("CG_GLM-*.nc", 0)) + assert(check_fileglob("CSPP_OR_GLM-*.nc", 0)) + +def test_issue5_realtime_early2(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--goes-sector", "conus", + "--create-tiles", + "--realtime", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740001200_e20220740001400_c20220740001419.nc"), + ]) + # we expect people using realtime mode to run this on every file, so a return code of 0 is expected on a file before the end of the minute + assert completed_process.returncode == 0 + assert(check_fileglob("CG_GLM-*.nc", 0)) + assert(check_fileglob("CSPP_OR_GLM-*.nc", 0)) + + +# test for providing two minutes with a minute in between that has no input +# the middle minute should produce no output +def test_issue7(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--goes-sector", "conus", + "--create-tiles", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740002000_e20220740002200_c20220740002228.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740002200_e20220740002400_c20220740002427.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740002400_e20220740003000_c20220740003018.nc"), + ]) + assert completed_process.returncode == 0 + # check for 2 output gridded files + assert(check_fileglob("CG_GLM-L2-GLMC-M3_G16*.nc", 2)) + assert(check_fileglob("CG_GLM-L2-GLMC-M3_G16_s20220740002000_e20220740003000_c*", 1)) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T08_20220315000300.nc", 1)) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T05_20220315000300.nc", 1)) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T04_20220315000300.nc", 1)) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMC-M3_G16_T07_20220315000300.nc", 1)) + +# test for proper handling of negative center lat/lons +def test_issue22(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--ctr-lat", "32.05", + "--ctr-lon", "-96.85", + "--goes-sector", "meso", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + ]) + assert completed_process.returncode == 0 + assert(check_fileglob("CG_GLM-L2-GLMM1-M3_G16_s20220740000000_e20220740001000_c*.nc", 1)) + +def test_issue23_oor_lon_high(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--ctr-lat", "32.05", + "--ctr-lon", "200", + "--goes-sector", "meso", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + ]) + assert completed_process.returncode != 0 + assert(check_fileglob("CG_GLM-L2-*.nc", 0)) + +def test_issue23_oor_lon_low(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--ctr-lat", "32.05", + "--ctr-lon", "-181", + "--goes-sector", "meso", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + ]) + assert completed_process.returncode != 0 + assert(check_fileglob("CG_GLM-L2-*.nc", 0)) + +def test_issue23_oor_lat_high(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--ctr-lat", "91", + "--ctr-lon", "-96.85", + "--goes-sector", "meso", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + ]) + assert completed_process.returncode != 0 + assert(check_fileglob("CG_GLM-L2-*.nc", 0)) + +def test_issue23_oor_lat_low(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--ctr-lat", "-90.30", + "--ctr-lon", "-96.85", + "--goes-sector", "meso", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + ]) + assert completed_process.returncode != 0 + assert(check_fileglob("CG_GLM-L2-*.nc", 0)) + +def test_issue24_meso1(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--ctr-lat", "32.05", + "--ctr-lon", "-96.85", + "--goes-sector", "meso1", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + ]) + assert completed_process.returncode == 0 + assert(check_fileglob("CG_GLM-L2-GLMM1-M3_G16_s20220740000000_e20220740001000_c*.nc", 1)) + +def test_issue24_meso2(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--ctr-lat", "32.05", + "--ctr-lon", "-96.85", + "--goes-sector", "meso2", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + ]) + assert completed_process.returncode == 0 + assert(check_fileglob("CG_GLM-L2-GLMM2-M3_G16_s20220740000000_e20220740001000_c*.nc", 1)) + +def test_issue24_meso2_tiles(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--ctr-lat", "32.05", + "--ctr-lon", "-96.85", + "--goes-sector", "meso2", + "--create-tiles", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + ]) + assert completed_process.returncode == 0 + assert(check_fileglob("CG_GLM-L2-GLMM2-M3_G16_s20220740000000_e20220740001000_c*.nc", 1)) + assert(check_fileglob("CSPP_OR_GLM-L2-GLMM2-M3_G16_T01_20220315000100.nc", 1)) + +# test that we still produce a file when there's no valid data inside the gridded region +def test_issue38_no_valid_data(): + completed_process = subprocess.run(['python', + MINUTE_GRIDDER, + "--ctr-lat", "43.0722", + "--ctr-lon", "-89.4008", + "--goes-sector", "meso", + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000000_e20220740000200_c20220740000227.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000200_e20220740000400_c20220740000428.nc"), + os.path.join(TESTDIR, "test-inputs/OR_GLM-L2-LCFA_G16_s20220740000400_e20220740001000_c20220740001027.nc"), + ]) + assert completed_process.returncode == 0 + assert(check_fileglob("CG_GLM-L2-GLMM1-M3_G16_s20220740000000_e20220740001000_c*.nc", 1)) + + # check that the file contents are blank too + mesofilename = glob("CG_GLM-L2-GLMM1-M3_G16_s20220740000000_e20220740001000_c*.nc")[0] + ds = netCDF4.Dataset(mesofilename, 'r') + assert(ds.variables['minimum_flash_area'][:].all() is np.ma.masked) + assert(ds.variables['total_energy'][:].all() is np.ma.masked) + assert(ds.variables['total_energy'][:].all() is np.ma.masked) + assert((ds.variables['DQF'][:] == 0).all()) diff --git a/tests/testlib/common.py b/tests/testlib/common.py new file mode 100644 index 0000000000000000000000000000000000000000..261bbbccc3c11aeb4edab0edd89dd60d34ae1c65 --- /dev/null +++ b/tests/testlib/common.py @@ -0,0 +1,18 @@ +import sys +import os + +# setting PYTHONPATH so we can work +LIBDIR = os.path.dirname(__file__) +TESTDIR = os.path.dirname(LIBDIR) +TOPDIR = os.path.dirname(TESTDIR) +PYDIR = os.path.join(TOPDIR, 'gridded_glm/libexec') +sys.path.append(PYDIR) +MINUTE_GRIDDER = os.path.join(PYDIR, "gridded_glm/_minute_gridder.py") + +from glob import glob +def check_fileglob(fileglob_pattern, nfiles=1): + files = glob(fileglob_pattern) + if len(files) == nfiles: + return True + else: + return False