Skip to content

Commit b8d22a3

Browse files
committed
misc test fixtures tokenserver
1 parent 513a84e commit b8d22a3

1 file changed

Lines changed: 290 additions & 0 deletions

File tree

tools/integration_tests/tokenserver/test_misc.py

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@
55

66
import unittest
77

8+
from integration_tests.tokenserver.conftest import (
9+
FXA_EMAIL_DOMAIN,
10+
NODE_ID,
11+
add_user,
12+
build_oauth_headers,
13+
count_users,
14+
get_replaced_users,
15+
get_user,
16+
)
817
from integration_tests.tokenserver.test_support import TestCase
918

1019
MAX_GENERATION = 9223372036854775807
@@ -239,3 +248,284 @@ def test_x_content_type_options(self):
239248
# Tokenserver responses should include the
240249
# `X-Content-Type-Options: nosniff` header
241250
self.assertEqual(res.headers["X-Content-Type-Options"], "nosniff")
251+
252+
253+
# ===========================================================================
254+
# pytest-style equivalents — added alongside the class above.
255+
# Once confirmed passing in CI the TestMisc class will be removed.
256+
# Fixtures are defined in tools/integration_tests/tokenserver/conftest.py.
257+
# ===========================================================================
258+
259+
260+
def test_unknown_app(ts_ctx):
261+
"""Test unknown app."""
262+
app = ts_ctx["app"]
263+
headers = build_oauth_headers(
264+
generation=1234, keys_changed_at=1234, client_state="aaaa"
265+
)
266+
res = app.get("/1.0/xXx/token", headers=headers, status=404)
267+
expected_error_response = {
268+
"errors": [
269+
{
270+
"description": "Unsupported application",
271+
"location": "url",
272+
"name": "application",
273+
}
274+
],
275+
"status": "error",
276+
}
277+
assert res.json == expected_error_response
278+
279+
280+
def test_unknown_version(ts_ctx):
281+
"""Test unknown version."""
282+
app = ts_ctx["app"]
283+
headers = build_oauth_headers(
284+
generation=1234, keys_changed_at=1234, client_state="aaaa"
285+
)
286+
res = app.get("/1.0/sync/1.2", headers=headers, status=404)
287+
expected_error_response = {
288+
"errors": [
289+
{
290+
"description": "Unsupported application version",
291+
"location": "url",
292+
"name": "1.2",
293+
}
294+
],
295+
"status": "error",
296+
}
297+
assert res.json == expected_error_response
298+
299+
300+
def test_valid_app(ts_ctx):
301+
"""Test valid app."""
302+
db_conn = ts_ctx["db_conn"]
303+
app = ts_ctx["app"]
304+
service_id = ts_ctx["service_id"]
305+
add_user(db_conn, service_id)
306+
headers = build_oauth_headers(
307+
generation=1234, keys_changed_at=1234, client_state="aaaa"
308+
)
309+
res = app.get("/1.0/sync/1.5", headers=headers)
310+
assert "https://example.com/1.5" in res.json["api_endpoint"]
311+
assert "duration" in res.json
312+
assert res.json["duration"] == 3600
313+
314+
315+
def test_current_user_is_the_most_up_to_date(ts_ctx):
316+
"""Test current user is the most up to date."""
317+
db_conn = ts_ctx["db_conn"]
318+
app = ts_ctx["app"]
319+
service_id = ts_ctx["service_id"]
320+
# Add some users
321+
add_user(db_conn, service_id, generation=1234, created_at=1234)
322+
add_user(db_conn, service_id, generation=1235, created_at=1234)
323+
add_user(db_conn, service_id, generation=1234, created_at=1235)
324+
uid = add_user(db_conn, service_id, generation=1236, created_at=1233)
325+
# Users are sorted by (generation, created_at), so the fourth user
326+
# record is considered to be the current user
327+
headers = build_oauth_headers(
328+
generation=1236, keys_changed_at=1234, client_state="aaaa"
329+
)
330+
res = app.get("/1.0/sync/1.5", headers=headers)
331+
assert res.json["uid"] == uid
332+
333+
334+
def test_user_creation_when_most_current_user_is_replaced(ts_ctx):
335+
"""Test user creation when most current user is replaced."""
336+
db_conn = ts_ctx["db_conn"]
337+
app = ts_ctx["app"]
338+
service_id = ts_ctx["service_id"]
339+
# Add some users
340+
uid1 = add_user(db_conn, service_id, generation=1234, created_at=1234)
341+
uid2 = add_user(db_conn, service_id, generation=1235, created_at=1235)
342+
uid3 = add_user(
343+
db_conn, service_id, generation=1236, created_at=1236, replaced_at=1237
344+
)
345+
seen_uids = [uid1, uid2, uid3]
346+
# Because the current user (the one with uid3) has been replaced, a new
347+
# user record is created
348+
headers = build_oauth_headers(
349+
generation=1237, keys_changed_at=1237, client_state="aaaa"
350+
)
351+
res = app.get("/1.0/sync/1.5", headers=headers)
352+
assert res.json["uid"] not in seen_uids
353+
354+
355+
def test_old_users_marked_as_replaced_in_race_recovery(ts_ctx):
356+
"""Test old users marked as replaced in race recovery."""
357+
db_conn = ts_ctx["db_conn"]
358+
app = ts_ctx["app"]
359+
service_id = ts_ctx["service_id"]
360+
# Add some users
361+
uid1 = add_user(db_conn, service_id, generation=1234, created_at=1234)
362+
uid2 = add_user(db_conn, service_id, generation=1235, created_at=1235)
363+
uid3 = add_user(db_conn, service_id, generation=1236, created_at=1240)
364+
# Make a request
365+
headers = build_oauth_headers(
366+
generation=1236, keys_changed_at=1236, client_state="aaaa"
367+
)
368+
res = app.get("/1.0/sync/1.5", headers=headers)
369+
# uid3 is associated with the current user
370+
assert res.json["uid"] == uid3
371+
# The users associated with uid1 and uid2 have replaced_at set to be
372+
# equal to created_at on the current user record
373+
user1 = get_user(db_conn, uid1)
374+
user2 = get_user(db_conn, uid2)
375+
assert user1["replaced_at"] == 1240
376+
assert user2["replaced_at"] == 1240
377+
378+
379+
def test_user_updates_with_new_client_state(ts_ctx):
380+
"""Test user updates with new client state."""
381+
db_conn = ts_ctx["db_conn"]
382+
app = ts_ctx["app"]
383+
service_id = ts_ctx["service_id"]
384+
# Start with a single user in the database
385+
uid = add_user(
386+
db_conn, service_id, generation=1234, keys_changed_at=1234, client_state="aaaa"
387+
)
388+
# Send a request, updating the generation, keys_changed_at, and client_state
389+
headers = build_oauth_headers(
390+
generation=1235, keys_changed_at=1235, client_state="bbbb"
391+
)
392+
res = app.get("/1.0/sync/1.5", headers=headers)
393+
# A new user should have been created
394+
assert count_users(db_conn) == 2
395+
assert uid != res.json["uid"]
396+
# The new user record should have the updated generation,
397+
# keys_changed_at, and client_state
398+
user = get_user(db_conn, res.json["uid"])
399+
assert user["generation"] == 1235
400+
assert user["keys_changed_at"] == 1235
401+
assert user["client_state"] == "bbbb"
402+
# The old user record should not have the updated values
403+
user = get_user(db_conn, uid)
404+
assert user["generation"] == 1234
405+
assert user["keys_changed_at"] == 1234
406+
assert user["client_state"] == "aaaa"
407+
# Get all the replaced users
408+
email = f"test@{FXA_EMAIL_DOMAIN}"
409+
replaced_users = get_replaced_users(db_conn, service_id, email)
410+
# Only one user should be replaced
411+
assert len(replaced_users) == 1
412+
# The replaced user record should have the old generation,
413+
# keys_changed_at, and client_state
414+
replaced_user = replaced_users[0]
415+
assert replaced_user["generation"] == 1234
416+
assert replaced_user["keys_changed_at"] == 1234
417+
assert replaced_user["client_state"] == "aaaa"
418+
419+
420+
def test_user_updates_with_same_client_state(ts_ctx):
421+
"""Test user updates with same client state."""
422+
db_conn = ts_ctx["db_conn"]
423+
app = ts_ctx["app"]
424+
service_id = ts_ctx["service_id"]
425+
# Start with a single user in the database
426+
uid = add_user(db_conn, service_id, generation=1234, keys_changed_at=1234)
427+
# Send a request, updating the generation and keys_changed_at but not
428+
# the client state
429+
headers = build_oauth_headers(
430+
generation=1235, keys_changed_at=1235, client_state="aaaa"
431+
)
432+
res = app.get("/1.0/sync/1.5", headers=headers)
433+
# A new user should not have been created
434+
assert count_users(db_conn) == 1
435+
assert uid == res.json["uid"]
436+
# The user record should have been updated
437+
user = get_user(db_conn, uid)
438+
assert user["generation"] == 1235
439+
assert user["keys_changed_at"] == 1235
440+
441+
442+
def test_retired_users_can_make_requests(ts_ctx):
443+
"""Test retired users can make requests."""
444+
db_conn = ts_ctx["db_conn"]
445+
app = ts_ctx["app"]
446+
service_id = ts_ctx["service_id"]
447+
# Add a retired user to the database
448+
add_user(db_conn, service_id, generation=MAX_GENERATION)
449+
headers = build_oauth_headers(
450+
generation=1235, keys_changed_at=1234, client_state="aaaa"
451+
)
452+
# Retired users cannot make requests with a generation smaller than
453+
# the max generation
454+
res = app.get("/1.0/sync/1.5", headers=headers, status=401)
455+
expected_error_response = {
456+
"status": "invalid-generation",
457+
"errors": [{"location": "body", "name": "", "description": "Unauthorized"}],
458+
}
459+
assert res.json == expected_error_response
460+
# Retired users can make requests with a generation number equal to
461+
# the max generation
462+
headers = build_oauth_headers(
463+
generation=MAX_GENERATION, keys_changed_at=1234, client_state="aaaa"
464+
)
465+
app.get("/1.0/sync/1.5", headers=headers)
466+
467+
468+
def test_replaced_users_can_make_requests(ts_ctx):
469+
"""Test replaced users can make requests."""
470+
db_conn = ts_ctx["db_conn"]
471+
app = ts_ctx["app"]
472+
service_id = ts_ctx["service_id"]
473+
# Add a replaced user to the database
474+
add_user(db_conn, service_id, generation=1234, created_at=1234, replaced_at=1234)
475+
headers = build_oauth_headers(
476+
generation=1234, keys_changed_at=1234, client_state="aaaa"
477+
)
478+
# Replaced users can make requests
479+
app.get("/1.0/sync/1.5", headers=headers)
480+
481+
482+
def test_retired_users_with_no_node_cannot_make_requests(ts_ctx):
483+
"""Test retired users with no node cannot make requests."""
484+
db_conn = ts_ctx["db_conn"]
485+
app = ts_ctx["app"]
486+
service_id = ts_ctx["service_id"]
487+
# Add a retired user to the database
488+
invalid_node_id = NODE_ID + 1
489+
add_user(db_conn, service_id, generation=MAX_GENERATION, nodeid=invalid_node_id)
490+
# Retired users without a node cannot make requests
491+
headers = build_oauth_headers(
492+
generation=MAX_GENERATION, keys_changed_at=1234, client_state="aaaa"
493+
)
494+
app.get("/1.0/sync/1.5", headers=headers, status=500)
495+
496+
497+
def test_replaced_users_with_no_node_can_make_requests(ts_ctx):
498+
"""Test replaced users with no node can make requests."""
499+
db_conn = ts_ctx["db_conn"]
500+
app = ts_ctx["app"]
501+
service_id = ts_ctx["service_id"]
502+
# Add a replaced user to the database
503+
invalid_node_id = NODE_ID + 1
504+
add_user(
505+
db_conn, service_id, created_at=1234, replaced_at=1234, nodeid=invalid_node_id
506+
)
507+
headers = build_oauth_headers(
508+
generation=1234, keys_changed_at=1234, client_state="aaaa"
509+
)
510+
# Replaced users without a node can make requests
511+
res = app.get("/1.0/sync/1.5", headers=headers)
512+
user = get_user(db_conn, res.json["uid"])
513+
# The user is assigned to a new node
514+
assert user["nodeid"] == NODE_ID
515+
516+
517+
def test_x_content_type_options(ts_ctx):
518+
"""Test x content type options."""
519+
db_conn = ts_ctx["db_conn"]
520+
app = ts_ctx["app"]
521+
service_id = ts_ctx["service_id"]
522+
add_user(
523+
db_conn, service_id, generation=1234, keys_changed_at=1234, client_state="aaaa"
524+
)
525+
headers = build_oauth_headers(
526+
generation=1234, keys_changed_at=1234, client_state="aaaa"
527+
)
528+
res = app.get("/1.0/sync/1.5", headers=headers)
529+
# Tokenserver responses should include the
530+
# `X-Content-Type-Options: nosniff` header
531+
assert res.headers["X-Content-Type-Options"] == "nosniff"

0 commit comments

Comments
 (0)