1#!/usr/bin/env python
2# Copyright 2015 the V8 project authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import mergeinfo
7import shutil
8import unittest
9
10from collections import namedtuple
11from os import path
12from subprocess import Popen, PIPE, check_call
13
14TEST_CONFIG = {
15  "GIT_REPO": "/tmp/test-v8-search-related-commits",
16}
17
18class TestMergeInfo(unittest.TestCase):
19
20  base_dir = TEST_CONFIG["GIT_REPO"]
21
22  def _execute_git(self, git_args):
23
24    fullCommand = ["git", "-C", self.base_dir] + git_args
25    p = Popen(args=fullCommand, stdin=PIPE,
26        stdout=PIPE, stderr=PIPE)
27    output, err = p.communicate()
28    rc = p.returncode
29    if rc != 0:
30      raise Exception(err)
31    return output
32
33  def setUp(self):
34    if path.exists(self.base_dir):
35      shutil.rmtree(self.base_dir)
36
37    check_call(["git", "init", self.base_dir])
38
39    # Initial commit
40    message = '''Initial commit'''
41
42    self._make_empty_commit(message)
43
44  def tearDown(self):
45    if path.exists(self.base_dir):
46      shutil.rmtree(self.base_dir)
47
48  def _assert_correct_standard_result(
49      self, result, all_commits, hash_of_first_commit):
50    self.assertEqual(len(result), 1, "Master commit not found")
51    self.assertTrue(
52        result.get(hash_of_first_commit),
53        "Master commit is wrong")
54
55    self.assertEqual(
56        len(result[hash_of_first_commit]),
57        1,
58        "Child commit not found")
59    self.assertEqual(
60        all_commits[2],
61        result[hash_of_first_commit][0],
62        "Child commit wrong")
63
64  def _get_commits(self):
65    commits = self._execute_git(
66        ["log", "--format=%H", "--reverse"]).splitlines()
67    return commits
68
69  def _make_empty_commit(self, message):
70    self._execute_git(["commit", "--allow-empty", "-m", message])
71    return self._get_commits()[-1]
72
73  def testCanDescribeCommit(self):
74    commits = self._get_commits()
75    hash_of_first_commit = commits[0]
76
77    result = mergeinfo.describe_commit(
78        self.base_dir,
79        hash_of_first_commit).splitlines()
80
81    self.assertEqual(
82        result[0],
83        'commit ' + hash_of_first_commit)
84
85  def testCanDescribeCommitSingleLine(self):
86    commits = self._get_commits()
87    hash_of_first_commit = commits[0]
88
89    result = mergeinfo.describe_commit(
90        self.base_dir,
91        hash_of_first_commit, True).splitlines()
92
93    self.assertEqual(
94        str(result[0]),
95        str(hash_of_first_commit[0:7]) + ' Initial commit')
96
97  def testSearchFollowUpCommits(self):
98    commits = self._get_commits()
99    hash_of_first_commit = commits[0]
100
101    message = 'Follow-up commit of '  + hash_of_first_commit
102    self._make_empty_commit(message)
103    self._make_empty_commit(message)
104    self._make_empty_commit(message)
105    commits = self._get_commits()
106    message = 'Not related commit'
107    self._make_empty_commit(message)
108
109    followups = mergeinfo.get_followup_commits(
110        self.base_dir,
111        hash_of_first_commit)
112    self.assertEqual(set(followups), set(commits[1:]))
113
114  def testSearchMerges(self):
115    self._execute_git(['branch', 'test'])
116    self._execute_git(['checkout', 'master'])
117    message = 'real initial commit'
118    self._make_empty_commit(message)
119    commits = self._get_commits()
120    hash_of_first_commit = commits[0]
121
122    self._execute_git(['checkout', 'test'])
123    message = 'Not related commit'
124    self._make_empty_commit(message)
125
126    # This should be found
127    message = 'Merge '  + hash_of_first_commit
128    hash_of_hit = self._make_empty_commit(message)
129
130    # This should be ignored
131    message = 'Cr-Branched-From: '  + hash_of_first_commit
132    hash_of_ignored = self._make_empty_commit(message)
133
134    self._execute_git(['checkout', 'master'])
135
136    followups = mergeinfo.get_followup_commits(
137        self.base_dir,
138        hash_of_first_commit)
139
140    # Check if follow ups and merges are not overlapping
141    self.assertEqual(len(followups), 0)
142
143    message = 'Follow-up commit of '  + hash_of_first_commit
144    hash_of_followup = self._make_empty_commit(message)
145
146    merges = mergeinfo.get_merge_commits(self.base_dir, hash_of_first_commit)
147    # Check if follow up is ignored
148    self.assertTrue(hash_of_followup not in merges)
149
150    # Check for proper return of merges
151    self.assertTrue(hash_of_hit in merges)
152    self.assertTrue(hash_of_ignored not in merges)
153
154  def testIsLkgr(self):
155    commits = self._get_commits()
156    hash_of_first_commit = commits[0]
157    self._make_empty_commit('This one is the lkgr head')
158    self._execute_git(['branch', 'remotes/origin/lkgr'])
159    hash_of_not_lkgr = self._make_empty_commit('This one is not yet lkgr')
160
161    self.assertTrue(mergeinfo.is_lkgr(
162      self.base_dir, hash_of_first_commit))
163    self.assertFalse(mergeinfo.is_lkgr(
164      self.base_dir, hash_of_not_lkgr))
165
166  def testShowFirstCanary(self):
167    commits = self._get_commits()
168    hash_of_first_commit = commits[0]
169
170    self.assertEqual(mergeinfo.get_first_canary(
171      self.base_dir, hash_of_first_commit), 'No Canary coverage')
172
173    self._execute_git(['branch', 'remotes/origin/chromium/2345'])
174    self._execute_git(['branch', 'remotes/origin/chromium/2346'])
175
176    self.assertEqual(mergeinfo.get_first_canary(
177      self.base_dir, hash_of_first_commit), '2345')
178
179if __name__ == "__main__":
180   unittest.main()
181