blob: 984644fc56206aa70a7bba2a7da0ae7b277b3667 [file] [log] [blame]
Antoine Mussobfd8f2a2014-09-23 15:31:40 +02001#!/usr/bin/env python
2
3# Copyright 2012 Hewlett-Packard Development Company, L.P.
4# Copyright 2014 Wikimedia Foundation Inc.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17
18import logging
19import os
20
21import git
James E. Blairba1c8c02017-10-04 08:47:48 -070022import testtools
Antoine Mussobfd8f2a2014-09-23 15:31:40 +020023
24from zuul.merger.merger import Repo
Tobias Henkel054eccc2017-12-20 11:36:19 +010025from tests.base import ZuulTestCase, FIXTURE_DIR, simple_layout
Antoine Mussobfd8f2a2014-09-23 15:31:40 +020026
Antoine Mussobfd8f2a2014-09-23 15:31:40 +020027
28class TestMergerRepo(ZuulTestCase):
29
30 log = logging.getLogger("zuul.test.merger.repo")
Paul Belanger83481b32016-11-13 19:00:23 -050031 tenant_config_file = 'config/single-tenant/main.yaml'
Antoine Mussobfd8f2a2014-09-23 15:31:40 +020032 workspace_root = None
33
34 def setUp(self):
Paul Belanger83481b32016-11-13 19:00:23 -050035 super(TestMergerRepo, self).setUp()
36 self.workspace_root = os.path.join(self.test_root, 'workspace')
Antoine Mussobfd8f2a2014-09-23 15:31:40 +020037
38 def test_ensure_cloned(self):
39 parent_path = os.path.join(self.upstream_root, 'org/project1')
40
41 # Forge a repo having a submodule
42 parent_repo = git.Repo(parent_path)
43 parent_repo.git.submodule('add', os.path.join(
44 self.upstream_root, 'org/project2'), 'subdir')
45 parent_repo.index.commit('Adding project2 as a submodule in subdir')
46 # git 1.7.8 changed .git from being a directory to a file pointing
47 # to the parent repository /.git/modules/*
48 self.assertTrue(os.path.exists(
49 os.path.join(parent_path, 'subdir', '.git')),
50 msg='.git file in submodule should be a file')
51
52 work_repo = Repo(parent_path, self.workspace_root,
Paul Belangeredadfed2017-10-05 16:04:27 -040053 'none@example.org', 'User Name', '0', '0')
Antoine Mussobfd8f2a2014-09-23 15:31:40 +020054 self.assertTrue(
55 os.path.isdir(os.path.join(self.workspace_root, 'subdir')),
56 msg='Cloned repository has a submodule placeholder directory')
57 self.assertFalse(os.path.exists(
58 os.path.join(self.workspace_root, 'subdir', '.git')),
59 msg='Submodule is not initialized')
60
61 sub_repo = Repo(
62 os.path.join(self.upstream_root, 'org/project2'),
63 os.path.join(self.workspace_root, 'subdir'),
Paul Belangeredadfed2017-10-05 16:04:27 -040064 'none@example.org', 'User Name', '0', '0')
Antoine Mussobfd8f2a2014-09-23 15:31:40 +020065 self.assertTrue(os.path.exists(
66 os.path.join(self.workspace_root, 'subdir', '.git')),
67 msg='Cloned over the submodule placeholder')
68
zhangyangyangc3e786f2017-09-13 10:47:52 +080069 self.assertEqual(
Antoine Mussobfd8f2a2014-09-23 15:31:40 +020070 os.path.join(self.upstream_root, 'org/project1'),
71 work_repo.createRepoObject().remotes[0].url,
72 message="Parent clone still point to upstream project1")
73
zhangyangyangc3e786f2017-09-13 10:47:52 +080074 self.assertEqual(
Antoine Mussobfd8f2a2014-09-23 15:31:40 +020075 os.path.join(self.upstream_root, 'org/project2'),
76 sub_repo.createRepoObject().remotes[0].url,
77 message="Sub repository points to upstream project2")
James E. Blairba1c8c02017-10-04 08:47:48 -070078
79 def test_clone_timeout(self):
80 parent_path = os.path.join(self.upstream_root, 'org/project1')
81 self.patch(git.Git, 'GIT_PYTHON_GIT_EXECUTABLE',
82 os.path.join(FIXTURE_DIR, 'fake_git.sh'))
83 work_repo = Repo(parent_path, self.workspace_root,
84 'none@example.org', 'User Name', '0', '0',
James E. Blairea398b52018-01-30 15:10:26 -080085 git_timeout=0.001, retry_attempts=1)
James E. Blairba1c8c02017-10-04 08:47:48 -070086 # TODO: have the merger and repo classes catch fewer
87 # exceptions, including this one on initialization. For the
88 # test, we try cloning again.
89 with testtools.ExpectedException(git.exc.GitCommandError,
90 '.*exit code\(-9\)'):
91 work_repo._ensure_cloned()
92
93 def test_fetch_timeout(self):
94 parent_path = os.path.join(self.upstream_root, 'org/project1')
95 work_repo = Repo(parent_path, self.workspace_root,
James E. Blairea398b52018-01-30 15:10:26 -080096 'none@example.org', 'User Name', '0', '0',
97 retry_attempts=1)
James E. Blairba1c8c02017-10-04 08:47:48 -070098 work_repo.git_timeout = 0.001
99 self.patch(git.Git, 'GIT_PYTHON_GIT_EXECUTABLE',
100 os.path.join(FIXTURE_DIR, 'fake_git.sh'))
101 with testtools.ExpectedException(git.exc.GitCommandError,
102 '.*exit code\(-9\)'):
103 work_repo.update()
James E. Blairea398b52018-01-30 15:10:26 -0800104
105 def test_fetch_retry(self):
106 parent_path = os.path.join(self.upstream_root, 'org/project1')
107 work_repo = Repo(parent_path, self.workspace_root,
108 'none@example.org', 'User Name', '0', '0',
109 retry_interval=1)
110 self.patch(git.Git, 'GIT_PYTHON_GIT_EXECUTABLE',
111 os.path.join(FIXTURE_DIR, 'git_fetch_error.sh'))
112 work_repo.update()
113 # This is created on the first fetch
114 self.assertTrue(os.path.exists(os.path.join(
115 self.workspace_root, 'stamp1')))
116 # This is created on the second fetch
117 self.assertTrue(os.path.exists(os.path.join(
118 self.workspace_root, 'stamp2')))
Tobias Henkel054eccc2017-12-20 11:36:19 +0100119
120
121class TestMergerWithAuthUrl(ZuulTestCase):
122 config_file = 'zuul-github-driver.conf'
123
124 git_url_with_auth = True
125
126 @simple_layout('layouts/merging-github.yaml', driver='github')
127 def test_changing_url(self):
128 """
129 This test checks that if getGitUrl returns different urls for the same
130 repo (which happens if an access token is part of the url) then the
131 remote urls are changed in the merger accordingly. This tests directly
132 the merger.
133 """
134
135 merger = self.executor_server.merger
136 repo = merger.getRepo('github', 'org/project')
137 first_url = repo.remote_url
138
139 repo = merger.getRepo('github', 'org/project')
140 second_url = repo.remote_url
141
142 # the urls should differ
143 self.assertNotEqual(first_url, second_url)
144
145 @simple_layout('layouts/merging-github.yaml', driver='github')
146 def test_changing_url_end_to_end(self):
147 """
148 This test checks that if getGitUrl returns different urls for the same
149 repo (which happens if an access token is part of the url) then the
150 remote urls are changed in the merger accordingly. This is an end to
151 end test.
152 """
153
154 A = self.fake_github.openFakePullRequest('org/project', 'master',
155 'PR title')
156 self.fake_github.emitEvent(A.getCommentAddedEvent('merge me'))
157 self.waitUntilSettled()
158 self.assertTrue(A.is_merged)
159
160 # get remote url of org/project in merger
161 repo = self.executor_server.merger.repos.get('github.com/org/project')
162 self.assertIsNotNone(repo)
163 git_repo = git.Repo(repo.local_path)
164 first_url = list(git_repo.remotes[0].urls)[0]
165
166 B = self.fake_github.openFakePullRequest('org/project', 'master',
167 'PR title')
168 self.fake_github.emitEvent(B.getCommentAddedEvent('merge me again'))
169 self.waitUntilSettled()
170 self.assertTrue(B.is_merged)
171
172 repo = self.executor_server.merger.repos.get('github.com/org/project')
173 self.assertIsNotNone(repo)
174 git_repo = git.Repo(repo.local_path)
175 second_url = list(git_repo.remotes[0].urls)[0]
176
177 # the urls should differ
178 self.assertNotEqual(first_url, second_url)