summaryrefslogtreecommitdiff
path: root/tests
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 /tests
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.
Diffstat (limited to 'tests')
-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()