How to use assertFirstLineStartsWith method in tempest

Best Python code snippet using tempest_python

test_alarm.py

Source:test_alarm.py Github

copy

Full Screen

...58 self.details_multiple(result)[0]['name'])59 params = "update --state ok"60 result = self.aodh('alarm', params=params,61 fail_ok=True, merge_stderr=True)62 self.assertFirstLineStartsWith(63 result.splitlines(),64 'You need to specify one of alarm ID and alarm name(--name) '65 'to update an alarm.')66 params = "delete %s" % name67 result = self.aodh('alarm', params=params)68 self.assertEqual("", result)69 params = "create --type event --name %s" % name70 result = self.aodh('alarm', params=params)71 alarm_id = self.details_multiple(result)[0]['alarm_id']72 params = "delete %s" % alarm_id73 result = self.aodh('alarm', params=params)74 self.assertEqual("", result)75 _test(uuidutils.generate_uuid())76 _test('normal-alarm-name')77 def test_event_scenario(self):78 PROJECT_ID = uuidutils.generate_uuid()79 # CREATE80 result = self.aodh(u'alarm',81 params=(u"create --type event --name ev_alarm1 "82 "--project-id %s" % PROJECT_ID))83 alarm = self.details_multiple(result)[0]84 ALARM_ID = alarm['alarm_id']85 self.assertEqual('ev_alarm1', alarm['name'])86 self.assertEqual('*', alarm['event_type'])87 # UPDATE IGNORE INVALID88 result = self.aodh(89 'alarm', params=("update %s --severity critical --threshold 10"90 % ALARM_ID))91 alarm_updated = self.details_multiple(result)[0]92 self.assertEqual(ALARM_ID, alarm_updated["alarm_id"])93 self.assertEqual('critical', alarm_updated['severity'])94 # UPDATE IGNORE INVALID95 result = self.aodh(96 'alarm', params=("update %s --event-type dummy" % ALARM_ID))97 alarm_updated = self.details_multiple(result)[0]98 self.assertEqual(ALARM_ID, alarm_updated["alarm_id"])99 self.assertEqual('dummy', alarm_updated['event_type'])100 # GET101 result = self.aodh(102 'alarm', params="show %s" % ALARM_ID)103 alarm_show = self.details_multiple(result)[0]104 self.assertEqual(ALARM_ID, alarm_show["alarm_id"])105 self.assertEqual(PROJECT_ID, alarm_show["project_id"])106 self.assertEqual('ev_alarm1', alarm_show['name'])107 self.assertEqual('dummy', alarm_show['event_type'])108 # GET BY NAME109 result = self.aodh(110 'alarm', params="show --name ev_alarm1")111 alarm_show = self.details_multiple(result)[0]112 self.assertEqual(ALARM_ID, alarm_show["alarm_id"])113 self.assertEqual(PROJECT_ID, alarm_show["project_id"])114 self.assertEqual('ev_alarm1', alarm_show['name'])115 self.assertEqual('dummy', alarm_show['event_type'])116 # GET BY NAME AND ID ERROR117 self.assertRaises(exceptions.CommandFailed,118 self.aodh, u'alarm',119 params=(u"show %s --name ev_alarm1" %120 ALARM_ID))121 # LIST122 result = self.aodh('alarm', params="list")123 self.assertIn(ALARM_ID,124 [r['alarm_id'] for r in self.parser.listing(result)])125 output_colums = ['alarm_id', 'type', 'name', 'state', 'severity',126 'enabled']127 for alarm_list in self.parser.listing(result):128 self.assertEqual(sorted(output_colums), sorted(alarm_list.keys()))129 if alarm_list["alarm_id"] == ALARM_ID:130 self.assertEqual('ev_alarm1', alarm_list['name'])131 # LIST WITH QUERY132 result = self.aodh('alarm',133 params=("list --query project_id=%s" % PROJECT_ID))134 alarm_list = self.parser.listing(result)[0]135 self.assertEqual(ALARM_ID, alarm_list["alarm_id"])136 self.assertEqual('ev_alarm1', alarm_list['name'])137 # DELETE138 result = self.aodh('alarm', params="delete %s" % ALARM_ID)139 self.assertEqual("", result)140 # GET FAIL141 result = self.aodh('alarm', params="show %s" % ALARM_ID,142 fail_ok=True, merge_stderr=True)143 expected = "Alarm %s not found (HTTP 404)" % ALARM_ID144 self.assertFirstLineStartsWith(result.splitlines(), expected)145 # DELETE FAIL146 result = self.aodh('alarm', params="delete %s" % ALARM_ID,147 fail_ok=True, merge_stderr=True)148 self.assertFirstLineStartsWith(result.splitlines(), expected)149 # LIST DOES NOT HAVE ALARM150 result = self.aodh('alarm', params="list")151 self.assertNotIn(ALARM_ID,152 [r['alarm_id'] for r in self.parser.listing(result)])153 def test_threshold_scenario(self):154 PROJECT_ID = uuidutils.generate_uuid()155 # CREATE156 result = self.aodh(u'alarm',157 params=(u"create --type threshold --name alarm_th "158 "-m meter_name --threshold 5 "159 "--project-id %s" % PROJECT_ID))160 alarm = self.details_multiple(result)[0]161 ALARM_ID = alarm['alarm_id']162 self.assertEqual('alarm_th', alarm['name'])163 self.assertEqual('meter_name', alarm['meter_name'])164 self.assertEqual('5.0', alarm['threshold'])165 # CREATE WITH --TIME-CONSTRAINT166 result = self.aodh(167 u'alarm',168 params=(u"create --type threshold --name alarm_tc "169 "-m meter_name --threshold 5 "170 "--time-constraint "171 "name=cons1;start='0 11 * * *';duration=300 "172 "--time-constraint "173 "name=cons2;start='0 23 * * *';duration=600 "174 "--project-id %s" % PROJECT_ID))175 alarm = self.details_multiple(result)[0]176 self.assertEqual('alarm_tc', alarm['name'])177 self.assertEqual('meter_name', alarm['meter_name'])178 self.assertEqual('5.0', alarm['threshold'])179 self.assertIsNotNone(alarm['time_constraints'])180 # CREATE FAIL MISSING PARAM181 self.assertRaises(exceptions.CommandFailed,182 self.aodh, u'alarm',183 params=(u"create --type threshold --name alarm_th "184 "--project-id %s" % PROJECT_ID))185 # UPDATE186 result = self.aodh(187 'alarm', params=("update %s --severity critical --threshold 10"188 % ALARM_ID))189 alarm_updated = self.details_multiple(result)[0]190 self.assertEqual(ALARM_ID, alarm_updated["alarm_id"])191 self.assertEqual('critical', alarm_updated['severity'])192 self.assertEqual('10.0', alarm_updated["threshold"])193 # GET194 result = self.aodh(195 'alarm', params="show %s" % ALARM_ID)196 alarm_show = self.details_multiple(result)[0]197 self.assertEqual(ALARM_ID, alarm_show["alarm_id"])198 self.assertEqual(PROJECT_ID, alarm_show["project_id"])199 self.assertEqual('alarm_th', alarm_show['name'])200 self.assertEqual('meter_name', alarm_show['meter_name'])201 self.assertEqual('10.0', alarm_show['threshold'])202 # GET BY NAME203 result = self.aodh(204 'alarm', params="show --name alarm_th")205 alarm_show = self.details_multiple(result)[0]206 self.assertEqual(ALARM_ID, alarm_show["alarm_id"])207 self.assertEqual(PROJECT_ID, alarm_show["project_id"])208 self.assertEqual('alarm_th', alarm_show['name'])209 self.assertEqual('meter_name', alarm_show['meter_name'])210 self.assertEqual('10.0', alarm_show['threshold'])211 # GET BY NAME AND ID ERROR212 self.assertRaises(exceptions.CommandFailed,213 self.aodh, u'alarm',214 params=(u"show %s --name alarm_th" %215 ALARM_ID))216 # LIST217 result = self.aodh('alarm', params="list")218 self.assertIn(ALARM_ID,219 [r['alarm_id'] for r in self.parser.listing(result)])220 output_colums = ['alarm_id', 'type', 'name', 'state', 'severity',221 'enabled']222 for alarm_list in self.parser.listing(result):223 self.assertEqual(sorted(output_colums), sorted(alarm_list.keys()))224 if alarm_list["alarm_id"] == ALARM_ID:225 self.assertEqual('alarm_th', alarm_list['name'])226 # LIST WITH PAGINATION227 # list with limit228 result = self.aodh('alarm',229 params="list --limit 1")230 alarm_list = self.parser.listing(result)231 self.assertEqual(1, len(alarm_list))232 # list with sort with key=name dir=asc233 result = self.aodh('alarm',234 params="list --sort name:asc")235 names = [r['name'] for r in self.parser.listing(result)]236 sorted_name = sorted(names)237 self.assertEqual(sorted_name, names)238 # list with sort with key=name dir=asc and key=alarm_id dir=asc239 result = self.aodh(u'alarm',240 params=(u"create --type threshold --name alarm_th "241 "-m meter_name --threshold 5 "242 "--project-id %s" % PROJECT_ID))243 created_alarm_id = self.details_multiple(result)[0]['alarm_id']244 result = self.aodh('alarm',245 params="list --sort name:asc --sort alarm_id:asc")246 alarm_list = self.parser.listing(result)247 ids_with_same_name = []248 names = []249 for alarm in alarm_list:250 names.append(['alarm_name'])251 if alarm['name'] == 'alarm_th':252 ids_with_same_name.append(alarm['alarm_id'])253 sorted_ids = sorted(ids_with_same_name)254 sorted_names = sorted(names)255 self.assertEqual(sorted_names, names)256 self.assertEqual(sorted_ids, ids_with_same_name)257 # list with sort with key=name dir=desc and with the marker equal to258 # the alarm_id of the alarm_th we created for this test.259 result = self.aodh('alarm',260 params="list --sort name:desc "261 "--marker %s" % created_alarm_id)262 self.assertIn('alarm_tc',263 [r['name'] for r in self.parser.listing(result)])264 self.aodh('alarm', params="delete %s" % created_alarm_id)265 # LIST WITH QUERY266 result = self.aodh('alarm',267 params=("list --query project_id=%s" % PROJECT_ID))268 alarm_list = self.parser.listing(result)[0]269 self.assertEqual(ALARM_ID, alarm_list["alarm_id"])270 self.assertEqual('alarm_th', alarm_list['name'])271 # DELETE272 result = self.aodh('alarm', params="delete %s" % ALARM_ID)273 self.assertEqual("", result)274 # GET FAIL275 result = self.aodh('alarm', params="show %s" % ALARM_ID,276 fail_ok=True, merge_stderr=True)277 expected = "Alarm %s not found (HTTP 404)" % ALARM_ID278 self.assertFirstLineStartsWith(result.splitlines(), expected)279 # DELETE FAIL280 result = self.aodh('alarm', params="delete %s" % ALARM_ID,281 fail_ok=True, merge_stderr=True)282 self.assertFirstLineStartsWith(result.splitlines(), expected)283 # LIST DOES NOT HAVE ALARM284 result = self.aodh('alarm', params="list")285 self.assertNotIn(ALARM_ID,286 [r['alarm_id'] for r in self.parser.listing(result)])287 def test_composite_scenario(self):288 project_id = uuidutils.generate_uuid()289 # CREATE290 result = self.aodh(u'alarm',291 params=(u'create --type composite --name calarm1 '292 ' --composite-rule \'{"or":[{"threshold"'293 ': 0.8,"meter_name": "cpu_util",'294 '"type": "threshold"},{"and": ['295 '{"threshold": 200, "meter_name": '296 '"disk.iops", "type": "threshold"},'297 '{"threshold": 1000,"meter_name":'298 '"network.incoming.packets.rate",'299 '"type": "threshold"}]}]}\' '300 '--project-id %s' % project_id))301 alarm = self.details_multiple(result)[0]302 alarm_id = alarm['alarm_id']303 self.assertEqual('calarm1', alarm['name'])304 self.assertEqual('composite', alarm['type'])305 self.assertIn('composite_rule', alarm)306 # CREATE FAIL MISSING PARAM307 self.assertRaises(exceptions.CommandFailed,308 self.aodh, u'alarm',309 params=(u"create --type composite --name calarm1 "310 "--project-id %s" % project_id))311 # UPDATE312 result = self.aodh(313 'alarm', params=("update %s --severity critical" % alarm_id))314 alarm_updated = self.details_multiple(result)[0]315 self.assertEqual(alarm_id, alarm_updated["alarm_id"])316 self.assertEqual('critical', alarm_updated['severity'])317 # GET318 result = self.aodh(319 'alarm', params="show %s" % alarm_id)320 alarm_show = self.details_multiple(result)[0]321 self.assertEqual(alarm_id, alarm_show["alarm_id"])322 self.assertEqual(project_id, alarm_show["project_id"])323 self.assertEqual('calarm1', alarm_show['name'])324 # GET BY NAME325 result = self.aodh(326 'alarm', params="show --name calarm1")327 alarm_show = self.details_multiple(result)[0]328 self.assertEqual(alarm_id, alarm_show["alarm_id"])329 self.assertEqual(project_id, alarm_show["project_id"])330 self.assertEqual('calarm1', alarm_show['name'])331 # GET BY NAME AND ID ERROR332 self.assertRaises(exceptions.CommandFailed,333 self.aodh, u'alarm',334 params=(u"show %s --name calarm1" %335 alarm_id))336 # LIST337 result = self.aodh('alarm', params="list")338 self.assertIn(alarm_id,339 [r['alarm_id'] for r in self.parser.listing(result)])340 output_colums = ['alarm_id', 'type', 'name', 'state', 'severity',341 'enabled']342 for alarm_list in self.parser.listing(result):343 self.assertEqual(sorted(output_colums), sorted(alarm_list.keys()))344 if alarm_list["alarm_id"] == alarm_id:345 self.assertEqual('calarm1', alarm_list['name'])346 # LIST WITH QUERY347 result = self.aodh('alarm',348 params=("list --query project_id=%s" % project_id))349 alarm_list = self.parser.listing(result)[0]350 self.assertEqual(alarm_id, alarm_list["alarm_id"])351 self.assertEqual('calarm1', alarm_list['name'])352 # DELETE353 result = self.aodh('alarm', params="delete %s" % alarm_id)354 self.assertEqual("", result)355 # GET FAIL356 result = self.aodh('alarm', params="show %s" % alarm_id,357 fail_ok=True, merge_stderr=True)358 expected = "Alarm %s not found (HTTP 404)" % alarm_id359 self.assertFirstLineStartsWith(result.splitlines(), expected)360 # DELETE FAIL361 result = self.aodh('alarm', params="delete %s" % alarm_id,362 fail_ok=True, merge_stderr=True)363 self.assertFirstLineStartsWith(result.splitlines(), expected)364 # LIST DOES NOT HAVE ALARM365 result = self.aodh('alarm', params="list")366 self.assertNotIn(alarm_id,367 [r['alarm_id'] for r in self.parser.listing(result)])368 def _test_alarm_create_show_query(self, create_params, expected_lines):369 def test(params):370 result = self.aodh('alarm', params=params)371 alarm = self.details_multiple(result)[0]372 for key, value in six.iteritems(expected_lines):373 self.assertEqual(value, alarm[key])374 return alarm375 alarm = test(create_params)376 params = 'show %s' % alarm['alarm_id']377 test(params)378 self.aodh('alarm', params='delete %s' % alarm['alarm_id'])379 def test_threshold_alarm_create_show_query(self):380 params = ('create --type threshold --name alarm-multiple-query '381 '-m cpu_util --threshold 90 --query "project_id=123;'382 'resource_id=456"')383 expected_lines = {384 'query': 'project_id = 123 AND',385 '': 'resource_id = 456'386 }387 self._test_alarm_create_show_query(params, expected_lines)388 params = ('create --type threshold --name alarm-single-query '389 '-m cpu_util --threshold 90 --query project_id=123')390 expected_lines = {'query': 'project_id = 123'}391 self._test_alarm_create_show_query(params, expected_lines)392 params = ('create --type threshold --name alarm-no-query '393 '-m cpu_util --threshold 90')394 self._test_alarm_create_show_query(params, {'query': ''})395 def test_event_alarm_create_show_query(self):396 params = ('create --type event --name alarm-multiple-query '397 '--query "traits.project_id=789;traits.resource_id=012"')398 expected_lines = {399 'query': 'traits.project_id = 789 AND',400 '': 'traits.resource_id = 012',401 }402 self._test_alarm_create_show_query(params, expected_lines)403 params = ('create --type event --name alarm-single-query '404 '--query "traits.project_id=789"')405 expected_lines = {'query': 'traits.project_id = 789'}406 self._test_alarm_create_show_query(params, expected_lines)407 params = 'create --type event --name alarm-no-query'408 self._test_alarm_create_show_query(params, {'query': ''})409 def test_set_get_alarm_state(self):410 result = self.aodh(411 'alarm',412 params=("create --type threshold --name alarm_state_test "413 "-m meter_name --threshold 5"))414 alarm = self.details_multiple(result)[0]415 alarm_id = alarm['alarm_id']416 result = self.aodh(417 'alarm', params="show %s" % alarm_id)418 alarm_show = self.details_multiple(result)[0]419 self.assertEqual('insufficient data', alarm_show['state'])420 result = self.aodh('alarm', params="state get %s" % alarm_id)421 state_get = self.details_multiple(result)[0]422 self.assertEqual('insufficient data', state_get['state'])423 self.aodh('alarm',424 params="state set --state ok %s" % alarm_id)425 result = self.aodh('alarm', params="state get %s" % alarm_id)426 state_get = self.details_multiple(result)[0]427 self.assertEqual('ok', state_get['state'])428 self.aodh('alarm', params='delete %s' % alarm_id)429class AodhClientGnocchiRulesTest(base.ClientTestBase):430 def test_gnocchi_resources_threshold_scenario(self):431 PROJECT_ID = uuidutils.generate_uuid()432 RESOURCE_ID = uuidutils.generate_uuid()433 req = requests.post(434 os.environ.get("GNOCCHI_ENDPOINT") + "/v1/resource/generic",435 auth=requests.auth.HTTPBasicAuth('admin', ''),436 json={437 "id": RESOURCE_ID,438 })439 self.assertEqual(201, req.status_code)440 # CREATE441 result = self.aodh(u'alarm',442 params=(u"create "443 "--type gnocchi_resources_threshold "444 "--name alarm_gn1 --metric cpu_util "445 "--threshold 80 "446 "--resource-id %s --resource-type generic "447 "--aggregation-method last "448 "--project-id %s"449 % (RESOURCE_ID, PROJECT_ID)))450 alarm = self.details_multiple(result)[0]451 ALARM_ID = alarm['alarm_id']452 self.assertEqual('alarm_gn1', alarm['name'])453 self.assertEqual('cpu_util', alarm['metric'])454 self.assertEqual('80.0', alarm['threshold'])455 self.assertEqual('last', alarm['aggregation_method'])456 self.assertEqual(RESOURCE_ID,457 alarm['resource_id'])458 self.assertEqual('generic', alarm['resource_type'])459 # CREATE FAIL MISSING PARAM460 self.assertRaises(exceptions.CommandFailed,461 self.aodh, u'alarm',462 params=(u"create "463 "--type gnocchi_resources_threshold "464 "--name alarm1 --metric cpu_util "465 "--resource-id %s --resource-type generic "466 "--aggregation-method last "467 "--project-id %s"468 % (RESOURCE_ID, PROJECT_ID)))469 # UPDATE470 result = self.aodh(471 'alarm', params=("update %s --severity critical --threshold 90"472 % ALARM_ID))473 alarm_updated = self.details_multiple(result)[0]474 self.assertEqual(ALARM_ID, alarm_updated["alarm_id"])475 self.assertEqual('critical', alarm_updated['severity'])476 self.assertEqual('90.0', alarm_updated["threshold"])477 # GET478 result = self.aodh(479 'alarm', params="show %s" % ALARM_ID)480 alarm_show = self.details_multiple(result)[0]481 self.assertEqual(ALARM_ID, alarm_show["alarm_id"])482 self.assertEqual(PROJECT_ID, alarm_show["project_id"])483 self.assertEqual('alarm_gn1', alarm_show['name'])484 self.assertEqual('cpu_util', alarm_show['metric'])485 self.assertEqual('90.0', alarm_show['threshold'])486 self.assertEqual('critical', alarm_show['severity'])487 self.assertEqual('last', alarm_show['aggregation_method'])488 self.assertEqual('generic', alarm_show['resource_type'])489 # GET BY NAME490 result = self.aodh(491 'alarm', params="show --name alarm_gn1")492 self.assertEqual(ALARM_ID, alarm_show["alarm_id"])493 self.assertEqual(PROJECT_ID, alarm_show["project_id"])494 self.assertEqual('alarm_gn1', alarm_show['name'])495 self.assertEqual('cpu_util', alarm_show['metric'])496 self.assertEqual('90.0', alarm_show['threshold'])497 self.assertEqual('critical', alarm_show['severity'])498 self.assertEqual('last', alarm_show['aggregation_method'])499 self.assertEqual('generic', alarm_show['resource_type'])500 # GET BY NAME AND ID ERROR501 self.assertRaises(exceptions.CommandFailed,502 self.aodh, u'alarm',503 params=(u"show %s --name alarm_gn1" %504 ALARM_ID))505 # LIST506 result = self.aodh('alarm', params="list")507 self.assertIn(ALARM_ID,508 [r['alarm_id'] for r in self.parser.listing(result)])509 output_colums = ['alarm_id', 'type', 'name', 'state', 'severity',510 'enabled']511 for alarm_list in self.parser.listing(result):512 self.assertEqual(sorted(output_colums), sorted(alarm_list.keys()))513 if alarm_list["alarm_id"] == ALARM_ID:514 self.assertEqual('alarm_gn1', alarm_list['name'])515 # LIST WITH QUERY516 result = self.aodh('alarm',517 params=("list --query project_id=%s" % PROJECT_ID))518 alarm_list = self.parser.listing(result)[0]519 self.assertEqual(ALARM_ID, alarm_list["alarm_id"])520 self.assertEqual('alarm_gn1', alarm_list['name'])521 # DELETE522 result = self.aodh('alarm', params="delete %s" % ALARM_ID)523 self.assertEqual("", result)524 # GET FAIL525 result = self.aodh('alarm', params="show %s" % ALARM_ID,526 fail_ok=True, merge_stderr=True)527 expected = "Alarm %s not found (HTTP 404)" % ALARM_ID528 self.assertFirstLineStartsWith(result.splitlines(), expected)529 # DELETE FAIL530 result = self.aodh('alarm', params="delete %s" % ALARM_ID,531 fail_ok=True, merge_stderr=True)532 self.assertFirstLineStartsWith(result.splitlines(), expected)533 # LIST DOES NOT HAVE ALARM534 result = self.aodh('alarm', params="list")535 self.assertNotIn(ALARM_ID,536 [r['alarm_id'] for r in self.parser.listing(result)])537 def test_gnocchi_aggr_by_resources_scenario(self):538 PROJECT_ID = uuidutils.generate_uuid()539 # CREATE540 result = self.aodh(541 u'alarm',542 params=(u"create "543 "--type "544 "gnocchi_aggregation_by_resources_threshold "545 "--name alarm1 --metric cpu --threshold 80 "546 "--query "547 '\'{"=": {"creator": "cr3at0r"}}\' '548 "--resource-type generic "549 "--aggregation-method last "550 "--project-id %s" % PROJECT_ID))551 alarm = self.details_multiple(result)[0]552 ALARM_ID = alarm['alarm_id']553 self.assertEqual('alarm1', alarm['name'])554 self.assertEqual('cpu', alarm['metric'])555 self.assertEqual('80.0', alarm['threshold'])556 self.assertEqual('last', alarm['aggregation_method'])557 self.assertEqual('generic', alarm['resource_type'])558 self.assertEqual('{"=": {"creator": "cr3at0r"}}',559 alarm['query'])560 # CREATE FAIL MISSING PARAM561 self.assertRaises(562 exceptions.CommandFailed,563 self.aodh, u'alarm',564 params=(u"create "565 "--type "566 "gnocchi_aggregation_by_resources_threshold "567 "--name alarm1 --metric cpu "568 "--query "569 '\'{"=": {"creator": "cr3at0r"}}\' '570 "--resource-type generic "571 "--aggregation-method last "572 "--project-id %s" % PROJECT_ID))573 # UPDATE574 result = self.aodh(575 'alarm', params=("update %s --severity critical --threshold 90"576 % ALARM_ID))577 alarm_updated = self.details_multiple(result)[0]578 self.assertEqual(ALARM_ID, alarm_updated["alarm_id"])579 self.assertEqual('critical', alarm_updated['severity'])580 self.assertEqual('90.0', alarm_updated["threshold"])581 # GET582 result = self.aodh(583 'alarm', params="show %s" % ALARM_ID)584 alarm_show = self.details_multiple(result)[0]585 self.assertEqual(ALARM_ID, alarm_show["alarm_id"])586 self.assertEqual(PROJECT_ID, alarm_show["project_id"])587 self.assertEqual('alarm1', alarm_show['name'])588 self.assertEqual('cpu', alarm_show['metric'])589 self.assertEqual('90.0', alarm_show['threshold'])590 self.assertEqual('critical', alarm_show['severity'])591 self.assertEqual('last', alarm_show['aggregation_method'])592 self.assertEqual('generic', alarm_show['resource_type'])593 # LIST594 result = self.aodh('alarm', params="list")595 self.assertIn(ALARM_ID,596 [r['alarm_id'] for r in self.parser.listing(result)])597 output_colums = ['alarm_id', 'type', 'name', 'state', 'severity',598 'enabled']599 for alarm_list in self.parser.listing(result):600 self.assertEqual(sorted(output_colums), sorted(alarm_list.keys()))601 if alarm_list["alarm_id"] == ALARM_ID:602 self.assertEqual('alarm1', alarm_list['name'])603 # DELETE604 result = self.aodh('alarm', params="delete %s" % ALARM_ID)605 self.assertEqual("", result)606 # GET FAIL607 result = self.aodh('alarm', params="show %s" % ALARM_ID,608 fail_ok=True, merge_stderr=True)609 expected = "Alarm %s not found (HTTP 404)" % ALARM_ID610 self.assertFirstLineStartsWith(result.splitlines(), expected)611 # DELETE FAIL612 result = self.aodh('alarm', params="delete %s" % ALARM_ID,613 fail_ok=True, merge_stderr=True)614 self.assertFirstLineStartsWith(result.splitlines(), expected)615 # LIST DOES NOT HAVE ALARM616 result = self.aodh('alarm', params="list")617 self.assertNotIn(ALARM_ID,618 [r['alarm_id'] for r in self.parser.listing(result)])619 def test_gnocchi_aggr_by_metrics_scenario(self):620 PROJECT_ID = uuidutils.generate_uuid()621 METRIC1 = 'cpu'622 METRIC2 = 'cpu_util'623 # CREATE624 result = self.aodh(625 u'alarm',626 params=(u"create "627 "--type gnocchi_aggregation_by_metrics_threshold "628 "--name alarm1 "629 "--metrics %s "630 "--metrics %s "631 "--threshold 80 "632 "--aggregation-method last "633 "--project-id %s"634 % (METRIC1, METRIC2, PROJECT_ID)))635 alarm = self.details_multiple(result)[0]636 ALARM_ID = alarm['alarm_id']637 self.assertEqual('alarm1', alarm['name'])638 metrics = "[u'cpu', u'cpu_util']" if six.PY2 else "['cpu', 'cpu_util']"639 self.assertEqual(metrics, alarm['metrics'])640 self.assertEqual('80.0', alarm['threshold'])641 self.assertEqual('last', alarm['aggregation_method'])642 # CREATE FAIL MISSING PARAM643 self.assertRaises(644 exceptions.CommandFailed,645 self.aodh, u'alarm',646 params=(u"create "647 "--type gnocchi_aggregation_by_metrics_threshold "648 "--name alarm1 "649 "--metrics %s "650 "--metrics %s "651 "--aggregation-method last "652 "--project-id %s"653 % (METRIC1, METRIC2, PROJECT_ID)))654 # UPDATE655 result = self.aodh(656 'alarm', params=("update %s --severity critical --threshold 90"657 % ALARM_ID))658 alarm_updated = self.details_multiple(result)[0]659 self.assertEqual(ALARM_ID, alarm_updated["alarm_id"])660 self.assertEqual('critical', alarm_updated['severity'])661 self.assertEqual('90.0', alarm_updated["threshold"])662 # GET663 result = self.aodh(664 'alarm', params="show %s" % ALARM_ID)665 alarm_show = self.details_multiple(result)[0]666 self.assertEqual(ALARM_ID, alarm_show["alarm_id"])667 self.assertEqual(PROJECT_ID, alarm_show["project_id"])668 self.assertEqual('alarm1', alarm_show['name'])669 self.assertEqual(metrics, alarm_show['metrics'])670 self.assertEqual('90.0', alarm_show['threshold'])671 self.assertEqual('critical', alarm_show['severity'])672 self.assertEqual('last', alarm_show['aggregation_method'])673 # LIST674 result = self.aodh('alarm', params="list")675 self.assertIn(ALARM_ID,676 [r['alarm_id'] for r in self.parser.listing(result)])677 for alarm_list in self.parser.listing(result):678 if alarm_list["alarm_id"] == ALARM_ID:679 self.assertEqual('alarm1', alarm_list['name'])680 # LIST WITH QUERY681 result = self.aodh('alarm',682 params=("list --query project_id=%s" % PROJECT_ID))683 alarm_list = self.parser.listing(result)[0]684 self.assertEqual(ALARM_ID, alarm_list["alarm_id"])685 self.assertEqual('alarm1', alarm_list['name'])686 # DELETE687 result = self.aodh('alarm', params="delete %s" % ALARM_ID)688 self.assertEqual("", result)689 # GET FAIL690 result = self.aodh('alarm', params="show %s" % ALARM_ID,691 fail_ok=True, merge_stderr=True)692 expected = "Alarm %s not found (HTTP 404)" % ALARM_ID693 self.assertFirstLineStartsWith(result.splitlines(), expected)694 # DELETE FAIL695 result = self.aodh('alarm', params="delete %s" % ALARM_ID,696 fail_ok=True, merge_stderr=True)697 self.assertFirstLineStartsWith(result.splitlines(), expected)698 # LIST DOES NOT HAVE ALARM699 result = self.aodh('alarm', params="list")700 output_colums = ['alarm_id', 'type', 'name', 'state', 'severity',701 'enabled']702 for alarm_list in self.parser.listing(result):703 self.assertEqual(sorted(output_colums), sorted(alarm_list.keys()))704 self.assertNotIn(ALARM_ID,...

Full Screen

Full Screen

client_testcase.py

Source:client_testcase.py Github

copy

Full Screen

...157 def setUp(self):158 super(CLIClientTestCase, self).setUp()159 self.clients = self._get_clients()160 self.parser = cli_output_parser161 def assertFirstLineStartsWith(self, lines, beginning):162 """assertFirstLineStartsWith163 Verify that the first line starts with a string164 :param lines: strings for each line of output165 :type lines: list166 :param beginning: verify this is at the beginning of the first line167 :type beginning: string168 """169 self.assertTrue(lines[0].startswith(beginning),170 msg=('Beginning of first line has invalid content: %s'171 % lines[:3]))172 def assertCommandFailed(self, message, fun, *args, **kwds):173 self.assertRaisesRegex(exceptions.CommandFailed, message,174 fun, *args, **kwds)175 def _get_clients(self):176 if self.me == Role.admin:177 self.cli = self.admin_cli178 elif self.me == Role.tenant:179 self.cli = self.tenant_cli180 else:181 self.cli = self.nonadmin_cli182 return self.cli183 def _as_admin(self):184 self.me = Role.admin185 self._get_clients()186 return self187 def _as_tenant(self):188 self.me = Role.tenant189 self._get_clients()190 def create_network_with_args(self, *args):191 """Wrapper utility that returns a test network."""192 the_params = ''193 for arg in args:194 the_params += ' '195 the_params += arg196 response = self.cli.neutron('net-create', params=the_params)197 self.assertFirstLineStartsWith(response.split('\n'),198 'Created a new network:')199 network = self.parser.details(response)200 self.networks.append(network)201 return network202 def create_network(self, network_name=None):203 """Wrapper utility that returns a test network."""204 network_name = network_name or data_utils.rand_name('test-network')205 return self.create_network_with_args(network_name)206 def delete_network(self, network_id):207 response = self.cli.neutron('net-delete', params=network_id)208 self.assertFirstLineStartsWith(response.split('\n'),209 'Deleted network')210 self.assertIn(network_id, response)211 def show_network(self, network_id):212 response = self.cli.neutron('net-show', params=network_id)213 network = self.parser.details(response)214 self.assertEqual(network['id'], network_id)215 return network216 def list_networks(self):217 response = self.cli.neutron('net-list')218 return response219 def show_subnet(self, subnet_id):220 response = self.cli.neutron('subnet-show', params=subnet_id)221 subnet = self.parser.details(response)222 self.assertEqual(subnet['id'], subnet_id)223 return subnet224 def delete_subnet(self, subnet_id):225 response = self.cli.neutron('subnet-delete', params=subnet_id)226 self.assertFirstLineStartsWith(response.split('\n'),227 'Deleted subnet')228 self.assertIn(subnet_id, response)229 def list_subnets(self):230 response = self.cli.neutron('subnet-list')231 return response232 def create_subnet_with_args(self, *args):233 """Wrapper utility that returns a test subnet."""234 the_params = ''235 for arg in args:236 the_params += ' '237 the_params += arg238 response = self.cli.neutron('subnet-create', params=the_params)239 self.assertFirstLineStartsWith(response.split('\n'),240 'Created a new subnet:')241 subnet = self.parser.details(response)242 self.subnets.append(subnet)243 return subnet244 def update_subnet_with_args(self, *args):245 """Wrapper utility that updates returns a test subnet."""246 the_params = ''247 for arg in args:248 the_params += ' '249 the_params += arg250 response = self.cli.neutron('subnet-update', params=the_params)251 self.assertFirstLineStartsWith(response.split('\n'),252 'Updated subnet:')253 def create_router_with_args(self, *args):254 """Wrapper utility that returns a test router."""255 the_params = ''256 for arg in args:257 the_params += ' '258 the_params += arg259 response = self.cli.neutron('router-create', params=the_params)260 self.assertFirstLineStartsWith(response.split('\n'),261 'Created a new router:')262 router = self.parser.details(response)263 self.routers.append(router)264 return router265 def create_router(self, router_name=None):266 """Wrapper utility that returns a test router."""267 router_name = router_name or data_utils.rand_name('test-router')268 return self.create_router_with_args(router_name)269 def update_router_with_args(self, *args):270 """Wrapper utility that returns a test router."""271 the_params = ''272 for arg in args:273 the_params += ' '274 the_params += arg275 response = self.cli.neutron('router-update', params=the_params)276 self.assertFirstLineStartsWith(response.split('\n'),277 'Updated router:')278 # router = self.parser.details(response)279 # return router280 def show_router(self, router_id):281 response = self.cli.neutron('router-show', params=router_id)282 router = self.parser.details(response)283 self.assertEqual(router['id'], router_id)284 return router285 def list_routers(self):286 response = self.cli.neutron('router-list')287 return response288 def set_router_gateway_with_args(self, *args):289 """Wrapper utility that sets the router gateway."""290 the_params = ''291 for arg in args:292 the_params += ' '293 the_params += arg294 response = self.cli.neutron('router-gateway-set', params=the_params)295 self.assertFirstLineStartsWith(response.split('\n'),296 'Set gateway for router')297 def add_router_interface_with_args(self, *args):298 """Wrapper utility that sets the router gateway."""299 the_params = ''300 for arg in args:301 the_params += ' '302 the_params += arg303 response = self.cli.neutron('router-interface-add', params=the_params)304 self.assertFirstLineStartsWith(response.split('\n'),305 'Added interface')306 def create_port_with_args(self, *args):307 """Wrapper utility that returns a test port."""308 the_params = ''309 for arg in args:310 the_params += ' '311 the_params += arg312 if (CONF.network.port_vnic_type == 'direct' and313 'switchdev' in CONF.network.port_profile.get('capabilities',314 [])):315 the_params += ' '316 the_params += '--vnic-type direct'317 the_params += ' '318 the_params += ('--binding:profile type=dict'319 ' capabilities=[switchdev]')320 response = self.cli.neutron('port-create', params=the_params)321 self.assertFirstLineStartsWith(response.split('\n'),322 'Created a new port:')323 port = self.parser.details(response)324 self.ports.append(port)325 return port326 def create_port(self, network, port_name=None):327 """Wrapper utility that returns a test port."""328 port_name = port_name or data_utils.rand_name('cli-test-port-')329 response = self.create_port_with_args("--name ", port_name,330 network['id'])331 return response332 def update_port_with_args(self, port_id, *args):333 the_params = ''334 for arg in args:335 the_params += ' '336 the_params += arg337 response = self.cli.neutron('port-update ',338 params=port_id + ' ' + the_params)339 self.assertFirstLineStartsWith(response.split('\n'), 'Updated port:')340 def show_port(self, port_id):341 response = self.cli.neutron('port-show', params=port_id)342 port = self.parser.details(response)343 self.assertEqual(port['id'], port_id)344 return port345 def create_floating_ip_with_args(self, *args):346 """Wrapper utility that returns a test floating_ip."""347 the_params = ''348 for arg in args:349 the_params += ' '350 the_params += arg351 response = self.cli.neutron('floatingip-create',352 params=the_params)353 self.assertFirstLineStartsWith(response.split('\n'),354 'Created a new floatingip:')355 floating_ip = self.parser.details(response)356 self.floating_ips.append(floating_ip)357 return floating_ip358 def update_floating_ip_with_args(self, *args):359 """Wrapper utility that returns a test floating_ip."""360 the_params = ''361 for arg in args:362 the_params += ' '363 the_params += arg364 response = self.cli.neutron('floatingip-update', params=the_params)365 self.assertFirstLineStartsWith(response.split('\n'),366 'Updated floatingip:')367 def create_floating_ip(self, floating_ip_name=None):368 """Wrapper utility that returns a test floating_ip."""369 floating_ip_name = floating_ip_name or data_utils.rand_name(370 'test-floating_ip')371 return self.create_floating_ip_with_args(floating_ip_name)372 def show_floating_ip(self, floating_ip_id):373 response = self.cli.neutron('floatingip-show', params=floating_ip_id)374 floating_ip = self.parser.details(response)375 return floating_ip376 def list_nuage_floating_ip_all(self):377 response = self.cli.neutron('nuage-floatingip-list')378 nuage_floating_ip_list = self.parser.details(response)379 return nuage_floating_ip_list380 def list_nuage_floating_ip_for_subnet(self, subnet_id):381 response = self.cli.neutron('nuage-floatingip-show --subnet ',382 params=subnet_id)383 nuage_floating_ip_list = self.parser.details(response)384 return nuage_floating_ip_list385 def list_nuage_floating_ip_for_port(self, port_id):386 response = self.cli.neutron('nuage-floatingip-show --subnet ',387 params=port_id)388 nuage_floating_ip_list = self.parser.details(response)389 return nuage_floating_ip_list390 def show_nuage_floating_ip(self, floating_ip_id):391 response = self.cli.neutron('floatingip-show', params=floating_ip_id)392 floating_ip = self.parser.details(response)393 return floating_ip394 def _kwargs_to_cli(self, **kwargs):395 params_str = ''396 if kwargs is not None:397 for key, value in iteritems(kwargs):398 print("%s == %s", (key, value))399 params_str += " --%s %s" % (key, value)400 params_str = params_str.replace("_", "-")401 return params_str402 def associate_floating_ip(self, floating_ip_id, port_id, **kwargs):403 the_params = self._kwargs_to_cli(**kwargs)404 return self.cli.neutron('floatingip-associate',405 params=floating_ip_id + ' ' +406 port_id + the_params)407 def disassociate_floating_ip(self, floating_ip_id):408 return self.cli.neutron('floatingip-disassociate',409 params=floating_ip_id)410 def create_nuage_l2bridge_cli(self, *args):411 the_params = ''412 for arg in args:413 the_params += ' '414 the_params += arg415 return self.cli.neutron('nuage-l2bridge-create',416 params=the_params)417 def show_nuage_l2bridge_cli(self, *args):418 the_params = ''419 for arg in args:420 the_params += ' '421 the_params += arg422 return self.cli.neutron('nuage-l2bridge-show',423 params=the_params)424 def delete_nuage_l2bridge_cli(self, id, name=None):425 if name:426 return self.cli.neutron('nuage-l2bridge-delete',427 params=' ' + name)428 else:429 return self.cli.neutron('nuage-l2bridge-delete',430 params=' ' + id)431 def update_nuage_l2bridge_cli(self, *args):432 the_params = ''433 for arg in args:434 the_params += ' '435 the_params += arg436 return self.cli.neutron('nuage-l2bridge-update',437 params=the_params)438 def create_security_group_with_args(self, *args):439 """Wrapper utility that returns a test security group."""440 the_params = ''441 for arg in args:442 the_params += ' '443 the_params += arg444 response = self.cli.neutron('security-group-create',445 params=the_params)446 self.assertFirstLineStartsWith(response.split('\n'),447 'Created a new security_group:')448 security_group = self.parser.details(response)449 self.security_groups.append(security_group)450 return security_group451 def update_security_group_with_args(self, *args):452 """Wrapper utility that returns a test security group."""453 the_params = ''454 for arg in args:455 the_params += ' '456 the_params += arg457 response = self.cli.neutron('security-group-update',458 params=the_params)459 self.assertFirstLineStartsWith(response.split('\n'),460 'Updated security_group:')461 security_group = self.parser.details(response)462 return security_group463 def show_security_group(self, sg_id):464 response = self.cli.neutron('security-group-show', params=sg_id)465 security_group = self.parser.details(response)466 self.assertEqual(security_group['id'], sg_id)467 return security_group468 def delete_security_group(self, sg_id):469 response = self.cli.neutron('security-group-delete', params=sg_id)470 self.assertFirstLineStartsWith(response.split('\n'),471 'Deleted security_group(s)')472 self.assertIn(sg_id, response)473 def create_security_group_rule_with_args(self, *args):474 """Wrapper utility that returns a test security group rule."""475 the_params = ''476 for arg in args:477 the_params += ' '478 the_params += arg479 response = self.cli.neutron('security-group-rule-create',480 params=the_params)481 self.assertFirstLineStartsWith(response.split('\n'),482 'Created a new security_group_rule:')483 security_group_rule = self.parser.details(response)484 self.security_group_rules.append(security_group_rule)485 return security_group_rule486 def create_vm_with_args(self, *args):487 """Wrapper utility that returns a test VM."""488 the_params = ''489 for arg in args:490 the_params += ' '491 the_params += arg492 response = self.cli.nova('boot', params=the_params)493 # self.assertFirstLineStartsWith(response.split('\n'),494 # 'Created a new VM:')495 vm = self.parser.details(response)496 self.vms.append(vm)497 return vm498 @classmethod499 def delete_router(cls, router):500 cls._clear_router_gateway(router['id'])501 interfaces = cls._list_router_ports(router['id'])502 for i in interfaces:503 fixed_ips = i['fixed_ips']504 fixed_ips_dict = json.loads(fixed_ips)505 subnet_id = fixed_ips_dict['subnet_id']506 cls._remove_router_interface_with_subnet_id(router['id'],507 subnet_id)508 cls._delete_router(router['id'])509 @classmethod510 def _delete_network(cls, network_id):511 cls.cli.neutron('net-delete', params=network_id)512 @classmethod513 def _delete_subnet(cls, subnet_id):514 cls.cli.neutron('subnet-delete', params=subnet_id)515 @classmethod516 def _delete_port(cls, port_id):517 cls.cli.neutron('port-delete', params=port_id)518 @classmethod519 def _delete_router(cls, router_id):520 cls.cli.neutron('router-delete', params=router_id)521 @classmethod522 def _delete_floating_ip(cls, floating_ip_id):523 cls.cli.neutron('floatingip-delete', params=floating_ip_id)524 @classmethod525 def _clear_router_gateway(cls, router_id):526 cls.cli.neutron('router-gateway-clear', params=router_id)527 @classmethod528 def _list_router_ports(cls, router_id):529 response = cls.cli.neutron('router-port-list', params=router_id)530 ports = cls.parser.listing(response)531 return ports532 @classmethod533 def _remove_router_interface_with_subnet_id(cls, router_id, subnet_id):534 response = cls.cli.neutron('router-interface-delete',535 params=router_id + ' ' + subnet_id)536 return response537 # @classmethod538 def _cli_create_redirect_target_with_args(self, *args):539 the_params = ''540 for arg in args:541 the_params += ' '542 the_params += arg543 response = self.cli.neutron('nuage-redirect-target-create',544 params=the_params)545 self.assertFirstLineStartsWith(response.split('\n'),546 'Created a new nuage_redirect_target:')547 redirect_target = self.parser.details(response)548 # self.nuage_redirect_targets.append(redirect_target)549 return redirect_target550 def _cli_create_nuage_redirect_target_in_l2_subnet(self, l2subnet,551 name=None):552 if name is None:553 name = data_utils.rand_name('cli-os-l2-rt')554 # parameters for nuage redirection target555 response = self.cli.neutron(556 'nuage-redirect-target-create --insertion-mode VIRTUAL_WIRE '557 '--redundancy-enabled false --subnet',558 params=l2subnet['name'] + ' ' + name)559 self.assertFirstLineStartsWith(response.split('\n'),560 'Created a new nuage_redirect_target:')561 redirect_target = self.parser.details(response)562 # self.nuage_redirect_targets.append(redirect_target)563 return redirect_target564 def _cli_create_nuage_redirect_target_in_l3_subnet(self, l3subnet,565 name=None):566 if name is None:567 name = data_utils.rand_name('cli-os-l3-rt')568 response = self.cli.neutron(569 'nuage-redirect-target-create --insertion-mode L3 '570 '--redundancy-enabled false --subnet',571 params=l3subnet['name'] + ' ' + name)572 self.assertFirstLineStartsWith(response.split('\n'),573 'Created a new nuage_redirect_target:')574 redirect_target = self.parser.details(response)575 # self.nuage_redirect_targets.append(redirect_target)576 return redirect_target577 def delete_redirect_target(self, redirect_target_id):578 self.cli.neutron('nuage-redirect-target-delete',579 params=redirect_target_id)580 def list_nuage_redirect_target_for_l2_subnet(self, l2subnet):581 response = self.cli.neutron('nuage-redirect-target-list --subnet ',582 params=l2subnet['id'])583 rt_list = self.parser.listing(response)584 return rt_list585 def list_nuage_redirect_target_for_port(self, port):586 response = self.cli.neutron('nuage-redirect-target-list --for-port ',...

Full Screen

Full Screen

test_archive_policy.py

Source:test_archive_policy.py Github

copy

Full Screen

...26 u'archive-policy', params=u"create %s"27 u" --back-window 0"28 u" -d granularity:1s,points:86400" % apname,29 fail_ok=True, merge_stderr=True)30 self.assertFirstLineStartsWith(31 result.split('\n'),32 "Archive policy %s already exists (HTTP 409)" % apname)33 # GET34 result = self.gnocchi(35 'archive-policy', params="show %s" % apname)36 policy = self.details_multiple(result)[0]37 self.assertEqual(apname, policy["name"])38 # LIST39 result = self.gnocchi(40 'archive-policy', params="list")41 policies = self.parser.listing(result)42 policy_from_list = [p for p in policies43 if p['name'] == apname][0]44 for field in ["back_window", "definition", "aggregation_methods"]:45 self.assertEqual(policy[field], policy_from_list[field])46 # UPDATE47 result = self.gnocchi(48 'archive-policy', params='update %s'49 ' -d granularity:1s,points:60' % apname)50 policy = self.details_multiple(result)[0]51 self.assertEqual(apname, policy["name"])52 # UPDATE FAIL53 result = self.gnocchi(54 'archive-policy', params='update %s'55 ' -d granularity:5s,points:86400' % apname,56 fail_ok=True, merge_stderr=True)57 self.assertFirstLineStartsWith(58 result.split('\n'),59 "Archive policy %s does not support change: 1.0 granularity "60 "interval was changed (HTTP 400)" % apname)61 # DELETE62 result = self.gnocchi('archive-policy',63 params="delete %s" % apname)64 self.assertEqual("", result)65 # GET FAIL66 result = self.gnocchi('archive-policy',67 params="show %s" % apname,68 fail_ok=True, merge_stderr=True)69 self.assertFirstLineStartsWith(70 result.split('\n'),71 "Archive policy %s does not exist (HTTP 404)" % apname)72 # DELETE FAIL73 result = self.gnocchi('archive-policy',74 params="delete %s" % apname,75 fail_ok=True, merge_stderr=True)76 self.assertFirstLineStartsWith(77 result.split('\n'),...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run tempest automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful