def test_main(self, schema_mock, query_mock, create_mock, delete_mock, index_mock, load_mock): sys.argv = ['cadc-tap', 'schema'] main_app() calls = [call()] schema_mock.assert_has_calls(calls) sys.argv = ['cadc-tap', 'query', 'QUERY'] main_app() calls = [call('QUERY', None, 'VOTable', None)] query_mock.assert_has_calls(calls) sys.argv = ['cadc-tap', 'create', 'tablename', 'path/to/file'] main_app() calls = [call('tablename', 'path/to/file', None)] create_mock.assert_has_calls(calls) sys.argv = ['cadc-tap', 'index', 'tablename', 'columnName'] main_app() calls = [call('tablename', 'columnName', False)] index_mock.assert_has_calls(calls) sys.argv = ['cadc-tap', 'load', 'tablename', 'path/to/file'] main_app() calls = [call('tablename', ['path/to/file'], 'tsv')] load_mock.assert_has_calls(calls)
def test_keyboard_interrupt(self, caps_get_mock, query_mock): caps_get_mock.return_value = BASE_URL query_mock.reset_mock() query_mock.side_effect = KeyboardInterrupt() sys.argv = ['cadc-tap', 'query', '-s', 'http://someservice', 'QUERY'] with patch('sys.stderr', new_callable=StringIO) as stderr_mock: try: main_app() except SystemExit: assert stderr_mock.getvalue() == 'KeyboardInterrupt\n'
def _get_permissions(cert, resource): """ parse permissions from the output of the schema command :return: array with permissions elements: owner, others, g-read, g-rwrite """ sys.argv = 'cadc-tap schema --cert {} {} {}'.format(cert, HOST, resource).split() with patch('sys.stdout', new_callable=StringIO) as stdout_mock: main_app() return stdout_mock.getvalue().split('\n')[-4].split()
def _create_table(monkeypatch, owner_cert): sys.argv = 'cadc-tap delete --cert {} {} {}'.format(CERT1, HOST, TABLE).split() try: monkeypatch.setattr('cadctap.core.input', lambda x: "yes") with patch('cadctap.core.sys.exit'): main_app() logger.debug('Deleted table {}'.format(TABLE)) except Exception as e: logger.debug('Cannot delete table {}. Reason: {}'.format( TABLE, str(e))) # create table sys.argv = 'cadc-tap create --cert {} {} {} {}'.format( owner_cert, HOST, TABLE, TABLE_DEF).split() try: main_app() logger.debug('Created table {}'.format(TABLE)) except Exception as e: logger.debug('Cannot create table {}. Reason: {}'.format( TABLE, str(e))) raise e
def _check_read_permissions(table, auth1=False, auth2=False, reg=False, anon=False): formats = ['VOTable', 'tsv', 'csv'] for cert, read_access in [(CERT1, auth1), (CERT2, auth2), (CERTREG, reg), (None, anon)]: logger.debug("User cert: {}".format(cert)) format = formats[random.randrange(0, 3)] if format == 'VOTable': out_format = BytesIO else: out_format = StringIO cert_opt = '--cert {}'.format(cert) if cert else '' sys.argv = \ 'cadc-tap query -f {} {} {}'.format(format, cert_opt, HOST).split() sys.argv.append('select * from {}'.format(TABLE)) if read_access: with patch('sys.stdout', new_callable=out_format) as stdout_mock: main_app() result = stdout_mock.getvalue() if out_format == BytesIO: assert b'<INFO name="QUERY_STATUS" value="OK" />' in result else: assert 'rows affected)' in result else: try: with patch('sys.stderr', new_callable=StringIO) as stdout_mock: main_app() assert False,\ 'Application should have aborted due to access error' except SystemExit as e: assert e.code == -1 assert 'is not found in TapSchema. Possible reasons: table ' \ 'does not exist or permission is denied.' in \ stdout_mock.getvalue() or 'permission denied on table' in \ stdout_mock.getvalue()
def test_help(self): """ Tests the helper displays for commands and subcommands in main""" self.maxDiff = None # help with open(os.path.join(TESTDATA_DIR, 'help.txt'), 'r') as myfile: usage = myfile.read() with patch('sys.stdout', new_callable=StringIO) as stdout_mock: sys.argv = ['cadc-tap', '--help'] with self.assertRaises(MyExitError): main_app() self.assertEqual(usage, stdout_mock.getvalue()) usage = ('usage: cadc-tap [-h] [-V] [-s SERVICE]\n' ' {schema,query,create,delete,index,load} ...' '\ncadc-tap: error: too few arguments\n') with patch('sys.stdout', new_callable=StringIO) as stdout_mock: with patch('sys.stderr', new_callable=StringIO) as stderr_mock: sys.argv = ['cadc-tap'] with self.assertRaises(MyExitError): main_app() self.assertEqual(usage, stderr_mock.getvalue()) # schema -h with open(os.path.join(TESTDATA_DIR, 'help_schema.txt'), 'r') as myfile: usage = myfile.read() with patch('sys.stdout', new_callable=StringIO) as stdout_mock: sys.argv = ['cadc-tap', 'schema', '--help'] with self.assertRaises(MyExitError): main_app() self.assertEqual(usage, stdout_mock.getvalue()) # query -h with open(os.path.join(TESTDATA_DIR, 'help_query.txt'), 'r') as myfile: usage = myfile.read() with patch('sys.stdout', new_callable=StringIO) as stdout_mock: sys.argv = ['cadc-tap', 'query', '--help'] with self.assertRaises(MyExitError): main_app() self.assertEqual(usage, stdout_mock.getvalue()) # create -h with open(os.path.join(TESTDATA_DIR, 'help_create.txt'), 'r') as myfile: usage = myfile.read() with patch('sys.stdout', new_callable=StringIO) as stdout_mock: sys.argv = ['cadc-tap', 'create', '--help'] with self.assertRaises(MyExitError): main_app() self.assertEqual(usage, stdout_mock.getvalue()) # delete -h with open(os.path.join(TESTDATA_DIR, 'help_delete.txt'), 'r') as myfile: usage = myfile.read() with patch('sys.stdout', new_callable=StringIO) as stdout_mock: sys.argv = ['cadc-tap', 'delete', '--help'] with self.assertRaises(MyExitError): main_app() self.assertEqual(usage, stdout_mock.getvalue()) # index -h with open(os.path.join(TESTDATA_DIR, 'help_index.txt'), 'r') as myfile: usage = myfile.read() with patch('sys.stdout', new_callable=StringIO) as stdout_mock: sys.argv = ['cadc-tap', 'index', '--help'] with self.assertRaises(MyExitError): main_app() self.assertEqual(usage, stdout_mock.getvalue()) # load -h with open(os.path.join(TESTDATA_DIR, 'help_load.txt'), 'r') as myfile: usage = myfile.read() with patch('sys.stdout', new_callable=StringIO) as stdout_mock: sys.argv = ['cadc-tap', 'load', '--help'] with self.assertRaises(MyExitError): main_app() self.assertEqual(usage, stdout_mock.getvalue())
def test_commands(monkeypatch): # test cadc TAP service with anonymous access sys.argv = ['cadc-tap', 'query', '-s', 'ivo://cadc.nrc.ca/tap', 'select observationID FROM caom2.Observation ' 'where observationID=\'dao_c122_2018_003262\''] with patch('sys.stdout', new_callable=StringIO) as stdout_mock: main_app() assert '<INFO name="QUERY_STATUS" value="OK" />' in stdout_mock.getvalue() assert '<TD>dao_c122_2018_003262</TD>' in stdout_mock.getvalue() # monkeypatch required for the "user interaction" sys.argv = 'cadc-tap delete --cert {} {}'.format(CERT, TABLE).split() try: monkeypatch.setattr('cadctap.core.input', lambda x: "yes") main_app() logger.debug('Deleted table {}'.format(TABLE)) except Exception as e: logger.debug( 'Cannot delete table {}. Reason: {}'.format(TABLE, str(e))) # create table sys.argv = 'cadc-tap create --cert {} {} {}'.format( CERT, TABLE, TABLE_DEF).split() try: main_app() logger.debug('Created table {}'.format(TABLE)) except Exception as e: logger.debug( 'Cannot create table {}. Reason: {}'.format(TABLE, str(e))) raise e sys.argv = 'cadc-tap query --cert {}'.format(CERT).split() sys.argv.append('select * from {}'.format(TABLE)) with patch('sys.stdout', new_callable=StringIO) as stdout_mock: main_app() assert '<INFO name="QUERY_STATUS" value="OK" />' in stdout_mock.getvalue() assert '<TABLEDATA />' in stdout_mock.getvalue() # create index sys.argv = 'cadc-tap index --cert {} {} article'.format( CERT, TABLE).split() try: main_app() logger.debug('Create index on {}.article'.format(TABLE)) except Exception as e: logger.debug( 'Cannot create index {}.article. Reason: {}'.format(TABLE, str(e))) raise e # load data csv format sys.argv = 'cadc-tap load -f csv --cert {} {} {}'.format( CERT, TABLE, os.path.join(TESTDATA_DIR, 'loadTable_csv.txt')).split() try: main_app() logger.debug('Load table {} (csv)'.format(TABLE)) except Exception as e: logger.debug( 'Cannot load table csv {}. Reason: {}'.format(TABLE, str(e))) raise e sys.argv = 'cadc-tap query --cert {}'.format(CERT).split() sys.argv.append('select * from {}'.format(TABLE)) with patch('sys.stdout', new_callable=StringIO) as stdout_mock: main_app() result = stdout_mock.getvalue() assert '<INFO name="QUERY_STATUS" value="OK" />' in result # 3 rows assert 3 == result.count('<TD>art') for i in range(1, 3): assert '<TD>art{}</TD>'.format(i) in result assert '<TD>{}</TD>'.format(i) in result # load data tsv format sys.argv = 'cadc-tap load --cert {} {} {}'.format( CERT, TABLE, os.path.join(TESTDATA_DIR, 'loadTable_tsv.txt')).split() try: main_app() logger.debug('Load table {} (tsv)'.format(TABLE)) except Exception as e: logger.debug( 'Cannot load tsv table {}. Reason: {}'.format(TABLE, str(e))) raise e sys.argv = 'cadc-tap query --cert {}'.format(CERT).split() sys.argv.append('select * from {}'.format(TABLE)) with patch('sys.stdout', new_callable=StringIO) as stdout_mock: main_app() result = stdout_mock.getvalue() assert '<INFO name="QUERY_STATUS" value="OK" />' in result # 6 rows assert 6 == result.count('<TD>art') for i in range(1, 6): assert '<TD>art{}</TD>'.format(i) in result assert '<TD>{}</TD>'.format(i) in result # load data BINTABLE format hdu0 = fits.PrimaryHDU() hdu0.header['COMMENT'] = 'Sample BINTABLE' c1 = fits.Column(name='article', array=np.array(['art6', 'art7', 'art8']), format='5A') c2 = fits.Column(name='count', array=np.array([6, 7, 8]), format='K') hdu1 = fits.BinTableHDU.from_columns([c1, c2]) new_hdul = fits.HDUList([hdu0, hdu1]) tempdir = tempfile.mkdtemp() bintb_file = os.path.join(tempdir, 'bintable.fits') new_hdul.writeto(bintb_file) sys.argv = 'cadc-tap load -f FITSTable --cert {} {} {}'.format( CERT, TABLE, bintb_file).split() try: main_app() logger.debug('Load table {} (bintable)'.format(TABLE)) except Exception as e: logger.debug( 'Cannot load table bintable {}. Reason: {}'.format(TABLE, str(e))) raise e sys.argv = 'cadc-tap query --cert {}'.format(CERT).split() sys.argv.append('select * from {}'.format(TABLE)) with patch('sys.stdout', new_callable=StringIO) as stdout_mock: main_app() result = stdout_mock.getvalue() assert '<INFO name="QUERY_STATUS" value="OK" />' in result # 9 rows assert 9 == result.count('<TD>art') for i in range(1, 9): assert '<TD>art{}</TD>'.format(i) in result assert '<TD>{}</TD>'.format(i) in result #TODO query with temporary table # cleanup sys.argv = 'cadc-tap delete --cert {} {}'.format(CERT, TABLE).split() try: monkeypatch.setattr('cadctap.core.input', lambda x: "yes") main_app() logger.debug('Deleted table {}'.format(TABLE)) except Exception as e: logger.debug( 'Cannot delete table {}. Reason: {}'.format(TABLE, str(e))) raise e
def test_main(self, schema_mock, query_mock, create_mock, delete_mock, index_mock, load_mock, permissions_mock): sys.argv = ['cadc-tap', 'schema'] main_app() calls = [call(None)] schema_mock.assert_has_calls(calls) sys.argv = ['cadc-tap', 'schema', 'mytable'] main_app() calls = [call('mytable')] schema_mock.assert_has_calls(calls) sys.argv = ['cadc-tap', 'create', '-d', 'tablename', 'path/to/file'] main_app() calls = [call('tablename', 'path/to/file', 'VOSITable')] create_mock.assert_has_calls(calls) sys.argv = ['cadc-tap', 'index', '-v', 'tablename', 'columnName'] main_app() calls = [call('tablename', 'columnName', False)] index_mock.assert_has_calls(calls) sys.argv = ['cadc-tap', 'load', 'tablename', 'path/to/file'] main_app() calls = [call('tablename', ['path/to/file'], 'tsv')] load_mock.assert_has_calls(calls) sys.argv = ['cadc-tap', 'query', '-s', 'http://someservice', 'QUERY'] main_app() calls = [call('QUERY', None, 'tsv', None, data_only=False, timeout=2)] query_mock.assert_has_calls(calls) query_mock.reset_mock() sys.argv = ['cadc-tap', 'query', '-q', '-s', 'http://someservice', 'QUERY'] main_app() calls = [call('QUERY', None, 'tsv', None, data_only=True, timeout=2)] query_mock.assert_has_calls(calls) query_mock.reset_mock() sys.argv = ['cadc-tap', 'query', '-s', 'http://someservice', '--timeout', '7', 'QUERY'] main_app() calls = [call('QUERY', None, 'tsv', None, data_only=False, timeout=7)] query_mock.assert_has_calls(calls) query_mock.reset_mock() query_file = os.path.join(TESTDATA_DIR, 'example_query.sql') sys.argv = ['cadc-tap', 'query', '-i', query_file, '-s', 'tap'] main_app() calls = [call('SELECT TOP 10 target_name FROM caom2.Observation', None, 'tsv', None, data_only=False, timeout=2)] query_mock.assert_has_calls(calls) sys.argv = ['cadc-tap', 'permission', 'o+r', 'table'] main_app() calls = [call('table', read_anon=True, read_only=None, read_write=None)] permissions_mock.assert_has_calls(calls) permissions_mock.reset_mock() sys.argv = ['cadc-tap', 'permission', 'g+rw', 'table', 'CADC1', 'CADC2'] main_app() calls = [call('table', read_anon=None, read_only='ivo://cadc.nrc.ca/gms?CADC1', read_write='ivo://cadc.nrc.ca/gms?CADC2')] permissions_mock.assert_has_calls(calls) permissions_mock.reset_mock() sys.argv = ['cadc-tap', 'permission', 'og-r', 'table'] main_app() calls = [call('table', read_anon=False, read_only='', read_write=None)] permissions_mock.assert_has_calls(calls)
def test_write_delete_permissions(monkeypatch): # monkeypatch required for the "user interaction" # set schema permissions sys.argv = 'cadc-tap permission --cert {} {} og-rw {}'.format( CERT1, HOST, DB_SCHEMA_NAME).split() main_app() sys.argv = 'cadc-tap permission --cert {} {} og+r {} {}'.format( CERT1, HOST, DB_SCHEMA_NAME, GROUP).split() main_app() sys.argv = 'cadc-tap schema --cert {} {} {}'.format( CERT1, HOST, DB_SCHEMA_NAME).split() with patch('sys.stdout', new_callable=StringIO) as stdout_mock: main_app() result = stdout_mock.getvalue() # create table with no credentials (Fail) sys.argv = 'cadc-tap create {} {} {}'.format(HOST, TABLE, TABLE_DEF).split() try: with patch('sys.stderr', new_callable=StringIO) as stdout_mock: main_app() assert False, 'Application should have aborted due to access error' except SystemExit as e: assert e.code == -1 assert 'permission denied' in stdout_mock.getvalue() # create table with no write permission in schema (Fail) for cert in [CERT2, CERTREG]: sys.argv = 'cadc-tap create --cert {} {} {} {}'.format( cert, HOST, TABLE, TABLE_DEF).split() try: with patch('sys.stderr', new_callable=StringIO) as stdout_mock: main_app() assert False,\ 'Application should have aborted due to access error' except SystemExit as e: assert e.code == -1 assert 'permission denied' in stdout_mock.getvalue() _create_table(monkeypatch, CERT1) # -------------------- test write access --------------- hdu0 = fits.PrimaryHDU() hdu0.header['COMMENT'] = 'Sample BINTABLE' c1 = fits.Column(name='article', array=np.array(['art1']), format='5A') c2 = fits.Column(name='count', array=np.array([1]), format='K') hdu1 = fits.BinTableHDU.from_columns([c1, c2]) new_hdul = fits.HDUList([hdu0, hdu1]) tempdir = tempfile.mkdtemp() bintb_file = os.path.join(tempdir, 'bintable.fits') new_hdul.writeto(bintb_file) sys.argv = 'cadc-tap load -f FITSTable --cert {} {} {} {}'.format( CERT2, HOST, TABLE, bintb_file).split() try: with patch('sys.stderr', new_callable=StringIO) as stdout_mock: main_app() assert False, 'Application should have aborted due to access error' except SystemExit as e: assert e.code == -1 assert 'permission denied' in stdout_mock.getvalue() # give write access and try again sys.argv = 'cadc-tap permission --cert {} {} g+w {} {}'.format( CERT1, HOST, TABLE, GROUP).split() main_app() sys.argv = 'cadc-tap load -f FITSTable --cert {} {} {} {}'.format( CERT2, HOST, TABLE, bintb_file).split() try: main_app() logger.debug('Load table {} (bintable)'.format(TABLE)) except Exception as e: logger.debug('Cannot load table bintable {}. Reason: {}'.format( TABLE, str(e))) raise e sys.argv = 'cadc-tap query -f VOTable --cert {} {}'.format(CERT1, HOST).split() sys.argv.append('select * from {}'.format(TABLE)) with patch('sys.stdout', new_callable=BytesIO) as stdout_mock: main_app() result = stdout_mock.getvalue() assert b'<INFO name="QUERY_STATUS" value="OK" />' in result # 1 row assert 1 == result.count(b'<TD>art') for i in range(1, 1): assert '<TD>art{}</TD>'.format(i).encode('utf-8') in result assert '<TD>{}</TD>'.format(i).encode('utf-8') in result # REG user still failing sys.argv = 'cadc-tap load -f FITSTable --cert {} {} {} {}'.format( CERTREG, HOST, TABLE, bintb_file).split() try: with patch('sys.stderr', new_callable=StringIO) as stdout_mock: main_app() assert False, 'Application should have aborted due to access error' except SystemExit as e: assert e.code == -1 assert 'permission denied' in stdout_mock.getvalue() # test remove with anon user sys.argv = 'cadc-tap delete {} {}'.format(HOST, TABLE).split() try: with patch('sys.stderr', new_callable=StringIO) as stdout_mock: monkeypatch.setattr('cadctap.core.input', lambda x: "yes") main_app() assert False, 'Application should have aborted due to access error' except SystemExit as e: assert e.code == -1 assert 'permission denied' in stdout_mock.getvalue() # same thing with user in no groups or in write group for cert in [CERT2, CERTREG]: sys.argv = 'cadc-tap delete --cert {} {} {}'.format( CERTREG, HOST, TABLE).split() try: with patch('sys.stderr', new_callable=StringIO) as stdout_mock: monkeypatch.setattr('cadctap.core.input', lambda x: "yes") main_app() assert False, 'Application should have aborted due to access error' except SystemExit as e: assert e.code == -1 assert 'permission denied' in stdout_mock.getvalue() # success if user is the owner sys.argv = 'cadc-tap delete --cert {} {} {}'.format(CERT1, HOST, TABLE).split() try: monkeypatch.setattr('cadctap.core.input', lambda x: "yes") main_app() logger.debug('Deleted table {}'.format(TABLE)) except Exception as e: logger.debug('Cannot delete table {}. Reason: {}'.format( TABLE, str(e))) raise e
def test_permission_settings(monkeypatch): sys.argv = 'cadc-tap permission --cert {} {} og-rw {}'.format( CERT1, HOST, DB_SCHEMA_NAME).split() main_app() # create a table _create_table(monkeypatch, CERT1) # schema permissions at the minimum - overrides table permissions assert [DN1, 'false', '-', '-'] == _get_permissions(CERT1, DB_SCHEMA_NAME) _check_read_permissions(TABLE, True, False, False, False) sys.argv = 'cadc-tap permission --cert {} {} g+r {} {}'.format( CERT1, HOST, TABLE, GROUP).split() main_app() assert [DN1, 'false', GROUP, '-'] == _get_permissions(CERT1, TABLE) _check_read_permissions(TABLE, True, False, False, False) sys.argv = 'cadc-tap permission --cert {} {} g+w {} {}'.format( CERT1, HOST, TABLE, GROUP).split() main_app() assert [DN1, 'false', GROUP, GROUP] == \ _get_permissions(CERT1, TABLE) _check_read_permissions(TABLE, True, False, False, False) sys.argv = 'cadc-tap permission --cert {} {} o+r {}'.format( CERT1, HOST, TABLE).split() main_app() assert [DN1, 'true', GROUP, GROUP] == \ _get_permissions(CERT1, TABLE) _check_read_permissions(TABLE, True, False, False, False) # change the schema permissions - table has all permissions sys.argv = 'cadc-tap permission --cert {} {} g+r {} {}'.format( CERT1, HOST, DB_SCHEMA_NAME, GROUP).split() main_app() assert [DN1, 'false', GROUP, '-'] == \ _get_permissions(CERT1, DB_SCHEMA_NAME) _check_read_permissions(TABLE, True, True, False, False) sys.argv = 'cadc-tap permission --cert {} {} g+w {} {}'.format( CERT1, HOST, DB_SCHEMA_NAME, GROUP).split() main_app() assert [DN1, 'false', GROUP, GROUP] == \ _get_permissions(CERT1, DB_SCHEMA_NAME) _check_read_permissions(TABLE, True, True, False, False) sys.argv = 'cadc-tap permission --cert {} {} o+r {}'.format( CERT1, HOST, DB_SCHEMA_NAME).split() main_app() assert [DN1, 'true', GROUP, GROUP] == \ _get_permissions(CERT1, DB_SCHEMA_NAME) _check_read_permissions(TABLE, True, True, True, True) # remove table and create a new one owned by CERT2 user _create_table(monkeypatch, CERT2) _check_read_permissions(TABLE, False, True, False, False) sys.argv = 'cadc-tap permission --cert {} {} g+r {} {}'.format( CERT2, HOST, TABLE, GROUP).split() main_app() assert [DN2, 'false', GROUP, '-'] == \ _get_permissions(CERT2, TABLE) _check_read_permissions(TABLE, True, True, False, False) sys.argv = 'cadc-tap permission --cert {} {} o+r {}'.format( CERT2, HOST, TABLE).split() main_app() assert [DN2, 'true', GROUP, '-'] == \ _get_permissions(CERT2, TABLE) _check_read_permissions(TABLE, True, True, True, True) sys.argv = 'cadc-tap permission --cert {} {} og-r {}'.format( CERT2, HOST, TABLE).split() main_app() assert [DN2, 'false', '-', '-'] == \ _get_permissions(CERT2, TABLE) # try to delete as CERT1 _create_table(monkeypatch, CERT1)