2
2
Test driver script for the Tableau Datasource Verification Tool
3
3
4
4
"""
5
+
5
6
import sys
6
7
7
8
if sys .version_info [0 ] < 3 :
21
22
from pathlib import Path
22
23
from typing import List , Optional , Tuple , Union
23
24
24
- from .config_gen .datasource_list import print_ds , print_configurations , print_logical_configurations
25
+ from .config_gen .datasource_list import TestRegistry , print_ds , print_configurations , print_logical_configurations
25
26
from .config_gen .tdvtconfig import TdvtInvocation
26
27
from .config_gen .test_config import TestSet , SingleLogicalTestSet , SingleExpressionTestSet , FileTestSet , TestConfig , RunTimeTestConfig
27
28
from .setup_env import create_test_environment , add_datasource
28
29
from .tabquery import *
29
- from .tdvt_core import generate_files , run_diff , run_tests , run_connectors_test_core
30
+ from .tdvt_core import generate_files , run_diff , run_tests , run_connectors_test_core , return_csv_dialect
30
31
from .version import __version__
31
32
32
33
# This contains the dictionary of configs you can run.
@@ -45,43 +46,46 @@ class TestOutputFiles(object):
45
46
combined_output = []
46
47
47
48
@classmethod
48
- def copy_output_file (c , src_name , src_dir ):
49
+ def copy_output_file (cls , src_name , src_dir , csv_dialect ):
49
50
src = os .path .join (src_dir , src_name )
50
51
logging .debug ("Copying {0} to output" .format (src ))
51
52
try :
52
53
with open (src , 'r' , encoding = 'utf8' ) as src_file :
53
- reader = csv .DictReader (src_file , dialect = 'tdvt' )
54
+ reader = csv .DictReader (src_file , dialect = csv_dialect )
54
55
for row in reader :
55
- c .combined_output .append (row )
56
+ cls .combined_output .append (row )
56
57
57
58
except IOError as e :
58
59
logging .debug ("Exception while copying files: " + str (e ))
59
60
return
60
61
61
62
@classmethod
62
- def write_test_results_csv (c , custom_output_dir : str = '' ):
63
- if not c .combined_output :
63
+ def write_test_results_csv (cls , perf_run : bool , custom_output_dir : str = '' ):
64
+ if not cls .combined_output :
64
65
logging .debug ("write_test_results_csv called with no test output" )
65
66
return
66
67
67
- logging .debug ("Copying output to {0}" .format (c .output_csv ))
68
+ logging .debug ("Copying output to {0}" .format (cls .output_csv ))
68
69
# Sort combined_output on the number of distinct functions (order of complexity)
69
70
sort_by_complexity = lambda row : len (row ['Functions' ].split (',' ))
70
71
try :
71
- c .combined_output .sort (key = sort_by_complexity )
72
+ cls .combined_output .sort (key = sort_by_complexity )
72
73
except KeyError as e :
73
74
logging .debug ("Tried to sort output on a key that doesn't exist. Leaving output unsorted." )
74
75
75
- dst = os .path .join (os .getcwd (), c .output_csv )
76
+ dst = os .path .join (os .getcwd (), cls .output_csv )
76
77
if custom_output_dir != '' :
77
- dst = os .path .join (Path (custom_output_dir ), c .output_csv )
78
+ dst = os .path .join (Path (custom_output_dir ), cls .output_csv )
78
79
try :
79
- dst_exists = os .path .isfile (dst )
80
80
with open (dst , 'w' , encoding = 'utf8' ) as dst_file :
81
- writer = csv .DictWriter (dst_file , fieldnames = c .combined_output [0 ],
82
- dialect = 'tdvt' , quoting = csv .QUOTE_MINIMAL )
81
+ writer = csv .DictWriter (
82
+ dst_file ,
83
+ fieldnames = cls .combined_output [0 ],
84
+ dialect = return_csv_dialect (perf_run ),
85
+ quoting = csv .QUOTE_MINIMAL
86
+ )
83
87
writer .writeheader ()
84
- for row in c .combined_output :
88
+ for row in cls .combined_output :
85
89
writer .writerow (row )
86
90
except IOError as e :
87
91
logging .debug ("Exception while writing to file: " + str (e ))
@@ -95,7 +99,7 @@ def do_test_queue_work(i, q):
95
99
abort_test_run = False
96
100
while True :
97
101
# This blocks if the queue is empty.
98
- work = q .get ()
102
+ work : TestRunner = q .get ()
99
103
100
104
work .run ()
101
105
@@ -135,8 +139,8 @@ def copy_files_to_zip(self, dst_file_name, src_dir, is_logs):
135
139
inner_output = os .path .join (optional_dir_name , file_to_be_zipped )
136
140
myzip .write (actual , inner_output )
137
141
138
- def copy_output_files (self ):
139
- TestOutputFiles .copy_output_file ("test_results.csv" , self .temp_dir )
142
+ def copy_output_files (self , csv_dialect ):
143
+ TestOutputFiles .copy_output_file ("test_results.csv" , self .temp_dir , csv_dialect )
140
144
141
145
def copy_test_result_file (self ):
142
146
src = os .path .join (self .temp_dir , "tdvt_output.json" )
@@ -179,10 +183,12 @@ def copy_test_result_file(self):
179
183
180
184
def copy_files_and_cleanup (self ):
181
185
left_temp_dir = False
186
+ csv_dialect = 'perflab' if self .test_config .run_as_perf else 'tdvt'
187
+ # if
182
188
try :
183
189
self .copy_files_to_zip (TestOutputFiles .output_actuals , self .temp_dir , is_logs = False )
184
190
self .copy_files_to_zip (TestOutputFiles .output_tabquery_log , self .temp_dir , is_logs = True )
185
- self .copy_output_files ()
191
+ self .copy_output_files (csv_dialect )
186
192
self .copy_test_result_file ()
187
193
except Exception as e :
188
194
print (e )
@@ -243,7 +249,9 @@ def get_datasource_registry(platform):
243
249
return reg
244
250
245
251
246
- def enqueue_single_test (args , ds_info : TestConfig , suite ) -> Union [Tuple [None , None ], Tuple [Union [SingleLogicalTestSet , SingleExpressionTestSet ], TdvtInvocation ]]: # noqa: E501
252
+ def enqueue_single_test (
253
+ args , ds_info : TestConfig , suite
254
+ ) -> Union [Tuple [None , None ], Tuple [Union [SingleLogicalTestSet , SingleExpressionTestSet ], TdvtInvocation ]]:
247
255
if not args .command == 'run-pattern' or not args .tds_pattern or (args .logical_pattern and args .expression_pattern ):
248
256
return None , None
249
257
@@ -483,6 +491,8 @@ def create_parser():
483
491
run_test_common_parser .add_argument ('--output-dir' , '-o' , dest = 'custom_output_dir' ,
484
492
help = 'Writes log files to a specified directory. The directory must exist.' ,
485
493
required = False , default = None , const = '*' , nargs = '?' )
494
+ run_test_common_parser .add_argument ('--perf-run' , dest = 'perf_run' , action = 'store_true' , default = False )
495
+ run_test_common_parser .add_argument ('--iteration' , dest = 'perf_iteration' , type = int )
486
496
subparsers = parser .add_subparsers (help = 'commands' , dest = 'command' )
487
497
488
498
#Get information.
@@ -507,7 +517,6 @@ def create_parser():
507
517
run_test_parser .add_argument ('--logical' , '-q' , dest = 'logical_only' , help = 'Only run logical tests whose config file name matches the supplied string, or all if blank.' , required = False , default = None , const = '*' , nargs = '?' )
508
518
run_test_parser .add_argument ('--expression' , '-e' , dest = 'expression_only' , help = 'Only run expression tests whose config file name matches the suppled string, or all if blank.' , required = False , default = None , const = '*' , nargs = '?' )
509
519
510
-
511
520
#Run test pattern.
512
521
run_test_pattern_parser = subparsers .add_parser ('run-pattern' , help = 'Run individual tests using a pattern.' , parents = [run_test_common_parser ], usage = run_pattern_usage_text )
513
522
run_test_pattern_parser .add_argument ('ds' , help = 'Comma separated list of Datasource names or groups to test. See the \' list\' command.' , nargs = '+' )
@@ -540,6 +549,14 @@ def register_tdvt_dialect():
540
549
custom_dialect .skipinitialspace = True
541
550
csv .register_dialect ('tdvt' , custom_dialect )
542
551
552
+ def register_perflab_dialect ():
553
+ custom_dialect = csv .excel
554
+ custom_dialect .lineterminator = '\n '
555
+ custom_dialect .delimiter = '|'
556
+ custom_dialect .strict = True
557
+ custom_dialect .skipinitialspace = True
558
+ csv .register_dialect ('perflab' , custom_dialect )
559
+
543
560
def check_if_custom_output_dir_exists (custom_output_dir : str ) -> bool :
544
561
return Path (custom_output_dir ).is_dir ()
545
562
@@ -576,6 +593,7 @@ def init():
576
593
ds_reg = get_datasource_registry (sys .platform )
577
594
configure_tabquery_path ()
578
595
register_tdvt_dialect ()
596
+ register_perflab_dialect ()
579
597
580
598
return parser , ds_reg , args
581
599
@@ -590,7 +608,7 @@ def active_thread_count(threads):
590
608
return active
591
609
592
610
593
- def test_runner (all_tests , test_queue , max_threads ) :
611
+ def test_runner (all_tests : List [ TestRunner ] , test_queue : queue . Queue , max_threads : int ) -> Tuple [ int , int , int , int ] :
594
612
for i in range (0 , max_threads ):
595
613
worker = threading .Thread (target = do_test_queue_work , args = (i , test_queue ))
596
614
worker .setDaemon (True )
@@ -607,11 +625,17 @@ def test_runner(all_tests, test_queue, max_threads):
607
625
skipped_tests += work .skipped_tests if work .skipped_tests else 0
608
626
disabled_tests += work .disabled_tests if work .disabled_tests else 0
609
627
total_tests += work .total_tests if work .total_tests else 0
610
- TestOutputFiles .write_test_results_csv (work .test_config .custom_output_dir )
628
+ is_perf_run = all_tests [0 ].test_config .run_as_perf
629
+ custom_output_dir = all_tests [0 ].test_config .custom_output_dir
630
+ TestOutputFiles .write_test_results_csv (is_perf_run , custom_output_dir )
611
631
return failed_tests , skipped_tests , disabled_tests , total_tests
612
632
613
633
614
- def run_tests_impl (tests : List [Tuple [TestSet , TestConfig ]], max_threads : int , args ) -> Optional [Tuple [int , int , int , int ]]:
634
+ def run_tests_impl (
635
+ tests : List [Tuple [TestSet , TdvtInvocation ]],
636
+ max_threads : int ,
637
+ args
638
+ ) -> Optional [Tuple [int , int , int , int ]]:
615
639
if not tests :
616
640
print ("No tests found. Check arguments." )
617
641
sys .exit ()
@@ -661,7 +685,8 @@ def run_tests_impl(tests: List[Tuple[TestSet, TestConfig]], max_threads: int, ar
661
685
print ("Starting smoke tests. Creating" , str (smoke_test_threads ), "worker threads.\n " )
662
686
663
687
failed_smoke_tests , skipped_smoke_tests , disabled_smoke_tests , total_smoke_tests = test_runner (
664
- smoke_tests , smoke_test_queue , smoke_test_threads )
688
+ smoke_tests , smoke_test_queue , smoke_test_threads
689
+ )
665
690
666
691
smoke_tests_run = total_smoke_tests - disabled_smoke_tests
667
692
@@ -727,7 +752,7 @@ def get_ds_list(ds):
727
752
ds_list = [x .strip () for x in ds_list ]
728
753
return ds_list
729
754
730
- def run_desired_tests (args , ds_registry ):
755
+ def run_desired_tests (args , ds_registry : TestRegistry ):
731
756
generate_files (ds_registry , False )
732
757
ds_to_run = ds_registry .get_datasources (get_ds_list (args .ds ))
733
758
if not ds_to_run :
@@ -744,7 +769,7 @@ def run_desired_tests(args, ds_registry):
744
769
sys .exit (0 )
745
770
746
771
max_threads = get_level_of_parallelization (args )
747
- test_sets : List [TestSet ] = []
772
+ test_sets : List [Tuple [ TestSet , TestConfig ], Tuple [ TestSet , TdvtInvocation ] ] = []
748
773
749
774
for ds in ds_to_run :
750
775
ds_info = ds_registry .get_datasource_info (ds )
0 commit comments