Skip to content

Commit 7d49386

Browse files
ujsquareddavisagli
andauthored
Add tests for @inherit service endpoint (#1902)
* feat: add tests for inherit service * add changelog * fix: remove instances of accessing `inherit` from returned response; adhers to PR #1900 * fix: make suggested changes --------- Co-authored-by: David Glick <[email protected]>
1 parent c7f8645 commit 7d49386

File tree

2 files changed

+203
-0
lines changed

2 files changed

+203
-0
lines changed

news/1897.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add tests for inherit service. @ujsquared
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
from plone import api
2+
from plone.app.testing import logout
3+
from plone.app.testing import setRoles
4+
from plone.app.testing import SITE_OWNER_NAME
5+
from plone.app.testing import SITE_OWNER_PASSWORD
6+
from plone.app.testing import TEST_USER_ID
7+
from plone.behavior.registration import BehaviorRegistration
8+
from plone.restapi.testing import PLONE_RESTAPI_DX_FUNCTIONAL_TESTING
9+
from plone.restapi.testing import RelativeSession
10+
from Products.CMFCore.interfaces import IFolderish
11+
from zope import schema
12+
from zope.component import adapter
13+
from zope.component import provideAdapter
14+
from zope.component import provideUtility
15+
from zope.interface import alsoProvides
16+
from zope.interface import implementer
17+
from zope.interface import Interface
18+
19+
import transaction
20+
import unittest
21+
22+
23+
class ITestBehavior(Interface):
24+
test_field = schema.TextLine(title="Test Field", required=False)
25+
26+
27+
class ITestBehaviorMarker(Interface):
28+
pass
29+
30+
31+
class ISecondBehavior(Interface):
32+
second_field = schema.TextLine(title="Second Field", required=False)
33+
34+
35+
class ISecondBehaviorMarker(Interface):
36+
pass
37+
38+
39+
@implementer(ITestBehavior)
40+
@adapter(IFolderish)
41+
class TestBehaviorAdapter:
42+
def __init__(self, context):
43+
self.context = context
44+
45+
@property
46+
def test_field(self):
47+
return getattr(self.context, "test_field", None)
48+
49+
@test_field.setter
50+
def test_field(self, value):
51+
setattr(self.context, "test_field", value)
52+
53+
54+
@implementer(ISecondBehavior)
55+
@adapter(IFolderish)
56+
class SecondBehaviorAdapter:
57+
def __init__(self, context):
58+
self.context = context
59+
60+
@property
61+
def second_field(self):
62+
return getattr(self.context, "second_field", None)
63+
64+
@second_field.setter
65+
def second_field(self, value):
66+
setattr(self.context, "second_field", value)
67+
68+
69+
class TestServiceInherit(unittest.TestCase):
70+
layer = PLONE_RESTAPI_DX_FUNCTIONAL_TESTING
71+
72+
def setUp(self):
73+
self.portal = self.layer["portal"]
74+
setRoles(self.portal, TEST_USER_ID, ["Manager"])
75+
76+
registration = BehaviorRegistration(
77+
title="ITestBehavior Registration",
78+
description="Test behavior",
79+
interface=ITestBehavior,
80+
marker=ITestBehaviorMarker,
81+
factory=TestBehaviorAdapter,
82+
)
83+
provideUtility(registration, name="plone.testbehavior.ITestBehavior")
84+
provideAdapter(TestBehaviorAdapter)
85+
86+
# Create main test content
87+
self.parent = api.content.create(
88+
container=self.portal,
89+
type="Folder",
90+
id="test_parent",
91+
title="Parent Folder",
92+
test_field="Inherited Value",
93+
)
94+
self.child = api.content.create(
95+
container=self.parent, type="Folder", id="test_child", title="Child Folder"
96+
)
97+
alsoProvides(self.parent, ITestBehaviorMarker)
98+
99+
transaction.commit()
100+
self.api_session = RelativeSession(self.portal.absolute_url())
101+
self.api_session.headers.update({"Accept": "application/json"})
102+
self.api_session.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD)
103+
104+
def tearDown(self):
105+
self.api_session.close()
106+
with api.env.adopt_roles(["Manager"]):
107+
api.content.delete(obj=self.parent)
108+
transaction.commit()
109+
110+
def test_inherit_service_with_behavior_field(self):
111+
url = f"{self.child.absolute_url()}/@inherit?expand.inherit.behaviors=plone.testbehavior.ITestBehavior"
112+
response = self.api_session.get(url)
113+
114+
self.assertEqual(response.status_code, 200)
115+
data = response.json()
116+
behavior_data = data["plone.testbehavior.ITestBehavior"]
117+
118+
self.assertEqual(behavior_data["data"]["test_field"], "Inherited Value")
119+
self.assertEqual(behavior_data["from"]["@id"], self.parent.absolute_url())
120+
121+
def test_inherit_service_no_behavior_specified(self):
122+
response = self.api_session.get(f"{self.child.absolute_url()}/@inherit")
123+
self.assertEqual(response.json(), {})
124+
125+
def test_inherit_service_invalid_behavior(self):
126+
url = f"{self.child.absolute_url()}/@inherit?expand.inherit.behaviors=invalid.behavior"
127+
response = self.api_session.get(url)
128+
self.assertNotIn("invalid.behavior", response.json())
129+
130+
def test_inherit_multiple_behaviors(self):
131+
registration = BehaviorRegistration(
132+
title="ISecondBehavior Registration",
133+
description="Test behavior",
134+
interface=ISecondBehavior,
135+
marker=ISecondBehaviorMarker,
136+
factory=SecondBehaviorAdapter,
137+
)
138+
provideUtility(registration, name="plone.testbehavior.ISecondBehavior")
139+
provideAdapter(SecondBehaviorAdapter)
140+
141+
self.parent.second_field = "Second Value"
142+
alsoProvides(self.parent, ISecondBehaviorMarker)
143+
transaction.commit()
144+
145+
url = f"{self.child.absolute_url()}/@inherit?expand.inherit.behaviors=plone.testbehavior.ITestBehavior,plone.testbehavior.ISecondBehavior"
146+
response = self.api_session.get(url)
147+
data = response.json()
148+
149+
self.assertIn("plone.testbehavior.ISecondBehavior", data)
150+
self.assertEqual(
151+
data["plone.testbehavior.ISecondBehavior"]["data"]["second_field"],
152+
"Second Value",
153+
)
154+
155+
def test_inherit_depth(self):
156+
grandchild = api.content.create(
157+
container=self.child, type="Folder", id="grandchild"
158+
)
159+
transaction.commit()
160+
161+
url = f"{grandchild.absolute_url()}/@inherit?expand.inherit.behaviors=plone.testbehavior.ITestBehavior"
162+
response = self.api_session.get(url)
163+
data = response.json()
164+
self.assertEqual(
165+
data["plone.testbehavior.ITestBehavior"]["from"]["title"], "Parent Folder"
166+
)
167+
168+
def test_inherit_permissions(self):
169+
restricted_parent = api.content.create(
170+
container=self.portal,
171+
type="Folder",
172+
id="restricted",
173+
title="Restricted Parent",
174+
test_field="Restricted Value",
175+
)
176+
restricted_child = api.content.create(
177+
container=restricted_parent,
178+
type="Folder",
179+
id="restricted_child",
180+
title="Restricted Child",
181+
)
182+
alsoProvides(restricted_parent, ITestBehaviorMarker)
183+
transaction.commit()
184+
185+
logout()
186+
anon_session = RelativeSession(self.portal.absolute_url())
187+
anon_session.headers.update({"Accept": "application/json"})
188+
189+
url = f"{restricted_child.absolute_url()}/@inherit?expand.inherit.behaviors=plone.testbehavior.ITestBehavior"
190+
response = anon_session.get(url)
191+
self.assertEqual(response.status_code, 401)
192+
193+
def test_inherit_expansion(self):
194+
response = self.api_session.get(
195+
f"{self.child.absolute_url()}?expand=inherit&expand.inherit.behaviors=plone.testbehavior.ITestBehavior"
196+
)
197+
self.assertEqual(
198+
"Inherited Value",
199+
response.json()["@components"]["inherit"][
200+
"plone.testbehavior.ITestBehavior"
201+
]["data"]["test_field"],
202+
)

0 commit comments

Comments
 (0)