Skip to content

Commit 11550ea

Browse files
authored
fix: functions slack sample (GoogleCloudPlatform#1345)
- fix timestamp - it was evaluating as empty because it was set to the string `'0'` - Wrote a unit test for debugging and figured we might as well keep it - misc test / function cleanup
1 parent 3c1c381 commit 11550ea

File tree

5 files changed

+114
-32
lines changed

5 files changed

+114
-32
lines changed

functions/slack_slash_command/index.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ function isValidSlackWebhook(ServerRequestInterface $request): bool
3838
}
3939

4040
// Compute signature
41-
$plaintext = 'v0:' . $timestamp . ':' . (string) $request->getBody();
42-
$hash = 'v0=' . hash_hmac('sha256', $plaintext, $SLACK_SECRET);
41+
$plaintext = sprintf('v0:%s:%s', $timestamp, $request->getBody());
42+
$hash = sprintf('v0=%s', hash_hmac('sha256', $plaintext, $SLACK_SECRET));
4343

4444
return $hash === $signature;
4545
}
@@ -83,7 +83,7 @@ function formatSlackMessage(Google_Service_Kgsearch_SearchResponse $kgResponse,
8383
], $attachmentJson);
8484
}
8585

86-
if ($entity['image']) {
86+
if (isset($entity['image'])) {
8787
$imageJson = $entity['image'];
8888
$attachmentJson['image_url'] = $imageJson['contentUrl'];
8989
}

functions/slack_slash_command/test/DeployTest.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ class DeployTest extends TestCase
3838
use CloudFunctionDeploymentTrait;
3939
use TestCasesTrait;
4040

41-
private static $entryPoint = 'receiveRequest';
42-
4341
/**
4442
* @dataProvider cases
4543
*/
@@ -76,8 +74,11 @@ public function testFunction(
7674
private static function doDeploy()
7775
{
7876
// Forward required env variables to Cloud Functions.
79-
$envVars = 'SLACK_SECRET=' . self::requireEnv('SLACK_SECRET') . ',';
80-
$envVars .= 'KG_API_KEY=' . self::requireEnv('KG_API_KEY');
77+
$envVars = sprintf(
78+
'SLACK_SECRET=%s,KG_API_KEY=%s',
79+
self::$slackSecret,
80+
self::$kgApiKey
81+
);
8182

8283
self::$fn->deploy(['--update-env-vars' => $envVars]);
8384
}

functions/slack_slash_command/test/IntegrationTest.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ class IntegrationTest extends TestCase
3232
use CloudFunctionLocalTestTrait;
3333
use TestCasesTrait;
3434

35-
private static $entryPoint = 'receiveRequest';
36-
3735
/**
3836
* Run the PHP server locally for the defined function.
3937
*
@@ -42,8 +40,8 @@ class IntegrationTest extends TestCase
4240
private static function doRun()
4341
{
4442
self::$fn->run([
45-
'SLACK_SECRET' => self::requireEnv('SLACK_SECRET'),
46-
'KG_API_KEY' => self::requireEnv('KG_API_KEY'),
43+
'SLACK_SECRET' => self::$slackSecret,
44+
'KG_API_KEY' => self::$kgApiKey,
4745
]);
4846
}
4947

functions/slack_slash_command/test/TestCasesTrait.php

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,35 +18,34 @@
1818

1919
namespace Google\Cloud\Samples\Functions\SlackSlashCommand\Test;
2020

21-
function _valid_headers($body): array
22-
{
23-
// Calculate test case signature
24-
$key = getenv('SLACK_SECRET');
25-
$plaintext = 'v0:0:' . $body;
26-
//var_dump($plaintext);
27-
$hash = 'v0=' . hash_hmac('sha256', $plaintext, $key);
28-
//var_dump($hash);
29-
30-
// Return new test case
31-
return [
32-
'plaintext' => $plaintext,
33-
'X-Slack-Request-Timestamp' => '0',
34-
'X-Slack-Signature' => $hash,
35-
];
36-
}
21+
use Google\Cloud\TestUtils\TestTrait;
3722

3823
trait TestCasesTrait
3924
{
25+
use TestTrait;
26+
27+
private static $entryPoint = 'receiveRequest';
28+
private static $slackSecret;
29+
private static $kgApiKey;
30+
31+
public static function getEnvVars()
32+
{
33+
self::$slackSecret = self::requireEnv('SLACK_SECRET');
34+
self::$kgApiKey = self::requireEnv('KG_API_KEY');
35+
}
36+
4037
public static function cases(): array
4138
{
39+
self::getEnvVars();
40+
4241
return [
4342
[
4443
'label' => 'Only allows POST',
4544
'body' => '',
4645
'method' => 'GET',
4746
'expected' => null,
4847
'statusCode' => '405',
49-
'headers' => _valid_headers('')
48+
'headers' => self::validHeaders('')
5049
],
5150
[
5251
'label' => 'Requires valid auth headers',
@@ -62,7 +61,7 @@ public static function cases(): array
6261
'method' => 'POST',
6362
'expected' => null,
6463
'statusCode' => '400',
65-
'headers' => _valid_headers(''),
64+
'headers' => self::validHeaders(''),
6665
],
6766
[
6867
'label' => 'Prohibits invalid signature',
@@ -82,24 +81,40 @@ public static function cases(): array
8281
'method' => 'POST',
8382
'expected' => 'No results match your query',
8483
'statusCode' => '200',
85-
'headers' => _valid_headers('text=asdfjkl13579'),
84+
'headers' => self::validHeaders('text=asdfjkl13579'),
8685
],
8786
[
8887
'label' => 'Handles query with results',
8988
'body' => 'text=lion',
9089
'method' => 'POST',
9190
'expected' => 'https:\/\/en.wikipedia.org\/wiki\/Lion',
9291
'statusCode' => '200',
93-
'headers' => _valid_headers('text=lion'),
92+
'headers' => self::validHeaders('text=lion'),
9493
],
9594
[
9695
'label' => 'Ignores extra URL parameters',
9796
'body' => 'unused=foo&text=lion',
9897
'method' => 'POST',
9998
'expected' => 'https:\/\/en.wikipedia.org\/wiki\/Lion',
10099
'statusCode' => '200',
101-
'headers' => _valid_headers('unused=foo&text=lion'),
100+
'headers' => self::validHeaders('unused=foo&text=lion'),
102101
],
103102
];
104103
}
104+
105+
private static function validHeaders($body): array
106+
{
107+
// Calculate test case signature
108+
$timestamp = date('U');
109+
$plaintext = sprintf('v0:%s:%s', $timestamp, $body);
110+
$hash = hash_hmac('sha256', $plaintext, self::$slackSecret);
111+
$signature = sprintf('v0=%s', $hash);
112+
113+
// Return new test case
114+
return [
115+
'plaintext' => $plaintext,
116+
'X-Slack-Request-Timestamp' => $timestamp,
117+
'X-Slack-Signature' => $signature,
118+
];
119+
}
105120
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
2+
/**
3+
* Copyright 2021 Google LLC.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Google\Cloud\Samples\Functions\SlackSlashCommand\Test;
20+
21+
use GuzzleHttp\Psr7\ServerRequest;
22+
use GuzzleHttp\Psr7\Response;
23+
use PHPUnit\Framework\TestCase;
24+
25+
require_once __DIR__ . '/TestCasesTrait.php';
26+
27+
/**
28+
* Unit tests for the Cloud Function.
29+
*/
30+
class UnitTest extends TestCase
31+
{
32+
use TestCasesTrait;
33+
34+
public static function setUpBeforeClass(): void
35+
{
36+
require_once __DIR__ . '/../index.php';
37+
}
38+
39+
/**
40+
* @dataProvider cases
41+
*/
42+
public function testFunction(
43+
$label,
44+
$body,
45+
$method,
46+
$expected,
47+
$statusCode,
48+
$headers
49+
): void {
50+
$request = new ServerRequest($method, '/', $headers, $body);
51+
$response = $this->runFunction(self::$entryPoint, [$request]);
52+
$this->assertEquals(
53+
$statusCode,
54+
$response->getStatusCode(),
55+
$label . ": status code"
56+
);
57+
58+
if ($expected !== null) {
59+
$output = (string) $response->getBody();
60+
$this->assertStringContainsString($expected, $output);
61+
}
62+
}
63+
64+
private static function runFunction($functionName, array $params = []): Response
65+
{
66+
return call_user_func_array($functionName, $params);
67+
}
68+
}

0 commit comments

Comments
 (0)