summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpennae <github@quasiparticle.net>2022-07-18 17:12:52 +0200
committerpennae <github@quasiparticle.net>2022-07-18 17:12:52 +0200
commita89158377f829720a98342cf434a18b962006ee7 (patch)
tree680e35a2e8e3311d832da336df8cf625c7bf07a7
parenta4a929218528920c4ae525e2510562dd209f6b3a (diff)
downloadminor-skulk-a89158377f829720a98342cf434a18b962006ee7.tar.gz
minor-skulk-a89158377f829720a98342cf434a18b962006ee7.tar.xz
minor-skulk-a89158377f829720a98342cf434a18b962006ee7.zip
speed up test suite
mostly by grouping tests that can reuse the same account (which is expensive to create) into classes and scoping accounts to classes.
-rw-r--r--tests/api.py6
-rw-r--r--tests/conftest.py27
-rw-r--r--tests/test_auth_account.py99
-rw-r--r--tests/test_auth_device.py557
-rw-r--r--tests/test_auth_email.py98
-rw-r--r--tests/test_auth_oauth.py619
-rw-r--r--tests/test_auth_password.py189
-rw-r--r--tests/test_auth_session.py85
-rw-r--r--tests/test_oauth.py109
-rw-r--r--tests/test_profile.py235
-rw-r--r--tests/test_push.py226
11 files changed, 1140 insertions, 1110 deletions
diff --git a/tests/api.py b/tests/api.py
index 32e1159..da82d37 100644
--- a/tests/api.py
+++ b/tests/api.py
@@ -213,9 +213,9 @@ class PushServer:
server = self.server = http.server.ThreadingHTTPServer(("localhost", PUSH_PORT), Handler)
threading.Thread(target=server.serve_forever).start()
- def wait(self, timeout=2):
+ def wait(self, timeout=0.5):
return self.q.get(timeout=timeout)
- def done(self, timeout=2):
+ def done(self, timeout=0.5):
try:
self.q.get(timeout=timeout)
return False
@@ -249,5 +249,5 @@ class MailServer:
def stop(self):
self.controller.stop()
- def wait(self, timeout=2):
+ def wait(self, timeout=0.5):
return self.q.get(timeout=timeout)
diff --git a/tests/conftest.py b/tests/conftest.py
index 43b32f2..bf877e2 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -12,7 +12,7 @@ def push_server():
s.server.shutdown()
s.server.server_close()
-@pytest.fixture
+@pytest.fixture(scope="class")
def mail_server():
s = MailServer()
yield s
@@ -55,17 +55,18 @@ def _account(client, primary, email, mail_server):
email1 = f"test.account-{os.urandom(8).hex()}@test-auth"
email2 = f"test.account2-{os.urandom(8).hex()}@test-auth"
-@pytest.fixture(params=[True, False], ids=["primary", "secondary"])
-def account(client, request, mail_server):
- for a in _account(client, request.param, email1, mail_server):
+@pytest.fixture(params=[True, False], ids=["primary", "secondary"], scope="class")
+def account(request, mail_server):
+ for a in _account(AuthClient(), request.param, email1, mail_server):
yield a
-@pytest.fixture(params=[True, False], ids=["primary", "secondary"])
-def account2(client, request, mail_server):
- for a in _account(client, request.param, email2, mail_server):
+@pytest.fixture(params=[True, False], ids=["primary", "secondary"], scope="class")
+def account2(request, mail_server):
+ for a in _account(AuthClient(), request.param, email2, mail_server):
yield a
-@pytest.fixture
-def unverified_account(client, mail_server):
+@pytest.fixture(scope="class")
+def unverified_account(mail_server):
+ client = AuthClient()
s = client.create_account(email1, "")
yield s
s.destroy_account(s.email, "")
@@ -109,10 +110,14 @@ def account_or_rt(account, request):
yield r
@pytest.fixture
-def forgot_token(account):
+def forgot_token(account, mail_server):
resp = account.post_a("/password/forgot/send_code", { 'email': account.email })
assert 'passwordForgotToken' in resp
assert resp['ttl'] == 300
assert resp['codeLength'] == 16
assert resp['tries'] == 1
- return PasswordChange(account.client, resp['passwordForgotToken'], 'passwordForgotToken')
+ (to, body) = mail_server.wait()
+ assert account.email in to
+ pc = PasswordChange(account.client, resp['passwordForgotToken'], 'passwordForgotToken')
+ pc.code = body.strip()
+ return pc
diff --git a/tests/test_auth_account.py b/tests/test_auth_account.py
index 0e7e22d..365a53c 100644
--- a/tests/test_auth_account.py
+++ b/tests/test_auth_account.py
@@ -41,15 +41,16 @@ def test_create_nomail(client):
'message': 'failed to send email'
}
-def test_create_exists(account):
- with pytest.raises(ClientError) as e:
- account.create_account(account.email, "")
- assert e.value.details == {
- 'code': 400,
- 'errno': 101,
- 'error': 'Bad Request',
- 'message': 'account already exists'
- }
+class TestCreateExists:
+ def test_create_exists(self, account):
+ with pytest.raises(ClientError) as e:
+ account.create_account(account.email, "")
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 101,
+ 'error': 'Bad Request',
+ 'message': 'account already exists'
+ }
@pytest.mark.parametrize("keys", [None, False, True])
@pytest.mark.parametrize("verify", [False, True])
@@ -120,25 +121,26 @@ def test_login_unverified(client, unverified_account):
'message': 'unverified account'
}
-def test_login_badcase(account):
- with pytest.raises(ClientError) as e:
- account.login(account.email.upper(), "")
- assert e.value.details == {
- 'code': 400,
- 'errno': 120,
- 'error': 'Bad Request',
- 'message': 'incorrect email case'
- }
+class TestBadLogin:
+ def test_login_badcase(self, account):
+ with pytest.raises(ClientError) as e:
+ account.login(account.email.upper(), "")
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 120,
+ 'error': 'Bad Request',
+ 'message': 'incorrect email case'
+ }
-def test_login_badpasswd(account):
- with pytest.raises(ClientError) as e:
- account.login(account.email, "ca0cb780-f114-405a-a5c2-1a4deb933a51")
- assert e.value.details == {
- 'code': 400,
- 'errno': 103,
- 'error': 'Bad Request',
- 'message': 'incorrect password'
- }
+ def test_login_badpasswd(self, account):
+ with pytest.raises(ClientError) as e:
+ account.login(account.email, "ca0cb780-f114-405a-a5c2-1a4deb933a51")
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 103,
+ 'error': 'Bad Request',
+ 'message': 'incorrect password'
+ }
@pytest.mark.parametrize("keys", [None, False, True])
def test_login(client, account, keys):
@@ -183,25 +185,26 @@ def test_destroy_noaccount(client):
'message': 'unknown account'
}
-def test_destroy_badcase(account):
- with pytest.raises(ClientError) as e:
- account.destroy_account(account.email.upper(), "")
- assert e.value.details == {
- 'code': 400,
- 'errno': 120,
- 'error': 'Bad Request',
- 'message': 'incorrect email case'
- }
+class TestBadDestroy:
+ def test_destroy_badcase(self, account):
+ with pytest.raises(ClientError) as e:
+ account.destroy_account(account.email.upper(), "")
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 120,
+ 'error': 'Bad Request',
+ 'message': 'incorrect email case'
+ }
-def test_destroy_badpasswd(account):
- with pytest.raises(ClientError) as e:
- account.destroy_account(account.email, "ca0cb780-f114-405a-a5c2-1a4deb933a51")
- assert e.value.details == {
- 'code': 400,
- 'errno': 103,
- 'error': 'Bad Request',
- 'message': 'incorrect password'
- }
+ def test_destroy_badpasswd(self, account):
+ with pytest.raises(ClientError) as e:
+ account.destroy_account(account.email, "ca0cb780-f114-405a-a5c2-1a4deb933a51")
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 103,
+ 'error': 'Bad Request',
+ 'message': 'incorrect password'
+ }
@pytest.mark.parametrize("auth", [
{},
@@ -224,9 +227,7 @@ def test_keys_invalid(client, auth):
@pytest.fixture
def reset_token(account, forgot_token, mail_server):
- (to, body) = mail_server.wait()
- assert account.email in to
- resp = forgot_token.post_a("/password/forgot/verify_code", { 'code': body.strip() })
+ resp = forgot_token.post_a("/password/forgot/verify_code", { 'code': forgot_token.code })
return AccountReset(account.client, resp['accountResetToken'])
@pytest.mark.parametrize("args", [
@@ -262,7 +263,7 @@ def test_reset(account, reset_token, mail_server, push_server):
}
assert push_server.done()
-def test_reset(account, reset_token, mail_server, push_server):
+def test_reset_twice(account, reset_token, mail_server, push_server):
reset_token.post_a("/account/reset", { 'authPW': auth_pw(account.email, "") })
with pytest.raises(ClientError) as e:
reset_token.post_a("/account/reset", { 'authPW': auth_pw(account.email, "") })
diff --git a/tests/test_auth_device.py b/tests/test_auth_device.py
index 8504ba7..5ec42f3 100644
--- a/tests/test_auth_device.py
+++ b/tests/test_auth_device.py
@@ -29,58 +29,113 @@ def test_create_noauth(client):
'message': 'invalid request signature'
}
-@pytest.mark.parametrize("args,code,errno,error,message", [
- ({ 'name': 'dev', 'availableCommands': {'a':1} },
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
- ({ 'name': 'dev', 'availableCommands': {'a':1}, 'extra': 0 },
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
- ({},
- 400, 108, 'Bad Request', 'missing parameter in request body'),
- ({ 'id': '00' * 16, 'name': 'dev' },
- 400, 108, 'Bad Request', 'missing parameter in request body'),
-])
-def test_create_invalid(account_or_rt, args, code, errno, error, message):
- with pytest.raises(ClientError) as e:
- account_or_rt.post_a("/account/device", args)
- assert e.value.details == {'code': code, 'errno': errno, 'error': error, 'message': message}
-
-def test_destroy_noauth(client, populate_devices):
- with pytest.raises(ClientError) as e:
- client.post_a("/account/device/destroy")
- assert e.value.details == {
- 'code': 401,
- 'errno': 109,
- 'error': 'Unauthorized',
- 'message': 'invalid request signature'
- }
- with pytest.raises(ClientError) as e:
- client.post_a("/account/device/destroy", {'id': populate_devices[0]['id']})
- assert e.value.details == {
- 'code': 401,
- 'errno': 109,
- 'error': 'Unauthorized',
- 'message': 'invalid request signature'
- }
-
-@pytest.mark.parametrize("args,code,errno,error,message", [
- ({ 'id': '00' },
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
- ({ 'id': '00' * 16, 'extra': 0 },
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
- ({ 'id': '00' * 16 },
- 400, 123, 'Bad Request', 'unknown device'),
-])
-def test_destroy_invalid(account_or_rt, args, code, errno, error, message):
- with pytest.raises(ClientError) as e:
- account_or_rt.post_a("/account/device/destroy", args)
- assert e.value.details == {'code': code, 'errno': errno, 'error': error, 'message': message}
+class TestBadCreate:
+ @pytest.mark.parametrize("args,code,errno,error,message", [
+ ({ 'name': 'dev', 'availableCommands': {'a':1} },
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ({ 'name': 'dev', 'availableCommands': {'a':1}, 'extra': 0 },
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ({},
+ 400, 108, 'Bad Request', 'missing parameter in request body'),
+ ({ 'id': '00' * 16, 'name': 'dev' },
+ 400, 108, 'Bad Request', 'missing parameter in request body'),
+ ])
+ def test_create_invalid(self, account_or_rt, args, code, errno, error, message):
+ with pytest.raises(ClientError) as e:
+ account_or_rt.post_a("/account/device", args)
+ assert e.value.details == {'code': code, 'errno': errno, 'error': error, 'message': message}
+
+class TestDestroyNoauth:
+ def test_destroy_noauth(self, client, populate_devices):
+ with pytest.raises(ClientError) as e:
+ client.post_a("/account/device/destroy")
+ assert e.value.details == {
+ 'code': 401,
+ 'errno': 109,
+ 'error': 'Unauthorized',
+ 'message': 'invalid request signature'
+ }
+ with pytest.raises(ClientError) as e:
+ client.post_a("/account/device/destroy", {'id': populate_devices[0]['id']})
+ assert e.value.details == {
+ 'code': 401,
+ 'errno': 109,
+ 'error': 'Unauthorized',
+ 'message': 'invalid request signature'
+ }
+
+class TestDestroyInvalid:
+ @pytest.mark.parametrize("args,code,errno,error,message", [
+ ({ 'id': '00' },
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ({ 'id': '00' * 16, 'extra': 0 },
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ({ 'id': '00' * 16 },
+ 400, 123, 'Bad Request', 'unknown device'),
+ ])
+ def test_destroy_invalid(self, account_or_rt, args, code, errno, error, message):
+ with pytest.raises(ClientError) as e:
+ account_or_rt.post_a("/account/device/destroy", args)
+ assert e.value.details == {'code': code, 'errno': errno, 'error': error, 'message': message}
def test_create_destroy(account_or_rt):
dev = account_or_rt.post_a("/account/device", device_data[0])
account_or_rt.post_a("/account/device/destroy", {'id': dev['id']})
-def test_create_unverified(unverified_account):
- unverified_account.post_a("/account/device", device_data[0])
+class TestUnverified:
+ def test_create_unverified(self, unverified_account):
+ unverified_account.post_a("/account/device", device_data[0])
+
+ def test_list_unverified(self, unverified_account):
+ with pytest.raises(ClientError) as e:
+ unverified_account.get_a("/account/devices")
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 138,
+ 'error': 'Bad Request',
+ 'message': 'unverified session'
+ }
+
+ def test_invoke_unverified(self, unverified_account):
+ body = {"target": "0" * 32, "command": "foo", "payload": {}, "ttl": 10}
+ with pytest.raises(ClientError) as e:
+ unverified_account.post_a("/account/devices/invoke_command", body)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 138,
+ 'error': 'Bad Request',
+ 'message': 'unverified session'
+ }
+
+ def test_commands_unverified(self, unverified_account):
+ with pytest.raises(ClientError) as e:
+ unverified_account.get_a("/account/device/commands?index=1")
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 138,
+ 'error': 'Bad Request',
+ 'message': 'unverified session'
+ }
+
+ def test_attached_clients_unverified(self, unverified_account):
+ with pytest.raises(ClientError) as e:
+ unverified_account.get_a("/account/attached_clients")
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 138,
+ 'error': 'Bad Request',
+ 'message': 'unverified session'
+ }
+
+ def test_attached_client_destroy_unverified(self, unverified_account):
+ with pytest.raises(ClientError) as e:
+ unverified_account.post_a("/account/attached_client/destroy")
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 138,
+ 'error': 'Bad Request',
+ 'message': 'unverified session'
+ }
def test_list_noauth(client):
with pytest.raises(ClientError) as e:
@@ -92,19 +147,10 @@ def test_list_noauth(client):
'message': 'invalid request signature'
}
-def test_list_unverified(unverified_account):
- with pytest.raises(ClientError) as e:
- unverified_account.get_a("/account/devices")
- assert e.value.details == {
- 'code': 400,
- 'errno': 138,
- 'error': 'Bad Request',
- 'message': 'unverified session'
- }
-
-def test_list_none(account_or_rt):
- devs = account_or_rt.get_a("/account/devices")
- assert devs == []
+class TestListNone:
+ def test_list_none(self, account_or_rt):
+ devs = account_or_rt.get_a("/account/devices")
+ assert devs == []
@pytest.mark.usefixtures("populate_devices")
def test_list(account_or_rt):
@@ -157,76 +203,68 @@ def test_invoke_noauth(client):
'message': 'invalid request signature'
}
-def test_invoke_unverified(unverified_account):
- body = {"target": "0" * 32, "command": "foo", "payload": {}, "ttl": 10}
- with pytest.raises(ClientError) as e:
- unverified_account.post_a("/account/devices/invoke_command", body)
- assert e.value.details == {
- 'code': 400,
- 'errno': 138,
- 'error': 'Bad Request',
- 'message': 'unverified session'
- }
-
-@pytest.mark.parametrize("args,code,errno,error,message", [
- ({"target": "00", "command": "foo", "payload": {}, "ttl": 10},
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
- ({"target": "00" * 16, "command": "foo", "payload": {}, "ttl": 10, 'extra': 0},
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
- ({"target": "0" * 32, "command": "foo", "payload": {}, "ttl": 10},
- 400, 123, 'Bad Request', 'unknown device'),
-])
-def test_invoke_invalid(account_or_rt, args, code, errno, error, message):
- with pytest.raises(ClientError) as e:
- account_or_rt.post_a("/account/devices/invoke_command", args)
- assert e.value.details == {'code': code, 'errno': errno, 'error': error, 'message': message}
-
-def test_invoke_nocmd(account_or_rt, populate_devices):
- body = {"target": populate_devices[0]['id'], "command": "foo", "payload": {}, "ttl": 10}
- with pytest.raises(ClientError) as e:
- account_or_rt.post_a("/account/devices/invoke_command", body)
- assert e.value.details == {
- 'code': 400,
- 'errno': 157,
- 'error': 'Bad Request',
- 'message': 'unavailable device command'
- }
+class TestBadInvoke:
+ @pytest.mark.parametrize("args,code,errno,error,message", [
+ ({"target": "00", "command": "foo", "payload": {}, "ttl": 10},
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ({"target": "00" * 16, "command": "foo", "payload": {}, "ttl": 10, 'extra': 0},
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ({"target": "0" * 32, "command": "foo", "payload": {}, "ttl": 10},
+ 400, 123, 'Bad Request', 'unknown device'),
+ ])
+ def test_invoke_invalid(self, account_or_rt, args, code, errno, error, message):
+ with pytest.raises(ClientError) as e:
+ account_or_rt.post_a("/account/devices/invoke_command", args)
+ assert e.value.details == {'code': code, 'errno': errno, 'error': error, 'message': message}
+
+ def test_invoke_nocmd(self, account_or_rt, populate_devices):
+ body = {"target": populate_devices[0]['id'], "command": "foo", "payload": {}, "ttl": 10}
+ with pytest.raises(ClientError) as e:
+ account_or_rt.post_a("/account/devices/invoke_command", body)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 157,
+ 'error': 'Bad Request',
+ 'message': 'unavailable device command'
+ }
+
+class TestInvokeOther:
+ def test_invoke_other_account(self, account_or_rt, account2):
+ dev = account2.post_a("/account/device", device_data[0])
+ body = {"target": dev['id'], "command": "foo", "payload": {}, "ttl": 10}
+ with pytest.raises(ClientError) as e:
+ account_or_rt.post_a("/account/devices/invoke_command", body)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 123,
+ 'error': 'Bad Request',
+ 'message': 'unknown device'
+ }
+
+class TestInvoke:
+ @pytest.mark.parametrize("ttl", [None, 1, 60, 999999999])
+ @pytest.mark.parametrize("has_sender", [False, True])
+ def test_invoke(self, account_or_rt, login, ttl, has_sender):
+ sender = account_or_rt.post_a("/account/device", device_data[1])['id'] if has_sender else None
+ dev = login.post_a("/account/device", device_data[0])
+
+ body = {
+ "target": dev['id'],
+ "command": "a",
+ "payload": { "data": str(random.random()), },
+ "ttl": ttl,
+ }
+ resp = account_or_rt.post_a("/account/devices/invoke_command", body)
+ assert resp['enqueued']
+ assert not resp['notified']
+ assert resp['notifyError'] == "no push callback"
-def test_invoke_other_account(account_or_rt, account2):
- dev = account2.post_a("/account/device", device_data[0])
- body = {"target": dev['id'], "command": "foo", "payload": {}, "ttl": 10}
- with pytest.raises(ClientError) as e:
- account_or_rt.post_a("/account/devices/invoke_command", body)
- assert e.value.details == {
- 'code': 400,
- 'errno': 123,
- 'error': 'Bad Request',
- 'message': 'unknown device'
- }
-
-@pytest.mark.parametrize("ttl", [None, 1, 60, 999999999])
-@pytest.mark.parametrize("has_sender", [False, True])
-def test_invoke(account_or_rt, login, ttl, has_sender):
- sender = account_or_rt.post_a("/account/device", device_data[1])['id'] if has_sender else None
- dev = login.post_a("/account/device", device_data[0])
-
- body = {
- "target": dev['id'],
- "command": "a",
- "payload": { "data": str(random.random()), },
- "ttl": ttl,
- }
- resp = account_or_rt.post_a("/account/devices/invoke_command", body)
- assert resp['enqueued']
- assert not resp['notified']
- assert resp['notifyError'] == "no push callback"
-
- cmd = login.get_a("/account/device/commands?index=0&limit=11")
- assert cmd['last']
- assert len(cmd['messages']) == 1
- assert cmd['messages'][0]['data']['command'] == 'a'
- assert cmd['messages'][0]['data']['payload'] == body['payload']
- assert cmd['messages'][0]['data']['sender'] == sender
+ cmd = login.get_a("/account/device/commands?index=0&limit=11")
+ assert cmd['last']
+ assert len(cmd['messages']) == 1
+ assert cmd['messages'][0]['data']['command'] == 'a'
+ assert cmd['messages'][0]['data']['payload'] == body['payload']
+ assert cmd['messages'][0]['data']['sender'] == sender
def test_commands_noauth(client):
with pytest.raises(ClientError) as e:
@@ -238,65 +276,56 @@ def test_commands_noauth(client):
'message': 'invalid request signature'
}
-def test_commands_unverified(unverified_account):
- with pytest.raises(ClientError) as e:
- unverified_account.get_a("/account/device/commands?index=1")
- assert e.value.details == {
- 'code': 400,
- 'errno': 138,
- 'error': 'Bad Request',
- 'message': 'unverified session'
- }
-
-def test_commands_nodev(account_or_rt):
- with pytest.raises(ClientError) as e:
- account_or_rt.get_a("/account/device/commands?index=1")
- assert e.value.details == {
- 'code': 400,
- 'errno': 123,
- 'error': 'Bad Request',
- 'message': 'unknown device'
- }
-
-@pytest.mark.parametrize('n_cmds,offset,limit', [
- (1, 0, 0),
- (1, 0, 1),
- (1, 0, 100),
- (1, 1, 0),
- (1, 1, 1),
- (1, 1, 100),
- (2, 0, 0),
- (2, 0, 1),
- (2, 0, 100),
- (2, 1, 0),
- (2, 1, 1),
- (2, 1, 100),
- (101, 0, 100),
- (101, 10, 100),
-])
-def test_device_commands_list(account_or_rt, login, n_cmds, offset, limit):
- account_or_rt.post_a("/account/device", device_data[1])['id']
- dev = login.post_a("/account/device", device_data[0])
-
- bodies = [ {
- "target": dev['id'],
- "command": "a",
- "payload": { "data": str(i), },
- } for i in range(0, n_cmds) ]
-
- for b in bodies:
- resp = account_or_rt.post_a("/account/devices/invoke_command", b)
- assert resp['enqueued']
- assert not resp['notified']
- assert resp['notifyError'] == "no push callback"
-
- cmd = login.get_a("/account/device/commands", params={ "index": 0, "limit": 1 })
- assert cmd == login.get_a("/account/device/commands", params={ "index": 0, "limit": 1 })
-
- first_index = cmd['index']
- cmds = login.get_a("/account/device/commands", params={ "limit": limit, "index": first_index + offset })
- assert cmds['last'] == (offset + limit >= n_cmds)
- assert len(cmds['messages']) == min(max(n_cmds - offset, 0), limit)
+class TestDeviceCommands:
+ def test_commands_nodev(self, account_or_rt):
+ with pytest.raises(ClientError) as e:
+ account_or_rt.get_a("/account/device/commands?index=1")
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 123,
+ 'error': 'Bad Request',
+ 'message': 'unknown device'
+ }
+
+ @pytest.mark.parametrize('n_cmds,offset,limit', [
+ (1, 0, 0),
+ (1, 0, 1),
+ (1, 0, 100),
+ (1, 1, 0),
+ (1, 1, 1),
+ (1, 1, 100),
+ (2, 0, 0),
+ (2, 0, 1),
+ (2, 0, 100),
+ (2, 1, 0),
+ (2, 1, 1),
+ (2, 1, 100),
+ (101, 0, 100),
+ (101, 10, 100),
+ ])
+ def test_device_commands_list(self, account_or_rt, login, n_cmds, offset, limit):
+ account_or_rt.post_a("/account/device", device_data[1])['id']
+ dev = login.post_a("/account/device", device_data[0])
+
+ bodies = [ {
+ "target": dev['id'],
+ "command": "a",
+ "payload": { "data": str(i), },
+ } for i in range(0, n_cmds) ]
+
+ for b in bodies:
+ resp = account_or_rt.post_a("/account/devices/invoke_command", b)
+ assert resp['enqueued']
+ assert not resp['notified']
+ assert resp['notifyError'] == "no push callback"
+
+ cmd = login.get_a("/account/device/commands", params={ "index": 0, "limit": 1 })
+ assert cmd == login.get_a("/account/device/commands", params={ "index": 0, "limit": 1 })
+
+ first_index = cmd['index']
+ cmds = login.get_a("/account/device/commands", params={ "limit": limit, "index": first_index + offset })
+ assert cmds['last'] == (offset + limit >= n_cmds)
+ assert len(cmds['messages']) == min(max(n_cmds - offset, 0), limit)
def test_attached_clients_unauth(client):
with pytest.raises(ClientError) as e:
@@ -308,25 +337,26 @@ def test_attached_clients_unauth(client):
'message': 'invalid request signature'
}
-def test_attached_clients_unverified(unverified_account):
- with pytest.raises(ClientError) as e:
- unverified_account.get_a("/account/attached_clients")
- assert e.value.details == {
- 'code': 400,
- 'errno': 138,
- 'error': 'Bad Request',
- 'message': 'unverified session'
- }
-
-def test_attached_clients_badauth(refresh_token):
- with pytest.raises(ClientError) as e:
- refresh_token.get_a("/account/attached_clients")
- assert e.value.details == {
- 'code': 401,
- 'errno': 109,
- 'error': 'Unauthorized',
- 'message': 'invalid request signature'
- }
+class TestAttachedClientBadauth:
+ def test_attached_clients_badauth(self, refresh_token):
+ with pytest.raises(ClientError) as e:
+ refresh_token.get_a("/account/attached_clients")
+ assert e.value.details == {
+ 'code': 401,
+ 'errno': 109,
+ 'error': 'Unauthorized',
+ 'message': 'invalid request signature'
+ }
+
+ def test_attached_client_destroy_badauth(self, refresh_token):
+ with pytest.raises(ClientError) as e:
+ refresh_token.post_a("/account/attached_client/destroy")
+ assert e.value.details == {
+ 'code': 401,
+ 'errno': 109,
+ 'error': 'Unauthorized',
+ 'message': 'invalid request signature'
+ }
def test_attached_clients(account, refresh_token, push_server):
dev1 = Device(account, "dev1")
@@ -366,69 +396,50 @@ def test_attached_client_destroy_unauth(client):
'message': 'invalid request signature'
}
-def test_attached_client_destroy_unverified(unverified_account):
- with pytest.raises(ClientError) as e:
- unverified_account.post_a("/account/attached_client/destroy")
- assert e.value.details == {
- 'code': 400,
- 'errno': 138,
- 'error': 'Bad Request',
- 'message': 'unverified session'
- }
-
-def test_attached_client_destroy_badauth(refresh_token):
- with pytest.raises(ClientError) as e:
- refresh_token.post_a("/account/attached_client/destroy")
- assert e.value.details == {
- 'code': 401,
- 'errno': 109,
- 'error': 'Unauthorized',
- 'message': 'invalid request signature'
- }
-
-@pytest.mark.parametrize("args,code,errno,error,message", [
- ({"sessionTokenId": "0"},
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
- ({"refreshTokenId": "0"},
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
- ({"deviceId": "0"},
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
- ({"sessionTokenId": "00" * 16, 'extra': 0},
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
- ({"sessionTokenId": "00" * 16, 'refreshTokenId': "00" * 16},
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
- ({"sessionTokenId": "00" * 16, 'refreshTokenId': "00" * 16, 'deviceId': "00" * 16},
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
- ({'refreshTokenId': "00" * 16, 'deviceId': "00" * 16},
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
-])
-def test_attached_client_destroy_invalid(account, args, code, errno, error, message):
- with pytest.raises(ClientError) as e:
- account.post_a("/account/attached_client/destroy", args)
- assert e.value.details == {'code': code, 'errno': errno, 'error': error, 'message': message}
-
-@pytest.mark.parametrize("fn", [
- (lambda d: {'sessionTokenId': d['sessionTokenId']}),
- (lambda d: {'refreshTokenId': d['refreshTokenId']}),
- (lambda d: {'deviceId': d['deviceId']}),
-], ids=["session", "refresh", "device"])
-def test_attached_client_destroy(account, refresh_token, fn):
- Device(refresh_token, "dev2")
- devs = account.get_a("/account/attached_clients")
- account.post_a("/account/attached_client/destroy", fn(devs[0]))
- devs2 = account.get_a("/account/attached_clients")
- assert len(devs2) == len(devs) - 1
-
-def test_attached_client_destroy_push(account, refresh_token, push_server):
- dev = Device(account, "dev")
- dev2 = Device(refresh_token, "dev2")
- dev.update_pcb(push_server.good("4ed8d1d3-e756-4866-9169-aafe612eb1e9"))
- account.post_a("/account/attached_client/destroy", { 'deviceId': dev2.id })
- p = push_server.wait()
- assert p[0] == "/4ed8d1d3-e756-4866-9169-aafe612eb1e9"
- assert dev.decrypt(p[2]) == {
- 'command': 'fxaccounts:device_disconnected',
- 'data': {'id': dev2.id},
- 'version': 1
- }
- assert push_server.done()
+class TestAttachedClients:
+ @pytest.mark.parametrize("args,code,errno,error,message", [
+ ({"sessionTokenId": "0"},
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ({"refreshTokenId": "0"},
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ({"deviceId": "0"},
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ({"sessionTokenId": "00" * 16, 'extra': 0},
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ({"sessionTokenId": "00" * 16, 'refreshTokenId': "00" * 16},
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ({"sessionTokenId": "00" * 16, 'refreshTokenId': "00" * 16, 'deviceId': "00" * 16},
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ({'refreshTokenId': "00" * 16, 'deviceId': "00" * 16},
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ])
+ def test_attached_client_destroy_invalid(self, account, args, code, errno, error, message):
+ with pytest.raises(ClientError) as e:
+ account.post_a("/account/attached_client/destroy", args)
+ assert e.value.details == {'code': code, 'errno': errno, 'error': error, 'message': message}
+
+ @pytest.mark.parametrize("fn", [
+ (lambda d: {'sessionTokenId': d['sessionTokenId']}),
+ (lambda d: {'refreshTokenId': d['refreshTokenId']}),
+ (lambda d: {'deviceId': d['deviceId']}),
+ ], ids=["session", "refresh", "device"])
+ def test_attached_client_destroy(self, account, refresh_token, fn):
+ Device(refresh_token, "dev2")
+ devs = account.get_a("/account/attached_clients")
+ account.post_a("/account/attached_client/destroy", fn(devs[0]))
+ devs2 = account.get_a("/account/attached_clients")
+ assert len(devs2) == len(devs) - 1
+
+ def test_attached_client_destroy_push(self, account, refresh_token, push_server):
+ dev = Device(account, "dev")
+ dev2 = Device(refresh_token, "dev2")
+ dev.update_pcb(push_server.good("4ed8d1d3-e756-4866-9169-aafe612eb1e9"))
+ account.post_a("/account/attached_client/destroy", { 'deviceId': dev2.id })
+ p = push_server.wait()
+ assert p[0] == "/4ed8d1d3-e756-4866-9169-aafe612eb1e9"
+ assert dev.decrypt(p[2]) == {
+ 'command': 'fxaccounts:device_disconnected',
+ 'data': {'id': dev2.id},
+ 'version': 1
+ }
+ assert push_server.done()
diff --git a/tests/test_auth_email.py b/tests/test_auth_email.py
index 319f2d4..b7fa65a 100644
--- a/tests/test_auth_email.py
+++ b/tests/test_auth_email.py
@@ -3,58 +3,60 @@ from fxa.errors import ClientError
from api import *
-def test_status_noauth(client, refresh_token):
- with pytest.raises(ClientError) as e:
- client.post_a("/recovery_email/status")
- assert e.value.details == {
- 'code': 401,
- 'errno': 109,
- 'error': 'Unauthorized',
- 'message': 'invalid request signature'
- }
- with pytest.raises(ClientError) as e:
- refresh_token.post_a("/recovery_email/status")
- assert e.value.details == {
- 'code': 401,
- 'errno': 109,
- 'error': 'Unauthorized',
- 'message': 'invalid request signature'
- }
+class TestUnverified:
+ def test_status_unverified(self, unverified_account):
+ resp = unverified_account.get_a("/recovery_email/status")
+ assert resp == {
+ 'email': unverified_account.email,
+ 'emailVerified': False,
+ 'sessionVerified': False,
+ 'verified': False
+ }
-def test_status_unverified(unverified_account):
- resp = unverified_account.get_a("/recovery_email/status")
- assert resp == {
- 'email': unverified_account.email,
- 'emailVerified': False,
- 'sessionVerified': False,
- 'verified': False
- }
+ @pytest.mark.parametrize("args,code,errno,error,message", [
+ ({ 'uid': '00', 'code': "" },
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ({ 'id': '00' * 16, 'code': 0 },
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ({ 'id': '00' * 16, 'code': "", 'extra': 0 },
+ 400, 107, 'Bad Request', 'invalid parameter in request body'),
+ ])
+ def test_verify_code_invalid(self, unverified_account, args, code, errno, error, message):
+ with pytest.raises(ClientError) as e:
+ unverified_account.post_a("/recovery_email/verify_code", args)
+ assert e.value.details == {'code': code, 'errno': errno, 'error': error, 'message': message}
-def test_status_verified(account):
- resp = account.get_a("/recovery_email/status")
- assert resp == {
- 'email': account.email,
- 'emailVerified': True,
- 'sessionVerified': True,
- 'verified': True
- }
+class TestVerified:
+ def test_status_noauth(self, client, refresh_token):
+ with pytest.raises(ClientError) as e:
+ client.post_a("/recovery_email/status")
+ assert e.value.details == {
+ 'code': 401,
+ 'errno': 109,
+ 'error': 'Unauthorized',
+ 'message': 'invalid request signature'
+ }
+ with pytest.raises(ClientError) as e:
+ refresh_token.post_a("/recovery_email/status")
+ assert e.value.details == {
+ 'code': 401,
+ 'errno': 109,
+ 'error': 'Unauthorized',
+ 'message': 'invalid request signature'
+ }
-@pytest.mark.parametrize("args,code,errno,error,message", [
- ({ 'uid': '00', 'code': "" },
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
- ({ 'id': '00' * 16, 'code': 0 },
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
- ({ 'id': '00' * 16, 'code': "", 'extra': 0 },
- 400, 107, 'Bad Request', 'invalid parameter in request body'),
-])
-def test_verify_code_invalid(unverified_account, args, code, errno, error, message):
- with pytest.raises(ClientError) as e:
- unverified_account.post_a("/recovery_email/verify_code", args)
- assert e.value.details == {'code': code, 'errno': errno, 'error': error, 'message': message}
+ def test_status_verified(self, account):
+ resp = account.get_a("/recovery_email/status")
+ assert resp == {
+ 'email': account.email,
+ 'emailVerified': True,
+ 'sessionVerified': True,
+ 'verified': True
+ }
-def test_verify_code(account):
- # fixture does all the work
- pass
+ def test_verify_code(self, account):
+ # fixture does all the work
+ pass
def test_verify_code_reuse(client, mail_server):
s = client.create_account("test@test", "")
diff --git a/tests/test_auth_oauth.py b/tests/test_auth_oauth.py
index 569d7ef..9c44f29 100644
--- a/tests/test_auth_oauth.py
+++ b/tests/test_auth_oauth.py
@@ -3,39 +3,317 @@ import pytest
import time
from fxa.errors import ClientError
-@pytest.mark.parametrize("client_id,scopes", [
- # firefox
- ("5882386c6d801776", "profile:write https://identity.mozilla.com/apps/oldsync https://identity.mozilla.com/tokens/session"),
- # fenix
- ("a2270f727f45f648", "profile https://identity.mozilla.com/apps/oldsync https://identity.mozilla.com/tokens/session"),
-])
-def test_oauth_client_scopes(account, client_id, scopes):
- body = {
- "client_id": client_id,
- "ttl": 60,
- "grant_type": "fxa-credentials",
- "access_type": "online",
- "scope": scopes,
- }
- s = account.post_a("/oauth/token", body)['access_token']
- account.post_a("/oauth/destroy", { "client_id": client_id, "token": s })
+class TestOauth:
+ @pytest.mark.parametrize("client_id,scopes", [
+ # firefox
+ ("5882386c6d801776", "profile:write https://identity.mozilla.com/apps/oldsync https://identity.mozilla.com/tokens/session"),
+ # fenix
+ ("a2270f727f45f648", "profile https://identity.mozilla.com/apps/oldsync https://identity.mozilla.com/tokens/session"),
+ ])
+ def test_oauth_client_scopes(self, account, client_id, scopes):
+ body = {
+ "client_id": client_id,
+ "ttl": 60,
+ "grant_type": "fxa-credentials",
+ "access_type": "online",
+ "scope": scopes,
+ }
+ s = account.post_a("/oauth/token", body)['access_token']
+ account.post_a("/oauth/destroy", { "client_id": client_id, "token": s })
-def test_oauth_authorization_noauth(account):
- body = {
- "client_id": "5882386c6d801776",
- "ttl": 60,
- "grant_type": "fxa-credentials",
- "access_type": "online",
- "scope": "profile",
- }
- with pytest.raises(ClientError) as e:
- account.post("/oauth/authorization", body)
- assert e.value.details == {
- 'code': 401,
- 'errno': 109,
- 'error': 'Unauthorized',
- 'message': 'invalid request signature'
- }
+ def test_oauth_authorization_noauth(self, account):
+ body = {
+ "client_id": "5882386c6d801776",
+ "ttl": 60,
+ "grant_type": "fxa-credentials",
+ "access_type": "online",
+ "scope": "profile",
+ }
+ with pytest.raises(ClientError) as e:
+ account.post("/oauth/authorization", body)
+ assert e.value.details == {
+ 'code': 401,
+ 'errno': 109,
+ 'error': 'Unauthorized',
+ 'message': 'invalid request signature'
+ }
+
+ @pytest.mark.parametrize("args", [
+ { "client_id": "5882386c6d801776", "state": "", "scope": "profile", "access_type": "invalid",
+ "code_challenge": "", "code_challenge_method": "S256", "response_type": "code" },
+ { "client_id": "5882386c6d801776", "state": "", "scope": "profile", "access_type": "online",
+ "code_challenge": "", "code_challenge_method": "invalid", "response_type": "code" },
+ { "client_id": "5882386c6d801776", "state": "", "scope": "profile", "access_type": "online",
+ "code_challenge": "", "code_challenge_method": "S256", "response_type": "invalid" },
+ ])
+ def test_oauth_authorization_invalid(self, account, args):
+ with pytest.raises(ClientError) as e:
+ account.post_a("/oauth/authorization", args)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 107,
+ 'error': 'Bad Request',
+ 'message': 'invalid parameter in request body'
+ }
+
+ def test_oauth_authorization_badclientid(self, account):
+ args = { "client_id": "invalid", "state": "", "scope": "profile", "access_type": "online",
+ "code_challenge": "", "code_challenge_method": "S256", "response_type": "code" }
+ with pytest.raises(ClientError) as e:
+ account.post_a("/oauth/authorization", args)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 162,
+ 'error': 'Bad Request',
+ 'message': 'unknown client_id'
+ }
+
+ def test_oauth_authorization_badscope(self, account):
+ args = { "client_id": "5882386c6d801776", "state": "", "scope": "invalid", "access_type": "online",
+ "code_challenge": "", "code_challenge_method": "S256", "response_type": "code" }
+ with pytest.raises(ClientError) as e:
+ account.post_a("/oauth/authorization", args)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 169,
+ 'error': 'Bad Request',
+ 'message': 'requested scopes not allowed'
+ }
+
+ # see below for combined /authorization + unauthed /token
+
+ def test_oauth_destroy_notoken(self, account):
+ args = { "client_id": "5882386c6d801776", "token": "00" * 32 }
+ with pytest.raises(ClientError) as e:
+ account.post("/oauth/destroy", args)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 107,
+ 'error': 'Bad Request',
+ 'message': 'invalid parameter in request body'
+ }
+
+ @pytest.mark.xfail
+ def test_oauth_destroy_badclient(self, account, refresh_token):
+ args = { "client_id": "other", "token": refresh_token.bearer }
+ with pytest.raises(ClientError) as e:
+ account.post("/oauth/destroy", args)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 107,
+ 'error': 'Bad Request',
+ 'message': 'invalid parameter in request body'
+ }
+
+ def test_oauth_scoped_keys_badclient(self, account):
+ with pytest.raises(ClientError) as e:
+ account.post_a("/account/scoped-key-data", {
+ "client_id": "invalid",
+ "scope": "https://identity.mozilla.com/apps/oldsync"
+ })
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 162,
+ 'error': 'Bad Request',
+ 'message': 'unknown client_id'
+ }
+
+ def test_oauth_scoped_keys_badscope(self, account):
+ with pytest.raises(ClientError) as e:
+ account.post_a("/account/scoped-key-data", {
+ "client_id": "5882386c6d801776",
+ "scope": "scope"
+ })
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 169,
+ 'error': 'Bad Request',
+ 'message': 'requested scopes not allowed'
+ }
+
+ def test_oauth_scoped_keys(self, account):
+ resp = account.post_a("/account/scoped-key-data", {
+ "client_id": "5882386c6d801776",
+ "scope": "https://identity.mozilla.com/apps/oldsync"
+ })
+ assert resp == {
+ "https://identity.mozilla.com/apps/oldsync": {
+ "identifier": "https://identity.mozilla.com/apps/oldsync",
+ "keyRotationSecret": "00" * 32,
+ "keyRotationTimestamp": 0,
+ },
+ }
+
+ @pytest.mark.parametrize("access_type", ["online", "offline"])
+ def test_oauth_token_fxa_badclient(self, account, access_type):
+ body = { "client_id": "invalid", "ttl": 60, "grant_type": "fxa-credentials",
+ "access_type": access_type, "scope": "profile" }
+ with pytest.raises(ClientError) as e:
+ account.post_a("/oauth/token", body)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 162,
+ 'error': 'Bad Request',
+ 'message': 'unknown client_id'
+ }
+
+ @pytest.mark.parametrize("access_type", ["online", "offline"])
+ def test_oauth_token_fxa_badscope(self, account, access_type):
+ body = { "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "fxa-credentials",
+ "access_type": access_type, "scope": "scope" }
+ with pytest.raises(ClientError) as e:
+ account.post_a("/oauth/token", body)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 169,
+ 'error': 'Bad Request',
+ 'message': 'requested scopes not allowed'
+ }
+
+ @pytest.mark.parametrize("args,code,error,errno,message", [
+ ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "authorization_code",
+ "code": "invalid", "code_verifier": "test" },
+ 400, 'Bad Request', 107, 'invalid parameter in request body'),
+ ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "authorization_code",
+ "code_verifier": "test", "extra": 0 },
+ 400, 'Bad Request', 107, 'invalid parameter in request body'),
+ ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "authorization_code",
+ "code": "00" * 32, "code_verifier": "test" },
+ 401, 'Unauthorized', 110, 'invalid authentication token'),
+ ({ "client_id": "invalid", "ttl": 60, "grant_type": "authorization_code",
+ "code_verifier": "test" },
+ 400, 'Bad Request', 162, 'unknown client_id'),
+ ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "authorization_code",
+ "code_verifier": "invalid" },
+ 400, 'Bad Request', 107, 'invalid parameter in request body'),
+ ])
+ def test_oauth_token_other_invalidcode(self, account, args, code, error, errno, message, auth_code):
+ args = copy.deepcopy(args)
+ if 'code' not in args: args['code'] = auth_code
+ with pytest.raises(ClientError) as e:
+ account.post("/oauth/token", args)
+ assert e.value.details == { 'code': code, 'errno': errno, 'error': error, 'message': message }
+
+ @pytest.mark.parametrize("args,code,error,errno,message", [
+ ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "fxa-credentials",
+ "scope": "profile", "access_type": "online" },
+ 400, 'Bad Request', 107, 'invalid parameter in request body'),
+ ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "refresh_token",
+ "refresh_token": "invalid", "code_verifier": "test" },
+ 400, 'Bad Request', 107, 'invalid parameter in request body'),
+ ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "refresh_token",
+ "scope": "profile", "extra": 0 },
+ 400, 'Bad Request', 107, 'invalid parameter in request body'),
+ ({ "client_id": "invalid", "ttl": 60, "grant_type": "refresh_token",
+ "scope": "profile" },
+ 400, 'Bad Request', 162, 'unknown client_id'),
+ ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "refresh_token",
+ "scope": "foo" },
+ 400, 'Bad Request', 169, 'requested scopes not allowed'),
+ ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "refresh_token",
+ "scope": "profile:write" },
+ 400, 'Bad Request', 169, 'requested scopes not allowed'),
+ ])
+ def test_oauth_token_other_invalidrefresh(self, account, args, code, error, errno, message, refresh_token):
+ args = copy.deepcopy(args)
+ if 'refresh_token' not in args: args['refresh_token'] = refresh_token.bearer
+ with pytest.raises(ClientError) as e:
+ account.post("/oauth/token", args)
+ assert e.value.details == { 'code': code, 'errno': errno, 'error': error, 'message': message }
+
+ @pytest.mark.parametrize("refresh", [False, True])
+ def test_oauth_fxa(self, account, refresh):
+ body = {
+ "client_id": "5882386c6d801776",
+ "ttl": 60,
+ "grant_type": "fxa-credentials",
+ "access_type": "offline" if refresh else "online",
+ "scope": "profile",
+ }
+ resp = account.post_a("/oauth/token", body)
+
+ assert 'access_token' in resp
+ assert ('refresh_token' in resp) == refresh
+ assert 'session_token' not in resp
+ assert resp['scope'] == 'profile'
+ assert resp['token_type'] == 'bearer'
+ assert resp['expires_in'] <= 60
+ assert (resp['auth_at'] - time.time()) < 10
+ assert 'keys_jwe' not in resp
+
+ @pytest.mark.parametrize("keys_jwe", [None, "keyskeyskeys"])
+ @pytest.mark.parametrize("refresh,session", [
+ (False, False),
+ (True, False),
+ (True, True),
+ ])
+ def test_oauth_auth_code(self, account, keys_jwe, refresh, session):
+ scope = "profile" + (" https://identity.mozilla.com/tokens/session" if session else "")
+ body = {
+ "client_id": "5882386c6d801776",
+ "state": "test",
+ "keys_jwe": keys_jwe,
+ "scope": scope,
+ "access_type": "offline" if refresh else "online",
+ "code_challenge": "n4bQgYhMfWWaL-qgxVrQFaO_TxsrC4Is0V1sFbDwCgg", # "test"
+ "code_challenge_method": "S256",
+ "response_type": "code",
+ }
+ resp = account.post_a("/oauth/authorization", body)
+ assert resp['state'] == "test"
+
+ body = {
+ "client_id": "5882386c6d801776",
+ "ttl": 60,
+ "grant_type": "authorization_code",
+ "code": resp['code'],
+ "code_verifier": "test",
+ }
+ resp = account.post("/oauth/token", body)
+ assert 'access_token' in resp
+ assert ('refresh_token' in resp) == refresh
+ assert ('session_token' in resp) == session
+ assert resp['scope'] == 'profile'
+ assert resp['token_type'] == 'bearer'
+ assert resp['expires_in'] <= 60
+ assert (resp['auth_at'] - time.time()) < 10
+ assert keys_jwe is None or (resp['keys_jwe'] == keys_jwe)
+
+ def test_oauth_refresh(self, account, refresh_token):
+ body = {
+ "client_id": "5882386c6d801776",
+ "ttl": 60,
+ "grant_type": "refresh_token",
+ "refresh_token": refresh_token.bearer,
+ "scope": "profile",
+ }
+ resp = account.post("/oauth/token", body)
+
+ assert 'access_token' in resp
+ assert 'refresh_token' not in resp
+ assert 'session_token' not in resp
+ assert resp['scope'] == 'profile'
+ assert resp['token_type'] == 'bearer'
+ assert resp['expires_in'] <= 60
+ assert (resp['auth_at'] - time.time()) < 10
+ assert 'keys_jwe' not in resp
+
+ @pytest.mark.parametrize("grant_type,access_type", [
+ ("authorization_code", "online"),
+ ("refresh_token", "online"),
+ ("fxa-credentials", "foo"),
+ ])
+ def test_oauth_token_fxa_invalid(self, account, grant_type, access_type):
+ body = { "client_id": "5882386c6d801776", "ttl": 60, "grant_type": grant_type,
+ "access_type": access_type, "scope": "scope" }
+ with pytest.raises(ClientError) as e:
+ account.post_a("/oauth/token", body)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 107,
+ 'error': 'Bad Request',
+ 'message': 'invalid parameter in request body'
+ }
def test_oauth_authorization_unverified(unverified_account):
body = {
@@ -54,99 +332,6 @@ def test_oauth_authorization_unverified(unverified_account):
'message': 'unverified session'
}
-@pytest.mark.parametrize("args", [
- { "client_id": "5882386c6d801776", "state": "", "scope": "profile", "access_type": "invalid",
- "code_challenge": "", "code_challenge_method": "S256", "response_type": "code" },
- { "client_id": "5882386c6d801776", "state": "", "scope": "profile", "access_type": "online",
- "code_challenge": "", "code_challenge_method": "invalid", "response_type": "code" },
- { "client_id": "5882386c6d801776", "state": "", "scope": "profile", "access_type": "online",
- "code_challenge": "", "code_challenge_method": "S256", "response_type": "invalid" },
-])
-def test_oauth_authorization_invalid(account, args):
- with pytest.raises(ClientError) as e:
- account.post_a("/oauth/authorization", args)
- assert e.value.details == {
- 'code': 400,
- 'errno': 107,
- 'error': 'Bad Request',
- 'message': 'invalid parameter in request body'
- }
-
-def test_oauth_authorization_badclientid(account):
- args = { "client_id": "invalid", "state": "", "scope": "profile", "access_type": "online",
- "code_challenge": "", "code_challenge_method": "S256", "response_type": "code" }
- with pytest.raises(ClientError) as e:
- account.post_a("/oauth/authorization", args)
- assert e.value.details == {
- 'code': 400,
- 'errno': 162,
- 'error': 'Bad Request',
- 'message': 'unknown client_id'
- }
-
-def test_oauth_authorization_badscope(account):
- args = { "client_id": "5882386c6d801776", "state": "", "scope": "invalid", "access_type": "online",
- "code_challenge": "", "code_challenge_method": "S256", "response_type": "code" }
- with pytest.raises(ClientError) as e:
- account.post_a("/oauth/authorization", args)
- assert e.value.details == {
- 'code': 400,
- 'errno': 169,
- 'error': 'Bad Request',
- 'message': 'requested scopes not allowed'
- }
-
-# see below for combined /authorization + unauthed /token
-
-def test_oauth_destroy_notoken(account):
- args = { "client_id": "5882386c6d801776", "token": "00" * 32 }
- with pytest.raises(ClientError) as e:
- account.post("/oauth/destroy", args)
- assert e.value.details == {
- 'code': 400,
- 'errno': 107,
- 'error': 'Bad Request',
- 'message': 'invalid parameter in request body'
- }
-
-@pytest.mark.xfail
-def test_oauth_destroy_badclient(account, refresh_token):
- args = { "client_id": "other", "token": refresh_token.bearer }
- with pytest.raises(ClientError) as e:
- account.post("/oauth/destroy", args)
- assert e.value.details == {
- 'code': 400,
- 'errno': 107,
- 'error': 'Bad Request',
- 'message': 'invalid parameter in request body'
- }
-
-def test_oauth_scoped_keys_badclient(account):
- with pytest.raises(ClientError) as e:
- account.post_a("/account/scoped-key-data", {
- "client_id": "invalid",
- "scope": "https://identity.mozilla.com/apps/oldsync"
- })
- assert e.value.details == {
- 'code': 400,
- 'errno': 162,
- 'error': 'Bad Request',
- 'message': 'unknown client_id'
- }
-
-def test_oauth_scoped_keys_badscope(account):
- with pytest.raises(ClientError) as e:
- account.post_a("/account/scoped-key-data", {
- "client_id": "5882386c6d801776",
- "scope": "scope"
- })
- assert e.value.details == {
- 'code': 400,
- 'errno': 169,
- 'error': 'Bad Request',
- 'message': 'requested scopes not allowed'
- }
-
def test_oauth_scoped_unverified(unverified_account):
with pytest.raises(ClientError) as e:
unverified_account.post_a("/account/scoped-key-data", {
@@ -160,62 +345,6 @@ def test_oauth_scoped_unverified(unverified_account):
'message': 'unverified session'
}
-def test_oauth_scoped_keys(account):
- resp = account.post_a("/account/scoped-key-data", {
- "client_id": "5882386c6d801776",
- "scope": "https://identity.mozilla.com/apps/oldsync"
- })
- assert resp == {
- "https://identity.mozilla.com/apps/oldsync": {
- "identifier": "https://identity.mozilla.com/apps/oldsync",
- "keyRotationSecret": "00" * 32,
- "keyRotationTimestamp": 0,
- },
- }
-
-@pytest.mark.parametrize("access_type", ["online", "offline"])
-def test_oauth_token_fxa_badclient(account, access_type):
- body = { "client_id": "invalid", "ttl": 60, "grant_type": "fxa-credentials",
- "access_type": access_type, "scope": "profile" }
- with pytest.raises(ClientError) as e:
- account.post_a("/oauth/token", body)
- assert e.value.details == {
- 'code': 400,
- 'errno': 162,
- 'error': 'Bad Request',
- 'message': 'unknown client_id'
- }
-
-@pytest.mark.parametrize("access_type", ["online", "offline"])
-def test_oauth_token_fxa_badscope(account, access_type):
- body = { "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "fxa-credentials",
- "access_type": access_type, "scope": "scope" }
- with pytest.raises(ClientError) as e:
- account.post_a("/oauth/token", body)
- assert e.value.details == {
- 'code': 400,
- 'errno': 169,
- 'error': 'Bad Request',
- 'message': 'requested scopes not allowed'
- }
-
-@pytest.mark.parametrize("grant_type,access_type", [
- ("authorization_code", "online"),
- ("refresh_token", "online"),
- ("fxa-credentials", "foo"),
-])
-def test_oauth_token_fxa_invalid(account, grant_type, access_type):
- body = { "client_id": "5882386c6d801776", "ttl": 60, "grant_type": grant_type,
- "access_type": access_type, "scope": "scope" }
- with pytest.raises(ClientError) as e:
- account.post_a("/oauth/token", body)
- assert e.value.details == {
- 'code': 400,
- 'errno': 107,
- 'error': 'Bad Request',
- 'message': 'invalid parameter in request body'
- }
-
def test_oauth_token_unverified(unverified_account):
body = { "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "fxa-credentials",
"access_type": "online", "scope": "profile" }
@@ -240,131 +369,3 @@ def auth_code(account):
"response_type": "code",
}
return account.post_a("/oauth/authorization", body)['code']
-
-@pytest.mark.parametrize("args,code,error,errno,message", [
- ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "authorization_code",
- "code": "invalid", "code_verifier": "test" },
- 400, 'Bad Request', 107, 'invalid parameter in request body'),
- ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "authorization_code",
- "code_verifier": "test", "extra": 0 },
- 400, 'Bad Request', 107, 'invalid parameter in request body'),
- ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "authorization_code",
- "code": "00" * 32, "code_verifier": "test" },
- 401, 'Unauthorized', 110, 'invalid authentication token'),
- ({ "client_id": "invalid", "ttl": 60, "grant_type": "authorization_code",
- "code_verifier": "test" },
- 400, 'Bad Request', 162, 'unknown client_id'),
- ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "authorization_code",
- "code_verifier": "invalid" },
- 400, 'Bad Request', 107, 'invalid parameter in request body'),
-])
-def test_oauth_token_other_invalidcode(account, args, code, error, errno, message, auth_code):
- args = copy.deepcopy(args)
- if 'code' not in args: args['code'] = auth_code
- with pytest.raises(ClientError) as e:
- account.post("/oauth/token", args)
- assert e.value.details == { 'code': code, 'errno': errno, 'error': error, 'message': message }
-
-@pytest.mark.parametrize("args,code,error,errno,message", [
- ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "fxa-credentials",
- "scope": "profile", "access_type": "online" },
- 400, 'Bad Request', 107, 'invalid parameter in request body'),
- ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "refresh_token",
- "refresh_token": "invalid", "code_verifier": "test" },
- 400, 'Bad Request', 107, 'invalid parameter in request body'),
- ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "refresh_token",
- "scope": "profile", "extra": 0 },
- 400, 'Bad Request', 107, 'invalid parameter in request body'),
- ({ "client_id": "invalid", "ttl": 60, "grant_type": "refresh_token",
- "scope": "profile" },
- 400, 'Bad Request', 162, 'unknown client_id'),
- ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "refresh_token",
- "scope": "foo" },
- 400, 'Bad Request', 169, 'requested scopes not allowed'),
- ({ "client_id": "5882386c6d801776", "ttl": 60, "grant_type": "refresh_token",
- "scope": "profile:write" },
- 400, 'Bad Request', 169, 'requested scopes not allowed'),
-])
-def test_oauth_token_other_invalidrefresh(account, args, code, error, errno, message, refresh_token):
- args = copy.deepcopy(args)
- if 'refresh_token' not in args: args['refresh_token'] = refresh_token.bearer
- with pytest.raises(ClientError) as e:
- account.post("/oauth/token", args)
- assert e.value.details == { 'code': code, 'errno': errno, 'error': error, 'message': message }
-
-@pytest.mark.parametrize("refresh", [False, True])
-def test_oauth_fxa(account, refresh):
- body = {
- "client_id": "5882386c6d801776",
- "ttl": 60,
- "grant_type": "fxa-credentials",
- "access_type": "offline" if refresh else "online",
- "scope": "profile",
- }
- resp = account.post_a("/oauth/token", body)
-
- assert 'access_token' in resp
- assert ('refresh_token' in resp) == refresh
- assert 'session_token' not in resp
- assert resp['scope'] == 'profile'
- assert resp['token_type'] == 'bearer'
- assert resp['expires_in'] <= 60
- assert (resp['auth_at'] - time.time()) < 10
- assert 'keys_jwe' not in resp
-
-@pytest.mark.parametrize("keys_jwe", [None, "keyskeyskeys"])
-@pytest.mark.parametrize("refresh,session", [
- (False, False),
- (True, False),
- (True, True),
-])
-def test_oauth_auth_code(account, keys_jwe, refresh, session):
- scope = "profile" + (" https://identity.mozilla.com/tokens/session" if session else "")
- body = {
- "client_id": "5882386c6d801776",
- "state": "test",
- "keys_jwe": keys_jwe,
- "scope": scope,
- "access_type": "offline" if refresh else "online",
- "code_challenge": "n4bQgYhMfWWaL-qgxVrQFaO_TxsrC4Is0V1sFbDwCgg", # "test"
- "code_challenge_method": "S256",
- "response_type": "code",
- }
- resp = account.post_a("/oauth/authorization", body)
- assert resp['state'] == "test"
-
- body = {
- "client_id": "5882386c6d801776",
- "ttl": 60,
- "grant_type": "authorization_code",
- "code": resp['code'],
- "code_verifier": "test",
- }
- resp = account.post("/oauth/token", body)
- assert 'access_token' in resp
- assert ('refresh_token' in resp) == refresh
- assert ('session_token' in resp) == session
- assert resp['scope'] == 'profile'
- assert resp['token_type'] == 'bearer'
- assert resp['expires_in'] <= 60
- assert (resp['auth_at'] - time.time()) < 10
- assert keys_jwe is None or (resp['keys_jwe'] == keys_jwe)
-
-def test_oauth_refresh(account, refresh_token):
- body = {
- "client_id": "5882386c6d801776",
- "ttl": 60,
- "grant_type": "refresh_token",
- "refresh_token": refresh_token.bearer,
- "scope": "profile",
- }
- resp = account.post("/oauth/token", body)
-
- assert 'access_token' in resp
- assert 'refresh_token' not in resp
- assert 'session_token' not in resp
- assert resp['scope'] == 'profile'
- assert resp['token_type'] == 'bearer'
- assert resp['expires_in'] <= 60
- assert (resp['auth_at'] - time.time()) < 10
- assert 'keys_jwe' not in resp
diff --git a/tests/test_auth_password.py b/tests/test_auth_password.py
index 7c2064a..fc7bb2b 100644
--- a/tests/test_auth_password.py
+++ b/tests/test_auth_password.py
@@ -4,38 +4,81 @@ from fxa.errors import ClientError
from api import *
-@pytest.mark.parametrize("args", [
- { 'email': "", 'oldAuthPW': '00' * 32 },
- { 'email': "test0@test", 'oldAuthPW': '00' },
- { 'email': "test0@test", 'oldAuthPW': '00' * 32, 'extra': 0 },
-])
-def test_change_start_invalid(account, args):
- with pytest.raises(ClientError) as e:
- account.post_a("/password/change/start", args)
- assert e.value.details == {
- 'code': 400,
- 'errno': 107,
- 'error': 'Bad Request',
- 'message': 'invalid parameter in request body'
- }
-
-def test_change_start_badaccount(account):
- with pytest.raises(ClientError) as e:
- account.post_a("/password/change/start", { 'email': "test0@test", 'oldAuthPW': '00' * 32 })
- assert e.value.details == {
- 'code': 400,
- 'errno': 102,
- 'error': 'Bad Request',
- 'message': 'unknown account'
- }
- with pytest.raises(ClientError) as e:
- account.post_a("/password/change/start", { 'email': account.email.upper(), 'oldAuthPW': '00' * 32 })
- assert e.value.details == {
- 'code': 400,
- 'errno': 120,
- 'error': 'Bad Request',
- 'message': 'incorrect email case'
- }
+class TestPasswordInvalid:
+ @pytest.mark.parametrize("args", [
+ { 'email': "", 'oldAuthPW': '00' * 32 },
+ { 'email': "test0@test", 'oldAuthPW': '00' },
+ { 'email': "test0@test", 'oldAuthPW': '00' * 32, 'extra': 0 },
+ ])
+ def test_change_start_invalid(self, account, args):
+ with pytest.raises(ClientError) as e:
+ account.post_a("/password/change/start", args)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 107,
+ 'error': 'Bad Request',
+ 'message': 'invalid parameter in request body'
+ }
+
+ def test_change_start_badaccount(self, account):
+ with pytest.raises(ClientError) as e:
+ account.post_a("/password/change/start", { 'email': "test0@test", 'oldAuthPW': '00' * 32 })
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 102,
+ 'error': 'Bad Request',
+ 'message': 'unknown account'
+ }
+ with pytest.raises(ClientError) as e:
+ account.post_a("/password/change/start", { 'email': account.email.upper(), 'oldAuthPW': '00' * 32 })
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 120,
+ 'error': 'Bad Request',
+ 'message': 'incorrect email case'
+ }
+
+ def test_change_start_badpw(self, account):
+ with pytest.raises(ClientError) as e:
+ account.post_a("/password/change/start", { 'email': account.email, 'oldAuthPW': '00' * 32 })
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 103,
+ 'error': 'Bad Request',
+ 'message': 'incorrect password'
+ }
+
+ @pytest.mark.parametrize("args", [
+ { 'email': "" },
+ { 'email': "test0@test", 'extra': 0 },
+ ])
+ def test_forgot_start_invalid(self, account, args):
+ with pytest.raises(ClientError) as e:
+ account.post_a("/password/forgot/send_code", args)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 107,
+ 'error': 'Bad Request',
+ 'message': 'invalid parameter in request body'
+ }
+
+ def test_change_forgot_badaccount(self, account):
+ with pytest.raises(ClientError) as e:
+ account.post_a("/password/forgot/send_code", { 'email': "test0@test" })
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 102,
+ 'error': 'Bad Request',
+ 'message': 'unknown account'
+ }
+ with pytest.raises(ClientError) as e:
+ account.post_a("/password/forgot/send_code", { 'email': account.email.upper() })
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 120,
+ 'error': 'Bad Request',
+ 'message': 'incorrect email case'
+ }
def test_change_start_unverified(unverified_account):
with pytest.raises(ClientError) as e:
@@ -50,16 +93,6 @@ def test_change_start_unverified(unverified_account):
'message': 'unverified account'
}
-def test_change_start_badpw(account):
- with pytest.raises(ClientError) as e:
- account.post_a("/password/change/start", { 'email': account.email, 'oldAuthPW': '00' * 32 })
- assert e.value.details == {
- 'code': 400,
- 'errno': 103,
- 'error': 'Bad Request',
- 'message': 'incorrect password'
- }
-
@pytest.fixture
def change_token(account):
pw = auth_pw(account.email, "")
@@ -67,20 +100,21 @@ def change_token(account):
assert 'keyFetchToken' in resp
return PasswordChange(account.client, resp['passwordChangeToken'])
-@pytest.mark.parametrize("args", [
- { 'authPW': '00', 'wrapKb': '00' * 32, 'sessionToken': '00' * 32, },
- { 'authPW': '00' * 32, 'wrapKb': '00', 'sessionToken': '00' * 32, },
- { 'authPW': '00' * 32, 'wrapKb': '00' * 32, 'sessionToken': '00', },
-])
-def test_change_finish_invalid(change_token, args):
- with pytest.raises(ClientError) as e:
- change_token.post_a("/password/change/finish", args)
- assert e.value.details == {
- 'code': 400,
- 'errno': 107,
- 'error': 'Bad Request',
- 'message': 'invalid parameter in request body'
- }
+class TestChangeInvalid:
+ @pytest.mark.parametrize("args", [
+ { 'authPW': '00', 'wrapKb': '00' * 32, 'sessionToken': '00' * 32, },
+ { 'authPW': '00' * 32, 'wrapKb': '00', 'sessionToken': '00' * 32, },
+ { 'authPW': '00' * 32, 'wrapKb': '00' * 32, 'sessionToken': '00', },
+ ])
+ def test_change_finish_invalid(self, change_token, args):
+ with pytest.raises(ClientError) as e:
+ change_token.post_a("/password/change/finish", args)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 107,
+ 'error': 'Bad Request',
+ 'message': 'invalid parameter in request body'
+ }
def test_change_finish(account, change_token, mail_server):
pw = auth_pw(account.email, "new")
@@ -124,38 +158,6 @@ def test_change_finish_twice(account, change_token, mail_server):
'message': 'invalid request signature'
}
-@pytest.mark.parametrize("args", [
- { 'email': "" },
- { 'email': "test0@test", 'extra': 0 },
-])
-def test_forgot_start_invalid(account, args):
- with pytest.raises(ClientError) as e:
- account.post_a("/password/forgot/send_code", args)
- assert e.value.details == {
- 'code': 400,
- 'errno': 107,
- 'error': 'Bad Request',
- 'message': 'invalid parameter in request body'
- }
-
-def test_change_forgot_badaccount(account):
- with pytest.raises(ClientError) as e:
- account.post_a("/password/forgot/send_code", { 'email': "test0@test" })
- assert e.value.details == {
- 'code': 400,
- 'errno': 102,
- 'error': 'Bad Request',
- 'message': 'unknown account'
- }
- with pytest.raises(ClientError) as e:
- account.post_a("/password/forgot/send_code", { 'email': account.email.upper() })
- assert e.value.details == {
- 'code': 400,
- 'errno': 120,
- 'error': 'Bad Request',
- 'message': 'incorrect email case'
- }
-
def test_change_forgot_unverified(unverified_account):
with pytest.raises(ClientError) as e:
unverified_account.post_a("/password/forgot/send_code", { 'email': unverified_account.email })
@@ -180,8 +182,6 @@ def test_forgot_finish_invalid(change_token, args):
}
def test_forgot_finish_badcode(account, forgot_token, mail_server):
- (to, body) = mail_server.wait()
- assert account.email in to
with pytest.raises(ClientError) as e:
resp = forgot_token.post_a("/password/forgot/verify_code", { 'code': '' })
assert e.value.details == {
@@ -192,17 +192,14 @@ def test_forgot_finish_badcode(account, forgot_token, mail_server):
}
def test_forgot_finish(account, forgot_token, mail_server):
- (to, body) = mail_server.wait()
- assert account.email in to
- resp = forgot_token.post_a("/password/forgot/verify_code", { 'code': body.strip() })
+ resp = forgot_token.post_a("/password/forgot/verify_code", { 'code': forgot_token.code })
assert 'accountResetToken' in resp
def test_forgot_finish_twice(account, forgot_token, mail_server):
- (to, body) = mail_server.wait()
- forgot_token.post_a("/password/forgot/verify_code", { 'code': body.strip() })
+ forgot_token.post_a("/password/forgot/verify_code", { 'code': forgot_token.code })
with pytest.raises(ClientError) as e:
- forgot_token.post_a("/password/forgot/verify_code", { 'code': body.strip() })
+ forgot_token.post_a("/password/forgot/verify_code", { 'code': forgot_token.code })
assert e.value.details == {
'code': 401,
'errno': 109,
diff --git a/tests/test_auth_session.py b/tests/test_auth_session.py
index 3a6e7c4..bcdd0bc 100644
--- a/tests/test_auth_session.py
+++ b/tests/test_auth_session.py
@@ -13,52 +13,53 @@ def test_session_loggedout(client):
'message': 'invalid request signature'
}
-def test_status(account):
- resp = account.get_a("/session/status")
- assert resp == { 'state': '', 'uid': account.props['uid'] }
+class TestSession:
+ def test_status(self, account):
+ resp = account.get_a("/session/status")
+ assert resp == { 'state': '', 'uid': account.props['uid'] }
-def test_resend(account, mail_server):
- c = account.login(account.email, "")
- (to, body) = mail_server.wait()
- assert to == [account.email]
- c.post_a("/session/resend_code", {})
- (to2, body2) = mail_server.wait()
- assert to == to2
- assert body == body2
+ def test_resend(self, account, mail_server):
+ c = account.login(account.email, "")
+ (to, body) = mail_server.wait()
+ assert to == [account.email]
+ c.post_a("/session/resend_code", {})
+ (to2, body2) = mail_server.wait()
+ assert to == to2
+ assert body == body2
-@pytest.mark.parametrize("args", [
- { 'custom_session_id': '00' },
- { 'extra': '00' },
-])
-def test_session_invalid(account, args):
- with pytest.raises(ClientError) as e:
- account.post_a("/session/destroy", args)
- assert e.value.details == {
- 'code': 400,
- 'errno': 107,
- 'error': 'Bad Request',
- 'message': 'invalid parameter in request body'
- }
+ @pytest.mark.parametrize("args", [
+ { 'custom_session_id': '00' },
+ { 'extra': '00' },
+ ])
+ def test_session_invalid(self, account, args):
+ with pytest.raises(ClientError) as e:
+ account.post_a("/session/destroy", args)
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 107,
+ 'error': 'Bad Request',
+ 'message': 'invalid parameter in request body'
+ }
-def test_session_noid(account):
- with pytest.raises(ClientError) as e:
- account.post_a("/session/destroy", { 'custom_session_id': '0' * 64 })
- assert e.value.details == {
- 'code': 400,
- 'errno': 123,
- 'error': 'Bad Request',
- 'message': 'unknown device'
- }
+ def test_session_noid(self, account):
+ with pytest.raises(ClientError) as e:
+ account.post_a("/session/destroy", { 'custom_session_id': '0' * 64 })
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 123,
+ 'error': 'Bad Request',
+ 'message': 'unknown device'
+ }
-def test_session_destroy_other(account, account2):
- with pytest.raises(ClientError) as e:
- account.post_a("/session/destroy", { 'custom_session_id': account2.auth.id })
- assert e.value.details == {
- 'code': 400,
- 'errno': 123,
- 'error': 'Bad Request',
- 'message': 'unknown device'
- }
+ def test_session_destroy_other(self, account, account2):
+ with pytest.raises(ClientError) as e:
+ account.post_a("/session/destroy", { 'custom_session_id': account2.auth.id })
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 123,
+ 'error': 'Bad Request',
+ 'message': 'unknown device'
+ }
def test_session_destroy_unverified(unverified_account):
unverified_account.destroy_session()
diff --git a/tests/test_oauth.py b/tests/test_oauth.py
index 3eb32ac..d809113 100644
--- a/tests/test_oauth.py
+++ b/tests/test_oauth.py
@@ -32,66 +32,67 @@ def test_destroy_invalid(oauth, args, code, errno, error, message):
oauth.post("/destroy", args)
assert e.value.details == {'code': code, 'errno': errno, 'error': error, 'message': message}
-def test_destroy_access(oauth, access_token):
- oauth.post("/verify", {'token': access_token})
- oauth.post("/destroy", {'access_token': access_token})
- with pytest.raises(ClientError) as e:
+class TestOauth:
+ def test_destroy_access(self, oauth, access_token):
oauth.post("/verify", {'token': access_token})
- assert e.value.details == {
- 'code': 400,
- 'errno': 109,
- 'error': 'Bad Request',
- 'message': 'invalid request parameter'
- }
+ oauth.post("/destroy", {'access_token': access_token})
+ with pytest.raises(ClientError) as e:
+ oauth.post("/verify", {'token': access_token})
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 109,
+ 'error': 'Bad Request',
+ 'message': 'invalid request parameter'
+ }
-def test_destroy_refresh(oauth, refresh_token):
- refresh_token.get_a("/account/devices")
- oauth.post("/destroy", {'refresh_token': refresh_token.bearer})
- with pytest.raises(ClientError) as e:
+ def test_destroy_refresh(self, oauth, refresh_token):
refresh_token.get_a("/account/devices")
- assert e.value.details == {
- 'code': 401,
- 'errno': 109,
- 'error': 'Unauthorized',
- 'message': 'invalid request signature'
- }
+ oauth.post("/destroy", {'refresh_token': refresh_token.bearer})
+ with pytest.raises(ClientError) as e:
+ refresh_token.get_a("/account/devices")
+ assert e.value.details == {
+ 'code': 401,
+ 'errno': 109,
+ 'error': 'Unauthorized',
+ 'message': 'invalid request signature'
+ }
-def test_destroy_any(oauth, access_token, refresh_token):
- oauth.post("/verify", {'token': access_token})
- oauth.post("/destroy", {'token': access_token})
- with pytest.raises(ClientError) as e:
+ def test_destroy_any(self, oauth, access_token, refresh_token):
oauth.post("/verify", {'token': access_token})
- assert e.value.details == {
- 'code': 400,
- 'errno': 109,
- 'error': 'Bad Request',
- 'message': 'invalid request parameter'
- }
+ oauth.post("/destroy", {'token': access_token})
+ with pytest.raises(ClientError) as e:
+ oauth.post("/verify", {'token': access_token})
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 109,
+ 'error': 'Bad Request',
+ 'message': 'invalid request parameter'
+ }
- refresh_token.get_a("/account/devices")
- oauth.post("/destroy", {'token': refresh_token.bearer})
- with pytest.raises(ClientError) as e:
refresh_token.get_a("/account/devices")
- assert e.value.details == {
- 'code': 401,
- 'errno': 109,
- 'error': 'Unauthorized',
- 'message': 'invalid request signature'
- }
+ oauth.post("/destroy", {'token': refresh_token.bearer})
+ with pytest.raises(ClientError) as e:
+ refresh_token.get_a("/account/devices")
+ assert e.value.details == {
+ 'code': 401,
+ 'errno': 109,
+ 'error': 'Unauthorized',
+ 'message': 'invalid request signature'
+ }
-def test_oauth_verify(account, oauth, access_token):
- assert oauth.post("/verify", {'token': access_token}) == {
- 'user': account.props['uid'],
- 'client_id': "5882386c6d801776",
- 'scope': ['profile'],
- }
+ def test_oauth_verify(self, account, oauth, access_token):
+ assert oauth.post("/verify", {'token': access_token}) == {
+ 'user': account.props['uid'],
+ 'client_id': "5882386c6d801776",
+ 'scope': ['profile'],
+ }
-def test_oauth_verify_refresh(oauth, refresh_token):
- with pytest.raises(ClientError) as e:
- oauth.post("/verify", {'token': refresh_token.bearer})
- assert e.value.details == {
- 'code': 400,
- 'errno': 109,
- 'error': 'Bad Request',
- 'message': 'invalid request parameter'
- }
+ def test_oauth_verify_refresh(self, oauth, refresh_token):
+ with pytest.raises(ClientError) as e:
+ oauth.post("/verify", {'token': refresh_token.bearer})
+ assert e.value.details == {
+ 'code': 400,
+ 'errno': 109,
+ 'error': 'Bad Request',
+ 'message': 'invalid request parameter'
+ }
diff --git a/tests/test_profile.py b/tests/test_profile.py
index 1e21ecc..13dc8b4 100644
--- a/tests/test_profile.py
+++ b/tests/test_profile.py
@@ -7,128 +7,129 @@ from api import *
def profile(account):
return account.profile()
-def test_profile_noauth(profile):
- with pytest.raises(ClientError) as e:
- profile.get("/profile")
- assert e.value.details == {
- 'code': 403,
- 'errno': 100,
- 'error': 'Forbidden',
- 'message': 'unauthorized'
- }
+class TestProfile:
+ def test_profile_noauth(self, profile):
+ with pytest.raises(ClientError) as e:
+ profile.get("/profile")
+ assert e.value.details == {
+ 'code': 403,
+ 'errno': 100,
+ 'error': 'Forbidden',
+ 'message': 'unauthorized'
+ }
-def test_display_name_noauth(profile):
- with pytest.raises(ClientError) as e:
- profile.post("/display_name", {'displayName': 'foo'})
- assert e.value.details == {
- 'code': 403,
- 'errno': 100,
- 'error': 'Forbidden',
- 'message': 'unauthorized'
- }
+ def test_display_name_noauth(self, profile):
+ with pytest.raises(ClientError) as e:
+ profile.post("/display_name", {'displayName': 'foo'})
+ assert e.value.details == {
+ 'code': 403,
+ 'errno': 100,
+ 'error': 'Forbidden',
+ 'message': 'unauthorized'
+ }
-def test_avatar_upload_noauth(profile):
- with pytest.raises(ClientError) as e:
- profile.post("/avatar/upload", "foo", headers={'content-type': 'image/png'})
- assert e.value.details == {
- 'code': 403,
- 'errno': 100,
- 'error': 'Forbidden',
- 'message': 'unauthorized'
- }
+ def test_avatar_upload_noauth(self, profile):
+ with pytest.raises(ClientError) as e:
+ profile.post("/avatar/upload", "foo", headers={'content-type': 'image/png'})
+ assert e.value.details == {
+ 'code': 403,
+ 'errno': 100,
+ 'error': 'Forbidden',
+ 'message': 'unauthorized'
+ }
-def test_avatar_delete_noauth(profile):
- with pytest.raises(ClientError) as e:
- profile.delete("/avatar/00000000000000000000000000000000")
- assert e.value.details == {
- 'code': 403,
- 'errno': 100,
- 'error': 'Forbidden',
- 'message': 'unauthorized'
- }
+ def test_avatar_delete_noauth(self, profile):
+ with pytest.raises(ClientError) as e:
+ profile.delete("/avatar/00000000000000000000000000000000")
+ assert e.value.details == {
+ 'code': 403,
+ 'errno': 100,
+ 'error': 'Forbidden',
+ 'message': 'unauthorized'
+ }
-def test_profile(account, profile):
- resp = profile.get_a("/profile")
- assert resp == {
- 'amrValues': None,
- 'avatar': f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000',
- 'avatarDefault': True,
- 'displayName': None,
- 'email': account.email,
- 'locale': None,
- 'subscriptions': None,
- 'twoFactorAuthentication': False,
- 'uid': account.props['uid']
- }
+ def test_profile(self, account, profile):
+ resp = profile.get_a("/profile")
+ assert resp == {
+ 'amrValues': None,
+ 'avatar': f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000',
+ 'avatarDefault': True,
+ 'displayName': None,
+ 'email': account.email,
+ 'locale': None,
+ 'subscriptions': None,
+ 'twoFactorAuthentication': False,
+ 'uid': account.props['uid']
+ }
-def test_display_name(account, profile):
- resp = profile.get_a("/profile")
- assert resp == {
- 'amrValues': None,
- 'avatar': f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000',
- 'avatarDefault': True,
- 'displayName': None,
- 'email': account.email,
- 'locale': None,
- 'subscriptions': None,
- 'twoFactorAuthentication': False,
- 'uid': account.props['uid']
- }
- profile.post_a("/display_name", {'displayName': 'foo'})
- resp = profile.get_a("/profile")
- assert resp == {
- 'amrValues': None,
- 'avatar': f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000',
- 'avatarDefault': True,
- 'displayName': 'foo',
- 'email': account.email,
- 'locale': None,
- 'subscriptions': None,
- 'twoFactorAuthentication': False,
- 'uid': account.props['uid']
- }
+ def test_display_name(self, account, profile):
+ resp = profile.get_a("/profile")
+ assert resp == {
+ 'amrValues': None,
+ 'avatar': f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000',
+ 'avatarDefault': True,
+ 'displayName': None,
+ 'email': account.email,
+ 'locale': None,
+ 'subscriptions': None,
+ 'twoFactorAuthentication': False,
+ 'uid': account.props['uid']
+ }
+ profile.post_a("/display_name", {'displayName': 'foo'})
+ resp = profile.get_a("/profile")
+ assert resp == {
+ 'amrValues': None,
+ 'avatar': f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000',
+ 'avatarDefault': True,
+ 'displayName': 'foo',
+ 'email': account.email,
+ 'locale': None,
+ 'subscriptions': None,
+ 'twoFactorAuthentication': False,
+ 'uid': account.props['uid']
+ }
-def test_avatar(account, profile):
- resp = profile.get_a("/avatar")
- assert resp == {
- 'avatar': f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000',
- 'avatarDefault': True,
- 'id': '00000000000000000000000000000000'
- }
+ def test_avatar(self, account, profile):
+ resp = profile.get_a("/avatar")
+ assert resp == {
+ 'avatar': f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000',
+ 'avatarDefault': True,
+ 'id': '00000000000000000000000000000000'
+ }
-def test_avatar_upload(account, profile):
- # server does not parse the bytes
- profile.post_a("/avatar/upload", "foo", headers={'content-type': 'image/png'})
- resp = profile.get_a("/avatar")
- new_id = resp['id']
- assert resp['avatar'] != f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000'
- assert not resp['avatarDefault']
- assert resp['id'] != '00000000000000000000000000000000'
- resp = profile.get_a("/profile")
- assert resp['avatar'] != f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000'
- assert not resp['avatarDefault']
+ def test_avatar_upload(self, account, profile):
+ # server does not parse the bytes
+ profile.post_a("/avatar/upload", "foo", headers={'content-type': 'image/png'})
+ resp = profile.get_a("/avatar")
+ new_id = resp['id']
+ assert resp['avatar'] != f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000'
+ assert not resp['avatarDefault']
+ assert resp['id'] != '00000000000000000000000000000000'
+ resp = profile.get_a("/profile")
+ assert resp['avatar'] != f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000'
+ assert not resp['avatarDefault']
-def test_avatar_delete(account, profile):
- # server does not parse the bytes
- profile.post_a("/avatar/upload", "foo", headers={'content-type': 'image/png'})
- resp = profile.get_a("/avatar")
- new_id = resp['id']
- profile.delete_a(f"/avatar/{new_id}")
- resp = profile.get_a("/avatar")
- assert resp == {
- 'avatar': f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000',
- 'avatarDefault': True,
- 'id': '00000000000000000000000000000000'
- }
- resp = profile.get_a("/profile")
- assert resp == {
- 'amrValues': None,
- 'avatar': f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000',
- 'avatarDefault': True,
- 'displayName': None,
- 'email': account.email,
- 'locale': None,
- 'subscriptions': None,
- 'twoFactorAuthentication': False,
- 'uid': account.props['uid']
- }
+ def test_avatar_delete(self, account, profile):
+ # server does not parse the bytes
+ profile.post_a("/avatar/upload", "foo", headers={'content-type': 'image/png'})
+ resp = profile.get_a("/avatar")
+ new_id = resp['id']
+ profile.delete_a(f"/avatar/{new_id}")
+ resp = profile.get_a("/avatar")
+ assert resp == {
+ 'avatar': f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000',
+ 'avatarDefault': True,
+ 'id': '00000000000000000000000000000000'
+ }
+ resp = profile.get_a("/profile")
+ assert resp == {
+ 'amrValues': None,
+ 'avatar': f'http://localhost:{API_PORT}/avatars/00000000000000000000000000000000',
+ 'avatarDefault': True,
+ 'displayName': resp['displayName'], # ignore this field
+ 'email': account.email,
+ 'locale': None,
+ 'subscriptions': None,
+ 'twoFactorAuthentication': False,
+ 'uid': account.props['uid']
+ }
diff --git a/tests/test_push.py b/tests/test_push.py
index e6d732a..37688ad 100644
--- a/tests/test_push.py
+++ b/tests/test_push.py
@@ -2,32 +2,38 @@ import pytest
from api import *
-def test_account_destroy(account, push_server):
- dev = Device(account, "dev", pcb=push_server.good("09d0114e-3b23-4ba3-8474-efac7433e3ba"))
- account.destroy_account(account.email, "")
- p = push_server.wait()
- assert p[0] == "/09d0114e-3b23-4ba3-8474-efac7433e3ba"
- assert dev.decrypt(p[2]) == {
- 'command': 'fxaccounts:account_destroyed',
- 'data': {'uid': account.props['uid']},
- 'version': 1,
- }
- assert push_server.done()
+# scope each test to not leak devices into the others
-def test_account_verify(client, push_server, mail_server):
- account = client.create_account("test@test", "")
- try:
- (to, body) = mail_server.wait()
- assert to == ["test@test"]
- data = json.loads(base64.urlsafe_b64decode(body.split("#/verify/", maxsplit=1)[1]).decode('utf8'))
- dev = Device(account, "dev", pcb=push_server.good("8accbe08-4040-44c2-8fd9-cf2669b56cb1"))
- account.post_a('/recovery_email/verify_code', { 'uid': data['uid'], 'code': data['code'] })
+class TestAccountDestroy:
+ def test_account_destroy(self, account, push_server):
+ dev = Device(account, "dev", pcb=push_server.good("09d0114e-3b23-4ba3-8474-efac7433e3ba"))
+ account.destroy_account(account.email, "")
p = push_server.wait()
- assert p[0] == "/8accbe08-4040-44c2-8fd9-cf2669b56cb1"
- assert p[2] == b''
+ assert p[0] == "/09d0114e-3b23-4ba3-8474-efac7433e3ba"
+ assert dev.decrypt(p[2]) == {
+ 'command': 'fxaccounts:account_destroyed',
+ 'data': {'uid': account.props['uid']},
+ 'version': 1,
+ }
assert push_server.done()
- finally:
- account.destroy_account(account.email, "")
+
+class TestAccountVerify:
+ def test_account_verify(self, client, push_server, mail_server):
+ account = client.create_account("test@test", "")
+ try:
+ (to, body) = mail_server.wait()
+ assert to == ["test@test"]
+ data = json.loads(base64.urlsafe_b64decode(body.split("#/verify/", maxsplit=1)[1]).decode('utf8'))
+ dev = Device(account, "dev", pcb=push_server.good("8accbe08-4040-44c2-8fd9-cf2669b56cb1"))
+ account.post_a('/recovery_email/verify_code', { 'uid': data['uid'], 'code': data['code'] })
+ p = push_server.wait()
+ assert p[0] == "/8accbe08-4040-44c2-8fd9-cf2669b56cb1"
+ assert p[2] == b''
+ assert push_server.done()
+ finally:
+ account.destroy_account(account.email, "")
+
+# these two destroy their sessions
def test_session_destroy(client, account, push_server):
dev1 = Device(account, "dev1")
@@ -57,91 +63,95 @@ def test_device_connected(client, account, push_server):
}
assert push_server.done()
-def test_device_invoke(account, login, push_server):
- dev = Device(account, "dev1", commands={'a':'a'}, pcb=push_server.good("3610b071-e2ef-4daa-a4e3-eaa74e50f2a0"))
- account.post_a("/account/devices/invoke_command", {
- "target": dev.id,
- "command": "a",
- "payload": {"data": "foo"},
- "ttl": 10,
- })
- p = push_server.wait()
- assert p[0] == "/3610b071-e2ef-4daa-a4e3-eaa74e50f2a0"
- msg = dev.decrypt(p[2])
- # NOTE needed because index is unpredictable due to pg sequence use
- del msg['data']['index']
- del msg['data']['url']
- assert msg == {
- 'command': 'fxaccounts:command_received',
- 'data': {'command': 'a', 'sender': dev.id},
- 'version': 1,
- }
- assert push_server.done()
+class TestDeviceInvoke:
+ def test_device_invoke(self, account, login, push_server):
+ dev = Device(account, "dev1", commands={'a':'a'}, pcb=push_server.good("3610b071-e2ef-4daa-a4e3-eaa74e50f2a0"))
+ account.post_a("/account/devices/invoke_command", {
+ "target": dev.id,
+ "command": "a",
+ "payload": {"data": "foo"},
+ "ttl": 10,
+ })
+ p = push_server.wait()
+ assert p[0] == "/3610b071-e2ef-4daa-a4e3-eaa74e50f2a0"
+ msg = dev.decrypt(p[2])
+ # NOTE needed because index is unpredictable due to pg sequence use
+ del msg['data']['index']
+ del msg['data']['url']
+ assert msg == {
+ 'command': 'fxaccounts:command_received',
+ 'data': {'command': 'a', 'sender': dev.id},
+ 'version': 1,
+ }
+ assert push_server.done()
-def test_expiry(account, login, push_server):
- dev = Device(account, "dev1", commands={'a':'a'}, pcb=push_server.bad("59ba8fcc-f3b0-4b1f-ac27-36d66e022d1e"))
- account.post_a("/account/devices/invoke_command", {
- "target": dev.id,
- "command": "a",
- "payload": {"data": "foo"},
- "ttl": 10,
- })
- p = push_server.wait()
- assert p[0] == "/err/59ba8fcc-f3b0-4b1f-ac27-36d66e022d1e"
- account.post_a("/account/devices/invoke_command", {
- "target": dev.id,
- "command": "a",
- "payload": {"data": "foo"},
- "ttl": 10,
- })
- with pytest.raises(queue.Empty):
- push_server.wait()
- dev.update_pcb(push_server.good("59ba8fcc-f3b0-4b1f-ac27-36d66e022d1e"))
- account.post_a("/account/devices/invoke_command", {
- "target": dev.id,
- "command": "a",
- "payload": {"data": "foo"},
- "ttl": 10,
- })
- p = push_server.wait()
- assert p[0] == "/59ba8fcc-f3b0-4b1f-ac27-36d66e022d1e"
- assert push_server.done()
+class TestExpiry:
+ def test_expiry(self, account, login, push_server):
+ dev = Device(account, "dev1", commands={'a':'a'}, pcb=push_server.bad("59ba8fcc-f3b0-4b1f-ac27-36d66e022d1e"))
+ account.post_a("/account/devices/invoke_command", {
+ "target": dev.id,
+ "command": "a",
+ "payload": {"data": "foo"},
+ "ttl": 10,
+ })
+ p = push_server.wait()
+ assert p[0] == "/err/59ba8fcc-f3b0-4b1f-ac27-36d66e022d1e"
+ account.post_a("/account/devices/invoke_command", {
+ "target": dev.id,
+ "command": "a",
+ "payload": {"data": "foo"},
+ "ttl": 10,
+ })
+ with pytest.raises(queue.Empty):
+ push_server.wait()
+ dev.update_pcb(push_server.good("59ba8fcc-f3b0-4b1f-ac27-36d66e022d1e"))
+ account.post_a("/account/devices/invoke_command", {
+ "target": dev.id,
+ "command": "a",
+ "payload": {"data": "foo"},
+ "ttl": 10,
+ })
+ p = push_server.wait()
+ assert p[0] == "/59ba8fcc-f3b0-4b1f-ac27-36d66e022d1e"
+ assert push_server.done()
-def test_device_notify(account, login, push_server):
- dev1 = Device(account, "dev1")
- dev2 = Device(login, "dev2")
- dev1.update_pcb(push_server.good("738ac7e3-96ef-461c-880c-0af20e311354"))
- dev2.update_pcb(push_server.good("85a98191-9486-46e2-877a-1152e3d4af4e"))
- account.post_a("/account/devices/notify", {
- "to": "all",
- "_endpointAction": "accountVerify",
- "excluded": [dev2.id],
- "payload": {'a':1},
- "TTL": 0,
- })
- p = push_server.wait()
- assert p[0] == "/738ac7e3-96ef-461c-880c-0af20e311354"
- assert dev1.decrypt(p[2]) == {'a':1}
- account.post_a("/account/devices/notify", {
- "to": [dev2.id],
- "_endpointAction": "accountVerify",
- "payload": {'a':2},
- "TTL": 0,
- })
- p = push_server.wait()
- assert p[0] == "/85a98191-9486-46e2-877a-1152e3d4af4e"
- assert dev2.decrypt(p[2]) == {'a':2}
- assert push_server.done()
+class TestDeviceNotify:
+ def test_device_notify(self, account, login, push_server):
+ dev1 = Device(account, "dev1")
+ dev2 = Device(login, "dev2")
+ dev1.update_pcb(push_server.good("738ac7e3-96ef-461c-880c-0af20e311354"))
+ dev2.update_pcb(push_server.good("85a98191-9486-46e2-877a-1152e3d4af4e"))
+ account.post_a("/account/devices/notify", {
+ "to": "all",
+ "_endpointAction": "accountVerify",
+ "excluded": [dev2.id],
+ "payload": {'a':1},
+ "TTL": 0,
+ })
+ p = push_server.wait()
+ assert p[0] == "/738ac7e3-96ef-461c-880c-0af20e311354"
+ assert dev1.decrypt(p[2]) == {'a':1}
+ account.post_a("/account/devices/notify", {
+ "to": [dev2.id],
+ "_endpointAction": "accountVerify",
+ "payload": {'a':2},
+ "TTL": 0,
+ })
+ p = push_server.wait()
+ assert p[0] == "/85a98191-9486-46e2-877a-1152e3d4af4e"
+ assert dev2.decrypt(p[2]) == {'a':2}
+ assert push_server.done()
-def test_profile(account, push_server):
- dev = Device(account, "dev", pcb=push_server.good("12608154-8942-4f1c-9de2-a56465d27d6e"))
- profile = account.profile()
- profile.post_a("/display_name", {"displayName": "foo"})
- p = push_server.wait()
- assert p[0] == "/12608154-8942-4f1c-9de2-a56465d27d6e"
- assert dev.decrypt(p[2]) == {'command': 'fxaccounts:profile_updated', 'version': 1}
- profile.post_a("/avatar/upload", "doesn't parse the image", headers={'content-type': 'image/png'})
- p = push_server.wait()
- assert p[0] == "/12608154-8942-4f1c-9de2-a56465d27d6e"
- assert dev.decrypt(p[2]) == {'command': 'fxaccounts:profile_updated', 'version': 1}
- assert push_server.done()
+class TestProfile:
+ def test_profile(self, account, push_server):
+ dev = Device(account, "dev", pcb=push_server.good("12608154-8942-4f1c-9de2-a56465d27d6e"))
+ profile = account.profile()
+ profile.post_a("/display_name", {"displayName": "foo"})
+ p = push_server.wait()
+ assert p[0] == "/12608154-8942-4f1c-9de2-a56465d27d6e"
+ assert dev.decrypt(p[2]) == {'command': 'fxaccounts:profile_updated', 'version': 1}
+ profile.post_a("/avatar/upload", "doesn't parse the image", headers={'content-type': 'image/png'})
+ p = push_server.wait()
+ assert p[0] == "/12608154-8942-4f1c-9de2-a56465d27d6e"
+ assert dev.decrypt(p[2]) == {'command': 'fxaccounts:profile_updated', 'version': 1}
+ assert push_server.done()