1#!/usr/bin/env python3 2# SPDX-License-Identifier: MIT 3 4# Copyright © 2021 Intel Corporation 5 6# Permission is hereby granted, free of charge, to any person obtaining a copy 7# of this software and associated documentation files (the "Software"), to deal 8# in the Software without restriction, including without limitation the rights 9# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10# copies of the Software, and to permit persons to whom the Software is 11# furnished to do so, subject to the following conditions: 12 13# The above copyright notice and this permission notice shall be included in 14# all copies or substantial portions of the Software. 15 16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22# SOFTWARE. 23 24from __future__ import annotations 25from unittest import mock 26import argparse 27import csv 28import contextlib 29import datetime 30import tempfile 31import os 32import pathlib 33import typing 34 35import pytest 36 37from . import gen_calendar_entries 38 39 40@contextlib.contextmanager 41def mock_csv(data: typing.List[gen_calendar_entries.CalendarRowType]) -> typing.Iterator[None]: 42 """Replace the actual CSV data with our test data.""" 43 with tempfile.TemporaryDirectory() as d: 44 c = os.path.join(d, 'calendar.csv') 45 with open(c, 'w') as f: 46 writer = csv.writer(f) 47 writer.writerows(data) 48 49 with mock.patch('bin.gen_calendar_entries.CALENDAR_CSV', pathlib.Path(c)): 50 yield 51 52 53@pytest.fixture(autouse=True, scope='module') 54def disable_git_commits() -> None: 55 """Mock out the commit function so no git commits are made during testing.""" 56 with mock.patch('bin.gen_calendar_entries.commit', mock.Mock()): 57 yield 58 59 60class TestReleaseStart: 61 62 def test_first_is_wednesday(self) -> None: 63 d = gen_calendar_entries._calculate_release_start('20', '0') 64 assert d.day == 15 65 assert d.month == 1 66 assert d.year == 2020 67 68 def test_first_is_before_wednesday(self) -> None: 69 d = gen_calendar_entries._calculate_release_start('19', '0') 70 assert d.day == 16 71 assert d.month == 1 72 assert d.year == 2019 73 74 def test_first_is_after_wednesday(self) -> None: 75 d = gen_calendar_entries._calculate_release_start('21', '0') 76 assert d.day == 13 77 assert d.month == 1 78 assert d.year == 2021 79 80 81class TestNextReleaseDate: 82 83 @contextlib.contextmanager 84 def _patch_date(date: datetime.date) -> typing.Iterator[None]: 85 mdate = mock.Mock() 86 mdate.today = mock.Mock(return_value=date) 87 with mock.patch('bin.gen_calendar_entries.datetime.date', mdate): 88 yield 89 90 class TestIsWeds: 91 92 @pytest.fixture(scope='class', autouse=True) 93 def data(self) -> None: 94 date = datetime.date(2021, 1, 6) 95 with TestNextReleaseDate._patch_date(date): 96 yield 97 98 @pytest.mark.parametrize( 99 'is_zero, expected', 100 [ 101 (True, 13), 102 (False, 20), 103 ], 104 ) 105 def test(self, is_zero: bool, expected: int) -> None: 106 date = gen_calendar_entries._calculate_next_release_date(is_zero) 107 assert date.day == expected 108 109 class TestBeforeWeds: 110 111 @pytest.fixture(scope='class', autouse=True) 112 def data(self) -> None: 113 date = datetime.date(2021, 1, 5) 114 with TestNextReleaseDate._patch_date(date): 115 yield 116 117 @pytest.mark.parametrize( 118 'is_zero, expected', 119 [ 120 (True, 13), 121 (False, 20), 122 ], 123 ) 124 def test(self, is_zero: bool, expected: int) -> None: 125 date = gen_calendar_entries._calculate_next_release_date(is_zero) 126 assert date.day == expected 127 128 class TestAfterWeds: 129 130 @pytest.fixture(scope='class', autouse=True) 131 def data(self) -> None: 132 date = datetime.date(2021, 1, 8) 133 with TestNextReleaseDate._patch_date(date): 134 yield 135 136 @pytest.mark.parametrize( 137 'is_zero, expected', 138 [ 139 (True, 13), 140 (False, 20), 141 ], 142 ) 143 def test(self, is_zero: bool, expected: int) -> None: 144 date = gen_calendar_entries._calculate_next_release_date(is_zero) 145 assert date.day == expected 146 147 148class TestRC: 149 150 ORIGINAL_DATA = [ 151 ('20.3', '2021-01-13', '20.3.3', 'Dylan Baker', ''), 152 ('', '2021-01-27', '20.3.4', 'Dylan Baker', 'Last planned release of the 20.3.x series'), 153 ] 154 155 @pytest.fixture(autouse=True, scope='class') 156 def mock_version(self) -> None: 157 """Keep the version set at a specific value.""" 158 with tempfile.TemporaryDirectory() as d: 159 v = os.path.join(d, 'version') 160 with open(v, 'w') as f: 161 f.write('21.0.0-devel\n') 162 163 with mock.patch('bin.gen_calendar_entries.VERSION', pathlib.Path(v)): 164 yield 165 166 @pytest.fixture(autouse=True) 167 def csv(self) -> None: 168 """inject our test data..""" 169 with mock_csv(self.ORIGINAL_DATA): 170 yield 171 172 def test_basic(self) -> None: 173 args: gen_calendar_entries.RCArguments = argparse.Namespace() 174 args.manager = "Dylan Baker" 175 gen_calendar_entries.release_candidate(args) 176 177 expected = self.ORIGINAL_DATA.copy() 178 expected.append(('21.0', '2021-01-13', f'21.0.0-rc1', 'Dylan Baker')) 179 expected.append(( '', '2021-01-20', f'21.0.0-rc2', 'Dylan Baker')) 180 expected.append(( '', '2021-01-27', f'21.0.0-rc3', 'Dylan Baker')) 181 expected.append(( '', '2021-02-03', f'21.0.0-rc4', 'Dylan Baker', 'Or 21.0.0 final.')) 182 183 actual = gen_calendar_entries.read_calendar() 184 185 assert actual == expected 186 187 188class TestExtend: 189 190 def test_one_release(self) -> None: 191 data = [ 192 ('20.3', '2021-01-13', '20.3.3', 'Dylan Baker', ''), 193 ('', '2021-01-27', '20.3.4', 'Dylan Baker', 'This is the last planned release of the 20.3.x series.'), 194 ] 195 196 args: gen_calendar_entries.ExtendArguments = argparse.Namespace() 197 args.series = '20.3' 198 args.count = 2 199 200 with mock_csv(data): 201 gen_calendar_entries.extend(args) 202 actual = gen_calendar_entries.read_calendar() 203 204 expected = [ 205 data[0], 206 ('', '2021-01-27', '20.3.4', 'Dylan Baker', ''), 207 ('', '2021-02-10', '20.3.5', 'Dylan Baker', ''), 208 ('', '2021-02-24', '20.3.6', 'Dylan Baker', 'This is the last planned release of the 20.3.x series.'), 209 ] 210 211 assert actual == expected 212 def test_one_release(self) -> None: 213 data = [ 214 ('20.3', '2021-01-13', '20.3.3', 'Dylan Baker', ''), 215 ('', '2021-01-27', '20.3.4', 'Dylan Baker', 'This is the last planned release of the 20.3.x series.'), 216 ('21.0', '2021-01-13', '21.0.1', 'Dylan Baker', ''), 217 ('', '2021-01-27', '21.0.2', 'Dylan Baker', ''), 218 ('', '2021-02-10', '21.0.3', 'Dylan Baker', ''), 219 ('', '2021-02-24', '21.0.4', 'Dylan Baker', 'This is the last planned release of the 21.0.x series.'), 220 ] 221 222 args: gen_calendar_entries.ExtendArguments = argparse.Namespace() 223 args.series = '21.0' 224 args.count = 1 225 226 with mock_csv(data): 227 gen_calendar_entries.extend(args) 228 actual = gen_calendar_entries.read_calendar() 229 230 expected = data.copy() 231 d = list(data[-1]) 232 d[-1] = '' 233 expected[-1] = tuple(d) 234 expected.extend([ 235 ('', '2021-03-10', '21.0.5', 'Dylan Baker', 'This is the last planned release of the 21.0.x series.'), 236 ]) 237 238 assert actual == expected 239 240 def test_rc(self) -> None: 241 data = [ 242 ('20.3', '2021-01-13', '20.3.3', 'Dylan Baker', ''), 243 ('', '2021-01-27', '20.3.4', 'Dylan Baker', 'This is the last planned release of the 20.3.x series.'), 244 ('21.0', '2021-01-13', '21.0.0-rc1', 'Dylan Baker', ''), 245 ('', '2021-01-20', '21.0.0-rc2', 'Dylan Baker', gen_calendar_entries.OR_FINAL.format('21.0')), 246 ] 247 248 args: gen_calendar_entries.ExtendArguments = argparse.Namespace() 249 args.series = '21.0' 250 args.count = 2 251 252 with mock_csv(data): 253 gen_calendar_entries.extend(args) 254 actual = gen_calendar_entries.read_calendar() 255 256 expected = data.copy() 257 d = list(expected[-1]) 258 d[-1] = '' 259 expected[-1] = tuple(d) 260 expected.extend([ 261 ('', '2021-01-27', '21.0.0-rc3', 'Dylan Baker', ''), 262 ('', '2021-02-03', '21.0.0-rc4', 'Dylan Baker', gen_calendar_entries.OR_FINAL.format('21.0')), 263 ]) 264 265 assert actual == expected 266 267 268class TestFinal: 269 270 @pytest.fixture(autouse=True, scope='class') 271 def _patch_date(self) -> typing.Iterator[None]: 272 mdate = mock.Mock() 273 mdate.today = mock.Mock(return_value=datetime.date(2021, 1, 6)) 274 with mock.patch('bin.gen_calendar_entries.datetime.date', mdate): 275 yield 276 277 ORIGINAL_DATA = [ 278 ('20.3', '2021-01-13', '20.3.3', 'Dylan Baker', ''), 279 ('', '2021-01-27', '20.3.4', 'Dylan Baker', 'Last planned release of the 20.3.x series'), 280 ] 281 282 @pytest.fixture(autouse=True) 283 def csv(self) -> None: 284 """inject our test data..""" 285 with mock_csv(self.ORIGINAL_DATA): 286 yield 287 288 def test_zero_released(self) -> None: 289 args: gen_calendar_entries.FinalArguments = argparse.Namespace() 290 args.manager = "Dylan Baker" 291 args.zero_released = True 292 args.series = '21.0' 293 gen_calendar_entries.final_release(args) 294 295 expected = self.ORIGINAL_DATA.copy() 296 expected.append(('21.0', '2021-01-20', f'21.0.1', 'Dylan Baker')) 297 expected.append(( '', '2021-02-03', f'21.0.2', 'Dylan Baker')) 298 expected.append(( '', '2021-02-17', f'21.0.3', 'Dylan Baker', gen_calendar_entries.LAST_RELEASE.format(args.series))) 299 300 actual = gen_calendar_entries.read_calendar() 301 302 assert actual == expected 303 304 def test_zero_not_released(self) -> None: 305 args: gen_calendar_entries.FinalArguments = argparse.Namespace() 306 args.manager = "Dylan Baker" 307 args.zero_released = False 308 args.series = '21.0' 309 gen_calendar_entries.final_release(args) 310 311 expected = self.ORIGINAL_DATA.copy() 312 expected.append(('21.0', '2021-01-13', f'21.0.0', 'Dylan Baker')) 313 expected.append(( '', '2021-01-27', f'21.0.1', 'Dylan Baker')) 314 expected.append(( '', '2021-02-10', f'21.0.2', 'Dylan Baker')) 315 expected.append(( '', '2021-02-24', f'21.0.3', 'Dylan Baker', gen_calendar_entries.LAST_RELEASE.format(args.series))) 316 317 actual = gen_calendar_entries.read_calendar() 318 319 assert actual == expected 320