How to use get_group_policy method in localstack

Best Python code snippet using localstack_python

IAM_IP_RESTRICTION_test.py

Source:IAM_IP_RESTRICTION_test.py Github

copy

Full Screen

1# Copyright 2017-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.2#3# Licensed under the Apache License, Version 2.0 (the "License"). You may4# not use this file except in compliance with the License. A copy of the License is located at5#6# http://aws.amazon.com/apache2.0/7#8# or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,9# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for10# the specific language governing permissions and limitations under the License.11import sys12import unittest13try:14 from unittest.mock import MagicMock15except ImportError:16 from mock import MagicMock17import botocore18##############19# Parameters #20##############21# Define the default resource to report to Config Rules22DEFAULT_RESOURCE_TYPE = 'AWS::IAM::User'23#############24# Main Code #25#############26CONFIG_CLIENT_MOCK = MagicMock()27STS_CLIENT_MOCK = MagicMock()28IAM_CLIENT_MOCK = MagicMock()29class Boto3Mock():30 @staticmethod31 def client(client_name, *args, **kwargs):32 if client_name == 'config':33 return CONFIG_CLIENT_MOCK34 if client_name == 'iam':35 return IAM_CLIENT_MOCK36 if client_name == 'sts':37 return STS_CLIENT_MOCK38 raise Exception("Attempting to create an unknown client")39sys.modules['boto3'] = Boto3Mock()40RULE = __import__('IAM_IP_RESTRICTION')41class InvalidParameterTest(unittest.TestCase):42 def setUp(self):43 CONFIG_CLIENT_MOCK.reset_mock()44 IAM_CLIENT_MOCK.reset_mock()45 too_many_char = ''.join([str(c) for c in range(60)])46 invalid_params = {47 'tooManyChar': '{"WhitelistedUserNames":"test-user-' + too_many_char + '"}',48 'invalidMaxIpNums': '{"WhitelistedUserNames":"test-user01,test-user02", "maxIpNums":"0"}',49 }50 def test_scenario02_user_whitelist_too_many_characters(self):51 response = RULE.lambda_handler(build_lambda_scheduled_event(rule_parameters=self.invalid_params['tooManyChar']), {})52 assert_customer_error_response(self, response, 'InvalidParameterValueException')53 def test_scenario03_max_ip_num_less_than_1(self):54 response = RULE.lambda_handler(build_lambda_scheduled_event(rule_parameters=self.invalid_params['invalidMaxIpNums']), {})55 assert_customer_error_response(self, response, 'InvalidParameterValueException')56class ComplianceTest(unittest.TestCase):57 rule_parameters = '{"SomeParameterKey":"SomeParameterValue","SomeParameterKey2":"SomeParameterValue2"}'58 invoking_event_iam_role_sample = '{"configurationItem":{"relatedEvents":[],"relationships":[],"configuration":{},"tags":{},"configurationItemCaptureTime":"2018-07-02T03:37:52.418Z","awsAccountId":"123456789012","configurationItemStatus":"ResourceDiscovered","resourceType":"AWS::IAM::Role","resourceId":"some-resource-id","resourceName":"some-resource-name","ARN":"some-arn"},"notificationCreationTime":"2018-07-02T23:05:34.445Z","messageType":"ConfigurationItemChangeNotification"}'59 def setUp(self):60 CONFIG_CLIENT_MOCK.reset_mock()61 IAM_CLIENT_MOCK.reset_mock()62 user_list_empty = {"Users" : []}63 user_whitelist = {'UserId': 'AIDAJYPPIFB65RV8YYLDU', 'UserName': 'sampleUser1'}64 user_not_whitelist = {'UserId': 'AIDAJYPPIFB65RV8YYLDV', 'UserName': 'sampleUser2'}65 user_list = {"Users": [user_whitelist, user_not_whitelist]}66 user_policy_name = 'IAMIPRestrictPolicy'67 allow_ip = '192.169.30.1/32'68 def test_scenario01_no_iam_users(self):69 IAM_CLIENT_MOCK.list_users = MagicMock(return_value=self.user_list_empty)70 response = RULE.lambda_handler(build_lambda_scheduled_event(), {})71 resp_expected = []72 resp_expected.append(build_expected_response("NOT_APPLICABLE", "123456789012", compliance_resource_type="AWS::::Account"))73 assert_successful_evaluation(self, response, resp_expected)74 def test_scenario04_compliant_user_whitelist(self):75 IAM_CLIENT_MOCK.list_users = MagicMock(return_value=self.user_list)76 response = RULE.lambda_handler(build_lambda_scheduled_event('{"WhitelistedUserNames":"sampleUser1"}'), {})77 resp_expected = []78 resp_expected.append(build_expected_response("COMPLIANT", self.user_whitelist['UserId'], annotation=f"This user {self.user_whitelist['UserName']} is whitelisted."))79 assert_successful_evaluation(self, response, resp_expected, 2)80 def test_scenario05_noncompliant_user_inline_policy_not_ip_allowed(self):81 self.__mock_only_user_inline_policy_not_ip_allowed()82 response = RULE.lambda_handler(build_lambda_scheduled_event('{"WhitelistedUserNames":"sampleUser1"}'), {})83 resp_expected = []84 resp_expected.append(build_expected_response("COMPLIANT", self.user_whitelist['UserId'], annotation=f"This user {self.user_whitelist['UserName']} is whitelisted."))85 resp_expected.append(build_expected_response("NON_COMPLIANT", self.user_not_whitelist['UserId'], annotation=f"This user {self.user_not_whitelist['UserName']} is not IP restricted."))86 assert_successful_evaluation(self, response, resp_expected, 2)87 def test_scenario06_noncompliant_user_attached_policy_not_ip_allowed(self):88 self.__mock_only_user_attached_policy_not_ip_allowed()89 response = RULE.lambda_handler(build_lambda_scheduled_event('{"WhitelistedUserNames":"sampleUser1"}'), {})90 resp_expected = []91 resp_expected.append(build_expected_response("COMPLIANT", self.user_whitelist['UserId'], annotation=f"This user {self.user_whitelist['UserName']} is whitelisted."))92 resp_expected.append(build_expected_response("NON_COMPLIANT", self.user_not_whitelist['UserId'], annotation=f"This user {self.user_not_whitelist['UserName']} is not IP restricted."))93 assert_successful_evaluation(self, response, resp_expected, 2)94 def test_scenario07_noncompliant_group_inline_policy_not_ip_allowed(self):95 self.__mock_only_group_inline_policy_not_ip_allowed()96 response = RULE.lambda_handler(build_lambda_scheduled_event('{"WhitelistedUserNames":"sampleUser1"}'), {})97 resp_expected = []98 resp_expected.append(build_expected_response("COMPLIANT", self.user_whitelist['UserId'], annotation=f"This user {self.user_whitelist['UserName']} is whitelisted."))99 resp_expected.append(build_expected_response("NON_COMPLIANT", self.user_not_whitelist['UserId'], annotation=f"This user {self.user_not_whitelist['UserName']} is not IP restricted."))100 assert_successful_evaluation(self, response, resp_expected, 2)101 def test_scenario08_noncompliant_group_attached_policy_not_ip_allowed(self):102 self.__mock_only_group_attached_policy_not_ip_allowed()103 response = RULE.lambda_handler(build_lambda_scheduled_event('{"WhitelistedUserNames":"sampleUser1"}'), {})104 resp_expected = []105 resp_expected.append(build_expected_response("COMPLIANT", self.user_whitelist['UserId'], annotation=f"This user {self.user_whitelist['UserName']} is whitelisted."))106 resp_expected.append(build_expected_response("NON_COMPLIANT", self.user_not_whitelist['UserId'], annotation=f"This user {self.user_not_whitelist['UserName']} is not IP restricted."))107 assert_successful_evaluation(self, response, resp_expected, 2)108 def test_scenario09_compliant_all_policy_ip_allowed(self):109 self.__mock_all_policy_ip_allowed()110 response = RULE.lambda_handler(build_lambda_scheduled_event('{"WhitelistedUserNames":"sampleUser1"}'), {})111 resp_expected = []112 resp_expected.append(build_expected_response("COMPLIANT", self.user_whitelist['UserId'], annotation=f"This user {self.user_whitelist['UserName']} is whitelisted."))113 resp_expected.append(build_expected_response("COMPLIANT", self.user_not_whitelist['UserId']))114 assert_successful_evaluation(self, response, resp_expected, 2)115 def test_scenario10_compliant_user_inline_policy_ip_denied(self):116 self.__mock_user_inline_policy_ip_denied()117 response = RULE.lambda_handler(build_lambda_scheduled_event('{"WhitelistedUserNames":"sampleUser1"}'), {})118 resp_expected = []119 resp_expected.append(build_expected_response("COMPLIANT", self.user_whitelist['UserId'], annotation=f"This user {self.user_whitelist['UserName']} is whitelisted."))120 resp_expected.append(build_expected_response("COMPLIANT", self.user_not_whitelist['UserId']))121 assert_successful_evaluation(self, response, resp_expected, 2)122 def test_scenario11_compliant_user_attached_policy_ip_denied(self):123 self.__mock_user_attached_policy_ip_denied()124 response = RULE.lambda_handler(build_lambda_scheduled_event('{"WhitelistedUserNames":"sampleUser1"}'), {})125 resp_expected = []126 resp_expected.append(build_expected_response("COMPLIANT", self.user_whitelist['UserId'], annotation=f"This user {self.user_whitelist['UserName']} is whitelisted."))127 resp_expected.append(build_expected_response("COMPLIANT", self.user_not_whitelist['UserId']))128 assert_successful_evaluation(self, response, resp_expected, 2)129 def test_scenario12_compliant_group_inline_policy_ip_denied(self):130 self.__mock_group_inline_policy_ip_denied()131 response = RULE.lambda_handler(build_lambda_scheduled_event('{"WhitelistedUserNames":"sampleUser1"}'), {})132 resp_expected = []133 resp_expected.append(build_expected_response("COMPLIANT", self.user_whitelist['UserId'], annotation=f"This user {self.user_whitelist['UserName']} is whitelisted."))134 resp_expected.append(build_expected_response("COMPLIANT", self.user_not_whitelist['UserId']))135 assert_successful_evaluation(self, response, resp_expected, 2)136 def test_scenario13_compliant_group_attached_policy_ip_denied(self):137 self.__mock_group_attached_policy_ip_denied()138 response = RULE.lambda_handler(build_lambda_scheduled_event('{"WhitelistedUserNames":"sampleUser1"}'), {})139 resp_expected = []140 resp_expected.append(build_expected_response("COMPLIANT", self.user_whitelist['UserId'], annotation=f"This user {self.user_whitelist['UserName']} is whitelisted."))141 resp_expected.append(build_expected_response("COMPLIANT", self.user_not_whitelist['UserId']))142 assert_successful_evaluation(self, response, resp_expected, 2)143 def test_scenario14_noncompliant_allowed_ip_addresses_greater_than_max_ip_nums(self):144 self.__mock_ip_restricted_greather_than_max_ip_nums()145 response = RULE.lambda_handler(build_lambda_scheduled_event('{"WhitelistedUserNames":"sampleUser1"}'), {})146 resp_expected = []147 resp_expected.append(build_expected_response("COMPLIANT", self.user_whitelist['UserId'], annotation=f"This user {self.user_whitelist['UserName']} is whitelisted."))148 resp_expected.append(build_expected_response("NON_COMPLIANT", self.user_not_whitelist['UserId'], annotation=f"IAM Policy includes more than maximum ip addresses: {RULE.DEFAULT_MAX_IP_NUMS+1}"))149 assert_successful_evaluation(self, response, resp_expected, 2)150 def __mock_only_user_inline_policy_not_ip_allowed(self):151 self.__mock_base()152 ip_allowed_policy = self.__ip_restricted_policy('Allow')153 base_policy = self.__policy_base('Allow')154 IAM_CLIENT_MOCK.get_user_policy = MagicMock(return_value=base_policy)155 IAM_CLIENT_MOCK.get_group_policy = MagicMock(return_value=ip_allowed_policy)156 IAM_CLIENT_MOCK.get_policy_version = MagicMock(return_value={'PolicyVersion': {'Document': ip_allowed_policy['PolicyDocument']}})157 def __mock_only_user_attached_policy_not_ip_allowed(self):158 self.__mock_base()159 ip_allowed_policy = self.__ip_restricted_policy('Allow')160 base_policy = self.__policy_base('Allow')161 IAM_CLIENT_MOCK.get_user_policy = MagicMock(return_value=ip_allowed_policy)162 IAM_CLIENT_MOCK.get_group_policy = MagicMock(return_value=ip_allowed_policy)163 IAM_CLIENT_MOCK.get_policy_version = MagicMock(return_value={'PolicyVersion': {'Document': base_policy['PolicyDocument']}})164 def __mock_only_group_inline_policy_not_ip_allowed(self):165 self.__mock_base()166 ip_allowed_policy = self.__ip_restricted_policy('Allow')167 base_policy = self.__policy_base('Allow')168 IAM_CLIENT_MOCK.get_user_policy = MagicMock(return_value=ip_allowed_policy)169 IAM_CLIENT_MOCK.get_group_policy = MagicMock(return_value=base_policy)170 IAM_CLIENT_MOCK.get_policy_version = MagicMock(return_value={'PolicyVersion': {'Document': ip_allowed_policy['PolicyDocument']}})171 def __mock_only_group_attached_policy_not_ip_allowed(self):172 self.__mock_base()173 ip_allowed_policy = self.__ip_restricted_policy('Allow')174 base_policy = self.__policy_base('Allow')175 IAM_CLIENT_MOCK.get_user_policy = MagicMock(return_value=ip_allowed_policy)176 IAM_CLIENT_MOCK.get_group_policy = MagicMock(return_value=ip_allowed_policy)177 IAM_CLIENT_MOCK.get_policy_version = MagicMock(return_value={'PolicyVersion': {'Document': base_policy['PolicyDocument']}})178 def __mock_all_policy_ip_allowed(self):179 self.__mock_base()180 ip_allowed_policy = self.__ip_restricted_policy('Allow')181 IAM_CLIENT_MOCK.get_user_policy = MagicMock(return_value=ip_allowed_policy)182 IAM_CLIENT_MOCK.get_group_policy = MagicMock(return_value=ip_allowed_policy)183 IAM_CLIENT_MOCK.get_policy_version = MagicMock(return_value={'PolicyVersion': {'Document': ip_allowed_policy['PolicyDocument']}})184 def __mock_user_inline_policy_ip_denied(self):185 self.__mock_base()186 ip_denied_policy = self.__ip_restricted_policy('Deny')187 base_policy = self.__policy_base('Allow')188 IAM_CLIENT_MOCK.get_user_policy = MagicMock(return_value=ip_denied_policy)189 IAM_CLIENT_MOCK.get_group_policy = MagicMock(return_value=base_policy)190 IAM_CLIENT_MOCK.get_policy_version = MagicMock(return_value={'PolicyVersion': {'Document': base_policy['PolicyDocument']}})191 def __mock_user_attached_policy_ip_denied(self):192 self.__mock_base()193 ip_denied_policy = self.__ip_restricted_policy('Deny')194 base_policy = self.__policy_base('Allow')195 IAM_CLIENT_MOCK.get_user_policy = MagicMock(return_value=base_policy)196 IAM_CLIENT_MOCK.get_group_policy = MagicMock(return_value=base_policy)197 IAM_CLIENT_MOCK.get_policy_version = MagicMock(return_value={'PolicyVersion': {'Document': ip_denied_policy['PolicyDocument']}})198 def __mock_group_inline_policy_ip_denied(self):199 self.__mock_base()200 ip_denied_policy = self.__ip_restricted_policy('Deny')201 base_policy = self.__policy_base('Allow')202 IAM_CLIENT_MOCK.get_user_policy = MagicMock(return_value=base_policy)203 IAM_CLIENT_MOCK.get_group_policy = MagicMock(return_value=ip_denied_policy)204 IAM_CLIENT_MOCK.get_policy_version = MagicMock(return_value={'PolicyVersion': {'Document': base_policy['PolicyDocument']}})205 def __mock_group_attached_policy_ip_denied(self):206 self.__mock_base()207 ip_denied_policy = self.__ip_restricted_policy('Deny')208 base_policy = self.__policy_base('Allow')209 IAM_CLIENT_MOCK.get_user_policy = MagicMock(return_value=base_policy)210 IAM_CLIENT_MOCK.get_group_policy = MagicMock(return_value=base_policy)211 IAM_CLIENT_MOCK.get_policy_version = MagicMock(return_value={'PolicyVersion': {'Document': ip_denied_policy['PolicyDocument']}})212 def __mock_ip_restricted_greather_than_max_ip_nums(self):213 self.__mock_base()214 ip_denied_policy = self.__ip_restricted_greather_than_max_ip_nums_policy('Deny')215 base_policy = self.__policy_base('Allow')216 IAM_CLIENT_MOCK.get_user_policy = MagicMock(return_value=ip_denied_policy)217 IAM_CLIENT_MOCK.get_group_policy = MagicMock(return_value=base_policy)218 IAM_CLIENT_MOCK.get_policy_version = MagicMock(return_value={'PolicyVersion': {'Document': base_policy['PolicyDocument']}})219 def __mock_base(self):220 inline_policy_name = {'PolicyNames': [self.user_policy_name]}221 attached_policy_name = {'AttachedPolicies': [{'PolicyName': 'samplePolicy', 'PolicyArn': 'arn:aws:iam::123456789000:policy/samplePolicy'}]}222 group_for_user = {'Groups': [{'GroupName': 'sampleGroup'}]}223 policy_version = {'Policy': {'DefaultVersionId': 'v1'}}224 IAM_CLIENT_MOCK.list_users = MagicMock(return_value=self.user_list)225 IAM_CLIENT_MOCK.list_user_policies = MagicMock(return_value=inline_policy_name)226 IAM_CLIENT_MOCK.list_attached_user_policies = MagicMock(return_value=attached_policy_name)227 IAM_CLIENT_MOCK.list_groups_for_user = MagicMock(return_value=group_for_user)228 IAM_CLIENT_MOCK.list_group_policies = MagicMock(return_value=inline_policy_name)229 IAM_CLIENT_MOCK.list_attached_group_policies(GroupName=attached_policy_name)230 IAM_CLIENT_MOCK.get_policy(PolicyArn=policy_version)231 def __ip_not_restricted_policy(self, effect):232 return self.__policy_base(effect)233 def __ip_restricted_policy(self, effect):234 if effect == 'Deny':235 condition = 'NotIpAddress'236 else:237 condition = 'IpAddress'238 policy = self.__policy_base(effect)239 policy['PolicyDocument']['Statement'][0]['Condition'] = {240 condition: {241 'aws:SourceIp': [self.allow_ip]242 }243 }244 return policy245 def __ip_restricted_greather_than_max_ip_nums_policy(self, effect):246 if effect == 'Deny':247 condition = 'NotIpAddress'248 else:249 condition = 'IpAddress'250 too_many_ip_addresses = [f'192.169.30.{n}/32' for n in range(RULE.DEFAULT_MAX_IP_NUMS+1)]251 policy = self.__policy_base(effect)252 policy['PolicyDocument']['Statement'][0]['Condition'] = {253 condition: {254 'aws:SourceIp': too_many_ip_addresses255 }256 }257 return policy258 def __policy_base(self, effect):259 policy = {260 'UserName': self.user_not_whitelist['UserName'],261 'PolicyName': self.user_policy_name,262 'PolicyDocument': {263 'Version': '2012-10-17',264 'Statement': [265 {266 'Action': '*',267 'Resource': '*',268 'Effect': effect269 }270 ]271 }272 }273 return policy274####################275# Helper Functions #276####################277def build_lambda_configurationchange_event(invoking_event, rule_parameters=None):278 event_to_return = {279 'configRuleName':'myrule',280 'executionRoleArn':'roleArn',281 'eventLeftScope': False,282 'invokingEvent': invoking_event,283 'accountId': '123456789012',284 'configRuleArn': 'arn:aws:config:us-east-1:123456789012:config-rule/config-rule-8fngan',285 'resultToken':'token'286 }287 if rule_parameters:288 event_to_return['ruleParameters'] = rule_parameters289 return event_to_return290def build_lambda_scheduled_event(rule_parameters=None):291 invoking_event = '{"messageType":"ScheduledNotification","notificationCreationTime":"2017-12-23T22:11:18.158Z"}'292 event_to_return = {293 'configRuleName':'myrule',294 'executionRoleArn':'roleArn',295 'eventLeftScope': False,296 'invokingEvent': invoking_event,297 'accountId': '123456789012',298 'configRuleArn': 'arn:aws:config:us-east-1:123456789012:config-rule/config-rule-8fngan',299 'resultToken':'token'300 }301 if rule_parameters:302 event_to_return['ruleParameters'] = rule_parameters303 return event_to_return304def build_expected_response(compliance_type, compliance_resource_id, compliance_resource_type=DEFAULT_RESOURCE_TYPE, annotation=None):305 if not annotation:306 return {307 'ComplianceType': compliance_type,308 'ComplianceResourceId': compliance_resource_id,309 'ComplianceResourceType': compliance_resource_type310 }311 return {312 'ComplianceType': compliance_type,313 'ComplianceResourceId': compliance_resource_id,314 'ComplianceResourceType': compliance_resource_type,315 'Annotation': annotation316 }317def assert_successful_evaluation(test_class, response, resp_expected, evaluations_count=1):318 if isinstance(response, dict):319 test_class.assertEquals(resp_expected['ComplianceResourceType'], response['ComplianceResourceType'])320 test_class.assertEquals(resp_expected['ComplianceResourceId'], response['ComplianceResourceId'])321 test_class.assertEquals(resp_expected['ComplianceType'], response['ComplianceType'])322 test_class.assertTrue(response['OrderingTimestamp'])323 if 'Annotation' in resp_expected or 'Annotation' in response:324 test_class.assertEquals(resp_expected['Annotation'], response['Annotation'])325 elif isinstance(response, list):326 test_class.assertEquals(evaluations_count, len(response))327 for i, response_expected in enumerate(resp_expected):328 test_class.assertEquals(response_expected['ComplianceResourceType'], response[i]['ComplianceResourceType'])329 test_class.assertEquals(response_expected['ComplianceResourceId'], response[i]['ComplianceResourceId'])330 test_class.assertEquals(response_expected['ComplianceType'], response[i]['ComplianceType'])331 test_class.assertTrue(response[i]['OrderingTimestamp'])332 if 'Annotation' in response_expected or 'Annotation' in response[i]:333 test_class.assertEquals(response_expected['Annotation'], response[i]['Annotation'])334def assert_customer_error_response(test_class, response, customer_error_code=None, customer_error_message=None):335 if customer_error_code:336 test_class.assertEqual(customer_error_code, response['customerErrorCode'])337 if customer_error_message:338 test_class.assertEqual(customer_error_message, response['customerErrorMessage'])339 test_class.assertTrue(response['customerErrorCode'])340 test_class.assertTrue(response['customerErrorMessage'])341 if "internalErrorMessage" in response:342 test_class.assertTrue(response['internalErrorMessage'])343 if "internalErrorDetails" in response:344 test_class.assertTrue(response['internalErrorDetails'])345def sts_mock():346 assume_role_response = {347 "Credentials": {348 "AccessKeyId": "string",349 "SecretAccessKey": "string",350 "SessionToken": "string"}}351 STS_CLIENT_MOCK.reset_mock(return_value=True)352 STS_CLIENT_MOCK.assume_role = MagicMock(return_value=assume_role_response)353##################354# Common Testing #355##################356class TestStsErrors(unittest.TestCase):357 def test_sts_unknown_error(self):358 RULE.ASSUME_ROLE_MODE = True359 RULE.evaluate_parameters = MagicMock(return_value=True)360 STS_CLIENT_MOCK.assume_role = MagicMock(side_effect=botocore.exceptions.ClientError(361 {'Error': {'Code': 'unknown-code', 'Message': 'unknown-message'}}, 'operation'))362 response = RULE.lambda_handler(build_lambda_configurationchange_event('{}'), {})363 assert_customer_error_response(364 self, response, 'InternalError', 'InternalError')365 def test_sts_access_denied(self):366 RULE.ASSUME_ROLE_MODE = True367 RULE.evaluate_parameters = MagicMock(return_value=True)368 STS_CLIENT_MOCK.assume_role = MagicMock(side_effect=botocore.exceptions.ClientError(369 {'Error': {'Code': 'AccessDenied', 'Message': 'access-denied'}}, 'operation'))370 response = RULE.lambda_handler(build_lambda_configurationchange_event('{}'), {})371 assert_customer_error_response(...

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 localstack 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