1 # Copyright 2015 Spirent Communications.
\r
3 # Licensed under the Apache License, Version 2.0 (the "License");
\r
4 # you may not use this file except in compliance with the License.
\r
5 # You may obtain a copy of the License at
\r
7 # http://www.apache.org/licenses/LICENSE-2.0
\r
9 # Unless required by applicable law or agreed to in writing, software
\r
10 # distributed under the License is distributed on an "AS IS" BASIS,
\r
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
12 # See the License for the specific language governing permissions and
\r
13 # limitations under the License.
\r
16 @author Spirent Comunications
\r
18 This test automates the RFC2544 throughput test using the Spirent
\r
19 TestCenter command sequencer. This test supports Python 2.7.
\r
22 from __future__ import print_function
\r
27 def create_dir(path):
\r
28 if not os.path.exists(path):
\r
31 except Exception, e:
\r
32 print("Failed to create directory %s: %s" % (path, str(e)))
\r
36 def write_query_results_to_csv(results_path, csv_results_file_prefix, query_results):
\r
37 create_dir(results_path)
\r
38 file = os.path.join(results_path, csv_results_file_prefix + ".csv")
\r
39 with open(file, "wb") as f:
\r
40 f.write(query_results["Columns"].replace(" ", ",") + "\n")
\r
41 for row in query_results["Output"].replace("} {", ",").replace("{", "").replace("}", "").split(","):
\r
42 f.write(row.replace(" ", ",") + "\n")
\r
45 def destroy_session(stc, lab_server_addr, test_session_name):
\r
46 stc.perform("CSServerConnectCommand",
\r
47 Host=lab_server_addr)
\r
49 cs_server = stc.get("system1", "children-csserver")
\r
51 cs_test_sessions = stc.get(cs_server, "children-cstestsession").split()
\r
53 for session in cs_test_sessions:
\r
54 name = stc.get(session, "Name")
\r
55 if test_session_name in name:
\r
56 stc.perform("CSDestroyTestSession",
\r
57 testSession=session)
\r
61 def create_session(stc, lab_server_addr, test_session_name):
\r
62 destroy_session(stc, lab_server_addr, test_session_name)
\r
63 stc.perform("CSTestSessionConnect",
\r
64 Host=lab_server_addr,
\r
65 CreateNewTestSession="TRUE",
\r
66 TestSessionName=test_session_name)
\r
69 def positive_int(value):
\r
72 raise argparse.ArgumentTypeError("%s is an invalid positive int value" % value)
\r
76 def percent_float(value):
\r
77 pvalue = float(value)
\r
78 if pvalue < 0.0 or pvalue > 100.0:
\r
79 raise argparse.ArgumentTypeError("%s not in range [0.0, 100.0]" % pvalue)
\r
84 parser = argparse.ArgumentParser()
\r
85 # Required parameters
\r
86 requirednamed = parser.add_argument_group("required named arguments")
\r
87 requirednamed.add_argument("--lab_server_addr",
\r
89 help="The IP address of the Spirent Lab Server",
\r
90 dest="lab_server_addr")
\r
91 requirednamed.add_argument("--license_server_addr",
\r
93 help="The IP address of the Spirent License Server",
\r
94 dest="license_server_addr")
\r
95 requirednamed.add_argument("--east_chassis_addr",
\r
97 help="The TestCenter chassis IP address to use for the east test port",
\r
98 dest="east_chassis_addr")
\r
99 requirednamed.add_argument("--east_slot_num",
\r
102 help="The TestCenter slot number to use for the east test port",
\r
103 dest="east_slot_num")
\r
104 requirednamed.add_argument("--east_port_num",
\r
107 help="The TestCenter port number to use for the east test port",
\r
108 dest="east_port_num")
\r
109 requirednamed.add_argument("--west_chassis_addr",
\r
111 help="The TestCenter chassis IP address to use for the west test port",
\r
112 dest="west_chassis_addr")
\r
113 requirednamed.add_argument("--west_slot_num",
\r
116 help="The TestCenter slot number to use for the west test port",
\r
117 dest="west_slot_num")
\r
118 requirednamed.add_argument("--west_port_num",
\r
121 help="The TestCenter port number to use for the west test port",
\r
122 dest="west_port_num")
\r
123 # Optional parameters
\r
124 optionalnamed = parser.add_argument_group("optional named arguments")
\r
125 optionalnamed.add_argument("--test_session_name",
\r
127 default="RFC2544 East-West Throughput",
\r
128 help="The friendly name to identify the Spirent Lab Server test session",
\r
129 dest="test_session_name")
\r
130 optionalnamed.add_argument("--results_dir",
\r
132 default="./Results",
\r
133 help="The directory to copy results to",
\r
134 dest="results_dir")
\r
135 optionalnamed.add_argument("--csv_results_file_prefix",
\r
137 default="Rfc2544Tput",
\r
138 help="The prefix for the CSV results files",
\r
139 dest="csv_results_file_prefix")
\r
140 optionalnamed.add_argument("--num_trials",
\r
144 help="The number of trials to execute during the test",
\r
146 optionalnamed.add_argument("--trial_duration_sec",
\r
150 help="The duration of each trial executed during the test",
\r
151 dest="trial_duration_sec")
\r
152 optionalnamed.add_argument("--traffic_pattern",
\r
154 choices=["BACKBONE", "MESH", "PAIR"],
\r
156 help="The traffic pattern between endpoints",
\r
157 dest="traffic_pattern")
\r
158 optionalnamed.add_argument("--search_mode",
\r
160 choices=["COMBO", "STEP", "BINARY"],
\r
162 help="The search mode used to find the throughput rate",
\r
163 dest="search_mode")
\r
164 optionalnamed.add_argument("--learning_mode",
\r
166 choices=["AUTO", "L2_LEARNING", "L3_LEARNING", "NONE"],
\r
168 help="The learning mode used during the test, default = 'NONE'",
\r
169 dest="learning_mode")
\r
170 optionalnamed.add_argument("--rate_lower_limit_pct",
\r
171 type=percent_float,
\r
174 help="The minimum percent line rate that will be used during the test",
\r
175 dest="rate_lower_limit_pct")
\r
176 optionalnamed.add_argument("--rate_upper_limit_pct",
\r
177 type=percent_float,
\r
180 help="The maximum percent line rate that will be used during the test",
\r
181 dest="rate_upper_limit_pct")
\r
182 optionalnamed.add_argument("--rate_initial_pct",
\r
183 type=percent_float,
\r
186 help="If Search Mode is BINARY, the percent line rate that will be used at the start of the test",
\r
187 dest="rate_initial_pct")
\r
188 optionalnamed.add_argument("--rate_step_pct",
\r
189 type=percent_float,
\r
192 help="If SearchMode is STEP, the percent load increase per step",
\r
193 dest="rate_step_pct")
\r
194 optionalnamed.add_argument("--resolution_pct",
\r
195 type=percent_float,
\r
198 help="The minimum percentage of load adjustment between iterations",
\r
199 dest="resolution_pct")
\r
200 optionalnamed.add_argument("--frame_size_list",
\r
201 type=lambda s: [int(item) for item in s.split(',')],
\r
204 help="A comma-delimited list of frame sizes",
\r
205 dest="frame_size_list")
\r
206 optionalnamed.add_argument("--acceptable_frame_loss_pct",
\r
207 type=percent_float,
\r
210 help="The maximum acceptable frame loss percent in any iteration",
\r
211 dest="acceptable_frame_loss_pct")
\r
212 optionalnamed.add_argument("--east_intf_addr",
\r
214 default="192.85.1.3",
\r
215 help="The address to assign to the first emulated device interface on the first east port",
\r
216 dest="east_intf_addr")
\r
217 optionalnamed.add_argument("--east_intf_gateway_addr",
\r
219 default="192.85.1.53",
\r
220 help="The gateway address to assign to the first emulated device interface on the first east port",
\r
221 dest="east_intf_gateway_addr")
\r
222 optionalnamed.add_argument("--west_intf_addr",
\r
224 default="192.85.1.53",
\r
225 help="The address to assign to the first emulated device interface on the first west port",
\r
226 dest="west_intf_addr")
\r
227 optionalnamed.add_argument("--west_intf_gateway_addr",
\r
229 default="192.85.1.53",
\r
230 help="The gateway address to assign to the first emulated device interface on the first west port",
\r
231 dest="west_intf_gateway_addr")
\r
232 parser.add_argument("-v",
\r
236 help="More output during operation when present",
\r
237 action="store_true",
\r
239 args = parser.parse_args()
\r
242 print("Make sure results directory exists")
\r
243 create_dir(args.results_dir)
\r
245 # Load Spirent Test Center library
\r
246 from StcPython import StcPython
\r
249 tx_port_loc = "//%s/%s/%s" % (args.east_chassis_addr,
\r
250 args.east_slot_num,
\r
251 args.east_port_num)
\r
252 rx_port_loc = "//%s/%s/%s" % (args.west_chassis_addr,
\r
253 args.west_slot_num,
\r
254 args.west_port_num)
\r
256 # This line will write the TestCenter commands to a log file
\r
257 stc.config("automationoptions", logto="test-op", loglevel="DEBUG")
\r
259 # Retrieve and display the current API version.
\r
261 print ("SpirentTestCenter system version: %s" % stc.get("system1", "version"))
\r
263 create_session(stc, args.lab_server_addr, args.test_session_name)
\r
269 print("Bring up license server")
\r
270 license_mgr = stc.get("system1", "children-licenseservermanager")
\r
272 print("license_mgr = %s" % license_mgr)
\r
273 stc.create("LicenseServer", under=license_mgr, server=args.license_server_addr)
\r
275 # Create the root project object
\r
277 print ("Creating project ...")
\r
278 project = stc.get("System1", "children-Project")
\r
282 print ("Creating ports ...")
\r
283 east_chassis_port = stc.create("port",
\r
285 location=tx_port_loc,
\r
286 useDefaultHost="False")
\r
287 west_chassis_port = stc.create("port",
\r
289 location=rx_port_loc,
\r
290 useDefaultHost="False")
\r
293 print ("Creating devices...")
\r
294 # Create emulated genparam for east port
\r
295 east_device_gen_params = stc.create("EmulatedDeviceGenParams",
\r
297 Port=east_chassis_port)
\r
298 # Create the DeviceGenEthIIIfParams object
\r
299 stc.create("DeviceGenEthIIIfParams",
\r
300 under=east_device_gen_params)
\r
301 # Configuring Ipv4 interfaces
\r
302 stc.create("DeviceGenIpv4IfParams",
\r
303 under=east_device_gen_params,
\r
304 Addr=args.east_intf_addr,
\r
305 Gateway=args.east_intf_gateway_addr)
\r
306 # Create Devices using the Device Wizard
\r
307 device_gen_config = stc.perform("DeviceGenConfigExpand",
\r
308 DeleteExisting="No",
\r
309 GenParams=east_device_gen_params)
\r
310 # Append to the device list
\r
311 device_list.append(device_gen_config['ReturnList'])
\r
313 # Create emulated genparam for west port
\r
314 west_device_gen_params = stc.create("EmulatedDeviceGenParams",
\r
316 Port=west_chassis_port)
\r
317 # Create the DeviceGenEthIIIfParams object
\r
318 stc.create("DeviceGenEthIIIfParams",
\r
319 under=west_device_gen_params)
\r
320 # Configuring Ipv4 interfaces
\r
321 stc.create("DeviceGenIpv4IfParams",
\r
322 under=west_device_gen_params,
\r
323 Addr=args.west_intf_addr,
\r
324 Gateway=args.west_intf_gateway_addr)
\r
325 # Create Devices using the Device Wizard
\r
326 device_gen_config = stc.perform("DeviceGenConfigExpand",
\r
327 DeleteExisting="No",
\r
328 GenParams=west_device_gen_params)
\r
329 # Append to the device list
\r
330 device_list.append(device_gen_config['ReturnList'])
\r
335 # Create the RFC 2544 throughput test
\r
337 print ("Set up the RFC2544 throughput test...")
\r
338 stc.perform("Rfc2544SetupThroughputTestCommand",
\r
339 AcceptableFrameLoss=args.acceptable_frame_loss_pct,
\r
340 Duration=args.trial_duration_sec,
\r
341 FrameSizeList=args.frame_size_list,
\r
342 LearningMode=args.learning_mode,
\r
343 NumOfTrials=args.num_trials,
\r
344 RateInitial=args.rate_initial_pct,
\r
345 RateLowerLimit=args.rate_lower_limit_pct,
\r
346 RateStep=args.rate_step_pct,
\r
347 RateUpperLimit=args.rate_upper_limit_pct,
\r
348 Resolution=args.resolution_pct,
\r
349 SearchMode=args.search_mode,
\r
350 TrafficPattern=args.traffic_pattern)
\r
352 # Save the configuration
\r
353 stc.perform("SaveToTcc", Filename="2544.tcc")
\r
355 # Connect to the hardware...
\r
356 stc.perform("AttachPorts", portList=stc.get("system1.project", "children-port"), autoConnect="TRUE")
\r
358 # Apply configuration.
\r
360 print("Apply configuration...")
\r
364 print("Starting the sequencer...")
\r
365 stc.perform("SequencerStart")
\r
367 # Wait for sequencer to finish
\r
368 print("Starting test... Please wait for the test to complete...")
\r
369 stc.waitUntilComplete()
\r
370 print("The test has completed... Saving results...")
\r
372 # Determine what the results database filename is...
\r
373 lab_server_resultsdb = stc.get("system1.project.TestResultSetting", "CurrentResultFileName")
\r
376 print("The lab server results database is %s" % lab_server_resultsdb)
\r
378 stc.perform("CSSynchronizeFiles",
\r
379 DefaultDownloadDir=args.results_dir)
\r
381 resultsdb = args.results_dir + lab_server_resultsdb.split("/Results")[1]
\r
383 print("The local summary DB file has been saved to %s" % resultsdb)
\r
385 # The returns the "RFC2544ThroughputTestResultDetailedSummaryView" table view from the results database.
\r
386 # There are other views available.
\r
387 resultsdict = stc.perform("QueryResult",
\r
388 DatabaseConnectionString=resultsdb,
\r
389 ResultPath="RFC2544ThroughputTestResultDetailedSummaryView")
\r
391 print("resultsdict[\"Columns\"]: %s" % resultsdict["Columns"])
\r
392 print("resultsdict[\"Output\"]: %s" % resultsdict["Output"])
\r
395 print("Result paths: %s" % stc.perform("GetTestResultSettingPaths"))
\r
397 # Write results to csv
\r
399 print("Writing CSV file to results directory %s" % args.results_dir)
\r
400 write_query_results_to_csv(args.results_dir, args.csv_results_file_prefix, resultsdict)
\r
402 except Exception, e:
\r
403 print("Exception: %s" % str(e))
\r
404 # destroy_session(stc, args.lab_server_addr, args.test_session_name)
\r
408 print("Disconnect from lab server")
\r
409 stc.perform("CSTestSessionDisconnect")
\r
412 print("Destroy session on lab server")
\r
413 # destroy_session(stc, args.lab_server_addr, args.test_session_name)
\r
414 print("Test complete!")
\r
417 if __name__ == "__main__":
\r