Mikhail Kraynov | e5cc81b | 2018-10-03 13:01:06 +0400 | [diff] [blame] | 1 | import jenkins |
Oleksii Zhurba | a25984b | 2018-06-15 15:30:41 -0500 | [diff] [blame] | 2 | from xml.dom import minidom |
| 3 | from cvp_checks import utils |
| 4 | import json |
| 5 | import pytest |
Mikhail Kraynov | 351e841 | 2018-10-04 18:27:44 +0400 | [diff] [blame] | 6 | import time |
| 7 | import os |
| 8 | from pygerrit2 import GerritRestAPI, HTTPBasicAuth |
| 9 | from requests import HTTPError |
| 10 | import git |
| 11 | |
| 12 | def join_to_gerrit(local_salt_client, gerrit_user, gerrit_password): |
| 13 | gerrit_port = local_salt_client.cmd( |
| 14 | 'I@gerrit:client and not I@salt:master', |
| 15 | 'pillar.get', |
| 16 | ['_param:haproxy_gerrit_bind_port'], |
| 17 | expr_form='compound').values()[0] |
| 18 | gerrit_address = local_salt_client.cmd( |
| 19 | 'I@gerrit:client and not I@salt:master', |
| 20 | 'pillar.get', |
| 21 | ['_param:haproxy_gerrit_bind_host'], |
| 22 | expr_form='compound').values()[0] |
| 23 | url = 'http://{0}:{1}'.format(gerrit_address,gerrit_port) |
| 24 | auth = HTTPBasicAuth(gerrit_user, gerrit_password) |
| 25 | rest = GerritRestAPI(url=url, auth=auth) |
| 26 | return rest |
Oleksii Zhurba | a25984b | 2018-06-15 15:30:41 -0500 | [diff] [blame] | 27 | |
Mikhail Kraynov | e5cc81b | 2018-10-03 13:01:06 +0400 | [diff] [blame] | 28 | def join_to_jenkins(local_salt_client, jenkins_user, jenkins_password): |
| 29 | jenkins_port = local_salt_client.cmd( |
| 30 | 'I@jenkins:client and not I@salt:master', |
| 31 | 'pillar.get', |
| 32 | ['_param:haproxy_jenkins_bind_port'], |
| 33 | expr_form='compound').values()[0] |
| 34 | jenkins_address = local_salt_client.cmd( |
| 35 | 'I@jenkins:client and not I@salt:master', |
| 36 | 'pillar.get', |
| 37 | ['_param:haproxy_jenkins_bind_host'], |
| 38 | expr_form='compound').values()[0] |
| 39 | jenkins_url = 'http://{0}:{1}'.format(jenkins_address,jenkins_port) |
| 40 | server = jenkins.Jenkins(jenkins_url, username=jenkins_user, password=jenkins_password) |
| 41 | return server |
| 42 | |
Mikhail Kraynov | 351e841 | 2018-10-04 18:27:44 +0400 | [diff] [blame] | 43 | def get_password(local_salt_client,service): |
| 44 | password = local_salt_client.cmd( |
| 45 | service, |
Mikhail Kraynov | e5cc81b | 2018-10-03 13:01:06 +0400 | [diff] [blame] | 46 | 'pillar.get', |
| 47 | ['_param:openldap_admin_password'], |
| 48 | expr_form='pillar').values()[0] |
Mikhail Kraynov | 351e841 | 2018-10-04 18:27:44 +0400 | [diff] [blame] | 49 | return password |
| 50 | |
| 51 | def test_drivetrain_gerrit(local_salt_client): |
| 52 | gerrit_password = get_password(local_salt_client,'gerrit:client') |
| 53 | gerrit_error = '' |
| 54 | current_date = time.strftime("%Y%m%d-%H.%M.%S", time.localtime()) |
| 55 | test_proj_name = "test-dt-{0}".format(current_date) |
| 56 | gerrit_port = local_salt_client.cmd( |
| 57 | 'I@gerrit:client and not I@salt:master', |
| 58 | 'pillar.get', |
| 59 | ['_param:haproxy_gerrit_bind_port'], |
| 60 | expr_form='compound').values()[0] |
| 61 | gerrit_address = local_salt_client.cmd( |
| 62 | 'I@gerrit:client and not I@salt:master', |
| 63 | 'pillar.get', |
| 64 | ['_param:haproxy_gerrit_bind_host'], |
| 65 | expr_form='compound').values()[0] |
| 66 | try: |
| 67 | #Connecting to gerrit and check connection |
| 68 | server = join_to_gerrit(local_salt_client,'admin',gerrit_password) |
| 69 | gerrit_check = server.get("/changes/?q=owner:self%20status:open") |
| 70 | #Check deleteproject plugin and skip test if the plugin is not installed |
| 71 | gerrit_plugins = server.get("/plugins/?all") |
| 72 | if 'deleteproject' not in gerrit_plugins: |
| 73 | pytest.skip("Delete-project plugin is not installed") |
| 74 | #Create test project and add description |
| 75 | server.put("/projects/"+test_proj_name) |
| 76 | server.put("/projects/"+test_proj_name+"/description",json={"description":"Test DriveTrain project","commit_message": "Update the project description"}) |
| 77 | except HTTPError, e: |
| 78 | gerrit_error = e |
| 79 | try: |
| 80 | #Create test folder and init git |
| 81 | repo_dir = os.path.join(os.getcwd(),test_proj_name) |
| 82 | file_name = os.path.join(repo_dir, current_date) |
| 83 | repo = git.Repo.init(repo_dir) |
| 84 | #Add remote url for this git repo |
| 85 | origin = repo.create_remote('origin', 'http://admin:{1}@{2}:{3}/{0}.git'.format(test_proj_name,gerrit_password,gerrit_address,gerrit_port)) |
| 86 | #Add commit-msg hook to automatically add Change-Id to our commit |
| 87 | os.system("curl -Lo {0}/.git/hooks/commit-msg 'http://admin:{1}@{2}:{3}/tools/hooks/commit-msg' > /dev/null 2>&1".format(repo_dir,gerrit_password,gerrit_address,gerrit_port)) |
| 88 | os.system("chmod u+x {0}/.git/hooks/commit-msg".format(repo_dir)) |
| 89 | #Create a test file |
| 90 | f = open(file_name, 'w+') |
| 91 | f.write("This is a test file for DriveTrain test") |
| 92 | f.close() |
| 93 | #Add file to git and commit it to Gerrit for review |
| 94 | repo.index.add([file_name]) |
| 95 | repo.index.commit("This is a test commit for DriveTrain test") |
| 96 | repo.git.push("origin", "HEAD:refs/for/master") |
| 97 | #Get change id from Gerrit. Set Code-Review +2 and submit this change |
| 98 | changes = server.get("/changes/?q=project:{0}".format(test_proj_name)) |
| 99 | last_change = changes[0].get('change_id') |
| 100 | server.post("/changes/{0}/revisions/1/review".format(last_change),json={"message":"All is good","labels":{"Code-Review":"+2"}}) |
| 101 | server.post("/changes/{0}/submit".format(last_change)) |
| 102 | except HTTPError, e: |
| 103 | gerrit_error = e |
| 104 | finally: |
| 105 | #Delete test project |
| 106 | server.post("/projects/"+test_proj_name+"/deleteproject~delete") |
| 107 | assert gerrit_error == '',\ |
| 108 | 'Something is wrong with Gerrit'.format(gerrit_error) |
| 109 | |
| 110 | |
| 111 | def test_drivetrain_jenkins_job(local_salt_client): |
| 112 | jenkins_password = get_password(local_salt_client,'jenkins:client') |
Mikhail Kraynov | e5cc81b | 2018-10-03 13:01:06 +0400 | [diff] [blame] | 113 | server = join_to_jenkins(local_salt_client,'admin',jenkins_password) |
| 114 | #Getting Jenkins test job name from configuration |
| 115 | config = utils.get_configuration() |
| 116 | jenkins_test_job = config['jenkins_test_job'] |
| 117 | if not jenkins_test_job or jenkins_test_job == '': |
| 118 | jenkins_test_job = 'git-mirror-downstream-mk-pipelines' |
| 119 | if server.get_job_name(jenkins_test_job): |
| 120 | next_build_num = server.get_job_info(jenkins_test_job)['nextBuildNumber'] |
| 121 | #If this is first build number skip building check |
| 122 | if next_build_num != 1: |
| 123 | #Check that test job is not running at this moment, |
| 124 | #Otherwise skip the test |
| 125 | last_build_num = server.get_job_info(jenkins_test_job)['lastBuild'].get('number') |
| 126 | last_build_status = server.get_build_info(jenkins_test_job,last_build_num)['building'] |
| 127 | if last_build_status: |
| 128 | pytest.skip("Test job {0} is already running").format(jenkins_test_job) |
| 129 | #This jenkins module doesn't work with build_job function without parameters |
| 130 | #Just send some fake parameters. All others will be used from default values |
| 131 | param_dict = {'foo':'bar'} |
| 132 | server.build_job(jenkins_test_job, param_dict) |
| 133 | timeout = 0 |
| 134 | #Use job status True by default to exclude timeout between build job and start job. |
| 135 | job_status = True |
| 136 | while job_status and ( timeout < 180 ): |
Mikhail Kraynov | 351e841 | 2018-10-04 18:27:44 +0400 | [diff] [blame] | 137 | time.sleep(10) |
Mikhail Kraynov | e5cc81b | 2018-10-03 13:01:06 +0400 | [diff] [blame] | 138 | timeout += 10 |
| 139 | job_status = server.get_build_info(jenkins_test_job,next_build_num)['building'] |
| 140 | job_result = server.get_build_info(jenkins_test_job,next_build_num)['result'] |
| 141 | else: |
| 142 | pytest.skip("The job {0} was not found").format(test_job_name) |
| 143 | assert job_result == 'SUCCESS', \ |
| 144 | '''Test job '{0}' build was not successfull or timeout is too small |
| 145 | '''.format(jenkins_test_job) |
Oleksii Zhurba | a25984b | 2018-06-15 15:30:41 -0500 | [diff] [blame] | 146 | |
| 147 | def test_drivetrain_services_replicas(local_salt_client): |
| 148 | salt_output = local_salt_client.cmd( |
Oleksii Zhurba | 0aeedf7 | 2018-07-30 11:24:01 -0500 | [diff] [blame] | 149 | 'I@gerrit:client', |
Oleksii Zhurba | a25984b | 2018-06-15 15:30:41 -0500 | [diff] [blame] | 150 | 'cmd.run', |
| 151 | ['docker service ls'], |
| 152 | expr_form='compound') |
| 153 | wrong_items = [] |
| 154 | for line in salt_output[salt_output.keys()[0]].split('\n'): |
| 155 | if line[line.find('/') - 1] != line[line.find('/') + 1] \ |
| 156 | and 'replicated' in line: |
| 157 | wrong_items.append(line) |
| 158 | assert len(wrong_items) == 0, \ |
| 159 | '''Some DriveTrain services doesn't have expected number of replicas: |
| 160 | {}'''.format(json.dumps(wrong_items, indent=4)) |
| 161 | |
| 162 | |
| 163 | def test_drivetrain_components_and_versions(local_salt_client): |
| 164 | config = utils.get_configuration() |
| 165 | version = config['drivetrain_version'] or [] |
| 166 | if not version or version == '': |
| 167 | pytest.skip("drivetrain_version is not defined. Skipping") |
| 168 | salt_output = local_salt_client.cmd( |
Oleksii Zhurba | 0aeedf7 | 2018-07-30 11:24:01 -0500 | [diff] [blame] | 169 | 'I@gerrit:client', |
Oleksii Zhurba | a25984b | 2018-06-15 15:30:41 -0500 | [diff] [blame] | 170 | 'cmd.run', |
| 171 | ['docker service ls'], |
| 172 | expr_form='compound') |
| 173 | not_found_services = ['gerrit_db', 'gerrit_server', 'jenkins_master', |
| 174 | 'jenkins_slave01', 'jenkins_slave02', |
| 175 | 'jenkins_slave03', 'ldap_admin', 'ldap_server'] |
| 176 | version_mismatch = [] |
| 177 | for line in salt_output[salt_output.keys()[0]].split('\n'): |
| 178 | for service in not_found_services: |
| 179 | if service in line: |
| 180 | not_found_services.remove(service) |
| 181 | if version != line.split()[4].split(':')[1]: |
| 182 | version_mismatch.append("{0}: expected " |
| 183 | "version is {1}, actual - {2}".format(service,version, |
| 184 | line.split()[4].split(':')[1])) |
| 185 | continue |
| 186 | assert len(not_found_services) == 0, \ |
| 187 | '''Some DriveTrain components are not found: |
| 188 | {}'''.format(json.dumps(not_found_services, indent=4)) |
| 189 | assert len(version_mismatch) == 0, \ |
| 190 | '''Version mismatch found: |
| 191 | {}'''.format(json.dumps(version_mismatch, indent=4)) |
| 192 | |
| 193 | |
| 194 | def test_jenkins_jobs_branch(local_salt_client): |
| 195 | config = utils.get_configuration() |
| 196 | expected_version = config['drivetrain_version'] or [] |
| 197 | if not expected_version or expected_version == '': |
| 198 | pytest.skip("drivetrain_version is not defined. Skipping") |
Mikhail Kraynov | 351e841 | 2018-10-04 18:27:44 +0400 | [diff] [blame] | 199 | jenkins_password = get_password(local_salt_client,'jenkins:client') |
Oleksii Zhurba | a25984b | 2018-06-15 15:30:41 -0500 | [diff] [blame] | 200 | version_mismatch = [] |
Mikhail Kraynov | e5cc81b | 2018-10-03 13:01:06 +0400 | [diff] [blame] | 201 | server = join_to_jenkins(local_salt_client,'admin',jenkins_password) |
| 202 | for job_instance in server.get_jobs(): |
| 203 | job_name = job_instance.get('name') |
| 204 | job_config = server.get_job_config(job_name) |
Oleksii Zhurba | a25984b | 2018-06-15 15:30:41 -0500 | [diff] [blame] | 205 | xml_data = minidom.parseString(job_config) |
| 206 | BranchSpec = xml_data.getElementsByTagName('hudson.plugins.git.BranchSpec') |
Mikhail Kraynov | e5cc81b | 2018-10-03 13:01:06 +0400 | [diff] [blame] | 207 | #We use master branch for pipeline-library in case of 'testing,stable,nighlty' versions |
| 208 | if expected_version in ['testing','nightly','stable']: |
| 209 | expected_version = 'master' |
Oleksii Zhurba | a25984b | 2018-06-15 15:30:41 -0500 | [diff] [blame] | 210 | if BranchSpec: |
| 211 | actual_version = BranchSpec[0].getElementsByTagName('name')[0].childNodes[0].data |
Mikhail Kraynov | e5cc81b | 2018-10-03 13:01:06 +0400 | [diff] [blame] | 212 | if ( actual_version != expected_version ) and ( job_name not in ['cvp-func','cvp-ha','cvp-perf'] ) : |
Oleksii Zhurba | a25984b | 2018-06-15 15:30:41 -0500 | [diff] [blame] | 213 | version_mismatch.append("Job {0} has {1} branch." |
Mikhail Kraynov | e5cc81b | 2018-10-03 13:01:06 +0400 | [diff] [blame] | 214 | "Expected {2}".format(job_name, |
Oleksii Zhurba | a25984b | 2018-06-15 15:30:41 -0500 | [diff] [blame] | 215 | actual_version, |
| 216 | expected_version)) |
| 217 | assert len(version_mismatch) == 0, \ |
| 218 | '''Some DriveTrain jobs have version/branch mismatch: |
| 219 | {}'''.format(json.dumps(version_mismatch, indent=4)) |