Skip to content

Commit 86f4fff

Browse files
committed
Improve tests
1 parent 829eac9 commit 86f4fff

File tree

5 files changed

+360
-5
lines changed

5 files changed

+360
-5
lines changed

.github/workflows/plone-package-test-gha.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ jobs:
2626
strategy:
2727
fail-fast: false
2828
matrix:
29-
plone-version: ['6.0', '6.1']
30-
python-version: ['3.10', '3.12']
29+
# '6.0' z3c.form ?
30+
plone-version: ['6.1']
31+
python-version: ['3.12', '3.13']
3132
steps:
3233
- name: Checkout codebase
3334
uses: actions/checkout@v4

base-6.0.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ environment-vars =
3333
zope_i18n_compile_mo_files true
3434
eggs =
3535
Plone
36+
horse-with-no-namespace
3637
Pillow
3738
imio.smartweb.common
3839
zcml =
3940
imio.smartweb.common
41+
initialization = import horse_with_no_namespace
4042

4143
[vscode]
4244
recipe = collective.recipe.vscode
@@ -62,4 +64,5 @@ scripts =
6264

6365
[versions]
6466
# Don't use a released version of imio.smartweb.common
67+
horse-with-no-namespace = 20250705.0
6568
imio.smartweb.common =

src/imio/smartweb/common/rest/endpoint.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ def search(self, query=None):
2525
if not types:
2626
raise Unauthorized("No types found, you are not allowed to search")
2727
self._constrain_query_by_path(query)
28-
if not query.get("path"):
29-
query["path"] = {"query": "/Plone"}
3028
# query = self._parse_query(query)
3129
if query.get("type_of_request") == "count_contents_types":
3230
results = self.count_contents_types(query)
@@ -164,7 +162,6 @@ def check_value_of_field(self, portal_type, field_name, expected_values):
164162
count = counter.get(key, 0)
165163
percent = (count / total) * 100 if total > 0 else 0
166164
result[label] = {"count": count, "percent": round(percent, 2)}
167-
168165
return result
169166

170167

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
# -*- coding: utf-8 -*-
2+
from imio.smartweb.common.rest.endpoint import FindEndpointHandler
3+
from imio.smartweb.common.testing import IMIO_SMARTWEB_COMMON_INTEGRATION_TESTING
4+
from plone import api
5+
from plone.app.testing import setRoles
6+
from plone.app.testing import TEST_USER_ID
7+
from plone.namedfile.file import NamedBlobFile, NamedBlobImage
8+
from unittest.mock import patch
9+
from zExceptions import Unauthorized
10+
11+
import unittest
12+
13+
14+
class TestRestEndpoint(unittest.TestCase):
15+
layer = IMIO_SMARTWEB_COMMON_INTEGRATION_TESTING
16+
17+
def setUp(self):
18+
self.request = self.layer["request"]
19+
self.portal = self.layer["portal"]
20+
21+
setRoles(self.portal, TEST_USER_ID, ["Manager"])
22+
# Simule un header d'auth présent dans la requête
23+
self.request._orig_env = {"HTTP_AUTHORIZATION": "Bearer TEST"}
24+
self.folder = api.content.create(
25+
container=self.portal,
26+
type="Folder",
27+
title="Folder",
28+
)
29+
self.doc1 = api.content.create(
30+
container=self.folder, type="Document", title="Doc 1"
31+
)
32+
self.doc2 = api.content.create(
33+
container=self.folder, type="Document", title="Doc 2"
34+
)
35+
self.page = api.content.create(
36+
container=self.folder, type="Document", title="Doc 3"
37+
)
38+
39+
def test_no_types(self):
40+
query = {
41+
"type_of_request": "count_contents_types",
42+
"portal_type": "Document",
43+
"path": {"query": self.portal.absolute_url_path()},
44+
"operator": "and",
45+
}
46+
handler = FindEndpointHandler(self.portal, self.request)
47+
self.assertRaises(Unauthorized, handler.search, query)
48+
49+
# ------------------------------
50+
# count_contents_types
51+
# ------------------------------
52+
@patch("imio.smartweb.common.rest.endpoint.get_json")
53+
def test_count_contents_types_operator_and(self, mjson):
54+
mjson.return_value = [
55+
{
56+
"@id": f"https://{self.portal.absolute_url()}/@types/Document",
57+
"addable": "false",
58+
"id": "Document",
59+
"immediately_addable": "false",
60+
"title": "Document",
61+
}
62+
]
63+
handler = FindEndpointHandler(self.portal, self.request)
64+
query = {
65+
"type_of_request": "count_contents_types",
66+
"portal_type": "Document",
67+
"path": {"query": self.portal.absolute_url_path()},
68+
"operator": "and",
69+
}
70+
res = handler.search(query)
71+
self.assertEqual(res, {"items": [{"portal_type": "Document", "nb_items": 3}]})
72+
73+
# Test without path in query.
74+
# Path is automaticaly set.
75+
query = {
76+
"type_of_request": "count_contents_types",
77+
"portal_type": "Document",
78+
"operator": "and",
79+
}
80+
res = handler.search(query)
81+
self.assertEqual(res, {"items": [{"portal_type": "Document", "nb_items": 3}]})
82+
83+
@patch("imio.smartweb.common.rest.endpoint.get_json")
84+
def test_count_contents_types_operator_or_multiple_types(self, mjson):
85+
mjson.return_value = [
86+
{
87+
"@id": f"https://{self.portal.absolute_url()}/@types/Document",
88+
"addable": "false",
89+
"id": "Document",
90+
"immediately_addable": "false",
91+
"title": "Document",
92+
},
93+
{
94+
"@id": f"https://{self.portal.absolute_url()}/@types/Folder",
95+
"addable": "false",
96+
"id": "Folder",
97+
"immediately_addable": "false",
98+
"title": "Folder",
99+
},
100+
]
101+
handler = FindEndpointHandler(self.portal, self.request)
102+
query = {
103+
"type_of_request": "count_contents_types",
104+
"portal_type": ["Document", "Folder"],
105+
"path": {"query": self.portal.absolute_url_path()},
106+
"operator": "and",
107+
}
108+
res = handler.search(query)
109+
self.assertEqual(
110+
res, {"items": [{"portal_type": ["Document", "Folder"], "nb_items": 4}]}
111+
)
112+
113+
@patch("imio.smartweb.common.rest.endpoint.get_json")
114+
def test_get_max_depth(self, mjson):
115+
mjson.return_value = [
116+
{
117+
"@id": f"https://{self.portal.absolute_url()}/@types/Document",
118+
"addable": "false",
119+
"id": "Document",
120+
"immediately_addable": "false",
121+
"title": "Document",
122+
}
123+
]
124+
handler = FindEndpointHandler(self.portal, self.request)
125+
res = handler.search({"type_of_request": "get_max_depth"})
126+
self.assertEqual(res["max_depth"], 3)
127+
128+
paths = {i["path"] for i in res["items"]}
129+
self.assertEqual(
130+
paths, {"/plone/folder/doc-2", "/plone/folder/doc-3", "/plone/folder/doc-1"}
131+
)
132+
133+
folder2 = api.content.create(
134+
container=self.folder,
135+
type="Folder",
136+
title="Folder 2",
137+
)
138+
139+
api.content.create(
140+
container=folder2,
141+
type="Document",
142+
title="Kamoulox",
143+
)
144+
handler = FindEndpointHandler(self.portal, self.request)
145+
res = handler.search({"type_of_request": "get_max_depth"})
146+
self.assertEqual(res["max_depth"], 4)
147+
148+
paths = {i["path"] for i in res["items"]}
149+
self.assertEqual(paths, {"/plone/folder/folder-2/kamoulox"})
150+
151+
@patch("imio.smartweb.common.rest.endpoint.get_json")
152+
def test_check_value_of_field_counts_and_percents(self, mjson):
153+
mjson.return_value = [
154+
{
155+
"@id": f"https://{self.portal.absolute_url()}/@types/Document",
156+
"addable": "false",
157+
"id": "Document",
158+
"immediately_addable": "false",
159+
"title": "Document",
160+
}
161+
]
162+
api.content.create(
163+
container=self.folder,
164+
type="Document",
165+
title="Doc 2",
166+
)
167+
handler = FindEndpointHandler(self.portal, self.request)
168+
q = {
169+
"type_of_request": "check_value_of_field",
170+
"portal_type": "Document",
171+
"field_name": "title",
172+
"expected_values": ["Doc 1", "Doc 2", "Doc 3"],
173+
}
174+
res = handler.search(q)
175+
# Number
176+
self.assertEqual(res["Doc 1"]["count"], 1)
177+
self.assertEqual(res["Doc 2"]["count"], 2)
178+
self.assertEqual(res["Doc 3"]["count"], 1)
179+
180+
# Pourcentages
181+
self.assertEqual(res["Doc 1"]["percent"], round(1 / 4 * 100, 2)) # 25%
182+
self.assertEqual(res["Doc 2"]["percent"], round(2 / 4 * 100, 2)) # 50%
183+
self.assertEqual(res["Doc 3"]["percent"], round(1 / 4 * 100, 2)) # 25%
184+
185+
@patch("imio.smartweb.common.rest.endpoint.get_json")
186+
def test_find_big_files_or_images(self, mjson):
187+
mjson.return_value = [
188+
{
189+
"@id": f"https://{self.portal.absolute_url()}/@types/Image",
190+
"addable": "false",
191+
"id": "Image",
192+
"immediately_addable": "false",
193+
"title": "Image",
194+
},
195+
{
196+
"@id": f"https://{self.portal.absolute_url()}/@types/File",
197+
"addable": "false",
198+
"id": "File",
199+
"immediately_addable": "false",
200+
"title": "File",
201+
},
202+
]
203+
api.content.create(
204+
container=self.folder,
205+
type="File",
206+
id="bigfile",
207+
title="Big file",
208+
file=NamedBlobFile(data=b"x" * 2500000, filename="big.pdf"), # 2,5 Mo
209+
)
210+
211+
api.content.create(
212+
container=self.folder,
213+
type="Image",
214+
id="smallimage",
215+
title="Small image",
216+
image=NamedBlobImage(data=b"x" * 100000, filename="small.jpg"), # 0,1 Mo
217+
)
218+
219+
api.content.create(
220+
container=self.folder,
221+
type="Image",
222+
id="bigimage",
223+
title="Big image",
224+
image=NamedBlobImage(data=b"x" * 3100000, filename="big.jpg"), # 3,1 Mo
225+
)
226+
handler = FindEndpointHandler(self.portal, self.request)
227+
q = {
228+
"type_of_request": "find_big_files_or_images",
229+
"portal_type": ["Image", "File"],
230+
"size": 1000000,
231+
}
232+
res = handler.search(q)
233+
# On attend seulement les gros
234+
titles = [it["title"] for it in res["items"]]
235+
self.assertEqual(set(titles), {"Big file", "Big image"})
236+
# Vérifie calcul Mo arrondi (2_500_000 bytes ≈ 2.38 Mo)
237+
big_entry = next(i for i in res["items"] if i["title"] == "Big file")
238+
self.assertAlmostEqual(big_entry["size"], round(2_500_000 / (1024 * 1024), 2))

0 commit comments

Comments
 (0)