-
Notifications
You must be signed in to change notification settings - Fork 243
/
test_NewsItem.py
195 lines (159 loc) · 6.75 KB
/
test_NewsItem.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# test_NewsItem.py -- Portage Unit Testing Functionality
# Copyright 2007-2023 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
from portage.tests import TestCase
from portage.news import NewsItem
from portage.dbapi.virtual import fakedbapi
from dataclasses import dataclass
from string import Template
from typing import Optional
from unittest.mock import mock_open, patch
import textwrap
# The specification for news items is GLEP 42 ("Critical News Reporting"):
# https://www.gentoo.org/glep/glep-0042.html
@dataclass
class FakeNewsItem(NewsItem):
title: str
author: str
content_type: str
posted: str
revision: int
news_item_format: str
content: str
display_if_installed: Optional[list[str]] = None
display_if_profile: Optional[list[str]] = None
display_if_keyword: Optional[list[str]] = None
item_template_header = Template(
textwrap.dedent(
"""
Title: ${title}
Author: ${author}
Content-Type: ${content_type}
Posted: ${posted}
Revision: ${revision}
News-Item-Format: ${news_item_format}
"""
)
)
def __post_init__(self):
super().__init__(path="mocked_news", name=self.title)
def isValid(self):
with patch("builtins.open", mock_open(read_data=str(self))):
return super().isValid()
# TODO: Migrate __str__ to NewsItem? NewsItem doesn't actually parse
# all fields right now though.
def __str__(self) -> str:
item = self.item_template_header.substitute(
title=self.title,
author=self.author,
content_type=self.content_type,
posted=self.posted,
revision=self.revision,
news_item_format=self.news_item_format,
)
for package in self.display_if_installed:
item += f"Display-If-Installed: {package}\n"
for profile in self.display_if_profile:
item += f"Display-If-Profile: {profile}\n"
for keyword in self.display_if_keyword:
item += f"Display-If-Keyword: {keyword}\n"
item += f"\n{self.content}"
return item
class NewsItemTestCase(TestCase):
# Default values for testing
placeholders = {
"title": "YourSQL Upgrades from 4.0 to 4.1",
"author": "Ciaran McCreesh <ciaranm@gentoo.org>",
"content_type": "Content-Type: text/plain",
"posted": "01-Nov-2005",
"revision": 1,
"news_item_format": "1.0",
"display_if_installed": [],
"display_if_profile": [],
"display_if_keyword": [],
"content": textwrap.dedent(
"""
YourSQL databases created using YourSQL version 4.0 are incompatible
with YourSQL version 4.1 or later. There is no reliable way to
automate the database format conversion, so action from the system
administrator is required before an upgrade can take place.
Please see the Gentoo YourSQL Upgrade Guide for instructions:
https://gentoo.org/doc/en/yoursql-upgrading.xml
Also see the official YourSQL documentation:
https://dev.example.com/doc/refman/4.1/en/upgrading-from-4-0.html
After upgrading, you should also recompile any packages which link
against YourSQL:
revdep-rebuild --library=libyoursqlclient.so.12
The revdep-rebuild tool is provided by app-portage/gentoolkit.
"""
),
}
def setUp(self) -> None:
self.profile = "/var/db/repos/gentoo/profiles/default-linux/x86/2007.0/"
self.keywords = "x86"
# Consumers only use ARCH, so avoid portage.settings by using a dict
self.settings = {"ARCH": "x86"}
# Use fake/test dbapi to avoid slow tests
self.vardb = fakedbapi(self.settings)
def _createNewsItem(self, *kwargs) -> FakeNewsItem:
# Use our placeholders unless overridden
news_args = self.placeholders.copy()
# Substitute in what we're given to allow for easily passing
# just custom values.
news_args.update(*kwargs)
return FakeNewsItem(**news_args)
def testBasicNewsItem(self):
# Simple test with no filter fields (Display-If-*)
item = self._createNewsItem()
self.assertTrue(item.isValid())
self.assertTrue(item.isRelevant(self.vardb, self.settings, self.profile))
# Does an invalid item fail? ("a" is not a valid package name)
item = self._createNewsItem({"display_if_installed": "a"})
self.assertFalse(item.isValid())
def testDisplayIfProfile(self):
# First, just check the simple case of one profile matching ours.
item = self._createNewsItem({"display_if_profile": [self.profile]})
self.assertTrue(item.isValid())
self.assertTrue(
item.isRelevant(self.vardb, self.settings, self.profile),
msg=f"Expected {item} to be relevant, but it was not!",
)
# Test the negative case: what if the only profile listed does *not* match ours?
item = self._createNewsItem({"display_if_profile": ["profiles/i-do-not-exist"]})
self.assertTrue(item.isValid())
self.assertFalse(
item.isRelevant(self.vardb, self.settings, self.profile),
msg=f"Expected {item} to be irrelevant, but it was relevant!",
)
def testDisplayIfInstalled(self):
self.vardb.cpv_inject("sys-apps/portage-2.0", {"SLOT": "0"})
item = self._createNewsItem({"display_if_installed": ["sys-apps/portage"]})
self.assertTrue(item.isValid())
self.assertTrue(
item.isRelevant(self.vardb, self.settings, self.profile),
msg=f"Expected {item} to be relevant, but it was not!",
)
# Test the negative case: a single Display-If-Installed listing
# a package we don't have.
item = self._createNewsItem(
{"display_if_installed": ["sys-apps/i-do-not-exist"]}
)
self.assertTrue(item.isValid())
self.assertFalse(
item.isRelevant(self.vardb, self.settings, self.profile),
msg=f"Expected {item} to be irrelevant, but it was relevant!",
)
def testDisplayIfKeyword(self):
item = self._createNewsItem({"display_if_keyword": [self.keywords]})
self.assertTrue(item.isValid())
self.assertTrue(
item.isRelevant(self.vardb, self.settings, self.profile),
msg=f"Expected {item} to be relevant, but it was not!",
)
# Test the negative case: a keyword we don't have set.
item = self._createNewsItem({"display_if_keyword": ["fake-keyword"]})
self.assertTrue(item.isValid())
self.assertFalse(
item.isRelevant(self.vardb, self.settings, self.profile),
msg=f"Expected {item} to be irrelevant, but it was relevant!",
)