diff --git a/README.md b/README.md index 287ea52..a994790 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ use Symfony\Component\Cache\Adapter\RedisAdapter; use Symfony\Contracts\Cache\CacheInterface; $orchHttpClient = new OrchHttpClient("https://orch.vanilla.localhost", "access-token-here"); -$siteProvider = new OrchSiteProvider($orchHttpClient, OrchCluster::REGION_AMS1_PROD1); +$siteProvider = new OrchSiteProvider($orchHttpClient, [OrchCluster::REGION_AMS1_PROD1]); // It is highly recommended to set a user-agent for network requests. $siteProvider->setUserAgent("my-service:1.0"); @@ -71,7 +71,7 @@ $cache = new MemcachedAdapter(/** Configuration here. */); $siteProvider->setCache($cache); # Region can be changed later -$siteProvider->setRegionID(OrchCluster::REGION_YUL1_PROD1); +$siteProvider->setRegionIDs([OrchCluster::REGION_YUL1_PROD1, OrchCluster::REGION_AMS1_PROD1]); ``` The orchestration provider needs to be configured with an authenticated `OrchHttpClient` and a region/network to load sites from. @@ -117,8 +117,7 @@ function doSomethingWithCluster(Cluster $cluster) { // A few getters $clusterID = $cluster->getClusterID(); - $region = $cluster->getRegion(); - $network = $cluster->getNetwork(); + $regionID = $cluster->getRegionID(); } function doSomethingWithSite(Site $site) diff --git a/src/Cluster.php b/src/Cluster.php index 778b405..aec4256 100644 --- a/src/Cluster.php +++ b/src/Cluster.php @@ -16,12 +16,15 @@ class Cluster public const REGION_AMS1_PROD1 = "ams1-prod1"; public const REGION_SJC1_PROD1 = "sjc1-prod1"; public const REGION_LOCALHOST = "localhost"; + public const REGION_MOCK = "mock"; + public const VALID_REGIONS = [ self::REGION_YUL1_DEV1, self::REGION_YUL1_PROD1, self::REGION_AMS1_PROD1, self::REGION_SJC1_PROD1, self::REGION_LOCALHOST, + self::REGION_MOCK, ]; private string $clusterID; diff --git a/src/Local/LocalSite.php b/src/Local/LocalSite.php index f69b90e..cfd0329 100644 --- a/src/Local/LocalSite.php +++ b/src/Local/LocalSite.php @@ -27,18 +27,13 @@ class LocalSite extends Site * @param string $configPath * @param SiteRecord $siteRecord * @param LocalSiteProvider $siteProvider - * @param HttpHandlerInterface $httpHandler * * @psalm-suppress InvalidArgument */ - public function __construct( - string $configPath, - SiteRecord $siteRecord, - LocalSiteProvider $siteProvider, - HttpHandlerInterface $httpHandler - ) { + public function __construct(string $configPath, SiteRecord $siteRecord, LocalSiteProvider $siteProvider) + { $this->configPath = $configPath; - parent::__construct($siteRecord, $siteProvider, $httpHandler); + parent::__construct($siteRecord, $siteProvider); } /** diff --git a/src/Local/LocalSiteProvider.php b/src/Local/LocalSiteProvider.php index 3d65856..12bb3ab 100644 --- a/src/Local/LocalSiteProvider.php +++ b/src/Local/LocalSiteProvider.php @@ -7,6 +7,7 @@ namespace Garden\Sites\Local; use Garden\Http\CurlHandler; +use Garden\Sites\Cluster; use Garden\Sites\Exceptions\ConfigLoadingException; use Garden\Sites\SiteProvider; use Garden\Sites\SiteRecord; @@ -31,7 +32,7 @@ class LocalSiteProvider extends SiteProvider */ public function __construct(string $siteConfigFsBasePath) { - parent::__construct("localhost"); + parent::__construct([Cluster::REGION_LOCALHOST]); $this->siteConfigFsBasePath = $siteConfigFsBasePath; } @@ -95,7 +96,7 @@ public function getSite(int $siteID): LocalSite $configPath = $siteRecord->getExtra("configPath") ?? ""; - $localSite = new LocalSite($this->siteConfigFsBasePath . $configPath, $siteRecord, $this, new CurlHandler()); + $localSite = new LocalSite($this->siteConfigFsBasePath . $configPath, $siteRecord, $this); return $localSite; } diff --git a/src/Mock/MockCluster.php b/src/Mock/MockCluster.php new file mode 100644 index 0000000..bdfa3ab --- /dev/null +++ b/src/Mock/MockCluster.php @@ -0,0 +1,23 @@ + + */ +class MockSite extends Site +{ + public const MOCK_CLUSTER_ID = "cl00000"; + + /** @var int */ + public int $maxJobConcurrency = 25; + + /** @var string */ + protected string $baseUrl; + + /** @var array|\ArrayAccess */ + protected $config; + + /** + * Constructor. + * + * @param string $baseUrl + * @param int $siteID + * @param array $config + * @param string $clusterID + * @param MockSiteProvider|null $mockSiteProvider + */ + public function __construct( + string $baseUrl, + int $siteID = MockSiteProvider::MOCK_SITE_ID, + array $config = [], + string $clusterID = self::MOCK_CLUSTER_ID, + MockSiteProvider $mockSiteProvider = null + ) { + $this->baseUrl = $baseUrl; + $this->config = $config; + $siteRecord = new SiteRecord($siteID, 0, $clusterID, $baseUrl); + parent::__construct($siteRecord, new MockSiteProvider()); + $this->generateKey(); + $this->setSystemToken("test123"); + $this->setConfigs([ + "Vanilla.AccountID" => 1, + "queue.disableFeedback" => true, + ]); + } + + /** + * @param MockSiteProvider $mockSiteProvider + * @return void + */ + public function setSiteProvider(MockSiteProvider $mockSiteProvider): void + { + $this->siteProvider = $mockSiteProvider; + } + + /** + * @return SiteRecord + */ + public function getSiteRecord(): SiteRecord + { + return $this->siteRecord; + } + + /** + * @inheritDoc + */ + protected function loadSiteConfig(): array + { + return $this->config; + } + + /** + * Set config values for the site. + * + * @param array $configs + * + * @return void + */ + public function setConfigs(array $configs): void + { + foreach ($configs as $key => $val) { + ArrayUtils::setByPath($key, $this->config, $val); + } + $this->clearConfigCache(); + } + + /** + * Generate a random private key. + */ + public function generateKey(): void + { + $privateKey = bin2hex(random_bytes(32)); + $this->setPrivateKey($privateKey); + } + + /** + * Set the config private key. + * + * @param string|null $key + */ + public function setPrivateKey(?string $key): void + { + $this->config["VanillaQueue"]["Keys"]["Private"] = $key; + } + + /** + * Set a value for the Garden.Scheduler.Token config field. + * + * @param string|null $value + * @return void + */ + public function setSchedulerToken(?string $value): void + { + $this->config["Garden"]["Scheduler"]["Token"] = $value; + } + + /** + * Set Api Key + * + * @param string|null $key + * @return void + */ + public function setSystemToken(?string $key): void + { + ArrayUtils::setByPath(self::CONF_SYSTEM_ACCESS_TOKEN, $this->config, $key); + } + + /** + * Set Site Account id + * + * @param int $accountID + * @return void + */ + public function setAccountID(int $accountID): void + { + $this->config["Vanilla"]["AccountID"] = $accountID; + } + + /** + * Set Elastic Secret + * + * @param ?string $secret + * @return void + */ + public function setElasticSecret(?string $secret): void + { + $this->config["ElasticDev"]["Secret"] = $secret; + } + + /** + * Set the site Plugins. + * + * @param array $plugins + * @return void + */ + public function setPlugins(array $plugins): void + { + $this->config["Plugins"] = $plugins; + } + + /** + * @return string + */ + public function getSearchServiceBaseUrl(): string + { + return "https://fake-search-service.test"; + } +} diff --git a/src/Mock/MockSiteProvider.php b/src/Mock/MockSiteProvider.php new file mode 100644 index 0000000..255cc5a --- /dev/null +++ b/src/Mock/MockSiteProvider.php @@ -0,0 +1,86 @@ + + */ +class MockSiteProvider extends SiteProvider +{ + const MOCK_SITE_ID = 123; + + /** @var array */ + private array $mockSites = []; + + /** + * Constructor. + * + * @param MockSite ...$mockSites One or more mock sites. + */ + public function __construct(MockSite ...$mockSites) + { + foreach ($mockSites as $mockLocalSite) { + $this->mockSites[$mockLocalSite->getSiteID()] = $mockLocalSite; + } + parent::__construct([Cluster::REGION_MOCK]); + $this->setCache(new NullAdapter()); + } + + /** + * Add a site. + * + * @param MockSite $mockSite + * @return void + */ + public function addSite(MockSite $mockSite): void + { + $mockSite->setSiteProvider($this); + $this->mockSites[$mockSite->getSiteID()] = $mockSite; + } + + /** + * @inheritDoc + */ + protected function loadAllSiteRecords(): array + { + $siteRecords = []; + foreach ($this->mockSites as $siteID => $site) { + $siteRecords[$siteID] = $site->getSiteRecord(); + } + + return $siteRecords; + } + + /** + * @inheritDoc + */ + public function getSite(int $siteID): Site + { + $site = $this->mockSites[$siteID] ?? null; + if ($site === null) { + throw new SiteNotFoundException($siteID); + } + return $site; + } + + /** + * @inheritDoc + */ + protected function loadAllClusters(): array + { + return [MockSite::MOCK_CLUSTER_ID => new LocalCluster(MockSite::MOCK_CLUSTER_ID)]; + } +} diff --git a/src/Orch/OrchSite.php b/src/Orch/OrchSite.php index 4ad5403..2a67f00 100644 --- a/src/Orch/OrchSite.php +++ b/src/Orch/OrchSite.php @@ -22,14 +22,10 @@ class OrchSite extends Site * * @param SiteRecord $siteRecord * @param OrchSiteProvider $siteProvider - * @param HttpHandlerInterface $httpHandler */ - public function __construct( - SiteRecord $siteRecord, - OrchSiteProvider $siteProvider, - HttpHandlerInterface $httpHandler - ) { - parent::__construct($siteRecord, $siteProvider, $httpHandler); + public function __construct(SiteRecord $siteRecord, OrchSiteProvider $siteProvider) + { + parent::__construct($siteRecord, $siteProvider); } /** diff --git a/src/Orch/OrchSiteProvider.php b/src/Orch/OrchSiteProvider.php index 7dd1e4c..a80ff78 100644 --- a/src/Orch/OrchSiteProvider.php +++ b/src/Orch/OrchSiteProvider.php @@ -26,11 +26,11 @@ class OrchSiteProvider extends SiteProvider * Constructor. * * @param OrchHttpClient $orchHttpClient A configured orch client. - * @param string $regionID One of the {@link Cluster::REGION_*} constants. + * @param string[] $regionIDs One or more of the {@link Cluster::REGION_*} constants. */ - public function __construct(OrchHttpClient $orchHttpClient, string $regionID) + public function __construct(OrchHttpClient $orchHttpClient, array $regionIDs) { - parent::__construct($regionID); + parent::__construct($regionIDs); $this->orchHttpClient = $orchHttpClient; } @@ -71,7 +71,7 @@ protected function loadAllSiteRecords(): array public function getSite(int $siteID): OrchSite { $siteRecord = $this->getSiteRecord($siteID); - $site = new OrchSite($siteRecord, $this, new CurlHandler()); + $site = new OrchSite($siteRecord, $this); return $site; } diff --git a/src/Site.php b/src/Site.php index e629e4c..f9f36b7 100644 --- a/src/Site.php +++ b/src/Site.php @@ -6,6 +6,7 @@ namespace Garden\Sites; +use Garden\Http\CurlHandler; use Garden\Http\HttpHandlerInterface; use Garden\Sites\Clients\SiteHttpClient; use Garden\Sites\Exceptions\BadApiCredentialsException; @@ -36,13 +37,12 @@ abstract class Site implements \JsonSerializable /** * @param SiteRecord $siteRecord * @param SiteProvider $siteProvider - * @param HttpHandlerInterface $httpHandler */ - public function __construct(SiteRecord $siteRecord, SiteProvider $siteProvider, HttpHandlerInterface $httpHandler) + public function __construct(SiteRecord $siteRecord, SiteProvider $siteProvider) { $this->siteRecord = $siteRecord; $this->siteProvider = $siteProvider; - $this->httpHandler = $httpHandler; + $this->httpHandler = new CurlHandler(); } /** diff --git a/src/SiteProvider.php b/src/SiteProvider.php index cdd808f..7cb765c 100644 --- a/src/SiteProvider.php +++ b/src/SiteProvider.php @@ -23,30 +23,30 @@ abstract class SiteProvider protected string $userAgent = "vanilla-sites-package"; - /** @var string The region sites should be loaded from. */ - protected string $regionID; + /** @var string[] The region sites should be loaded from. */ + protected array $regionIDs; /** * Constructor. * - * @param string $regionID One of the {@link Cluster::REGION_*} constants + * @param string[] $regionIDs One or more of the {@link Cluster::REGION_*} constants */ - public function __construct(string $regionID) + public function __construct(array $regionIDs) { $this->cache = new ArrayAdapter(); - $this->regionID = $regionID; + $this->regionIDs = $regionIDs; } /** * Set the region we should be filtering too. * - * @param string $regionID + * @param string[] $regionIDs * * @return void */ - public function setRegionID(string $regionID): void + public function setRegionIDs(array $regionIDs): void { - $this->regionID = $regionID; + $this->regionIDs = $regionIDs; } /** @@ -201,7 +201,7 @@ public function getClusters(): array }); $filteredClusters = array_filter($allClusters, function (Cluster $cluster) { - return $cluster->getRegionID() === $this->regionID; + return in_array($cluster->getRegionID(), $this->regionIDs); }); return $filteredClusters; diff --git a/tests/BaseSitesTestCase.php b/tests/BaseSitesTestCase.php index d011b18..1454cfa 100644 --- a/tests/BaseSitesTestCase.php +++ b/tests/BaseSitesTestCase.php @@ -45,7 +45,7 @@ abstract public function provideExpectedSites(): iterable; public function testSiteClientBaseUrl(ExpectedSite $expectedSite) { $provider = $this->siteProvider(); - $provider->setRegionID($expectedSite->expectedRegionID); + $provider->setRegionIDs([$expectedSite->expectedRegionID]); $site = $provider->getSite($expectedSite->getSiteID()); $siteClient = $site->httpClient(); $siteClient->setThrowExceptions(false); @@ -66,7 +66,7 @@ public function testSiteClientBaseUrl(ExpectedSite $expectedSite) public function testSiteClientAuth(ExpectedSite $expectedSite): void { $provider = $this->siteProvider(); - $provider->setRegionID($expectedSite->expectedRegionID); + $provider->setRegionIDs([$expectedSite->expectedRegionID]); $site = $provider->getSite($expectedSite->getSiteID()); $siteClient = $site->httpClient(); $siteClient->setThrowExceptions(false); @@ -100,7 +100,7 @@ public function testSiteClientAuth(ExpectedSite $expectedSite): void public function testValidSites(ExpectedSite $expectedSite): void { $provider = $this->siteProvider(); - $provider->setRegionID($expectedSite->expectedRegionID); + $provider->setRegionIDs([$expectedSite->expectedRegionID]); $site = $provider->getSite($expectedSite->getSiteID()); $expectedSite->assertMatchesSite($site); $expectedSite->assertConfigsMatchSite($site); diff --git a/tests/MockSitesTest.php b/tests/MockSitesTest.php new file mode 100644 index 0000000..1224a82 --- /dev/null +++ b/tests/MockSitesTest.php @@ -0,0 +1,31 @@ +addSite($site2); + + $this->assertSame($site1, $siteProvider->getSite(1)); + $this->assertSame($site2, $siteProvider->getSite(2)); + } +} diff --git a/tests/OrchSitesTest.php b/tests/OrchSitesTest.php index e70dc10..dd48d8e 100644 --- a/tests/OrchSitesTest.php +++ b/tests/OrchSitesTest.php @@ -48,7 +48,7 @@ public function siteProvider(): OrchSiteProvider $this->fail("Mock handler wasn't configured"); } $orchClient->setHandler($this->mockHandler); - $orchProvider = new OrchSiteProvider($orchClient, Cluster::REGION_YUL1_DEV1); + $orchProvider = new OrchSiteProvider($orchClient, [Cluster::REGION_YUL1_DEV1]); $requestRoot = __DIR__ . "/mock-orch"; $requestPaths = iterator_to_array(FileUtils::iterateFiles($requestRoot, "/.*\.json$/")); @@ -161,7 +161,7 @@ public function provideSiteFiltering(): iterable public function testSiteFiltering(string $regionID, array $expectedSiteIDs) { $siteProvider = $this->siteProvider(); - $siteProvider->setRegionID($regionID); + $siteProvider->setRegionIDs([$regionID]); $allSites = $siteProvider->getSites(); $this->assertCount(count($expectedSiteIDs), $allSites);