66
77import redshift_connector
88
9- # from warnings import filterwarnings
9+ # Pre-reqs
10+ # These tests require the following:
11+ # - A single Redshift instance OR two Redshift instances configured for datasharing as consumer and producer.
12+ # - Config.ini entry for [ci-cluster] file populated with the host and port of the single Redshift instance or the
13+ # producer instance if you want to test datasharing metadata methods
14+ #
15+ # How to use this test file
16+ # The included tests can be run to ensure the expected Redshift system tables are queried. Running this test via CLI
17+ # and using tee can enable to you compare and contrast result sets returned by metadata APIs on multiple clusters with
18+ # different patch versions. Please note the result set output is only useful if the same data is accessible by the
19+ # database user in all test situations.
1020
1121
1222conf : configparser .ConfigParser = configparser .ConfigParser ()
@@ -145,23 +155,27 @@ def test_get_schemas(mocker, _input, db_kwargs) -> None:
145155 database_metadata_current_db_only_val , _args = _input
146156 db_kwargs ["database_metadata_current_db_only" ] = database_metadata_current_db_only_val
147157 with redshift_connector .connect (** db_kwargs ) as conn :
148- assert conn .is_single_database_metadata is database_metadata_current_db_only_val
149-
150158 with conn .cursor () as cursor :
151159 spy = mocker .spy (cursor , "execute" )
152160 result : typing .Tuple = cursor .get_schemas (** _args )
153- # ensure query was executed with arguments passed to get_schemas
161+ print (result )
162+ # ensure execute was called
154163 assert spy .called
155- assert spy .call_count == 1
156-
157- if _args ["schema_pattern" ] is not None : # should be in parameterized portion
158- assert _args ["schema_pattern" ] in spy .call_args [0 ][1 ]
164+ assert spy .call_count == 1 # call in get_schemas()
159165
166+ # ensure execute was called with the catalog value in the prepared statement
160167 if _args ["catalog" ] is not None :
161168 assert _args ["catalog" ] in spy .call_args [0 ][0 ]
162169
163- assert len (result ) > 0 , print (spy .call_args , "\n " , result )
164- assert len (result [0 ]) == 2
170+ # ensure execute was called with below bind parameters
171+ if _args ["schema_pattern" ] is not None :
172+ assert _args ["schema_pattern" ] in spy .call_args [0 ][1 ]
173+
174+ # assert query text executed contains the target table name
175+ if conn .is_single_database_metadata :
176+ assert "FROM pg_catalog.pg_namespace" in spy .call_args [0 ][0 ]
177+ else :
178+ assert "FROM PG_CATALOG.SVV_ALL_SCHEMAS" in spy .call_args [0 ][0 ]
165179
166180
167181def get_tables_test_data () -> typing .List [typing .Optional [typing .Tuple [bool , typing .Dict [str , typing .Any ]]]]:
@@ -272,35 +286,54 @@ def test_get_tables(mocker, _input, db_kwargs) -> None:
272286 database_metadata_current_db_only_val , _args = _input
273287 db_kwargs ["database_metadata_current_db_only" ] = database_metadata_current_db_only_val
274288 with redshift_connector .connect (** db_kwargs ) as conn :
275- assert conn .is_single_database_metadata is database_metadata_current_db_only_val
276-
277289 with conn .cursor () as cursor :
278290 spy = mocker .spy (cursor , "execute" )
279291 result : typing .Tuple = cursor .get_tables (** _args )
280292 print (result )
281- # ensure query was executed with arguments passed to get_schemas
293+ # ensure execute was called
282294 assert spy .called
283295
284- if _args ["schema_pattern" ] is not None and database_metadata_current_db_only_val :
296+ if _args ["schema_pattern" ] is not None and conn . is_single_database_metadata :
285297 assert spy .call_count == 2 # call in __schema_pattern_match(), get_tables()
286298 else :
287- assert spy .call_count == 1
288-
289- if _args ["schema_pattern" ] is not None : # should be in parameterized portion
290- print (spy .call_args )
291- print (spy .call_args [0 ][1 ])
292- print (_args , database_metadata_current_db_only_val , TestListCatalog .test_schema )
293- assert _args ["schema_pattern" ] in spy .call_args [0 ][1 ], print (spy .call_args )
299+ assert spy .call_count == 1 # call in get_tables()
294300
301+ # ensure execute was called with the catalog value in the prepared statement
295302 if _args ["catalog" ] is not None :
296303 assert _args ["catalog" ] in spy .call_args [0 ][0 ]
297304
305+ # ensure execute was called with below bind parameters
298306 for arg in (_args ["schema_pattern" ], _args ["table_name_pattern" ]):
299307 if arg is not None :
300308 assert arg in spy .call_args [0 ][1 ]
301309
302- assert len (result ) > 0 , print (spy .call_args , "\n " , result )
303- assert len (result [0 ]) == 10
310+ # we cannot easily know what schema pattern matches in Python driver, so
311+ # we check table is one of a few options based on whether is_single_database_metadata
312+ # is true or false
313+
314+ possible_not_ds_tables = (
315+ "FROM svv_tables" , # universal
316+ "FROM pg_catalog.pg_namespace n, pg_catalog.pg_class" , # local
317+ "FROM svv_external_tables" , # external
318+ )
319+ possible_ds_tables = (
320+ "FROM PG_CATALOG.SVV_ALL_TABLES" , # universal
321+ "FROM pg_catalog.pg_namespace n, pg_catalog.pg_class" , # local
322+ "FROM svv_external_tables" , # external
323+ )
324+
325+ if conn .is_single_database_metadata :
326+ for table in possible_not_ds_tables :
327+ if table in spy .call_args [0 ][0 ]:
328+ assert 1 == 1
329+ return
330+ assert 1 == 0 , spy .call_args [0 ][0 ]
331+ else :
332+ for table in possible_ds_tables :
333+ if table in spy .call_args [0 ][0 ]:
334+ assert 1 == 1
335+ return
336+ assert 1 == 0 , spy .call_args [0 ][0 ]
304337
305338
306339def get_columns_test_data () -> typing .List [typing .Tuple [bool , typing .Dict [str , typing .Optional [str ]]]]:
@@ -482,19 +515,19 @@ def test_get_columns(mocker, _input, db_kwargs) -> None:
482515 database_metadata_current_db_only_val , _args = _input
483516 db_kwargs ["database_metadata_current_db_only" ] = database_metadata_current_db_only_val
484517 with redshift_connector .connect (** db_kwargs ) as conn :
485- assert conn .is_single_database_metadata is database_metadata_current_db_only_val
486-
487518 with conn .cursor () as cursor :
488519 spy = mocker .spy (cursor , "execute" )
489520 result : typing .Tuple = cursor .get_columns (** _args )
490- # ensure query was executed with arguments passed to get_schemas
521+ print (result )
522+ # ensure execute was called
491523 assert spy .called
492524
493- if _args ["schema_pattern" ] is not None and database_metadata_current_db_only_val :
525+ if _args ["schema_pattern" ] is not None and conn . is_single_database_metadata :
494526 assert spy .call_count == 2 # call in __schema_pattern_match(), get_columns()
495527 else :
496- assert spy .call_count == 1
528+ assert spy .call_count == 1 # call in get_columns()
497529
530+ # ensure execute was called with below bind parameters
498531 for arg in (
499532 _args ["catalog" ],
500533 _args ["schema_pattern" ],
@@ -504,5 +537,54 @@ def test_get_columns(mocker, _input, db_kwargs) -> None:
504537 if arg is not None :
505538 assert arg in spy .call_args [0 ][0 ]
506539
507- assert len (result ) > 0 , print (spy .call_args , "\n " , result )
508- assert len (result [0 ]) == 24
540+ # we cannot easily know what schema pattern matches in Python driver, so
541+ # we check table is one of a few options based on whether is_single_database_metadata
542+ # is true or false
543+
544+ possible_not_ds_tables = (
545+ "FROM svv_columns" , # universal
546+ "FROM pg_catalog.pg_namespace" , # local
547+ "FROM svv_external_columns" , # external
548+ )
549+ possible_ds_tables = (
550+ "FROM PG_CATALOG.svv_all_columns" , # universal
551+ "FROM pg_catalog.pg_namespace" , # local
552+ "FROM svv_external_columns" , # external
553+ )
554+
555+ if conn .is_single_database_metadata :
556+ for table in possible_not_ds_tables :
557+ if table in spy .call_args [0 ][0 ]:
558+ assert 1 == 1
559+ return
560+ assert 1 == 0 , spy .call_args [0 ][0 ]
561+ else :
562+ for table in possible_ds_tables :
563+ if table in spy .call_args [0 ][0 ]:
564+ assert 1 == 1
565+ return
566+ assert 1 == 0 , spy .call_args [0 ][0 ]
567+
568+
569+ def get_catalogs_test_data () -> typing .List [bool ]:
570+ return [True , False ]
571+
572+
573+ @pytest .mark .skip (reason = "manual" )
574+ @pytest .mark .parametrize ("_input" , get_catalogs_test_data ())
575+ def test_get_catalogs (mocker , _input , db_kwargs ) -> None :
576+ database_metadata_current_db_only_val = _input
577+ db_kwargs ["database_metadata_current_db_only" ] = database_metadata_current_db_only_val
578+ with redshift_connector .connect (** db_kwargs ) as conn :
579+ with conn .cursor () as cursor :
580+ spy = mocker .spy (cursor , "execute" )
581+ result : typing .Tuple = cursor .get_catalogs ()
582+ print (result )
583+ # ensure execute was called
584+ assert spy .called
585+ assert spy .call_count == 1 # call in get_catalogs()
586+
587+ if conn .is_single_database_metadata :
588+ assert "current_database()" in spy .call_args [0 ][0 ]
589+ else :
590+ assert "PG_CATALOG.SVV_REDSHIFT_DATABASES" in spy .call_args [0 ][0 ]
0 commit comments