Merge "pkt_gen: STC - Imix Genome Support"
[vswitchperf.git] / tools / pkt_gen / testcenter / testcenter-rfc2544-rest.py
1 # Copyright 2016-2017 Spirent Communications.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #   http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 # Invalid name of file, must be used '_' instead '-'
16 # pylint: disable=invalid-name
17 '''
18 @author Spirent Communications
19
20 This test automates the RFC2544 tests using the Spirent
21 TestCenter REST APIs. This test supports Python 3.4
22
23 '''
24 import argparse
25 import collections
26 import logging
27 import os
28 import sqlite3
29
30 _LOGGER = logging.getLogger(__name__)
31
32 GENOME_PKTSIZE_ENCODING = {"a": 64, "b": 128, "c": 256, "d": 512,
33                            "e": 1024, "f": 1280, "g": 1518, "h": 2112}
34
35
36 def genome2weights(sequence):
37     """ Convert genome sequence to packetsize weights"""
38     weights = collections.defaultdict(int)
39     for char in GENOME_PKTSIZE_ENCODING:
40         charcount = sequence.count(char)
41         if charcount:
42             weights[GENOME_PKTSIZE_ENCODING[char]] = charcount
43     return weights
44
45
46 def create_dir(path):
47     """Create the directory as specified in path """
48     if not os.path.exists(path):
49         try:
50             os.makedirs(path)
51         except OSError as ex:
52             _LOGGER.error("Failed to create directory %s: %s", path, str(ex))
53             raise
54
55
56 def write_histogram_to_csv(results_path, csv_results_file_prefix,
57                            counts, ranges):
58     """ Write the results of the query to the CSV """
59     filec = os.path.join(results_path, csv_results_file_prefix + ".csv")
60     with open(filec, "wb") as result_file:
61         for key in counts:
62             result_file.write(str(key) + "\n")
63             result_file.write(str(ranges) + "\n")
64             result_file.write(str(counts[key]) + "\n")
65
66
67 def write_query_results_to_csv(results_path, csv_results_file_prefix,
68                                query_results):
69     """ Write the results of the query to the CSV """
70     create_dir(results_path)
71     filec = os.path.join(results_path, csv_results_file_prefix + ".csv")
72     with open(filec, "wb") as result_file:
73         result_file.write(query_results["Columns"].replace(" ", ",") + "\n")
74         for row in (query_results["Output"].replace("} {", ",").
75                     replace("{", "").replace("}", "").split(",")):
76             result_file.write(row.replace(" ", ",") + "\n")
77
78
79 def positive_int(value):
80     """ Positive Integer type for Arguments """
81     ivalue = int(value)
82     if ivalue <= 0:
83         raise argparse.ArgumentTypeError(
84             "%s is an invalid positive int value" % value)
85     return ivalue
86
87
88 def percent_float(value):
89     """ Floating type for Arguments """
90     pvalue = float(value)
91     if pvalue < 0.0 or pvalue > 100.0:
92         raise argparse.ArgumentTypeError(
93             "%s not in range [0.0, 100.0]" % pvalue)
94     return pvalue
95
96
97 # pylint: disable=too-many-branches, too-many-statements, too-many-locals
98 def main():
99     """ Read the arguments, Invoke Test and Return the results"""
100     parser = argparse.ArgumentParser()
101     # Required parameters
102     required_named = parser.add_argument_group("required named arguments")
103     required_named.add_argument("--lab_server_addr",
104                                 required=True,
105                                 help=("The IP address of the"
106                                       "Spirent Lab Server"),
107                                 dest="lab_server_addr")
108     required_named.add_argument("--license_server_addr",
109                                 required=True,
110                                 help=("The IP address of the Spirent"
111                                       "License Server"),
112                                 dest="license_server_addr")
113     required_named.add_argument("--east_chassis_addr",
114                                 required=True,
115                                 help=("The TestCenter chassis IP address to"
116                                       "use for the east test port"),
117                                 dest="east_chassis_addr")
118     required_named.add_argument("--east_slot_num",
119                                 type=positive_int,
120                                 required=True,
121                                 help=("The TestCenter slot number to"
122                                       "use for the east test port"),
123                                 dest="east_slot_num")
124     required_named.add_argument("--east_port_num",
125                                 type=positive_int,
126                                 required=True,
127                                 help=("The TestCenter port number to use"
128                                       "for the east test port"),
129                                 dest="east_port_num")
130     required_named.add_argument("--west_chassis_addr",
131                                 required=True,
132                                 help=("The TestCenter chassis IP address"
133                                       "to use for the west test port"),
134                                 dest="west_chassis_addr")
135     required_named.add_argument("--west_slot_num",
136                                 type=positive_int,
137                                 required=True,
138                                 help=("The TestCenter slot number to use"
139                                       "for the west test port"),
140                                 dest="west_slot_num")
141     required_named.add_argument("--west_port_num",
142                                 type=positive_int,
143                                 required=True,
144                                 help=("The TestCenter port number to"
145                                       "use for the west test port"),
146                                 dest="west_port_num")
147     # Optional parameters
148     optional_named = parser.add_argument_group("optional named arguments")
149     optional_named.add_argument("--metric",
150                                 required=False,
151                                 help=("One among - throughput, latency,\
152                                       backtoback and frameloss"),
153                                 choices=["throughput", "latency",
154                                          "backtoback", "frameloss"],
155                                 default="throughput",
156                                 dest="metric")
157     optional_named.add_argument("--test_session_name",
158                                 required=False,
159                                 default="RFC2544 East-West Throughput",
160                                 help=("The friendly name to identify"
161                                       "the Spirent Lab Server test session"),
162                                 dest="test_session_name")
163
164     optional_named.add_argument("--test_user_name",
165                                 required=False,
166                                 default="RFC2544 East-West User",
167                                 help=("The friendly name to identify the"
168                                       "Spirent Lab Server test user"),
169                                 dest="test_user_name")
170     optional_named.add_argument("--results_dir",
171                                 required=False,
172                                 default="./Results",
173                                 help="The directory to copy results to",
174                                 dest="results_dir")
175     optional_named.add_argument("--vsperf_results_dir",
176                                 required=False,
177                                 default="./Results",
178                                 help="The directory to copy results to",
179                                 dest="vsperf_results_dir")
180     optional_named.add_argument("--csv_results_file_prefix",
181                                 required=False,
182                                 default="Rfc2544Tput",
183                                 help="The prefix for the CSV results files",
184                                 dest="csv_results_file_prefix")
185     optional_named.add_argument("--num_trials",
186                                 type=positive_int,
187                                 required=False,
188                                 default=1,
189                                 help=("The number of trials to execute during"
190                                       "the test"),
191                                 dest="num_trials")
192     optional_named.add_argument("--trial_duration_sec",
193                                 type=positive_int,
194                                 required=False,
195                                 default=60,
196                                 help=("The duration of each trial executed"
197                                       "during the test"),
198                                 dest="trial_duration_sec")
199     optional_named.add_argument("--traffic_pattern",
200                                 required=False,
201                                 choices=["BACKBONE", "MESH", "PAIR"],
202                                 default="PAIR",
203                                 help="The traffic pattern between endpoints",
204                                 dest="traffic_pattern")
205     optional_named.add_argument("--traffic_custom",
206                                 required=False,
207                                 default=None,
208                                 help="The traffic pattern between endpoints",
209                                 dest="traffic_custom")
210     optional_named.add_argument("--search_mode",
211                                 required=False,
212                                 choices=["COMBO", "STEP", "BINARY"],
213                                 default="BINARY",
214                                 help=("The search mode used to find the"
215                                       "throughput rate"),
216                                 dest="search_mode")
217     optional_named.add_argument("--learning_mode",
218                                 required=False,
219                                 choices=["AUTO", "L2_LEARNING",
220                                          "L3_LEARNING", "NONE"],
221                                 default="AUTO",
222                                 help=("The learning mode used during the test,"
223                                       "default is 'NONE'"),
224                                 dest="learning_mode")
225     optional_named.add_argument("--rate_lower_limit_pct",
226                                 type=percent_float,
227                                 required=False,
228                                 default=1.0,
229                                 help=("The minimum percent line rate that"
230                                       "will be used during the test"),
231                                 dest="rate_lower_limit_pct")
232     optional_named.add_argument("--rate_upper_limit_pct",
233                                 type=percent_float,
234                                 required=False,
235                                 default=99.0,
236                                 help=("The maximum percent line rate that"
237                                       "will be used during the test"),
238                                 dest="rate_upper_limit_pct")
239     optional_named.add_argument("--rate_initial_pct",
240                                 type=percent_float,
241                                 required=False,
242                                 default=99.0,
243                                 help=("If Search Mode is BINARY, the percent"
244                                       "line rate that will be used at the"
245                                       "start of the test"),
246                                 dest="rate_initial_pct")
247     optional_named.add_argument("--rate_step_pct",
248                                 type=percent_float,
249                                 required=False,
250                                 default=10.0,
251                                 help=("If SearchMode is STEP, the percent"
252                                       "load increase per step"),
253                                 dest="rate_step_pct")
254     optional_named.add_argument("--resolution_pct",
255                                 type=percent_float,
256                                 required=False,
257                                 default=1.0,
258                                 help=("The minimum percentage of load"
259                                       "adjustment between iterations"),
260                                 dest="resolution_pct")
261     optional_named.add_argument("--frame_size_list",
262                                 type=lambda s: [int(item)
263                                                 for item in s.split(',')],
264                                 required=False,
265                                 default=[256],
266                                 help="A comma-delimited list of frame sizes",
267                                 dest="frame_size_list")
268     optional_named.add_argument("--acceptable_frame_loss_pct",
269                                 type=percent_float,
270                                 required=False,
271                                 default=0.0,
272                                 help=("The maximum acceptable frame loss"
273                                       "percent in any iteration"),
274                                 dest="acceptable_frame_loss_pct")
275     optional_named.add_argument("--east_intf_addr",
276                                 required=False,
277                                 default="192.85.1.3",
278                                 help=("The address to assign to the first"
279                                       "emulated device interface on the first"
280                                       "east port"),
281                                 dest="east_intf_addr")
282     optional_named.add_argument("--east_intf_gateway_addr",
283                                 required=False,
284                                 default="192.85.1.53",
285                                 help=("The gateway address to assign to the"
286                                       "first emulated device interface on the"
287                                       "first east port"),
288                                 dest="east_intf_gateway_addr")
289     optional_named.add_argument("--west_intf_addr",
290                                 required=False,
291                                 default="192.85.1.53",
292                                 help=("The address to assign to the first"
293                                       "emulated device interface on the"
294                                       "first west port"),
295                                 dest="west_intf_addr")
296     optional_named.add_argument("--west_intf_gateway_addr",
297                                 required=False,
298                                 default="192.85.1.53",
299                                 help=("The gateway address to assign to"
300                                       "the first emulated device interface"
301                                       "on the first west port"),
302                                 dest="west_intf_gateway_addr")
303     optional_named.add_argument("--latency_histogram",
304                                 required=False,
305                                 action="store_true",
306                                 help="latency histogram is required in output?",
307                                 dest="latency_histogram")
308     optional_named.add_argument("--imix",
309                                 required=False,
310                                 default="",
311                                 help=("IMIX specification as genome"
312                                       "Encoding - RFC 6985"),
313                                 dest="imix")
314     parser.add_argument("-v",
315                         "--verbose",
316                         required=False,
317                         default=True,
318                         help="More output during operation when present",
319                         action="store_true",
320                         dest="verbose")
321     args = parser.parse_args()
322
323     if args.verbose:
324         _LOGGER.debug("Creating results directory")
325     create_dir(args.results_dir)
326
327     session_name = args.test_session_name
328     user_name = args.test_user_name
329     # pylint: disable=import-error
330     try:
331         # Load Spirent REST Library
332         from stcrestclient import stchttp
333
334         stc = stchttp.StcHttp(args.lab_server_addr)
335         session_id = stc.new_session(user_name, session_name)
336         stc.join_session(session_id)
337     except RuntimeError as err:
338         _LOGGER.error(err)
339         raise
340
341     # Get STC system info.
342     tx_port_loc = "//%s/%s/%s" % (args.east_chassis_addr,
343                                   args.east_slot_num,
344                                   args.east_port_num)
345     rx_port_loc = "//%s/%s/%s" % (args.west_chassis_addr,
346                                   args.west_slot_num,
347                                   args.west_port_num)
348
349     # Retrieve and display the server information
350     if args.verbose:
351         _LOGGER.debug("SpirentTestCenter system version: %s",
352                       stc.get("system1", "version"))
353
354     # pylint: disable=too-many-nested-blocks
355     try:
356         device_list = []
357         port_list = []
358         if args.verbose:
359             _LOGGER.debug("Bring up license server")
360         license_mgr = stc.get("system1", "children-licenseservermanager")
361         if args.verbose:
362             _LOGGER.debug("license_mgr = %s", license_mgr)
363         stc.create("LicenseServer", under=license_mgr, attributes={
364             "server": args.license_server_addr})
365
366         # Create the root project object
367         if args.verbose:
368             _LOGGER.debug("Creating project ...")
369         project = stc.get("System1", "children-Project")
370
371         # Configure any custom traffic parameters
372         if args.traffic_custom == "cont":
373             if args.verbose:
374                 _LOGGER.debug("Configure Continuous Traffic")
375             stc.create("ContinuousTestConfig", under=project)
376
377         # Create ports
378         if args.verbose:
379             _LOGGER.debug("Creating ports ...")
380         east_chassis_port = stc.create('port', project)
381         if args.verbose:
382             _LOGGER.debug("Configuring TX port ...")
383         stc.config(east_chassis_port, {'location': tx_port_loc})
384         port_list.append(east_chassis_port)
385
386         west_chassis_port = stc.create('port', project)
387         if args.verbose:
388             _LOGGER.debug("Configuring RX port ...")
389         stc.config(west_chassis_port, {'location': rx_port_loc})
390         port_list.append(west_chassis_port)
391
392         # Create emulated genparam for east port
393         east_device_gen_params = stc.create("EmulatedDeviceGenParams",
394                                             under=project,
395                                             attributes={"Port":
396                                                         east_chassis_port})
397         # Create the DeviceGenEthIIIfParams object
398         stc.create("DeviceGenEthIIIfParams",
399                    under=east_device_gen_params,
400                    attributes={'UseDefaultPhyMac': True})
401
402         # Configuring Ipv4 interfaces
403         stc.create("DeviceGenIpv4IfParams",
404                    under=east_device_gen_params,
405                    attributes={"Addr": args.east_intf_addr,
406                                "Gateway": args.east_intf_gateway_addr})
407         # Create Devices using the Device Wizard
408         device_gen_config = stc.perform("DeviceGenConfigExpand",
409                                         params={"DeleteExisting": "No",
410                                                 "GenParams":
411                                                 east_device_gen_params})
412         # Append to the device list
413         device_list.append(device_gen_config['ReturnList'])
414
415         # Create emulated genparam for west port
416         west_device_gen_params = stc.create("EmulatedDeviceGenParams",
417                                             under=project,
418                                             attributes={"Port":
419                                                         west_chassis_port})
420         # Create the DeviceGenEthIIIfParams object
421         stc.create("DeviceGenEthIIIfParams",
422                    under=west_device_gen_params,
423                    attributes={'UseDefaultPhyMac': True})
424
425         # Configuring Ipv4 interfaces
426         stc.create("DeviceGenIpv4IfParams",
427                    under=west_device_gen_params,
428                    attributes={"Addr": args.west_intf_addr,
429                                "Gateway": args.west_intf_gateway_addr})
430         # Create Devices using the Device Wizard
431         device_gen_config = stc.perform("DeviceGenConfigExpand",
432                                         params={"DeleteExisting": "No",
433                                                 "GenParams":
434                                                 west_device_gen_params})
435         # Append to the device list
436         device_list.append(device_gen_config['ReturnList'])
437         if args.verbose:
438             _LOGGER.debug(device_list)
439
440         # Configure Histogram
441         if args.latency_histogram:
442             # Generic Configuration
443             histResOptions = stc.get("project1", 'children-ResultOptions')
444             stc.config(histResOptions, {'ResultViewMode': 'HISTOGRAM'})
445             # East Port Configuration
446             histAnaEast = stc.get(east_chassis_port, 'children-Analyzer')
447             histAnaEastConfig = stc.get(histAnaEast, 'children-AnalyzerConfig')
448             stc.config(histAnaEastConfig, {'HistogramMode': 'LATENCY'})
449             eLatHist = stc.get(histAnaEastConfig, 'children-LatencyHistogram')
450             stc.config(eLatHist, {'ConfigMode': 'CONFIG_LIMIT_MODE',
451                                   'BucketSizeUnit': 'ten_nanoseconds',
452                                   'Active': 'TRUE',
453                                   'DistributionMode': 'CENTERED_MODE'})
454             # West Port Configuration
455             histAnaWest = stc.get(west_chassis_port, 'children-Analyzer')
456             histAnaWestConfig = stc.get(histAnaWest, 'children-AnalyzerConfig')
457             stc.config(histAnaWestConfig, {'HistogramMode': 'LATENCY'})
458             wLatHist = stc.get(histAnaWestConfig, 'children-LatencyHistogram')
459             stc.config(wLatHist, {'ConfigMode': 'CONFIG_LIMIT_MODE',
460                                   'BucketSizeUnit': 'ten_nanoseconds',
461                                   'Active': 'TRUE',
462                                   'DistributionMode': 'CENTERED_MODE'})
463             gBucketSizeList = stc.get(wLatHist, 'BucketSizeList')
464             # gLimitSizeList  = stc.get(wLatHist, 'LimitList')
465
466         # IMIX configuration
467         fld = None
468         if args.imix:
469             args.frame_size_list = []
470             weights = genome2weights(args.imix)
471             fld = stc.create('FrameLengthDistribution', under=project)
472             def_slots = stc.get(fld, "children-framelengthdistributionslot")
473             stc.perform("Delete", params={"ConfigList": def_slots})
474             for fsize in weights:
475                 stc.create('framelengthdistributionslot', under=fld,
476                            attributes={'FixedFrameLength': fsize,
477                                        'Weight': weights[fsize]})
478
479         # Create the RFC 2544 'metric test
480         if args.metric == "throughput":
481             if args.verbose:
482                 _LOGGER.debug("Set up the RFC2544 throughput test...")
483             stc.perform("Rfc2544SetupThroughputTestCommand",
484                         params={"AcceptableFrameLoss":
485                                 args.acceptable_frame_loss_pct,
486                                 "Duration": args.trial_duration_sec,
487                                 "FrameSizeList": args.frame_size_list,
488                                 "LearningMode": args.learning_mode,
489                                 "NumOfTrials": args.num_trials,
490                                 "RateInitial": args.rate_initial_pct,
491                                 "RateLowerLimit": args.rate_lower_limit_pct,
492                                 "RateStep": args.rate_step_pct,
493                                 "RateUpperLimit": args.rate_upper_limit_pct,
494                                 "Resolution": args.resolution_pct,
495                                 "SearchMode": args.search_mode,
496                                 "TrafficPattern": args.traffic_pattern,
497                                 "FrameSizeDistributionList": fld})
498         elif args.metric == "backtoback":
499             stc.perform("Rfc2544SetupBackToBackTestCommand",
500                         params={"AcceptableFrameLoss":
501                                 args.acceptable_frame_loss_pct,
502                                 "Duration": args.trial_duration_sec,
503                                 "FrameSizeList": args.frame_size_list,
504                                 "LearningMode": args.learning_mode,
505                                 "LatencyType": args.latency_type,
506                                 "NumOfTrials": args.num_trials,
507                                 "RateInitial": args.rate_initial_pct,
508                                 "RateLowerLimit": args.rate_lower_limit_pct,
509                                 "RateStep": args.rate_step_pct,
510                                 "RateUpperLimit": args.rate_upper_limit_pct,
511                                 "Resolution": args.resolution_pct,
512                                 "SearchMode": args.search_mode,
513                                 "TrafficPattern": args.traffic_pattern})
514         elif args.metric == "frameloss":
515             stc.perform("Rfc2544SetupFrameLossTestCommand",
516                         params={"AcceptableFrameLoss":
517                                 args.acceptable_frame_loss_pct,
518                                 "Duration": args.trial_duration_sec,
519                                 "FrameSizeList": args.frame_size_list,
520                                 "LearningMode": args.learning_mode,
521                                 "LatencyType": args.latency_type,
522                                 "NumOfTrials": args.num_trials,
523                                 "RateInitial": args.rate_initial_pct,
524                                 "RateLowerLimit": args.rate_lower_limit_pct,
525                                 "RateStep": args.rate_step_pct,
526                                 "RateUpperLimit": args.rate_upper_limit_pct,
527                                 "Resolution": args.resolution_pct,
528                                 "SearchMode": args.search_mode,
529                                 "TrafficPattern": args.traffic_pattern})
530         elif args.metric == "latency":
531             stc.perform("Rfc2544SetupLatencyTestCommand",
532                         params={"AcceptableFrameLoss":
533                                 args.acceptable_frame_loss_pct,
534                                 "Duration": args.trial_duration_sec,
535                                 "FrameSizeList": args.frame_size_list,
536                                 "LearningMode": args.learning_mode,
537                                 "LatencyType": args.latency_type,
538                                 "NumOfTrials": args.num_trials,
539                                 "RateInitial": args.rate_initial_pct,
540                                 "RateLowerLimit": args.rate_lower_limit_pct,
541                                 "RateStep": args.rate_step_pct,
542                                 "RateUpperLimit": args.rate_upper_limit_pct,
543                                 "Resolution": args.resolution_pct,
544                                 "SearchMode": args.search_mode,
545                                 "TrafficPattern": args.traffic_pattern})
546
547         # Save the configuration
548         stc.perform("SaveToTcc", params={"Filename": "2544.tcc"})
549         # Connect to the hardware...
550         stc.perform("AttachPorts", params={"portList": stc.get(
551             "system1.project", "children-port"), "autoConnect": "TRUE"})
552         # Apply configuration.
553         if args.verbose:
554             _LOGGER.debug("Apply configuration...")
555         stc.apply()
556
557         if args.verbose:
558             _LOGGER.debug("Starting the sequencer...")
559         stc.perform("SequencerStart")
560
561         # Wait for sequencer to finish
562         _LOGGER.info(
563             "Starting test... Please wait for the test to complete...")
564         stc.wait_until_complete()
565         _LOGGER.info("The test has completed... Saving results...")
566
567         # Determine what the results database filename is...
568         lab_server_resultsdb = stc.get(
569             "system1.project.TestResultSetting", "CurrentResultFileName")
570
571         if args.verbose:
572             _LOGGER.debug("The lab server results database is %s",
573                           lab_server_resultsdb)
574
575         # Create Latency Histogram CSV file()
576         if args.latency_histogram:
577             hist_dict_counts = {}
578             for file_url in stc.files():
579                 if '-FrameSize-' in file_url:
580                     stc.download(file_url)
581                     filename = file_url.split('/')[-1]
582                     if os.path.exists(os.getcwd() + '/' + filename):
583                         conn = sqlite3.connect(os.getcwd() + '/' + filename)
584                         # cursor = conn.execute(
585                         #    'select * from RxEotStreamResults')
586                         # names = [desc[0] for desc in cursor.description]
587                         counts = conn.execute("SELECT \
588                                               HistBin1Count, HistBin2Count,\
589                                               HistBin3Count, HistBin4Count,\
590                                               HistBin5Count, HistBin6Count,\
591                                               HistBin7Count, HistBin8Count,\
592                                               HistBin9Count, HistBin10Count,\
593                                               HistBin11Count, HistBin12Count,\
594                                               HistBin13Count, HistBin14Count, \
595                                               HistBin15Count, HistBin16Count \
596                                               from RxEotStreamResults")
597                         strs = filename.split('-')
598                         key = strs[strs.index('FrameSize')+1]
599                         if key in hist_dict_counts:
600                             hist_dict_counts[key] = [a+b for a, b in
601                                                      zip(counts.fetchone(),
602                                                          hist_dict_counts[key])]
603                         else:
604                             hist_dict_counts[key] = counts.fetchone()
605                         conn.close()
606
607             write_histogram_to_csv(args.vsperf_results_dir, 'Histogram',
608                                    hist_dict_counts,
609                                    gBucketSizeList)
610
611         stc.perform("CSSynchronizeFiles",
612                     params={"DefaultDownloadDir": args.results_dir})
613
614         resultsdb = args.results_dir + \
615             lab_server_resultsdb.split("/Results")[1]
616
617         if not os.path.exists(resultsdb):
618             resultsdb = lab_server_resultsdb
619             _LOGGER.info("Failed to create the local summary DB File, using"
620                          " the remote DB file instead.")
621         else:
622             _LOGGER.info(
623                 "The local summary DB file has been saved to %s", resultsdb)
624
625         # The returns the "RFC2544ThroughputTestResultDetailedSummaryView"
626         # table view from the results database.
627         # There are other views available.
628
629         if args.metric == "throughput":
630             resultsdict = (
631                 stc.perform("QueryResult",
632                             params={
633                                 "DatabaseConnectionString":
634                                 resultsdb,
635                                 "ResultPath":
636                                 ("RFC2544ThroughputTestResultDetailed"
637                                  "SummaryView")}))
638
639         # The returns the "RFC2544BacktoBackTestResultDetailedSummaryView"
640         # table view from the results database.
641         # There are other views available.
642         elif args.metric == "backtoback":
643             resultsdict = (
644                 stc.perform("QueryResult",
645                             params={
646                                 "DatabaseConnectionString":
647                                 resultsdb,
648                                 "ResultPath":
649                                 ("RFC2544Back2BackTestResultDetailed"
650                                  "SummaryView")}))
651
652         # The returns the "RFC2544LatencyTestResultDetailedSummaryView"
653         # table view from the results database.
654         # There are other views available.
655         elif args.metric == "latency":
656             resultsdict = (
657                 stc.perform("QueryResult",
658                             params={
659                                 "DatabaseConnectionString":
660                                 resultsdb,
661                                 "ResultPath":
662                                 ("RFC2544LatencyTestResultDetailed"
663                                  "SummaryView")}))
664
665         # The returns the "RFC2544FrameLossTestResultDetailedSummaryView"
666         # table view from the results database.
667         # There are other views available.
668         elif args.metric == "frameloss":
669             resultsdict = (
670                 stc.perform("QueryResult",
671                             params={
672                                 "DatabaseConnectionString":
673                                 resultsdb,
674                                 "ResultPath":
675                                 ("RFC2544FrameLossTestResultDetailed"
676                                  "SummaryView")}))
677         if args.verbose:
678             _LOGGER.debug("resultsdict[\"Columns\"]: %s",
679                           resultsdict["Columns"])
680             _LOGGER.debug("resultsdict[\"Output\"]: %s", resultsdict["Output"])
681             _LOGGER.debug("Result paths: %s",
682                           stc.perform("GetTestResultSettingPaths"))
683
684             # Write results to csv
685             _LOGGER.debug("Writing CSV file to results directory %s",
686                           args.results_dir)
687         write_query_results_to_csv(
688             args.results_dir, args.csv_results_file_prefix, resultsdict)
689
690     except RuntimeError as e:
691         _LOGGER.error(e)
692
693     if args.verbose:
694         _LOGGER.debug("Destroy session on lab server")
695     stc.end_session()
696
697     _LOGGER.info("Test complete!")
698
699 if __name__ == "__main__":
700     main()