diff --git a/src/Utopia/Messaging/Adapters/Push/FCM.php b/src/Utopia/Messaging/Adapters/Push/FCM.php index 8a4d8ac2..0ff05537 100644 --- a/src/Utopia/Messaging/Adapters/Push/FCM.php +++ b/src/Utopia/Messaging/Adapters/Push/FCM.php @@ -32,7 +32,7 @@ public function getName(): string */ public function getMaxMessagesPerRequest(): int { - return 1000; + return 5000; } /** @@ -42,27 +42,78 @@ public function getMaxMessagesPerRequest(): int */ protected function process(Push $message): string { - return $this->request( - method: 'POST', - url: 'https://fcm.googleapis.com/fcm/send', - headers: [ - 'Content-Type: application/json', - "Authorization: key={$this->serverKey}", + $payload = [ + 'notification' => [ + 'title' => $message->getTitle(), + 'body' => $message->getBody(), + 'click_action' => $message->getAction(), + 'icon' => $message->getIcon(), + 'badge' => $message->getBadge(), + 'color' => $message->getColor(), + 'sound' => $message->getSound(), + 'tag' => $message->getTag(), ], - body: \json_encode([ - 'registration_ids' => $message->getTo(), - 'notification' => [ - 'title' => $message->getTitle(), - 'body' => $message->getBody(), - 'click_action' => $message->getAction(), - 'icon' => $message->getIcon(), - 'badge' => $message->getBadge(), - 'color' => $message->getColor(), - 'sound' => $message->getSound(), - 'tag' => $message->getTag(), - ], - 'data' => $message->getData(), - ]) - ); + 'data' => $message->getData(), + ]; + + return \json_encode($this->notify($message->getTo(), $payload)); + } + + private function notify(array $to, array $payload): array + { + $url = 'https://fcm.googleapis.com/fcm/send'; + + $headers = [ + 'Content-Type: application/json', + "Authorization: key={$this->serverKey}", + ]; + + $tokenChunks = array_chunk($to, 1000); + + $sh = curl_share_init(); + curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); + + $mh = curl_multi_init(); + + $channels = []; + + foreach ($tokenChunks as $tokens) { + $ch = curl_init(); + + $payload['registration_ids'] = $tokens; + + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); + curl_setopt($ch, CURLOPT_SHARE, $sh); + + curl_multi_add_handle($mh, $ch); + + $channels[] = $ch; + } + + $running = null; + do { + curl_multi_exec($mh, $running); + curl_multi_select($mh); + } while ($running > 0); + + $results = []; + + foreach ($channels as $ch) { + $results[] = [ + 'statusCode' => curl_getinfo($ch, CURLINFO_HTTP_CODE), + 'response' => json_decode(curl_multi_getcontent($ch), true), // Decoding JSON response to an associative array + ]; + + curl_multi_remove_handle($mh, $ch); + } + + curl_multi_close($mh); + curl_share_close($sh); + + return $results; } } diff --git a/tests/e2e/Email/EmailTest.php b/tests/e2e/Email/EmailTest.php index 40606255..d1b5908f 100644 --- a/tests/e2e/Email/EmailTest.php +++ b/tests/e2e/Email/EmailTest.php @@ -35,4 +35,36 @@ public function testSendEmail() $this->assertEquals($subject, $lastEmail['subject']); $this->assertEquals($content, \trim($lastEmail['text'])); } + + public function testSendEmailBenchmark() + { + $sender = new Mock(); + + $to = 'tester@localhost.test'; + $subject = 'Test Subject'; + $content = 'Test Content'; + $from = 'sender@localhost.test'; + + $message = new Email( + to: [$to], + subject: $subject, + content: $content, + from: $from + ); + + $sender->send($message); + + $start = microtime(true); + + for ($i = 0; $i < 1000; $i++) { + $sender->send($message); + } + + $end = microtime(true); + + $time = floor(($end - $start) * 1000); + + echo "\nEmail: $time ms\n"; + $this->assertGreaterThan(0, $time); + } } diff --git a/tests/e2e/Email/MailgunTest.php b/tests/e2e/Email/MailgunTest.php index fed2489d..307a12a7 100644 --- a/tests/e2e/Email/MailgunTest.php +++ b/tests/e2e/Email/MailgunTest.php @@ -39,4 +39,41 @@ public function testSendEmail() $this->assertArrayHasKey('message', $result); $this->assertTrue(str_contains(strtolower($result['message']), 'queued')); } + + public function testSendEmailBenchmark() + { + $key = getenv('MAILGUN_API_KEY'); + $domain = getenv('MAILGUN_DOMAIN'); + + $sender = new Mailgun( + apiKey: $key, + domain: $domain, + isEU: false + ); + + $to = getenv('TEST_EMAIL'); + $subject = 'Test Subject'; + $content = 'Test Content'; + $from = 'sender@'.$domain; + + $message = new Email( + to: [$to], + from: $from, + subject: $subject, + content: $content, + ); + + $start = microtime(true); + + for ($i = 0; $i < 1000; $i++) { + $sender->send($message); + } + + $end = microtime(true); + + $time = floor(($end - $start) * 1000); + + echo "\nMailgun: $time ms\n"; + $this->assertGreaterThan(0, $time); + } } diff --git a/tests/e2e/Email/SendgridTest.php b/tests/e2e/Email/SendgridTest.php index 9437b167..051f0315 100644 --- a/tests/e2e/Email/SendgridTest.php +++ b/tests/e2e/Email/SendgridTest.php @@ -31,4 +31,35 @@ public function testSendEmail() $this->assertEquals($response, ''); } + + public function testSendEmailBenchmark() + { + $key = getenv('SENDGRID_API_KEY'); + $sender = new Sendgrid($key); + + $to = getenv('TEST_EMAIL'); + $subject = 'Test Subject'; + $content = 'Test Content'; + $from = getenv('TEST_FROM_EMAIL'); + + $message = new Email( + to: [$to], + from: $from, + subject: $subject, + content: $content, + ); + + $start = microtime(true); + + for ($i = 0; $i < 1000; $i++) { + $sender->send($message); + } + + $end = microtime(true); + + $time = floor(($end - $start) * 1000); + + echo "\nSendgrid: $time ms\n"; + $this->assertGreaterThan(0, $time); + } } diff --git a/tests/e2e/Push/APNSTest.php b/tests/e2e/Push/APNSTest.php index cbd1a354..a6e13b7a 100644 --- a/tests/e2e/Push/APNSTest.php +++ b/tests/e2e/Push/APNSTest.php @@ -36,4 +36,41 @@ public function testSend(): void $this->assertEquals('success', $response->status); } } + + public function testAPNSBenchmark() + { + $authKey = getenv('APNS_AUTHKEY_8KVVCLA3HL'); + $authKeyId = getenv('APNS_AUTH_ID'); + $teamId = getenv('APNS_TEAM_ID'); + $bundleId = getenv('APNS_BUNDLE_ID'); + $endpoint = 'https://api.sandbox.push.apple.com:443'; + + $adapter = new APNSAdapter($authKey, $authKeyId, $teamId, $bundleId, $endpoint); + + $message = new Push( + to: [getenv('APNS_TO')], + title: 'TestTitle', + body: 'TestBody', + data: null, + action: null, + sound: 'default', + icon: null, + color: null, + tag: null, + badge: '1' + ); + + $start = microtime(true); + + for ($i = 0; $i < 5000; $i++) { + $adapter->send($message); + } + + $end = microtime(true); + + $time = floor(($end - $start) * 1000); + + echo "\nAPNSTest: $time ms\n"; + $this->assertGreaterThan(0, $time); + } } diff --git a/tests/e2e/Push/FCMTest.php b/tests/e2e/Push/FCMTest.php index f7befabe..cb19cf11 100644 --- a/tests/e2e/Push/FCMTest.php +++ b/tests/e2e/Push/FCMTest.php @@ -28,10 +28,45 @@ public function testSend(): void badge: '1' ); - $response = \json_decode($adapter->send($message)); + $response = $adapter->send($message); + $response = \json_decode($response); $this->assertNotEmpty($response); - $this->assertEquals(1, $response->success); - $this->assertEquals(0, $response->failure); + // $this->assertEquals(200, $response['statusCode']); + } + + public function testSendBenchmark(): void + { + $serverKey = getenv('FCM_SERVER_KEY'); + + $adapter = new FCMAdapter($serverKey); + + $to = []; + + for ($i = 0; $i < 5000; $i++) { + $to[] = getenv('FCM_SERVER_TO'); + } + + $message = new Push( + to: $to, + title: 'TestTitle', + body: 'TestBody', + data: null, + action: null, + sound: 'default', + icon: null, + color: null, + tag: null, + badge: '1' + ); + + $start = microtime(true); + + $adapter->send($message); + + $time = floor((microtime(true) - $start) * 1000); + + echo "\nFCMTest: $time ms\n"; + $this->assertGreaterThan(0, $time); } } diff --git a/tests/e2e/SMS/SMSTest.php b/tests/e2e/SMS/SMSTest.php index b7cdb8be..2e3199de 100644 --- a/tests/e2e/SMS/SMSTest.php +++ b/tests/e2e/SMS/SMSTest.php @@ -32,4 +32,28 @@ public function testSendSMS() $this->assertEquals('+987654321', $smsRequest['data']['from']); $this->assertEquals('+123456789', $smsRequest['data']['to']); } + + public function testSendSMSBenchmark() + { + $sender = new Mock('username', 'password'); + + $message = new SMS( + to: ['+123456789'], + content: 'Test Content', + from: '+987654321' + ); + + $start = microtime(true); + + for ($i = 0; $i < 1000; $i++) { + $sender->send($message); + } + + $end = microtime(true); + + $time = floor(($end - $start) * 1000); + + echo "\nSMSTest: $time ms\n"; + $this->assertGreaterThan(0, $time); + } } diff --git a/tests/e2e/SMS/TwilioTest.php b/tests/e2e/SMS/TwilioTest.php index 7e45d620..a40453d4 100644 --- a/tests/e2e/SMS/TwilioTest.php +++ b/tests/e2e/SMS/TwilioTest.php @@ -29,4 +29,30 @@ public function testSendSMS() $this->assertEquals($from, $result->from); $this->assertNull($result->error_message); } + + public function testSendSMSBenchmark() + { + $sender = new Twilio(getenv('TWILIO_ACCOUNT_SID'), getenv('TWILIO_AUTH_TOKEN')); + $to = '+15005550006'; + $from = getenv('TWILIO_FROM'); + + $message = new SMS( + to: [$to], + content: 'Test Content', + from: $from + ); + + $start = microtime(true); + + for ($i = 0; $i < 100; $i++) { + $sender->send($message); + } + + $end = microtime(true); + + $time = floor(($end - $start) * 1000); + + echo "\nTwilioTest: $time ms\n"; + $this->assertGreaterThan(0, $time); + } } diff --git a/tests/e2e/SMS/VonageTest.php b/tests/e2e/SMS/VonageTest.php index 02f89228..8b198821 100644 --- a/tests/e2e/SMS/VonageTest.php +++ b/tests/e2e/SMS/VonageTest.php @@ -31,4 +31,31 @@ public function testSendSMS() $this->assertEquals(1, count($result['messages'])); $this->assertEquals('1', $result['message-count']); } + + public function testSendSMSBenchmark() + { + $apiKey = getenv('VONAGE_API_KEY'); + $apiSecret = getenv('VONAGE_API_SECRET'); + + $sender = new Vonage($apiKey, $apiSecret); + + $message = new SMS( + to: ['447700900000'], + content: 'Test Content', + from: getenv('VONAGE_FROM') + ); + + $start = microtime(true); + + for ($i = 0; $i < 500; $i++) { + $sender->send($message); + } + + $end = microtime(true); + + $time = floor(($end - $start) * 1000); + + echo "\nVonageTest: $time ms\n"; + $this->assertGreaterThan(0, $time); + } }