1 # Copyright 2015 Spirent Communications.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
16 @author Spirent Comunications
18 This test automates the RFC2544 throughput test using the Spirent
19 TestCenter command sequencer. This test supports Python 2.7.
22 from __future__ import print_function
25 from conf import settings
29 if not os.path.exists(path):
33 print("Failed to create directory %s: %s" % (path, str(e)))
37 def write_query_results_to_csv(results_path, csv_results_file_prefix, query_results):
38 create_dir(results_path)
39 file = os.path.join(results_path, csv_results_file_prefix + ".csv")
40 with open(file, "wb") as f:
41 f.write(query_results["Columns"].replace(" ", ",") + "\n")
42 for row in query_results["Output"].replace("} {", ",").replace("{", "").replace("}", "").split(","):
43 f.write(row.replace(" ", ",") + "\n")
46 def destroy_session(stc, lab_server_addr, test_session_name):
47 stc.perform("CSServerConnectCommand",
50 cs_server = stc.get("system1", "children-csserver")
52 cs_test_sessions = stc.get(cs_server, "children-cstestsession").split()
54 for session in cs_test_sessions:
55 name = stc.get(session, "Name")
56 if test_session_name in name:
57 stc.perform("CSDestroyTestSession",
62 def create_session(stc, lab_server_addr, test_session_name):
63 destroy_session(stc, lab_server_addr, test_session_name)
64 stc.perform("CSTestSessionConnect",
66 CreateNewTestSession="TRUE",
67 TestSessionName=test_session_name)
70 def positive_int(value):
73 raise argparse.ArgumentTypeError("%s is an invalid positive int value" % value)
77 def percent_float(value):
79 if pvalue < 0.0 or pvalue > 100.0:
80 raise argparse.ArgumentTypeError("%s not in range [0.0, 100.0]" % pvalue)
85 parser = argparse.ArgumentParser()
87 requirednamed = parser.add_argument_group("required named arguments")
88 requirednamed.add_argument("--lab_server_addr",
90 help="The IP address of the Spirent Lab Server",
91 dest="lab_server_addr")
92 requirednamed.add_argument("--license_server_addr",
94 help="The IP address of the Spirent License Server",
95 dest="license_server_addr")
96 requirednamed.add_argument("--east_chassis_addr",
98 help="The TestCenter chassis IP address to use for the east test port",
99 dest="east_chassis_addr")
100 requirednamed.add_argument("--east_slot_num",
103 help="The TestCenter slot number to use for the east test port",
104 dest="east_slot_num")
105 requirednamed.add_argument("--east_port_num",
108 help="The TestCenter port number to use for the east test port",
109 dest="east_port_num")
110 requirednamed.add_argument("--west_chassis_addr",
112 help="The TestCenter chassis IP address to use for the west test port",
113 dest="west_chassis_addr")
114 requirednamed.add_argument("--west_slot_num",
117 help="The TestCenter slot number to use for the west test port",
118 dest="west_slot_num")
119 requirednamed.add_argument("--west_port_num",
122 help="The TestCenter port number to use for the west test port",
123 dest="west_port_num")
124 # Optional parameters
125 optionalnamed = parser.add_argument_group("optional named arguments")
126 optionalnamed.add_argument("--test_session_name",
128 default="RFC2544 East-West Throughput",
129 help="The friendly name to identify the Spirent Lab Server test session",
130 dest="test_session_name")
131 optionalnamed.add_argument("--results_dir",
133 default=settings.getValue("TRAFFICGEN_STC_RESULTS_DIR"),
134 help="The directory to copy results to",
136 optionalnamed.add_argument("--csv_results_file_prefix",
138 default="Rfc2544Tput",
139 help="The prefix for the CSV results files",
140 dest="csv_results_file_prefix")
141 optionalnamed.add_argument("--num_trials",
145 help="The number of trials to execute during the test",
147 optionalnamed.add_argument("--trial_duration_sec",
151 help="The duration of each trial executed during the test",
152 dest="trial_duration_sec")
153 optionalnamed.add_argument("--traffic_pattern",
155 choices=["BACKBONE", "MESH", "PAIR"],
157 help="The traffic pattern between endpoints",
158 dest="traffic_pattern")
159 optionalnamed.add_argument("--search_mode",
161 choices=["COMBO", "STEP", "BINARY"],
163 help="The search mode used to find the throughput rate",
165 optionalnamed.add_argument("--learning_mode",
167 choices=["AUTO", "L2_LEARNING", "L3_LEARNING", "NONE"],
169 help="The learning mode used during the test, default = 'NONE'",
170 dest="learning_mode")
171 optionalnamed.add_argument("--rate_lower_limit_pct",
175 help="The minimum percent line rate that will be used during the test",
176 dest="rate_lower_limit_pct")
177 optionalnamed.add_argument("--rate_upper_limit_pct",
181 help="The maximum percent line rate that will be used during the test",
182 dest="rate_upper_limit_pct")
183 optionalnamed.add_argument("--rate_initial_pct",
187 help="If Search Mode is BINARY, the percent line rate that will be used at the start of the test",
188 dest="rate_initial_pct")
189 optionalnamed.add_argument("--rate_step_pct",
193 help="If SearchMode is STEP, the percent load increase per step",
194 dest="rate_step_pct")
195 optionalnamed.add_argument("--resolution_pct",
199 help="The minimum percentage of load adjustment between iterations",
200 dest="resolution_pct")
201 optionalnamed.add_argument("--frame_size_list",
202 type=lambda s: [int(item) for item in s.split(',')],
205 help="A comma-delimited list of frame sizes",
206 dest="frame_size_list")
207 optionalnamed.add_argument("--acceptable_frame_loss_pct",
211 help="The maximum acceptable frame loss percent in any iteration",
212 dest="acceptable_frame_loss_pct")
213 optionalnamed.add_argument("--east_intf_addr",
215 default="192.85.1.3",
216 help="The address to assign to the first emulated device interface on the first east port",
217 dest="east_intf_addr")
218 optionalnamed.add_argument("--east_intf_gateway_addr",
220 default="192.85.1.53",
221 help="The gateway address to assign to the first emulated device interface on the first east port",
222 dest="east_intf_gateway_addr")
223 optionalnamed.add_argument("--west_intf_addr",
225 default="192.85.1.53",
226 help="The address to assign to the first emulated device interface on the first west port",
227 dest="west_intf_addr")
228 optionalnamed.add_argument("--west_intf_gateway_addr",
230 default="192.85.1.53",
231 help="The gateway address to assign to the first emulated device interface on the first west port",
232 dest="west_intf_gateway_addr")
233 parser.add_argument("-v",
237 help="More output during operation when present",
240 args = parser.parse_args()
243 print("Make sure results directory exists")
244 create_dir(args.results_dir)
246 # Load Spirent Test Center library
247 from StcPython import StcPython
250 tx_port_loc = "//%s/%s/%s" % (args.east_chassis_addr,
253 rx_port_loc = "//%s/%s/%s" % (args.west_chassis_addr,
257 # This line will write the TestCenter commands to a log file
258 stc.config("automationoptions", logto="test-op", loglevel="DEBUG")
260 # Retrieve and display the current API version.
262 print ("SpirentTestCenter system version: %s" % stc.get("system1", "version"))
264 create_session(stc, args.lab_server_addr, args.test_session_name)
270 print("Bring up license server")
271 license_mgr = stc.get("system1", "children-licenseservermanager")
273 print("license_mgr = %s" % license_mgr)
274 stc.create("LicenseServer", under=license_mgr, server=args.license_server_addr)
276 # Create the root project object
278 print ("Creating project ...")
279 project = stc.get("System1", "children-Project")
283 print ("Creating ports ...")
284 east_chassis_port = stc.create("port",
286 location=tx_port_loc,
287 useDefaultHost="False")
288 west_chassis_port = stc.create("port",
290 location=rx_port_loc,
291 useDefaultHost="False")
294 print ("Creating devices...")
295 # Create emulated genparam for east port
296 east_device_gen_params = stc.create("EmulatedDeviceGenParams",
298 Port=east_chassis_port)
299 # Create the DeviceGenEthIIIfParams object
300 stc.create("DeviceGenEthIIIfParams",
301 under=east_device_gen_params)
302 # Configuring Ipv4 interfaces
303 stc.create("DeviceGenIpv4IfParams",
304 under=east_device_gen_params,
305 Addr=args.east_intf_addr,
306 Gateway=args.east_intf_gateway_addr)
307 # Create Devices using the Device Wizard
308 device_gen_config = stc.perform("DeviceGenConfigExpand",
310 GenParams=east_device_gen_params)
311 # Append to the device list
312 device_list.append(device_gen_config['ReturnList'])
314 # Create emulated genparam for west port
315 west_device_gen_params = stc.create("EmulatedDeviceGenParams",
317 Port=west_chassis_port)
318 # Create the DeviceGenEthIIIfParams object
319 stc.create("DeviceGenEthIIIfParams",
320 under=west_device_gen_params)
321 # Configuring Ipv4 interfaces
322 stc.create("DeviceGenIpv4IfParams",
323 under=west_device_gen_params,
324 Addr=args.west_intf_addr,
325 Gateway=args.west_intf_gateway_addr)
326 # Create Devices using the Device Wizard
327 device_gen_config = stc.perform("DeviceGenConfigExpand",
329 GenParams=west_device_gen_params)
330 # Append to the device list
331 device_list.append(device_gen_config['ReturnList'])
336 # Create the RFC 2544 throughput test
338 print ("Set up the RFC2544 throughput test...")
339 stc.perform("Rfc2544SetupThroughputTestCommand",
340 AcceptableFrameLoss=args.acceptable_frame_loss_pct,
341 Duration=args.trial_duration_sec,
342 FrameSizeList=args.frame_size_list,
343 LearningMode=args.learning_mode,
344 NumOfTrials=args.num_trials,
345 RateInitial=args.rate_initial_pct,
346 RateLowerLimit=args.rate_lower_limit_pct,
347 RateStep=args.rate_step_pct,
348 RateUpperLimit=args.rate_upper_limit_pct,
349 Resolution=args.resolution_pct,
350 SearchMode=args.search_mode,
351 TrafficPattern=args.traffic_pattern)
353 # Save the configuration
354 stc.perform("SaveToTcc", Filename="2544.tcc")
356 # Connect to the hardware...
357 stc.perform("AttachPorts", portList=stc.get("system1.project", "children-port"), autoConnect="TRUE")
359 # Apply configuration.
361 print("Apply configuration...")
365 print("Starting the sequencer...")
366 stc.perform("SequencerStart")
368 # Wait for sequencer to finish
369 print("Starting test... Please wait for the test to complete...")
370 stc.waitUntilComplete()
371 print("The test has completed... Saving results...")
373 # Determine what the results database filename is...
374 lab_server_resultsdb = stc.get("system1.project.TestResultSetting", "CurrentResultFileName")
377 print("The lab server results database is %s" % lab_server_resultsdb)
379 stc.perform("CSSynchronizeFiles",
380 DefaultDownloadDir=args.results_dir)
382 resultsdb = args.results_dir + lab_server_resultsdb.split("/Results")[1]
384 print("The local summary DB file has been saved to %s" % resultsdb)
386 # The returns the "RFC2544ThroughputTestResultDetailedSummaryView" table view from the results database.
387 # There are other views available.
388 resultsdict = stc.perform("QueryResult",
389 DatabaseConnectionString=resultsdb,
390 ResultPath="RFC2544ThroughputTestResultDetailedSummaryView")
392 print("resultsdict[\"Columns\"]: %s" % resultsdict["Columns"])
393 print("resultsdict[\"Output\"]: %s" % resultsdict["Output"])
396 print("Result paths: %s" % stc.perform("GetTestResultSettingPaths"))
398 # Write results to csv
400 print("Writing CSV file to results directory %s" % args.results_dir)
401 write_query_results_to_csv(args.results_dir, args.csv_results_file_prefix, resultsdict)
404 print("Exception: %s" % str(e))
405 # destroy_session(stc, args.lab_server_addr, args.test_session_name)
409 print("Disconnect from lab server")
410 stc.perform("CSTestSessionDisconnect")
413 print("Destroy session on lab server")
414 # destroy_session(stc, args.lab_server_addr, args.test_session_name)
415 print("Test complete!")
418 if __name__ == "__main__":