Coverage for .tox / coverage / lib / python3.11 / site-packages / wuttaweb / testing.py: 100%

85 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-02-04 06:44 -0600

1# -*- coding: utf-8; -*- 

2################################################################################ 

3# 

4# wuttaweb -- Web App for Wutta Framework 

5# Copyright © 2024-2025 Lance Edgar 

6# 

7# This file is part of Wutta Framework. 

8# 

9# Wutta Framework is free software: you can redistribute it and/or modify it 

10# under the terms of the GNU General Public License as published by the Free 

11# Software Foundation, either version 3 of the License, or (at your option) any 

12# later version. 

13# 

14# Wutta Framework is distributed in the hope that it will be useful, but 

15# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 

16# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 

17# more details. 

18# 

19# You should have received a copy of the GNU General Public License along with 

20# Wutta Framework. If not, see <http://www.gnu.org/licenses/>. 

21# 

22################################################################################ 

23""" 

24WuttaWeb - test utilities 

25""" 

26 

27import re 

28import sys 

29from unittest.mock import MagicMock 

30 

31import fanstatic 

32import pytest 

33from pyramid import testing 

34from webtest import TestApp 

35 

36from wuttjamaican.testing import DataTestCase 

37from wuttjamaican.db.model.base import metadata 

38 

39from wuttaweb import subscribers, app as appmod 

40from wuttaweb.conf import WuttaWebConfigExtension 

41 

42 

43class WebTestCase(DataTestCase): 

44 """ 

45 Base class for test suites requiring a full (typical) web app. 

46 """ 

47 

48 mako_directories = ["wuttaweb:templates"] 

49 

50 def setUp(self): # pylint: disable=empty-docstring 

51 """ """ 

52 self.setup_web() 

53 

54 def setup_web(self): 

55 """ 

56 Perform setup for the testing web app. 

57 """ 

58 self.setup_db() 

59 self.request = self.make_request() 

60 self.pyramid_config = testing.setUp( 

61 request=self.request, 

62 settings={ 

63 "wutta_config": self.config, 

64 "mako.directories": self.mako_directories, 

65 "pyramid_deform.template_search_path": "wuttaweb:templates/deform", 

66 }, 

67 ) 

68 

69 # init web 

70 self.pyramid_config.include("pyramid_deform") 

71 self.pyramid_config.include("pyramid_mako") 

72 self.pyramid_config.add_directive( 

73 "add_wutta_permission_group", "wuttaweb.auth.add_permission_group" 

74 ) 

75 self.pyramid_config.add_directive( 

76 "add_wutta_permission", "wuttaweb.auth.add_permission" 

77 ) 

78 self.pyramid_config.add_directive( 

79 "add_wutta_master_view", "wuttaweb.conf.add_master_view" 

80 ) 

81 self.pyramid_config.add_subscriber( 

82 "wuttaweb.subscribers.before_render", "pyramid.events.BeforeRender" 

83 ) 

84 self.pyramid_config.include("wuttaweb.static") 

85 

86 # nb. mock out fanstatic env..good enough for now to avoid errors.. 

87 needed = fanstatic.init_needed() 

88 self.request.environ[fanstatic.NEEDED] = needed 

89 

90 # setup new request w/ anonymous user 

91 event = MagicMock(request=self.request) 

92 subscribers.new_request(event) 

93 

94 def user_getter(request, **kwargs): # pylint: disable=unused-argument 

95 pass 

96 

97 subscribers.new_request_set_user( 

98 event, db_session=self.session, user_getter=user_getter 

99 ) 

100 

101 def tearDown(self): 

102 self.teardown_web() 

103 

104 def teardown_web(self): 

105 """ 

106 Perform teardown for the testing web app. 

107 """ 

108 testing.tearDown() 

109 self.teardown_db() 

110 

111 def make_request(self): 

112 """ 

113 Make and return a new dummy request object. 

114 """ 

115 return testing.DummyRequest(client_addr="127.0.0.1") 

116 

117 

118@pytest.mark.versioned 

119class VersionWebTestCase(WebTestCase): 

120 """ 

121 Base class for test suites requiring a full (typical) web app, 

122 with Continuum versioning support. 

123 """ 

124 

125 def setUp(self): 

126 self.setup_versioning() 

127 

128 def setup_versioning(self): 

129 """ 

130 Perform setup for the testing web app. 

131 """ 

132 self.setup_web() 

133 

134 def tearDown(self): 

135 self.teardown_versioning() 

136 

137 def teardown_versioning(self): 

138 """ 

139 Perform teardown for the testing web app. 

140 """ 

141 import sqlalchemy_continuum as continuum # pylint: disable=import-outside-toplevel 

142 

143 continuum.remove_versioning() 

144 continuum.versioning_manager.transaction_cls = continuum.TransactionFactory() 

145 self.teardown_web() 

146 

147 def make_config(self, files=None, **kwargs): 

148 """ 

149 Make and customize the config object. 

150 

151 We override this to explicitly enable the versioning feature. 

152 """ 

153 from wutta_continuum.conf import ( # pylint: disable=import-outside-toplevel 

154 WuttaContinuumConfigExtension, 

155 ) 

156 

157 config = super().make_config(files, **kwargs) 

158 config.setdefault("wutta_continuum.enable_versioning", "true") 

159 

160 # nb. must purge model classes from sys.modules, so they will 

161 # be reloaded and sqlalchemy-continuum can reconfigure 

162 if "wuttjamaican.db.model" in sys.modules: 

163 del sys.modules["wuttjamaican.db.model.batch"] 

164 del sys.modules["wuttjamaican.db.model.upgrades"] 

165 del sys.modules["wuttjamaican.db.model.auth"] 

166 del sys.modules["wuttjamaican.db.model.base"] 

167 del sys.modules["wuttjamaican.db.model"] 

168 

169 self.assertNotIn("user_version", metadata.tables) 

170 

171 ext = WuttaWebConfigExtension() 

172 ext.configure(config) 

173 

174 ext = WuttaContinuumConfigExtension() 

175 ext.startup(config) 

176 

177 return config 

178 

179 

180# TODO: this interface likely needs to change. it is only used 

181# by a single test so far, in tests/views/test_users.py 

182@pytest.mark.functional 

183class FunctionalTestCase(DataTestCase): 

184 """ 

185 Base class for test suites requiring a fully complete web app, for 

186 sake of functional tests. 

187 

188 .. warning:: 

189 

190 This class is very new and not yet mature; it will surely change. 

191 """ 

192 

193 wsgi_main_app = None 

194 

195 def make_config(self, **kwargs): # pylint: disable=arguments-differ 

196 sqlite_path = self.write_file("test.sqlite", "") 

197 self.sqlite_engine_url = f"sqlite:///{sqlite_path}" 

198 

199 config_path = self.write_file( 

200 "test.ini", 

201 f""" 

202[wutta.db] 

203default.url = {self.sqlite_engine_url} 

204 

205[alembic] 

206script_location = wuttjamaican.db:alembic 

207version_locations = wuttjamaican.db:alembic/versions 

208""", 

209 ) 

210 

211 return super().make_config([config_path], **kwargs) 

212 

213 def make_webtest(self): # pylint: disable=missing-function-docstring 

214 webapp = appmod.make_wsgi_app( 

215 self.wsgi_main_app or appmod.main, config=self.config 

216 ) 

217 

218 return TestApp(webapp) 

219 

220 def get_csrf_token(self, testapp): # pylint: disable=missing-function-docstring 

221 res = testapp.get("/login") 

222 match = re.search( 

223 r'<input name="_csrf" type="hidden" value="(\w+)" />', res.text 

224 ) 

225 self.assertTrue(match) 

226 return match.group(1)