Coverage for tests\test_post_api_projects.py: 100.00%

87 statements  

« prev     ^ index     » next       coverage.py v7.4.3, created at 2024-03-22 23:23 +0100

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

2 

3""" 

4* Name: interactive-clustering-gui/tests/test_post_api_projects.py 

5* Description: Unittests for `app` module on the `POST /api/projects` route. 

6* Author: Erwan Schild 

7* Created: 22/02/2022 

8* Licence: CeCILL (https://cecill.info/licences.fr.html) 

9""" 

10 

11# ============================================================================== 

12# IMPORT PYTHON DEPENDENCIES 

13# ============================================================================== 

14 

15import json 

16import os 

17from pathlib import Path 

18from typing import Any, Dict 

19 

20import pytest 

21 

22from cognitivefactory.interactive_clustering_gui.models.states import ICGUIStates 

23 

24# ============================================================================== 

25# test_ko_empty_project_name 

26# ============================================================================== 

27 

28 

29@pytest.mark.asyncio() 

30async def test_ko_empty_project_name(async_client): 

31 """ 

32 Test the `POST /api/projects` route with empty project_name. 

33 

34 Arguments: 

35 async_client: Fixture providing an HTTP client, declared in `conftest.py`. 

36 """ 

37 # Assert HTTP client is created. 

38 assert async_client 

39 

40 # Assert route `POST /api/projects` works. 

41 with open(Path(__file__).parent / "dummies" / "dummy_24.csv", "rb") as dataset_fileobject: 

42 response_post = await async_client.post( 

43 url="/api/projects", 

44 params={ 

45 "project_name": " \n ", 

46 }, 

47 files={ 

48 "dataset_file": ( 

49 "dummy_24.csv", 

50 dataset_fileobject, 

51 "text/csv", 

52 ), 

53 }, 

54 ) 

55 assert response_post.status_code == 400 

56 assert response_post.json() == { 

57 "detail": "The project name ' \n ' is invalid.", 

58 } 

59 

60 # Assert route `GET /api/projects` is kept empty. 

61 response_get = await async_client.get(url="/api/projects") 

62 assert response_get.status_code == 200 

63 assert response_get.json() == [] # noqa: WPS520 

64 

65 

66# ============================================================================== 

67# test_ko_bad_csv 

68# ============================================================================== 

69 

70 

71@pytest.mark.asyncio() 

72async def test_ko_bad_csv(async_client): 

73 """ 

74 Test the `POST /api/projects` route with bad .csv dataset. 

75 

76 Arguments: 

77 async_client: Fixture providing an HTTP client, declared in `conftest.py`. 

78 """ 

79 # Assert HTTP client is created. 

80 assert async_client 

81 

82 # Assert route `POST /api/projects` works. 

83 with open(Path(__file__).parent / "dummies" / "dummy_24.xlsx", "rb") as dataset_fileobject: 

84 response_post = await async_client.post( 

85 url="/api/projects", 

86 params={ 

87 "project_name": "unittests ! with bad .CSV", 

88 }, 

89 files={ 

90 "dataset_file": ( 

91 "dummy_24.xlsx", 

92 dataset_fileobject, 

93 "text/csv", 

94 ), 

95 }, 

96 ) 

97 assert response_post.status_code == 400 

98 assert response_post.json() == { 

99 "detail": "The dataset file is invalid. `.csv` file, with `;` separator, must contain a list of texts in the first column, with no header.", 

100 } 

101 

102 # Assert route `GET /api/projects` is kept empty. 

103 response_get = await async_client.get(url="/api/projects") 

104 assert response_get.status_code == 200 

105 assert response_get.json() == [] # noqa: WPS520 

106 

107 

108# ============================================================================== 

109# test_ko_bad_xlsx 

110# ============================================================================== 

111 

112 

113@pytest.mark.asyncio() 

114async def test_ko_bad_xlsx(async_client): 

115 """ 

116 Test the `POST /api/projects` route with bad .xlsx dataset. 

117 

118 Arguments: 

119 async_client: Fixture providing an HTTP client, declared in `conftest.py`. 

120 """ 

121 # Assert HTTP client is created. 

122 assert async_client 

123 

124 # Assert route `POST /api/projects` works. 

125 with open(Path(__file__).parent / "dummies" / "dummy_24.csv", "rb") as dataset_fileobject: 

126 response_post = await async_client.post( 

127 url="/api/projects", 

128 params={ 

129 "project_name": "unittests ! with bad .XLSX", 

130 }, 

131 files={ 

132 "dataset_file": ( 

133 "dummy_24.csv", 

134 dataset_fileobject, 

135 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", 

136 ), 

137 }, 

138 ) 

139 assert response_post.status_code == 400 

140 assert response_post.json() == { 

141 "detail": "The dataset file is invalid. `.xlsx` file must contain a list of texts in the first column, with no header.", 

142 } 

143 

144 # Assert route `GET /api/projects` is kept empty. 

145 response_get = await async_client.get(url="/api/projects") 

146 assert response_get.status_code == 200 

147 assert response_get.json() == [] # noqa: WPS520 

148 

149 

150# ============================================================================== 

151# test_ko_dataset_type 

152# ============================================================================== 

153 

154 

155@pytest.mark.asyncio() 

156async def test_ko_dataset_type(async_client): 

157 """ 

158 Test the `POST /api/projects` route with bad dataset type. 

159 

160 Arguments: 

161 async_client: Fixture providing an HTTP client, declared in `conftest.py`. 

162 """ 

163 # Assert HTTP client is created. 

164 assert async_client 

165 

166 # Assert route `POST /api/projects` works. 

167 with open(Path(__file__).parent / "dummies" / "dummy_24.txt", "rb") as dataset_fileobject: 

168 response_post = await async_client.post( 

169 url="/api/projects", 

170 params={ 

171 "project_name": "unittests ! with bad .XLSX", 

172 }, 

173 files={ 

174 "dataset_file": ( 

175 "dummy_24.txt", 

176 dataset_fileobject, 

177 "text/plain", 

178 ), 

179 }, 

180 ) 

181 assert response_post.status_code == 400 

182 assert response_post.json() == { 

183 "detail": "The file type 'text/plain' is not supported. Please use '.csv' (`;` separator) or '.xlsx' file.", 

184 } 

185 

186 # Assert route `GET /api/projects` is kept empty. 

187 response_get = await async_client.get(url="/api/projects") 

188 assert response_get.status_code == 200 

189 assert response_get.json() == [] # noqa: WPS520 

190 

191 

192# ============================================================================== 

193# test_ok_csv 

194# ============================================================================== 

195 

196 

197@pytest.mark.asyncio() 

198async def test_ok_csv(async_client, tmp_path): 

199 """ 

200 Test the `POST /api/projects` route with .csv dataset. 

201 

202 Arguments: 

203 async_client: Fixture providing an HTTP client, declared in `conftest.py`. 

204 tmp_path: The temporary path given for this test, declared in `conftest.py`. 

205 """ 

206 # Assert HTTP client is created. 

207 assert async_client 

208 

209 # Assert route `POST /api/projects` works. 

210 with open(Path(__file__).parent / "dummies" / "dummy_24.csv", "rb") as dataset_fileobject: 

211 response_post = await async_client.post( 

212 url="/api/projects", 

213 params={ 

214 "project_name": "unittests ! with .CSV", 

215 }, 

216 files={ 

217 "dataset_file": ( 

218 "dummy_24.csv", 

219 dataset_fileobject, 

220 "text/csv", 

221 ), 

222 }, 

223 ) 

224 assert response_post.status_code == 201 

225 assert list(response_post.json().keys()) == ["project_id", "detail"] 

226 created_project_id: str = response_post.json()["project_id"] 

227 

228 # Assert route `GET /api/projects` works and contains the created project. 

229 response_get = await async_client.get(url="/api/projects") 

230 assert response_get.status_code == 200 

231 assert created_project_id in response_get.json() 

232 

233 # Assert created project has needed stored files. 

234 assert sorted(os.listdir(tmp_path / created_project_id)) == [ 

235 "clustering.json", 

236 "constraints.json", 

237 "metadata.json", 

238 "modelization.json", 

239 "sampling.json", 

240 "settings.json", 

241 "status.json", 

242 "texts.json", 

243 ] 

244 

245 # Case of `metadata.json`. 

246 with open(tmp_path / created_project_id / "metadata.json", "r") as metadata_fileobject: 

247 project_metadata: Dict[str, Any] = json.load(metadata_fileobject) 

248 assert project_metadata["project_id"] == created_project_id 

249 assert project_metadata["project_name"] == "unittests ! with .CSV" 

250 assert "creation_timestamp" in project_metadata.keys() 

251 

252 # Case of `status.json`. 

253 with open(tmp_path / created_project_id / "status.json", "r") as status_fileobject: 

254 project_status: Dict[str, Any] = json.load(status_fileobject) 

255 assert project_status == { 

256 "iteration_id": 0, 

257 "state": ICGUIStates.INITIALIZATION_WITHOUT_MODELIZATION, 

258 "task": None, 

259 } 

260 

261 

262# ============================================================================== 

263# test_ok_xlsx 

264# ============================================================================== 

265 

266 

267@pytest.mark.asyncio() 

268async def test_ok_xlsx(async_client, tmp_path): 

269 """ 

270 Test the `POST /api/projects` route with .xlsx dataset. 

271 

272 Arguments: 

273 async_client: Fixture providing an HTTP client, declared in `conftest.py`. 

274 tmp_path: The temporary path given for this test, declared in `conftest.py`. 

275 """ 

276 # Assert HTTP client is created. 

277 assert async_client 

278 

279 # Assert route `POST /api/projects` works. 

280 with open(Path(__file__).parent / "dummies" / "dummy_24.xlsx", "rb") as dataset_fileobject: 

281 response_post = await async_client.post( 

282 url="/api/projects", 

283 params={ 

284 "project_name": "unittests ! with .XLSX", 

285 }, 

286 files={ 

287 "dataset_file": ( 

288 "dummy_24.xlsx", 

289 dataset_fileobject, 

290 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", 

291 ), 

292 }, 

293 ) 

294 assert response_post.status_code == 201 

295 assert list(response_post.json().keys()) == ["project_id", "detail"] 

296 created_project_id: str = response_post.json()["project_id"] 

297 

298 # Assert route `GET /api/projects` works and contains the created project. 

299 response_get = await async_client.get(url="/api/projects") 

300 assert response_get.status_code == 200 

301 assert created_project_id in response_get.json() 

302 

303 # Assert created project has needed stored files. 

304 assert sorted(os.listdir(tmp_path / created_project_id)) == [ 

305 "clustering.json", 

306 "constraints.json", 

307 "metadata.json", 

308 "modelization.json", 

309 "sampling.json", 

310 "settings.json", 

311 "status.json", 

312 "texts.json", 

313 ] 

314 

315 # Case of `metadata.json`. 

316 with open(tmp_path / created_project_id / "metadata.json", "r") as metadata_fileobject: 

317 project_metadata: Dict[str, Any] = json.load(metadata_fileobject) 

318 assert project_metadata["project_id"] == created_project_id 

319 assert project_metadata["project_name"] == "unittests ! with .XLSX" 

320 assert "creation_timestamp" in project_metadata.keys() 

321 

322 # Case of `status.json`. 

323 with open(tmp_path / created_project_id / "status.json", "r") as status_fileobject: 

324 project_status: Dict[str, Any] = json.load(status_fileobject) 

325 assert project_status == { 

326 "iteration_id": 0, 

327 "state": ICGUIStates.INITIALIZATION_WITHOUT_MODELIZATION, 

328 "task": None, 

329 }