Skip to content

Commit b5ef357

Browse files
authored
Add support for relative path in FUNCTION_SOURCE (GoogleCloudPlatform#20)
1 parent e609b9b commit b5ef357

File tree

8 files changed

+157
-10
lines changed

8 files changed

+157
-10
lines changed

router.php

100644100755
Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,26 @@
2929
/**
3030
* Determine the function source file to load
3131
*/
32+
// Ensure function source is loaded relative to the application root directory
33+
$documentRoot = __DIR__ . '/../../../';
3234
if ($functionSource = getenv('FUNCTION_SOURCE', true)) {
33-
// when function src is set by environment variable
34-
if (!file_exists($functionSource)) {
35-
throw new RuntimeException(sprintf(
36-
'Unable to load function from "%s"', $functionSource));
35+
if (0 !== strpos($functionSource, '/')) {
36+
// Make the path relative
37+
$relativeSource = $documentRoot . $functionSource;
38+
if (!file_exists($relativeSource)) {
39+
throw new RuntimeException(sprintf(
40+
'Unable to load function from "%s"',
41+
getenv('FUNCTION_SOURCE', true)
42+
));
43+
}
44+
require_once $relativeSource;
45+
} else {
46+
require_once $functionSource;
3747
}
38-
require_once $functionSource;
39-
} elseif (file_exists($functionSource = __DIR__ . '/../../../index.php')) {
48+
} elseif (file_exists($defaultSource = $documentRoot . 'index.php')) {
4049
// When running from vendor/google/cloud-functions-framework, default to
41-
// "index.php" in the root project for the function source.
42-
require_once $functionSource;
50+
// "index.php" in the root of the application.
51+
require_once $defaultSource;
4352
} else {
4453
// Do nothing - assume the function source is being autoloaded.
4554
}
@@ -52,6 +61,10 @@
5261
if (false === $target) {
5362
throw new RuntimeException('FUNCTION_TARGET is not set');
5463
}
64+
if (!is_callable($target)) {
65+
throw new InvalidArgumentException(sprintf(
66+
'Function target is not callable: "%s"', $target));
67+
}
5568
$signatureType = getenv('FUNCTION_SIGNATURE_TYPE', true);
5669
if (false === $signatureType) {
5770
throw new RuntimeException('FUNCTION_SIGNATURE_TYPE is not set');

src/Invoker.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ class Invoker
2525
{
2626
private $function;
2727

28-
public function __construct($target, $signatureType)
28+
/**
29+
* @param $target callable The callable to be invoked
30+
* @param $signatureType The signature type of the target callable, either
31+
* "event" or "http".
32+
*/
33+
public function __construct(callable $target, string $signatureType)
2934
{
3035
if ($signatureType === 'http') {
3136
$this->function = new HttpFunctionWrapper($target);

tests/InvokerTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public function testInvalidSignatureType()
3030
{
3131
$this->expectException('InvalidArgumentException');
3232
$this->expectExceptionMessage('Invalid signature type: "invalid-signature-type"');
33-
new Invoker('httpFunction', 'invalid-signature-type');
33+
new Invoker([$this, 'invokeThis'], 'invalid-signature-type');
3434
}
3535

3636
public function testHttpInvoker()

tests/fixtures/absolute.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
3+
function helloDefault()
4+
{
5+
return "Hello Absolute!";
6+
}

tests/fixtures/composer.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"repositories": [
3+
{
4+
"type": "path",
5+
"url": "%s",
6+
"options": {
7+
"symlink": false
8+
}
9+
}
10+
],
11+
"require": {
12+
"google/cloud-functions-framework": "dev-master"
13+
}
14+
}

tests/fixtures/index.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
3+
function helloDefault()
4+
{
5+
return "Hello Default!";
6+
}

tests/fixtures/relative.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
3+
function helloDefault()
4+
{
5+
return "Hello Relative!";
6+
}

tests/vendorTest.php

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
/**
3+
* Copyright 2020 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+
18+
namespace Google\CloudFunctions\Tests;
19+
20+
use PHPUnit\Framework\TestCase;
21+
22+
/**
23+
* Tests for when this package is installed in a vendored directory
24+
*
25+
* @group gcf-framework
26+
* @runInSeparateProcess
27+
*/
28+
class vendorTest extends TestCase
29+
{
30+
private static $tmpDir;
31+
32+
public static function setUpBeforeClass(): void
33+
{
34+
if ('true' === getenv('TRAVIS')) {
35+
self::markTestSkipped('These tests do not pass on travis');
36+
}
37+
mkdir($tmpDir = sys_get_temp_dir() . '/ff-php-test-' . rand());
38+
chdir($tmpDir);
39+
40+
// Copy Fixtures
41+
file_put_contents('composer.json', sprintf(
42+
file_get_contents(__DIR__ . '/fixtures/composer.json'),
43+
dirname(__DIR__)
44+
));
45+
passthru('composer install');
46+
47+
self::$tmpDir = $tmpDir;
48+
}
49+
50+
public function testDefaultFunctionSource()
51+
{
52+
copy(__DIR__ . '/fixtures/index.php', self::$tmpDir . '/index.php');
53+
$cmd = sprintf(
54+
'FUNCTION_SOURCE=' .
55+
' FUNCTION_SIGNATURE_TYPE=http' .
56+
' FUNCTION_TARGET=helloDefault' .
57+
' php %s/vendor/bin/router.php',
58+
self::$tmpDir
59+
);
60+
exec($cmd, $output);
61+
62+
$this->assertEquals(['Hello Default!'], $output);
63+
}
64+
65+
public function testRelativeFunctionSource()
66+
{
67+
copy(__DIR__ . '/fixtures/relative.php', self::$tmpDir . '/relative.php');
68+
putenv('FUNCTION_SOURCE=');
69+
$cmd = sprintf(
70+
'FUNCTION_SOURCE=relative.php' .
71+
' FUNCTION_SIGNATURE_TYPE=http' .
72+
' FUNCTION_TARGET=helloDefault' .
73+
' php %s/vendor/bin/router.php',
74+
self::$tmpDir
75+
);
76+
exec($cmd, $output);
77+
78+
$this->assertEquals(['Hello Relative!'], $output);
79+
}
80+
81+
public function testAbsoluteFunctionSource()
82+
{
83+
copy(__DIR__ . '/fixtures/absolute.php', self::$tmpDir . '/absolute.php');
84+
putenv('FUNCTION_SOURCE=');
85+
$cmd = sprintf(
86+
'FUNCTION_SOURCE=%s/absolute.php' .
87+
' FUNCTION_SIGNATURE_TYPE=http' .
88+
' FUNCTION_TARGET=helloDefault' .
89+
' php %s/vendor/bin/router.php',
90+
self::$tmpDir,
91+
self::$tmpDir
92+
);
93+
exec($cmd, $output);
94+
95+
$this->assertEquals(['Hello Absolute!'], $output);
96+
}
97+
}

0 commit comments

Comments
 (0)