def test_run_fisheries_workspace_in_json(self): """CLI: Run the fisheries model with JSON-defined workspace.""" from natcap.invest import cli parameter_set_path = os.path.join( os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'fisheries', 'spiny_lobster_belize.invs.json') datastack_dict = json.load(open(parameter_set_path)) datastack_dict['args']['workspace_dir'] = self.workspace_dir new_parameter_set_path = os.path.join( self.workspace_dir, 'paramset.invs.json') with open(new_parameter_set_path, 'w') as parameter_set_file: parameter_set_file.write( json.dumps(datastack_dict, indent=4, sort_keys=True)) with mock.patch( 'natcap.invest.fisheries.fisheries.execute', return_value=None) as patched_model: cli.main([ 'run', 'fisheries', # uses an exact modelname '--datastack', new_parameter_set_path, '--headless', ]) patched_model.assert_called_once()
def test_validate_carbon_json(self): """CLI: Get validation results as JSON from cli.""" from natcap.invest import cli datastack_dict = { 'model_name': 'natcap.invest.carbon', 'invest_version': '3.10', 'args': {} } datastack_dict['args']['workspace_dir'] = self.workspace_dir new_parameter_set_path = os.path.join( self.workspace_dir, 'paramset.invs.json') with open(new_parameter_set_path, 'w') as parameter_set_file: parameter_set_file.write( json.dumps(datastack_dict, indent=4, sort_keys=True)) with redirect_stdout() as stdout_stream: with self.assertRaises(SystemExit) as exit_cm: cli.main([ 'validate', new_parameter_set_path, '--json', ]) stdout = stdout_stream.getvalue() stdout_json = json.loads(stdout) self.assertEqual(len(stdout_json), 1) # Some required keys are missing, so we have validation results self.assertEqual(len(stdout_json['validation_results']), 1) # Validation returned successfully, so error code 0 even though there # are warnings. self.assertEqual(exit_cm.exception.code, 0)
def test_validate_carbon(self): """CLI: Validate a model inputs through the cli.""" from natcap.invest import cli, validation datastack_dict = { 'model_name': 'natcap.invest.carbon', 'invest_version': '3.10', 'args': {} } datastack_dict['args']['workspace_dir'] = self.workspace_dir new_parameter_set_path = os.path.join( self.workspace_dir, 'paramset.invs.json') with open(new_parameter_set_path, 'w') as parameter_set_file: parameter_set_file.write( json.dumps(datastack_dict, indent=4, sort_keys=True)) with redirect_stdout() as stdout_stream: with self.assertRaises(SystemExit) as exit_cm: cli.main([ 'validate', new_parameter_set_path, ]) validation_output = stdout_stream.getvalue() # it's expected that these keys are missing because the only # key we included was the workspace_dir expected_warning = [(['carbon_pools_path', 'lulc_cur_path'], validation.MESSAGES['MISSING_KEY'])] self.assertEqual(validation_output, str(expected_warning)) self.assertEqual(exit_cm.exception.code, 0)
def test_validate_fisheries(self): """CLI: Validate the fisheries model inputs through the cli.""" from natcap.invest import cli parameter_set_path = os.path.join( os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'fisheries', 'spiny_lobster_belize.invs.json') # The InVEST sample data JSON arguments don't have a workspace, so I # need to add it in. datastack_dict = json.load(open(parameter_set_path)) datastack_dict['args']['workspace_dir'] = self.workspace_dir new_parameter_set_path = os.path.join( self.workspace_dir, 'paramset.invs.json') with open(new_parameter_set_path, 'w') as parameter_set_file: parameter_set_file.write( json.dumps(datastack_dict, indent=4, sort_keys=True)) with redirect_stdout() as stdout_stream: with self.assertRaises(SystemExit) as exit_cm: cli.main([ 'validate', new_parameter_set_path, ]) self.assertTrue(len(stdout_stream.getvalue()) > 0) self.assertEqual(exit_cm.exception.code, 0)
def test_invest_getspec(self): """Translation: test that CLI getspec output is translated.""" from natcap.invest import cli with patch('sys.stdout', new=io.StringIO()) as out: with self.assertRaises(SystemExit): cli.main(['--language', TEST_LANG, 'getspec', 'carbon']) result = out.getvalue() self.assertIn(TEST_MESSAGES['current LULC'], result)
def test_serve_port_argument(self): """CLI: serve entry-point parses port subargument.""" from natcap.invest import cli with unittest.mock.patch('natcap.invest.ui_server.app.run', return_value=None) as patched_app: with self.assertRaises(SystemExit) as exit_cm: cli.main(['serve', '--port', '12345']) self.assertEqual(exit_cm.exception.code, 0)
def test_serve(self): """CLI: serve entry-point exists; flask app can import.""" from natcap.invest import cli with unittest.mock.patch('natcap.invest.ui_server.app.run', return_value=None) as patched_app: with self.assertRaises(SystemExit) as exit_cm: cli.main(['serve']) self.assertEqual(exit_cm.exception.code, 0)
def test_invest_list(self): """Translation: test that CLI list output is translated.""" from natcap.invest import cli with patch('sys.stdout', new=io.StringIO()) as out: with self.assertRaises(SystemExit): cli.main(['--language', TEST_LANG, 'list']) result = out.getvalue() self.assertIn(TEST_MESSAGES['Available models:'], result) self.assertIn(TEST_MESSAGES['Carbon Storage and Sequestration'], result)
def test_run_fisheries_no_datastack(self): """CLI: Run the fisheries model through the cli without a datastack.""" from natcap.invest import cli with self.assertRaises(SystemExit) as exit_cm: cli.main([ 'run', 'fisheries', # uses an exact modelname '--headless', '--workspace', self.workspace_dir, ]) self.assertEqual(exit_cm.exception.code, 1)
def test_export_python(self): """CLI: Export a python script for a given model.""" from natcap.invest import cli target_filepath = os.path.join(self.workspace_dir, 'foo.py') with redirect_stdout() as stdout_stream: with self.assertRaises(SystemExit) as exit_cm: cli.main(['export-py', 'carbon', '-f', target_filepath]) self.assertTrue(os.path.exists(target_filepath)) # the contents of the file are asserted in CLIUnitTests self.assertEqual(exit_cm.exception.code, 0)
def test_list_json(self): """CLI: Verify no error when listing models as JSON.""" from natcap.invest import cli with redirect_stdout() as stdout_stream: with self.assertRaises(SystemExit) as exit_cm: cli.main(['list', '--json']) # Verify that we can load the JSON object without error stdout_value = stdout_stream.getvalue() loaded_list_object = json.loads(stdout_value) self.assertEqual(type(loaded_list_object), dict) self.assertEqual(exit_cm.exception.code, 0)
def test_run_coastal_blue_carbon_no_workspace(self): """CLI: Run a model through the cli without a workspace.""" from natcap.invest import cli parameter_set_path = os.path.join( os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'coastal_blue_carbon', 'cbc_galveston_bay.invs.json') with self.assertRaises(SystemExit) as exit_cm: cli.main([ 'run', 'coastal_blue_carbon', # uses an exact modelname '--datastack', parameter_set_path, '--headless', ]) self.assertEqual(exit_cm.exception.code, 1)
def test_run_fisheries_no_workspace(self): """CLI: Run the fisheries model through the cli without a workspace.""" from natcap.invest import cli parameter_set_path = os.path.join( os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'fisheries', 'spiny_lobster_belize.invs.json') with self.assertRaises(SystemExit) as exit_cm: cli.main([ 'run', 'fisheries', # uses an exact modelname '--datastack', parameter_set_path, '--headless', ]) self.assertEqual(exit_cm.exception.code, 1)
def test_invest_list(self): """Translation: test that CLI list output is translated.""" # patch the LOCALE_DIR variable in natcap/invest/__init__.py # this is where gettext will look for translations with patch('natcap.invest.LOCALE_DIR', self.test_locale_dir): from natcap.invest import cli # capture stdout with patch('sys.stdout', new=io.StringIO()) as out: with self.assertRaises(SystemExit): cli.main(['--language', TEST_LANG, 'list']) result = out.getvalue() self.assertIn(TEST_MESSAGES['Available models:'], result) self.assertIn(TEST_MESSAGES['Carbon Storage and Sequestration'], result)
def test_run_ambiguous_modelname(self): """CLI: Raise an error when an ambiguous model name used.""" from natcap.invest import cli parameter_set_path = os.path.join( os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'fisheries', 'spiny_lobster_belize.invs.json') with self.assertRaises(SystemExit) as exit_cm: cli.main([ 'run', 'fish', # ambiguous substring '--datastack', parameter_set_path, '--headless', '--workspace', self.workspace_dir, ]) self.assertEqual(exit_cm.exception.code, 1)
def test_export_python_default_filepath(self): """CLI: Export a python script without passing a filepath.""" from natcap.invest import cli model = 'carbon' # cannot write this file to self.workspace because we're # specifically testing the file is created in a default location. expected_filepath = f'{model}_execute.py' with redirect_stdout() as stdout_stream: with self.assertRaises(SystemExit) as exit_cm: cli.main(['export-py', model]) self.assertTrue(os.path.exists(expected_filepath)) os.remove(expected_filepath) self.assertEqual(exit_cm.exception.code, 0)
def test_run_fisheries_invalid_datastack(self): """CLI: Run the fisheries model through the cli invalid datastack.""" from natcap.invest import cli parameter_set_path = os.path.join( self.workspace_dir, 'bad-paramset.invs.json') with open(parameter_set_path, 'w') as paramset_file: paramset_file.write('not a json object') with self.assertRaises(SystemExit) as exit_cm: cli.main([ 'run', 'fisheries', # uses an exact modelname '--datastack', parameter_set_path, '--headless', ]) self.assertEqual(exit_cm.exception.code, 1)
def test_run_model(self): """CLI-GUI: Run a model GUI through the cli.""" from natcap.invest import cli parameter_set_path = os.path.join( os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'fisheries', 'spiny_lobster_belize.invs.json') # I tried patching the model import via mock, but GUI would hang. I'd # rather have a reliable test that takes a few more seconds than a test # that hangs. cli.main([ '--debug', 'quickrun', 'fisheries', parameter_set_path, '--workspace', self.workspace_dir, ])
def test_validate_invalid_json(self): """CLI: Validate invalid json files set an error code.""" from natcap.invest import cli paramset_path = os.path.join(self.workspace_dir, 'invalid.json') with open(paramset_path, 'w') as opened_file: opened_file.write('not a json object') with redirect_stdout() as stdout_stream: with self.assertRaises(SystemExit) as exit_cm: cli.main([ 'validate', paramset_path, '--json', ]) self.assertTrue(len(stdout_stream.getvalue()) == 0) self.assertEqual(exit_cm.exception.code, 1)
def test_run_coastal_blue_carbon(self): """CLI: Run a model through the cli.""" from natcap.invest import cli parameter_set_path = os.path.join( os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'coastal_blue_carbon', 'cbc_galveston_bay.invs.json') with unittest.mock.patch( 'natcap.invest.coastal_blue_carbon.coastal_blue_carbon.execute', return_value=None) as patched_model: cli.main([ 'run', 'coastal_blue_carbon', # uses an exact modelname '--datastack', parameter_set_path, '--headless', '--workspace', self.workspace_dir, ]) patched_model.assert_called_once()
def test_invest_validate(self): """Translation: test that CLI validate output is translated.""" datastack = { # write datastack to a JSON file 'model_name': 'natcap.invest.carbon', 'invest_version': '0.0', 'args': {} } datastack_path = os.path.join(self.workspace_dir, 'datastack.json') with open(datastack_path, 'w') as file: json.dump(datastack, file) from natcap.invest import cli with patch('sys.stdout', new=io.StringIO()) as out: with self.assertRaises(SystemExit): cli.main(['--language', TEST_LANG, 'validate', datastack_path]) result = out.getvalue() self.assertIn(TEST_MESSAGES[missing_key_msg], result)
def test_run_fisheries(self): """CLI: Run the fisheries model through the cli.""" from natcap.invest import cli parameter_set_path = os.path.join(os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'fisheries', 'spiny_lobster_belize.invs.json') cli.main([ 'fisheries', # uses an exact modelname '--debug', # set logging '--datastack', parameter_set_path, '--headless', '--workspace', self.workspace_dir, '--overwrite', ])
def test_model_alias(self): """CLI: Use a model alias through the CLI.""" from natcap.invest import cli parameter_set_path = os.path.join(os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'coastal_blue_carbon', 'cbc_galveston_bay.invs.json') cli.main([ 'cbc', # uses an alias '--datastack', parameter_set_path, '--headless', '--workspace', self.workspace_dir, '--overwrite', ])
def test_run_fisheries(self): """CLI: Run the fisheries model through the cli.""" from natcap.invest import cli parameter_set_path = os.path.join( os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'fisheries', 'spiny_lobster_belize.invs.json') with mock.patch( 'natcap.invest.fisheries.fisheries.execute', return_value=None) as patched_model: cli.main([ 'run', 'fisheries', # uses an exact modelname '--datastack', parameter_set_path, '--headless', '--workspace', self.workspace_dir, ]) patched_model.assert_called_once()
def test_validate_coastal_blue_carbon_missing_workspace(self): """CLI: Validate a model inputs with missing workspace.""" from natcap.invest import cli parameter_set_path = os.path.join( os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'coastal_blue_carbon', 'cbc_galveston_bay.invs.json') # The InVEST sample data JSON arguments don't have a workspace. In # this case, I want to leave it out and verify validation catches it. with redirect_stdout() as stdout_stream: with self.assertRaises(SystemExit) as exit_cm: cli.main([ 'validate', parameter_set_path, ]) self.assertTrue(len(stdout_stream.getvalue()) > 0) # Validation failed, not the program. self.assertEqual(exit_cm.exception.code, 0)
def test_validate_fisheries_json(self): """CLI: Validate the fisheries model inputs as JSON through the cli.""" from natcap.invest import cli parameter_set_path = os.path.join(os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'fisheries', 'spiny_lobster_belize.invs.json') # The InVEST sample data JSON arguments don't have a workspace, so I # need to add it in. datastack_dict = json.load(open(parameter_set_path)) datastack_dict['args']['workspace_dir'] = self.workspace_dir # In this case, I also want to set one of the inputs to an invalid path # to test the presentation of a validation error. datastack_dict['args']['aoi_vector_path'] = os.path.join( self.workspace_dir, 'not-a-vector.shp') new_parameter_set_path = os.path.join(self.workspace_dir, 'paramset.invs.json') with open(new_parameter_set_path, 'w') as parameter_set_file: parameter_set_file.write( json.dumps(datastack_dict, indent=4, sort_keys=True)) with redirect_stdout() as stdout_stream: with self.assertRaises(SystemExit) as exit_cm: cli.main([ 'validate', new_parameter_set_path, '--json', ]) stdout = stdout_stream.getvalue() stdout_json = json.loads(stdout) self.assertEqual(len(stdout_json), 1) # migration path, aoi_vector_path, population_csv_path not found # population_csv_dir is also incorrect, but shouldn't be marked # invalid because do_batch is False self.assertEqual(len(stdout_json['validation_results']), 3) # Validation returned successfully, so error code 0 even though there # are warnings. self.assertEqual(exit_cm.exception.code, 0)
def test_validate_fisheries_missing_workspace_json(self): """CLI: Validate the fisheries model inputs through the cli.""" from natcap.invest import cli parameter_set_path = os.path.join( os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'fisheries', 'spiny_lobster_belize.invs.json') # The InVEST sample data JSON arguments don't have a workspace. In # this case, I want to leave it out and verify validation catches it. with redirect_stdout() as stdout_stream: with self.assertRaises(SystemExit) as exit_cm: cli.main([ 'validate', parameter_set_path, '--json', ]) stdout = stdout_stream.getvalue() self.assertTrue(len(stdout) > 0) self.assertEqual(len(json.loads(stdout)), 1) # workspace_dir invalid # Validation failed, not the program. self.assertEqual(exit_cm.exception.code, 0)
def test_run_model(self): """CLI-GUI: Run a model GUI through the cli.""" from natcap.invest import cli # Choosing DelineatIt because there are only two required inputs, # we already have them in the test data repo, and it runs fast. input_data_dir = os.path.join(os.path.dirname(__file__), '..', 'data', 'invest-test-data', 'delineateit', 'input') datastack_dict = { 'model_name': 'natcap.invest.delineateit.delineateit', 'invest_version': '3.10', 'args': { 'dem_path': os.path.join(input_data_dir, 'dem.tif'), 'outlet_vector_path': os.path.join(input_data_dir, 'outlets.shp') } } parameter_set_path = os.path.join(self.workspace_dir, 'paramset.invs.json') with open(parameter_set_path, 'w') as parameter_set_file: parameter_set_file.write( json.dumps(datastack_dict, indent=4, sort_keys=True)) # I tried patching the model import via mock, but GUI would hang. I'd # rather have a reliable test that takes a few more seconds than a test # that hangs. cli.main([ '--debug', 'quickrun', 'delineateit', parameter_set_path, '--workspace', os.path.join(self.workspace_dir, 'newdir'), # avoids alert about overwrite ])
def test_list(self): """CLI: Verify no error when listing models.""" from natcap.invest import cli with self.assertRaises(SystemExit) as exit_cm: cli.main(['--list']) self.assertEqual(exit_cm.exception.code, 0)
def test_no_model_matches(self): """CLI: raise an error when no model name matches what's given.""" from natcap.invest import cli with self.assertRaises(SystemExit) as exit_cm: cli.main('qwerty') self.assertEqual(exit_cm.exception.code, 1)