@@ -74,102 +74,11 @@ def test_outbox_not_found():
7474 response = APIClient ().get (reverse ("actor-outbox" , kwargs = {"pk" : 99999 }))
7575 assert response .status_code == status .HTTP_404_NOT_FOUND
7676
77-
78- # LOLA Authentication Tests
79-
8077"""
81- Tests the complete request-response cycle with different authentication states
82- to verify that endpoints properly serve enhanced data for LOLA-authenticated requests .
78+ Edge case tests for LOLA authentication.
79+ These tests focus on specific edge cases: URL params, outbox filtering, error handling, headers .
8380"""
8481class TestLOLAAuthenticationAPI :
85- # Constants for OAuth scopes
86- LOLA_SCOPE = 'activitypub_account_portability read write'
87- BASIC_SCOPE = 'read write'
88-
89- # Helper methods for repeated assertions
90-
91- # Helper to verify standard ActivityPub fields
92- def assert_basic_activitypub_structure (self , data , actor , mock_request ):
93- assert data ["@context" ] == build_actor_context ()
94- assert data ["type" ] == "Person"
95-
96- assert data ["id" ] == build_actor_id (actor .id , mock_request )
97- assert data ["preferredUsername" ] == actor .username
98-
99- # Helper to verify LOLA fields are absent
100- def assert_no_lola_fields (self , data ):
101- lola_fields = ["accountPortabilityOauth" , "content" , "blocked" , "migration" ]
102- for field in lola_fields :
103- assert field not in data
104-
105- # Helper to verify LOLA fields are present and properly formatted
106- def assert_has_lola_fields (self , data , actor ):
107- assert "accountPortabilityOauth" in data
108- assert "content" in data
109- assert "blocked" in data
110- assert "migration" in data
111-
112- # Verify LOLA URLs are properly formatted
113- assert data ["accountPortabilityOauth" ].endswith ("/oauth/authorize/" )
114- assert data ["content" ].endswith (f"/actors/{ actor .id } /content" )
115- assert data ["blocked" ].endswith (f"/actors/{ actor .id } /blocked" )
116- assert data ["migration" ].endswith (f"/actors/{ actor .id } /outbox" )
117-
118- # Helper to create authenticated client
119- def get_authenticated_client (self , token ):
120- client = APIClient ()
121- client .credentials (HTTP_AUTHORIZATION = f'Bearer { token .token } ' )
122- return client
123-
124- # Test that unauthenticated requests return basic ActivityPub data only
125- @pytest .mark .django_db
126- def test_actor_detail_unauthenticated_returns_basic_activitypub (self , mock_request ):
127- actor = create_isolated_actor ("unauthenticated_test" )
128- client = APIClient ()
129-
130- response = client .get (reverse ("actor-detail" , kwargs = {"pk" : actor .id }))
131-
132- # Should succeed with basic ActivityPub response
133- assert response .status_code == status .HTTP_200_OK
134-
135- data = response .data
136- # Use helper methods for assertions
137- self .assert_basic_activitypub_structure (data , actor , mock_request )
138- self .assert_no_lola_fields (data )
139-
140- # Test that LOLA-authenticated requests return enhanced data with collection URLs
141- @pytest .mark .django_db
142- def test_actor_detail_with_lola_scope_returns_enhanced_data (self , mock_request ):
143- actor = create_isolated_actor ("lola_enhanced_test" )
144- lola_token = AccessTokenFactory (lola_scope = True )
145- client = self .get_authenticated_client (lola_token )
146-
147- response = client .get (reverse ("actor-detail" , kwargs = {"pk" : actor .id }))
148-
149- # Should succeed with enhanced response
150- assert response .status_code == status .HTTP_200_OK
151-
152- data = response .data
153- # Use helper methods for assertions
154- self .assert_basic_activitypub_structure (data , actor , mock_request )
155- self .assert_has_lola_fields (data , actor )
156-
157- # Test that authenticated requests without LOLA scope return basic data
158- @pytest .mark .django_db
159- def test_actor_detail_with_basic_token_returns_basic_data (self , mock_request ):
160- actor = create_isolated_actor ("basic_token_test" )
161- basic_token = AccessTokenFactory (scope = self .BASIC_SCOPE )
162- client = self .get_authenticated_client (basic_token )
163-
164- response = client .get (reverse ("actor-detail" , kwargs = {"pk" : actor .id }))
165-
166- # Should succeed but return basic data (no LOLA scope)
167- assert response .status_code == status .HTTP_200_OK
168-
169- data = response .data
170- # Use helper methods for assertions
171- self .assert_basic_activitypub_structure (data , actor , mock_request )
172- self .assert_no_lola_fields (data )
17382
17483 # Test that URL parameter authentication works for LOLA testing
17584 @pytest .mark .django_db
@@ -183,10 +92,8 @@ def test_actor_detail_url_parameter_authentication(self):
18392 response = client .get (f"{ url } ?auth_token={ lola_token .token } " )
18493
18594 assert response .status_code == status .HTTP_200_OK
186-
187- data = response .data
188- # Should have LOLA fields (proves URL parameter auth worked)
189- self .assert_has_lola_fields (data , actor )
95+ # Should have migration field (proves URL parameter auth worked)
96+ assert "migration" in response .data
19097
19198 # Test that outbox shows different content based on authentication
19299 @pytest .mark .django_db
@@ -224,38 +131,6 @@ def test_outbox_content_filtering_by_authentication(self, mock_request):
224131 assert public_data ["id" ] == expected_outbox_id
225132 assert lola_data ["id" ] == expected_outbox_id
226133
227- # Test that demonstrates clear differences between public and LOLA responses
228- @pytest .mark .django_db
229- def test_side_by_side_authentication_comparison (self ):
230- actor = create_isolated_actor ("comparison_test" )
231- lola_token = AccessTokenFactory (lola_scope = True )
232-
233- # Public request
234- public_client = APIClient ()
235- public_response = public_client .get (reverse ("actor-detail" , kwargs = {"pk" : actor .id }))
236- public_data = public_response .data
237-
238- # LOLA request
239- lola_client = self .get_authenticated_client (lola_token )
240- lola_response = lola_client .get (reverse ("actor-detail" , kwargs = {"pk" : actor .id }))
241- lola_data = lola_response .data
242-
243- # Both should succeed
244- assert public_response .status_code == status .HTTP_200_OK
245- assert lola_response .status_code == status .HTTP_200_OK
246-
247- # Both should have identical basic fields
248- basic_fields = ["@context" , "type" , "id" , "preferredUsername" , "name" , "previously" ]
249- for field in basic_fields :
250- assert public_data [field ] == lola_data [field ]
251-
252- # Only LOLA should have enhanced fields
253- lola_fields = ["accountPortabilityOauth" , "content" , "blocked" , "migration" ]
254- for field in lola_fields :
255- assert field not in public_data
256- assert field in lola_data
257- assert isinstance (lola_data [field ], str ) # Should be URL strings
258-
259134 # Test that invalid tokens gracefully degrade to unauthenticated behavior
260135 @pytest .mark .django_db
261136 def test_invalid_token_graceful_degradation (self ):
@@ -268,13 +143,8 @@ def test_invalid_token_graceful_degradation(self):
268143
269144 # Should succeed with public data (graceful degradation)
270145 assert response .status_code == status .HTTP_200_OK
271-
272- data = response .data
273- assert data ["type" ] == "Person"
274- # Should NOT have LOLA fields (invalid token treated as unauthenticated)
275- assert "accountPortabilityOauth" not in data
276- assert "content" not in data
277- assert "blocked" not in data
146+ # Should NOT have migration field (invalid token = unauthenticated)
147+ assert "migration" not in response .data
278148
279149 # Test graceful handling of malformed authorization headers
280150 @pytest .mark .parametrize ("malformed_header" , [
@@ -284,25 +154,25 @@ def test_invalid_token_graceful_degradation(self):
284154 "InvalidFormat token" , # Malformed header
285155 ])
286156 @pytest .mark .django_db
287- def test_malformed_authorization_header_handling (self , malformed_header , mock_request ):
157+ def test_malformed_authorization_header_handling (self , malformed_header ):
288158 actor = create_isolated_actor ("malformed_header_test" )
289159 client = APIClient ()
290160 client .credentials (HTTP_AUTHORIZATION = malformed_header )
291161
292162 response = client .get (reverse ("actor-detail" , kwargs = {"pk" : actor .id }))
293163
294- # Should succeed with public data for all malformed cases
164+ # Should succeed with public data (malformed auth = unauthenticated)
295165 assert response .status_code == status .HTTP_200_OK
296- data = response .data
297- self .assert_basic_activitypub_structure (data , actor , mock_request )
298- self .assert_no_lola_fields (data )
166+ # Should NOT have migration field
167+ assert "migration" not in response .data
299168
300169 # Test that content-type headers are set correctly for API responses
301170 @pytest .mark .django_db
302171 def test_content_type_headers_set_correctly (self ):
303172 actor = create_isolated_actor ("content_type_test" )
304173 lola_token = AccessTokenFactory (lola_scope = True )
305- client = self .get_authenticated_client (lola_token )
174+ client = APIClient ()
175+ client .credentials (HTTP_AUTHORIZATION = f'Bearer { lola_token .token } ' )
306176
307177 # Request with format=json
308178 response = client .get (reverse ("actor-detail" , kwargs = {"pk" : actor .id }), {"format" : "json" })
@@ -312,10 +182,8 @@ def test_content_type_headers_set_correctly(self):
312182 assert response ["Content-Type" ] == "application/json"
313183 # Should have CORS header for federation
314184 assert response ["Access-Control-Allow-Origin" ] == "*"
315-
316- # Should still have LOLA fields
317- data = response .data
318- assert "accountPortabilityOauth" in data
185+ # Should have migration field (authenticated)
186+ assert "migration" in response .data
319187
320188
321189# LOLA Following Collection Tests
0 commit comments