{-# LANGUAGE DuplicateRecordFields #-}
{-# OPTIONS_GHC -Wno-ambiguous-fields #-}

module Test.PushToken where

import API.Common
import API.Gundeck
import SetupHelpers
import Testlib.Prelude

testRegisterPushToken :: App ()
testRegisterPushToken :: App ()
testRegisterPushToken = do
  Value
alice <- Domain -> CreateUser -> App Value
forall domain.
(HasCallStack, MakesValue domain) =>
domain -> CreateUser -> App Value
randomUser Domain
OwnDomain CreateUser
forall a. Default a => a
def
  String
aliceC2 <- App String
randomClientId
  String
aliceC1 <- App String
randomClientId

  -- Client 1 with 4 tokens
  String
c1Apns1 <- HasCallStack => TokenLength -> App String
TokenLength -> App String
randomSnsToken TokenLength
APNS
  String
c1Apns1Overlap <- HasCallStack => TokenLength -> App String
TokenLength -> App String
randomSnsToken TokenLength
APNS
  String
c1Apns2 <- HasCallStack => TokenLength -> App String
TokenLength -> App String
randomSnsToken TokenLength
APNS
  String
c1Gcm1 <- HasCallStack => TokenLength -> App String
TokenLength -> App String
randomSnsToken TokenLength
GCM

  -- Client 2 with 1 token
  String
c2Apns1 <- HasCallStack => TokenLength -> App String
TokenLength -> App String
randomSnsToken TokenLength
APNS
  String
c2Gcm1 <- HasCallStack => TokenLength -> App String
TokenLength -> App String
randomSnsToken TokenLength
GCM
  String
c2Gcm1Overlap <- HasCallStack => TokenLength -> App String
TokenLength -> App String
randomSnsToken TokenLength
GCM

  let apnsToken :: String -> String -> PushToken
apnsToken = String -> String -> String -> String -> PushToken
PushToken String
"APNS_SANDBOX" String
"test"
  let gcmToken :: String -> String -> PushToken
gcmToken = String -> String -> String -> String -> PushToken
PushToken String
"GCM" String
"test"

  let c1Apns1Token :: PushToken
c1Apns1Token = String -> String -> PushToken
apnsToken String
c1Apns1 String
aliceC1
  let c1Apns1OverlapToken :: PushToken
c1Apns1OverlapToken = String -> String -> PushToken
apnsToken String
c1Apns1Overlap String
aliceC1
  let c1Apns2Token :: PushToken
c1Apns2Token = (String -> String -> PushToken
apnsToken String
c1Apns2 String
aliceC1 :: PushToken) {app = "com.wire.ent"} -- diff app prevents overlap
  let c1Gcm1Token :: PushToken
c1Gcm1Token = String -> String -> PushToken
gcmToken String
c1Gcm1 String
aliceC1

  let c2Apns1Token :: PushToken
c2Apns1Token = String -> String -> PushToken
apnsToken String
c2Apns1 String
aliceC2
  let c2Gcm1Token :: PushToken
c2Gcm1Token = String -> String -> PushToken
gcmToken String
c2Gcm1 String
aliceC2
  let c2Gcm1OverlapToken :: PushToken
c2Gcm1OverlapToken = String -> String -> PushToken
gcmToken String
c2Gcm1Overlap String
aliceC2

  -- Register non-overlapping tokens for client 1
  HasCallStack => Int -> Response -> App ()
Int -> Response -> App ()
assertStatus Int
201 (Response -> App ()) -> App Response -> App ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (Value -> PushToken -> App Response
forall token user.
(HasCallStack, MakesValue token, MakesValue user) =>
user -> token -> App Response
postPushToken Value
alice PushToken
c1Apns1Token)
  HasCallStack => Int -> Response -> App ()
Int -> Response -> App ()
assertStatus Int
201 (Response -> App ()) -> App Response -> App ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (Value -> PushToken -> App Response
forall token user.
(HasCallStack, MakesValue token, MakesValue user) =>
user -> token -> App Response
postPushToken Value
alice PushToken
c1Apns2Token)
  HasCallStack => Int -> Response -> App ()
Int -> Response -> App ()
assertStatus Int
201 (Response -> App ()) -> App Response -> App ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (Value -> PushToken -> App Response
forall token user.
(HasCallStack, MakesValue token, MakesValue user) =>
user -> token -> App Response
postPushToken Value
alice PushToken
c1Gcm1Token)

  -- register non-overlapping tokens for client 2
  HasCallStack => Int -> Response -> App ()
Int -> Response -> App ()
assertStatus Int
201 (Response -> App ()) -> App Response -> App ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (Value -> PushToken -> App Response
forall token user.
(HasCallStack, MakesValue token, MakesValue user) =>
user -> token -> App Response
postPushToken Value
alice PushToken
c2Apns1Token)
  HasCallStack => Int -> Response -> App ()
Int -> Response -> App ()
assertStatus Int
201 (Response -> App ()) -> App Response -> App ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (Value -> PushToken -> App Response
forall token user.
(HasCallStack, MakesValue token, MakesValue user) =>
user -> token -> App Response
postPushToken Value
alice PushToken
c2Gcm1Token)

  App Response -> (Response -> App ()) -> App ()
forall a.
HasCallStack =>
App Response -> (Response -> App a) -> App a
bindResponse (Value -> App Response
forall user. MakesValue user => user -> App Response
listPushTokens Value
alice) \Response
resp -> do
    Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
    Value
allTokens <- Response
resp.json App Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"tokens"
    Value
allTokens
      Value -> [PushToken] -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatchSet` [ PushToken
c1Apns1Token,
                         PushToken
c1Apns2Token,
                         PushToken
c1Gcm1Token,
                         PushToken
c2Apns1Token,
                         PushToken
c2Gcm1Token
                       ]

  -- Resistering an overlapping token overwrites it.
  HasCallStack => Int -> Response -> App ()
Int -> Response -> App ()
assertStatus Int
201 (Response -> App ()) -> App Response -> App ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Value -> PushToken -> App Response
forall token user.
(HasCallStack, MakesValue token, MakesValue user) =>
user -> token -> App Response
postPushToken Value
alice PushToken
c1Apns1OverlapToken
  HasCallStack => Int -> Response -> App ()
Int -> Response -> App ()
assertStatus Int
201 (Response -> App ()) -> App Response -> App ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Value -> PushToken -> App Response
forall token user.
(HasCallStack, MakesValue token, MakesValue user) =>
user -> token -> App Response
postPushToken Value
alice PushToken
c2Gcm1OverlapToken

  App Response -> (Response -> App ()) -> App ()
forall a.
HasCallStack =>
App Response -> (Response -> App a) -> App a
bindResponse (Value -> App Response
forall user. MakesValue user => user -> App Response
listPushTokens Value
alice) \Response
resp -> do
    Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
    Value
allTokens <- Response
resp.json App Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"tokens"
    Value
allTokens
      Value -> [PushToken] -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatchSet` [ PushToken
c1Apns1OverlapToken,
                         PushToken
c1Apns2Token,
                         PushToken
c1Gcm1Token,
                         PushToken
c2Apns1Token,
                         PushToken
c2Gcm1OverlapToken
                       ]

  -- Push tokens are deleted alongside clients
  HasCallStack => Int -> Response -> App ()
Int -> Response -> App ()
assertStatus Int
200 (Response -> App ()) -> App Response -> App ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Value -> String -> App Response
forall user client.
(MakesValue user, MakesValue client) =>
user -> client -> App Response
unregisterClient Value
alice String
aliceC1
  HasCallStack => Int -> Response -> App ()
Int -> Response -> App ()
assertStatus Int
200 (Response -> App ()) -> App Response -> App ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Value -> String -> App Response
forall user client.
(MakesValue user, MakesValue client) =>
user -> client -> App Response
unregisterClient Value
alice String
aliceC2

  App Response -> (Response -> App ()) -> App ()
forall a.
HasCallStack =>
App Response -> (Response -> App a) -> App a
bindResponse (Value -> App Response
forall user. MakesValue user => user -> App Response
listPushTokens Value
alice) \Response
resp -> do
    Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
    Value
allTokens <- Response
resp.json App Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"tokens"
    Value
allTokens
      Value -> [PushToken] -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatchSet` ([] :: [PushToken])

testVoipTokenRegistrationFails :: App ()
testVoipTokenRegistrationFails :: App ()
testVoipTokenRegistrationFails = do
  Value
alice <- Domain -> CreateUser -> App Value
forall domain.
(HasCallStack, MakesValue domain) =>
domain -> CreateUser -> App Value
randomUser Domain
OwnDomain CreateUser
forall a. Default a => a
def
  String
aliceC2 <- App String
randomClientId

  String
token <- HasCallStack => TokenLength -> App String
TokenLength -> App String
randomSnsToken TokenLength
APNS
  let apnsVoipToken :: PushToken
apnsVoipToken = String -> String -> String -> String -> PushToken
PushToken String
"APNS_VOIP_SANDBOX" String
"test" String
token String
aliceC2
  Value -> PushToken -> App Response
forall token user.
(HasCallStack, MakesValue token, MakesValue user) =>
user -> token -> App Response
postPushToken Value
alice PushToken
apnsVoipToken App Response -> (Response -> App ()) -> App ()
forall a.
HasCallStack =>
App Response -> (Response -> App a) -> App a
`bindResponse` \Response
resp -> do
    Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
400
    Response
resp.json App Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"label" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"apns-voip-not-supported"