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