Skip to content

Commit 97fc583

Browse files
committed
incorporate vfsStreams
1 parent e80aa37 commit 97fc583

File tree

4 files changed

+62
-39
lines changed

4 files changed

+62
-39
lines changed

src/ResourceDetectors/DigitalOcean/.phan/config.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
//
4343
// Note that the **only** effect of choosing `'5.6'` is to infer that functions removed in php 7.0 exist.
4444
// (See `backward_compatibility_checks` for additional options)
45-
'target_php_version' => '8.0',
45+
'target_php_version' => '8.1',
4646

4747
// If enabled, missing properties will be created when
4848
// they are first seen. If false, we'll report an

src/ResourceDetectors/DigitalOcean/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
},
2121
"require-dev": {
2222
"friendsofphp/php-cs-fixer": "^3.54",
23+
"mikey179/vfsstream": "^1.6.11",
2324
"nyholm/psr7": "*",
2425
"phan/phan": "^5.4",
2526
"phpstan/phpstan": "^1.10.13",

src/ResourceDetectors/DigitalOcean/src/DigitalOceanDetector.php

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,18 @@ final class DigitalOceanDetector implements ResourceDetectorInterface
3030
private const DO_PUBLIC_ENDPOINT_URL = 'https://api.digitalocean.com/v2/';
3131
private const ENV_DO_API_TOKEN = 'DIGITALOCEAN_ACCESS_TOKEN';
3232

33+
public function __construct(private readonly string $rootPath = '/')
34+
{
35+
}
36+
3337
public function getResource(): ResourceInfo
3438
{
3539
$client = Discovery::find();
3640
$requestFactory = MessageFactoryResolver::create()->resolveRequestFactory();
3741
$token = $_SERVER[self::ENV_DO_API_TOKEN] ?? '';
3842

3943
/** Bail early if wrong environment */
40-
if (!self::isDigitalOcean()) {
44+
if (!$this->isDigitalOcean()) {
4145
self::logNotice('DigitalOcean resource detector enabled in non-DigitalOcean environment');
4246

4347
return ResourceInfoFactory::emptyResource();
@@ -46,10 +50,10 @@ public function getResource(): ResourceInfo
4650
try {
4751
/** Attributes available locally - all non-privileged lookups */
4852
$attributes = [
49-
ResourceAttributes::CLOUD_PLATFORM => self::readSMBIOS('product_family'),
50-
ResourceAttributes::CLOUD_PROVIDER => self::readSMBIOS('sys_vendor'),
53+
ResourceAttributes::CLOUD_PLATFORM => $this->readSMBIOS('product_family'),
54+
ResourceAttributes::CLOUD_PROVIDER => $this->readSMBIOS('sys_vendor'),
5155
ResourceAttributes::HOST_ARCH => ResourceAttributeValues::HOST_ARCH_AMD64,
52-
ResourceAttributes::HOST_ID => self::readSMBIOS('board_asset_tag'),
56+
ResourceAttributes::HOST_ID => $this->readSMBIOS('board_asset_tag'),
5357
ResourceAttributes::HOST_NAME => gethostname(),
5458
ResourceAttributes::OS_TYPE => ResourceAttributeValues::OS_TYPE_LINUX,
5559
];
@@ -118,10 +122,10 @@ public function getResource(): ResourceInfo
118122
return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL);
119123
}
120124

121-
private static function isDigitalOcean(): bool
125+
private function isDigitalOcean(): bool
122126
{
123127
try {
124-
$sysVendor = self::readSMBIOS('sys_vendor');
128+
$sysVendor = $this->readSMBIOS('sys_vendor');
125129
} catch (UnexpectedValueException) {
126130
return false;
127131
}
@@ -132,9 +136,9 @@ private static function isDigitalOcean(): bool
132136
return true;
133137
}
134138

135-
private static function readSMBIOS(string $dmiKeyword): string
139+
private function readSMBIOS(string $dmiKeyword): string
136140
{
137-
$dmiValue = file_get_contents(sprintf('/sys/devices/virtual/dmi/id/%s', $dmiKeyword));
141+
$dmiValue = file_get_contents(sprintf('%ssys/devices/virtual/dmi/id/%s', $this->rootPath, $dmiKeyword));
138142
if ($dmiValue === false) {
139143
throw new UnexpectedValueException('Failed to read SMBIOS value from sysfs.');
140144
}

src/ResourceDetectors/DigitalOcean/tests/Unit/DigitalOceanDetectorTest.php

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,13 @@
1313
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
1414
use OpenTelemetry\SemConv\ResourceAttributes;
1515
use OpenTelemetry\SemConv\ResourceAttributeValues;
16+
use org\bovigo\vfs\vfsStream;
17+
use org\bovigo\vfs\vfsStreamDirectory;
1618
use PHPUnit\Framework\Attributes\CoversClass;
1719
use PHPUnit\Framework\TestCase;
1820
use Psr\Http\Message\RequestInterface;
1921
use Zalas\PHPUnit\Globals\Attribute\Server;
2022

21-
function file_get_contents(string $filename)
22-
{
23-
if (($_SERVER['FAIL_IO'] ?? 'false') === 'true') {
24-
return false;
25-
}
26-
if (str_starts_with($filename, '/sys/devices/virtual/dmi/id')) {
27-
return match (substr($filename, 28)) {
28-
'sys_vendor' => (($_SERVER['WRONG_VENDOR'] ?? 'false') === 'true') ? 'AWS' : 'DigitalOcean',
29-
'product_family' => 'DigitalOcean_Droplet',
30-
'board_asset_tag' => '10000000',
31-
default => 'unknown'
32-
};
33-
}
34-
35-
return \file_get_contents($filename);
36-
}
37-
3823
function gethostname()
3924
{
4025
return 'test-server';
@@ -44,21 +29,37 @@ function gethostname()
4429
class DigitalOceanDetectorTest extends TestCase
4530
{
4631
private mixed $errorLog;
32+
private vfsStreamDirectory $vfs;
4733

4834
public function setUp(): void
4935
{
36+
/** mock sysfs with DigitalOcean SMBIOS pointers */
37+
$this->vfs = vfsStream::setup('/', structure: [
38+
'sys' => [
39+
'devices' => [
40+
'virtual' => [
41+
'dmi' => [
42+
'id' => [
43+
'board_asset_tag' => '10000000',
44+
'product_family' => 'DigitalOcean_Droplet',
45+
'sys_vendor' => 'DigitalOcean',
46+
],
47+
],
48+
],
49+
],
50+
],
51+
]);
52+
53+
/** mock stdout for `error_log` */
5054
$this->errorLog = tmpfile();
5155
/** @psalm-suppress PossiblyFalseArgument */
5256
ini_set('error_log', stream_get_meta_data($this->errorLog)['uri']);
5357

58+
/** mock HTTP client and DigitalOcean API responses */
5459
$responseFactory = MessageFactoryResolver::create()->resolveResponseFactory();
5560
$client = $this->createStub(Psr18Client::class);
5661
$client->method('sendRequest')->willReturnCallback(function (RequestInterface $request) use ($responseFactory) {
5762
if ((string) $request->getUri() === 'http://169.254.169.254/metadata/v1.json') {
58-
if (($_SERVER['FAIL_METADATA'] ?? 'false') === 'true') {
59-
return $responseFactory->createResponse(500);
60-
}
61-
6263
/** @psalm-suppress PossiblyFalseArgument */
6364
return $responseFactory->createResponse()->withBody(
6465
Stream::create(file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mock-metadata.json'))
@@ -102,7 +103,7 @@ public function test_droplet_attributes_with_no_authz()
102103
ResourceAttributes::HOST_NAME => 'test-server',
103104
ResourceAttributes::OS_TYPE => ResourceAttributeValues::OS_TYPE_LINUX,
104105
]),
105-
(new DigitalOceanDetector())->getResource()->getAttributes()
106+
(new DigitalOceanDetector($this->vfs->url()))->getResource()->getAttributes()
106107
);
107108
}
108109

@@ -121,7 +122,7 @@ public function test_droplet_attributes_with_account_only_authz()
121122
ResourceAttributes::HOST_NAME => 'test-server',
122123
ResourceAttributes::OS_TYPE => ResourceAttributeValues::OS_TYPE_LINUX,
123124
]),
124-
(new DigitalOceanDetector())->getResource()->getAttributes()
125+
(new DigitalOceanDetector($this->vfs->url()))->getResource()->getAttributes()
125126
);
126127
/** @psalm-suppress PossiblyFalseArgument */
127128
$this->assertStringContainsString(
@@ -148,7 +149,7 @@ public function test_droplet_attributes_with_droplet_only_authz()
148149
ResourceAttributes::HOST_TYPE => 's-1vcpu-1gb',
149150
ResourceAttributes::OS_NAME => 'Debian',
150151
]),
151-
(new DigitalOceanDetector())->getResource()->getAttributes()
152+
(new DigitalOceanDetector($this->vfs->url()))->getResource()->getAttributes()
152153
);
153154
/** @psalm-suppress PossiblyFalseArgument */
154155
$this->assertStringContainsString(
@@ -157,12 +158,23 @@ public function test_droplet_attributes_with_droplet_only_authz()
157158
);
158159
}
159160

160-
#[Server('FAIL_METADATA', 'true')]
161161
public function test_no_droplet_attributes()
162162
{
163+
/** mock HTTP client and with failing response */
164+
$client = $this->createStub(Psr18Client::class);
165+
$client->method('sendRequest')->willReturnCallback(function () {
166+
$responseFactory = MessageFactoryResolver::create()->resolveResponseFactory();
167+
168+
return $responseFactory->createResponse(500);
169+
});
170+
$clientDiscoverer = $this->createStub(DiscoveryInterface::class);
171+
$clientDiscoverer->method('available')->willReturn(true);
172+
$clientDiscoverer->method('create')->willReturn($client);
173+
Discovery::setDiscoverers([$clientDiscoverer]);
174+
163175
$this->assertEquals(
164176
ResourceInfoFactory::emptyResource(),
165-
(new DigitalOceanDetector())->getResource()
177+
(new DigitalOceanDetector($this->vfs->url()))->getResource()
166178
);
167179
/** @psalm-suppress PossiblyFalseArgument */
168180
$this->assertStringContainsString(
@@ -171,12 +183,16 @@ public function test_no_droplet_attributes()
171183
);
172184
}
173185

174-
#[Server('WRONG_VENDOR', 'true')]
175186
public function test_not_digitalocean_environment()
176187
{
188+
/** mock sysfs with AWS SMBIOS pointers */
189+
$vfs = vfsStream::setup('/', structure: ['sys' => ['devices' => ['virtual' => ['dmi' => ['id' => [
190+
'sys_vendor' => 'AWS',
191+
]]]]]]);
192+
177193
$this->assertEquals(
178194
ResourceInfoFactory::emptyResource(),
179-
(new DigitalOceanDetector())->getResource()
195+
(new DigitalOceanDetector($vfs->url()))->getResource()
180196
);
181197
/** @psalm-suppress PossiblyFalseArgument */
182198
$this->assertStringContainsString(
@@ -185,12 +201,14 @@ public function test_not_digitalocean_environment()
185201
);
186202
}
187203

188-
#[Server('FAIL_IO', 'true')]
189204
public function test_not_linux()
190205
{
206+
/** mock sysfs with no SMBIOS pointers */
207+
$vfs = vfsStream::setup('/');
208+
191209
$this->assertEquals(
192210
ResourceInfoFactory::emptyResource(),
193-
(new DigitalOceanDetector())->getResource()
211+
(new DigitalOceanDetector($vfs->url()))->getResource()
194212
);
195213
/** @psalm-suppress PossiblyFalseArgument */
196214
$this->assertStringContainsString(

0 commit comments

Comments
 (0)