1*61c4878aSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*61c4878aSAndroid Build Coastguard Worker# Copyright 2022 The Pigweed Authors 3*61c4878aSAndroid Build Coastguard Worker# 4*61c4878aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); you may not 5*61c4878aSAndroid Build Coastguard Worker# use this file except in compliance with the License. You may obtain a copy of 6*61c4878aSAndroid Build Coastguard Worker# the License at 7*61c4878aSAndroid Build Coastguard Worker# 8*61c4878aSAndroid Build Coastguard Worker# https://www.apache.org/licenses/LICENSE-2.0 9*61c4878aSAndroid Build Coastguard Worker# 10*61c4878aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*61c4878aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12*61c4878aSAndroid Build Coastguard Worker# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13*61c4878aSAndroid Build Coastguard Worker# License for the specific language governing permissions and limitations under 14*61c4878aSAndroid Build Coastguard Worker# the License. 15*61c4878aSAndroid Build Coastguard Worker"""Tests for gitmodules.""" 16*61c4878aSAndroid Build Coastguard Worker 17*61c4878aSAndroid Build Coastguard Workerfrom pathlib import Path 18*61c4878aSAndroid Build Coastguard Workerimport tempfile 19*61c4878aSAndroid Build Coastguard Workerimport unittest 20*61c4878aSAndroid Build Coastguard Workerfrom unittest.mock import MagicMock 21*61c4878aSAndroid Build Coastguard Worker 22*61c4878aSAndroid Build Coastguard Workerfrom pw_presubmit import gitmodules, PresubmitFailure 23*61c4878aSAndroid Build Coastguard Worker 24*61c4878aSAndroid Build Coastguard Worker 25*61c4878aSAndroid Build Coastguard Workerdef dotgitmodules( 26*61c4878aSAndroid Build Coastguard Worker name: str = 'foo', 27*61c4878aSAndroid Build Coastguard Worker url: str | None = None, 28*61c4878aSAndroid Build Coastguard Worker host: str | None = None, 29*61c4878aSAndroid Build Coastguard Worker branch: str | None = 'main', 30*61c4878aSAndroid Build Coastguard Worker): 31*61c4878aSAndroid Build Coastguard Worker cfg = f'[submodule "{name}"]\n' 32*61c4878aSAndroid Build Coastguard Worker cfg += f'path = {name}\n' 33*61c4878aSAndroid Build Coastguard Worker if url is None and host is None: 34*61c4878aSAndroid Build Coastguard Worker host = 'host' 35*61c4878aSAndroid Build Coastguard Worker if host: 36*61c4878aSAndroid Build Coastguard Worker cfg += f'url = https://{host}.googlesource.com/{name}\n' 37*61c4878aSAndroid Build Coastguard Worker else: 38*61c4878aSAndroid Build Coastguard Worker assert url 39*61c4878aSAndroid Build Coastguard Worker cfg += f'url = {url}\n' 40*61c4878aSAndroid Build Coastguard Worker if branch: 41*61c4878aSAndroid Build Coastguard Worker cfg += f'branch = {branch}\n' 42*61c4878aSAndroid Build Coastguard Worker return cfg 43*61c4878aSAndroid Build Coastguard Worker 44*61c4878aSAndroid Build Coastguard Worker 45*61c4878aSAndroid Build Coastguard Workerclass TestGitmodules(unittest.TestCase): 46*61c4878aSAndroid Build Coastguard Worker """Test gitmodules check.""" 47*61c4878aSAndroid Build Coastguard Worker 48*61c4878aSAndroid Build Coastguard Worker def setUp(self): 49*61c4878aSAndroid Build Coastguard Worker self.ctx: MagicMock = None 50*61c4878aSAndroid Build Coastguard Worker 51*61c4878aSAndroid Build Coastguard Worker def _run(self, config: gitmodules.Config, contents: str) -> None: 52*61c4878aSAndroid Build Coastguard Worker self.ctx = MagicMock() 53*61c4878aSAndroid Build Coastguard Worker self.ctx.fail = MagicMock() 54*61c4878aSAndroid Build Coastguard Worker 55*61c4878aSAndroid Build Coastguard Worker with tempfile.TemporaryDirectory() as tempdir: 56*61c4878aSAndroid Build Coastguard Worker path = Path(tempdir) / '.gitmodules' 57*61c4878aSAndroid Build Coastguard Worker with path.open('w') as outs: 58*61c4878aSAndroid Build Coastguard Worker outs.write(contents) 59*61c4878aSAndroid Build Coastguard Worker 60*61c4878aSAndroid Build Coastguard Worker gitmodules.process_gitmodules(self.ctx, config, path) 61*61c4878aSAndroid Build Coastguard Worker 62*61c4878aSAndroid Build Coastguard Worker def test_ok_no_submodules(self) -> None: 63*61c4878aSAndroid Build Coastguard Worker self._run(gitmodules.Config(), '') 64*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_not_called() 65*61c4878aSAndroid Build Coastguard Worker 66*61c4878aSAndroid Build Coastguard Worker def test_no_submodules_allowed(self) -> None: 67*61c4878aSAndroid Build Coastguard Worker self._run( 68*61c4878aSAndroid Build Coastguard Worker gitmodules.Config(allow_submodules=False), 69*61c4878aSAndroid Build Coastguard Worker dotgitmodules(url='../foo'), 70*61c4878aSAndroid Build Coastguard Worker ) 71*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_called() 72*61c4878aSAndroid Build Coastguard Worker 73*61c4878aSAndroid Build Coastguard Worker def test_ok_default(self) -> None: 74*61c4878aSAndroid Build Coastguard Worker self._run(gitmodules.Config(), dotgitmodules(url='../foo')) 75*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_not_called() 76*61c4878aSAndroid Build Coastguard Worker 77*61c4878aSAndroid Build Coastguard Worker def test_ok_restrictive(self) -> None: 78*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config( 79*61c4878aSAndroid Build Coastguard Worker allow_non_googlesource_hosts=False, 80*61c4878aSAndroid Build Coastguard Worker allowed_googlesource_hosts=('host',), 81*61c4878aSAndroid Build Coastguard Worker require_relative_urls=True, 82*61c4878aSAndroid Build Coastguard Worker allow_sso=False, 83*61c4878aSAndroid Build Coastguard Worker allow_git_corp_google_com=False, 84*61c4878aSAndroid Build Coastguard Worker require_branch=True, 85*61c4878aSAndroid Build Coastguard Worker ) 86*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules(url='../foo')) 87*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_not_called() 88*61c4878aSAndroid Build Coastguard Worker 89*61c4878aSAndroid Build Coastguard Worker def test_validate_ok(self) -> None: 90*61c4878aSAndroid Build Coastguard Worker def validator(ctx, path, name, props) -> None: 91*61c4878aSAndroid Build Coastguard Worker _ = name 92*61c4878aSAndroid Build Coastguard Worker if 'bad' in props['url']: 93*61c4878aSAndroid Build Coastguard Worker ctx.fail('bad', path) 94*61c4878aSAndroid Build Coastguard Worker 95*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config(validator=validator) 96*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules(host='host')) 97*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_not_called() 98*61c4878aSAndroid Build Coastguard Worker 99*61c4878aSAndroid Build Coastguard Worker def test_validate_fail(self) -> None: 100*61c4878aSAndroid Build Coastguard Worker def validator(ctx, path, name, props) -> None: 101*61c4878aSAndroid Build Coastguard Worker _ = name 102*61c4878aSAndroid Build Coastguard Worker if 'bad' in props['url']: 103*61c4878aSAndroid Build Coastguard Worker ctx.fail('bad', path) 104*61c4878aSAndroid Build Coastguard Worker 105*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config(validator=validator) 106*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules(host='badhost')) 107*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_called() 108*61c4878aSAndroid Build Coastguard Worker 109*61c4878aSAndroid Build Coastguard Worker def test_non_google_ok(self) -> None: 110*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config( 111*61c4878aSAndroid Build Coastguard Worker allow_non_googlesource_hosts=True 112*61c4878aSAndroid Build Coastguard Worker ) 113*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules(url='https://github.com/foo/bar')) 114*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_not_called() 115*61c4878aSAndroid Build Coastguard Worker 116*61c4878aSAndroid Build Coastguard Worker def test_non_google_fail(self) -> None: 117*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config( 118*61c4878aSAndroid Build Coastguard Worker allow_non_googlesource_hosts=False 119*61c4878aSAndroid Build Coastguard Worker ) 120*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules(url='https://github.com/foo/bar')) 121*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_called() 122*61c4878aSAndroid Build Coastguard Worker 123*61c4878aSAndroid Build Coastguard Worker def test_bad_allowed_googlesource_hosts(self) -> None: 124*61c4878aSAndroid Build Coastguard Worker with self.assertRaises(PresubmitFailure): 125*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config( 126*61c4878aSAndroid Build Coastguard Worker allowed_googlesource_hosts=('pigweed-review',) 127*61c4878aSAndroid Build Coastguard Worker ) 128*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules()) 129*61c4878aSAndroid Build Coastguard Worker 130*61c4878aSAndroid Build Coastguard Worker def test_bad_type_allowed_googlesource_hosts(self) -> None: 131*61c4878aSAndroid Build Coastguard Worker with self.assertRaises(AssertionError): 132*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config( 133*61c4878aSAndroid Build Coastguard Worker allowed_googlesource_hosts=('pigweed') 134*61c4878aSAndroid Build Coastguard Worker ) 135*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules()) 136*61c4878aSAndroid Build Coastguard Worker 137*61c4878aSAndroid Build Coastguard Worker def test_allowed_googlesource_hosts_ok(self) -> None: 138*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config( 139*61c4878aSAndroid Build Coastguard Worker allowed_googlesource_hosts=( 140*61c4878aSAndroid Build Coastguard Worker 'pigweed', 141*61c4878aSAndroid Build Coastguard Worker 'pigweed-internal', 142*61c4878aSAndroid Build Coastguard Worker ) 143*61c4878aSAndroid Build Coastguard Worker ) 144*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules(host='pigweed-internal')) 145*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_not_called() 146*61c4878aSAndroid Build Coastguard Worker 147*61c4878aSAndroid Build Coastguard Worker def test_allowed_googlesource_hosts_fail(self) -> None: 148*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config( 149*61c4878aSAndroid Build Coastguard Worker allowed_googlesource_hosts=('pigweed-internal',) 150*61c4878aSAndroid Build Coastguard Worker ) 151*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules(host='pigweed')) 152*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_called() 153*61c4878aSAndroid Build Coastguard Worker 154*61c4878aSAndroid Build Coastguard Worker def test_require_relative_urls_ok(self) -> None: 155*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config(require_relative_urls=False) 156*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules(host='foo')) 157*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_not_called() 158*61c4878aSAndroid Build Coastguard Worker 159*61c4878aSAndroid Build Coastguard Worker def test_require_relative_urls_fail(self) -> None: 160*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config(require_relative_urls=True) 161*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules(host='foo')) 162*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_called() 163*61c4878aSAndroid Build Coastguard Worker 164*61c4878aSAndroid Build Coastguard Worker def test_allow_sso_ok(self) -> None: 165*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config(allow_sso=True) 166*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules(url='sso://host/foo')) 167*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_not_called() 168*61c4878aSAndroid Build Coastguard Worker 169*61c4878aSAndroid Build Coastguard Worker def test_allow_sso_fail(self) -> None: 170*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config(allow_sso=False) 171*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules(url='sso://host/foo')) 172*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_called() 173*61c4878aSAndroid Build Coastguard Worker 174*61c4878aSAndroid Build Coastguard Worker def test_allow_git_corp_google_com_ok(self) -> None: 175*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config( 176*61c4878aSAndroid Build Coastguard Worker allow_git_corp_google_com=True 177*61c4878aSAndroid Build Coastguard Worker ) 178*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules(url='https://foo.git.corp.google.com/bar')) 179*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_not_called() 180*61c4878aSAndroid Build Coastguard Worker 181*61c4878aSAndroid Build Coastguard Worker def test_allow_git_corp_google_com_fail(self) -> None: 182*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config( 183*61c4878aSAndroid Build Coastguard Worker allow_git_corp_google_com=False 184*61c4878aSAndroid Build Coastguard Worker ) 185*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules(url='https://foo.git.corp.google.com/bar')) 186*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_called() 187*61c4878aSAndroid Build Coastguard Worker 188*61c4878aSAndroid Build Coastguard Worker def test_require_branch_ok(self) -> None: 189*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config(require_branch=False) 190*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules(branch=None)) 191*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_not_called() 192*61c4878aSAndroid Build Coastguard Worker 193*61c4878aSAndroid Build Coastguard Worker def test_require_branch_fail(self) -> None: 194*61c4878aSAndroid Build Coastguard Worker cfg: gitmodules.Config = gitmodules.Config(require_branch=True) 195*61c4878aSAndroid Build Coastguard Worker self._run(cfg, dotgitmodules(branch=None)) 196*61c4878aSAndroid Build Coastguard Worker self.ctx.fail.assert_called() 197*61c4878aSAndroid Build Coastguard Worker 198*61c4878aSAndroid Build Coastguard Worker 199*61c4878aSAndroid Build Coastguard Workerif __name__ == '__main__': 200*61c4878aSAndroid Build Coastguard Worker unittest.main() 201