Initial commit: CloudOps infrastructure platform
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit;
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Mautic\CoreBundle\Helper\CacheStorageHelper;
|
||||
use Mautic\CoreBundle\Helper\EncryptionHelper;
|
||||
use Mautic\CoreBundle\Helper\PathsHelper;
|
||||
use Mautic\CoreBundle\Model\NotificationModel;
|
||||
use Mautic\LeadBundle\Field\FieldsWithUniqueIdentifier;
|
||||
use Mautic\LeadBundle\Model\CompanyModel;
|
||||
use Mautic\LeadBundle\Model\DoNotContact as DoNotContactModel;
|
||||
use Mautic\LeadBundle\Model\FieldModel;
|
||||
use Mautic\LeadBundle\Model\LeadModel;
|
||||
use Mautic\PluginBundle\Integration\AbstractIntegration;
|
||||
use Mautic\PluginBundle\Model\IntegrationEntityModel;
|
||||
use Monolog\Logger;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\Routing\Router;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class AbstractIntegrationTest extends TestCase
|
||||
{
|
||||
public function testParseCallbackResponseWithUTF8StringThatContainsControlChars(): void
|
||||
{
|
||||
$integrationDouble = $this->buildAbstractIntegrationDouble();
|
||||
|
||||
$jsonString = <<<JSON
|
||||
{
|
||||
"webinars": [
|
||||
{
|
||||
"topic": "【】 "
|
||||
}
|
||||
]
|
||||
}
|
||||
JSON;
|
||||
|
||||
$json = $integrationDouble->parseCallbackResponse($jsonString);
|
||||
self::assertArrayHasKey('webinars', $json);
|
||||
}
|
||||
|
||||
private function buildAbstractIntegrationDouble(): AbstractIntegration
|
||||
{
|
||||
// creating a double since we can't instantiate
|
||||
// we also need to expose some things for better unit test coverage
|
||||
return new class($this->createMock(EventDispatcherInterface::class), $this->createMock(CacheStorageHelper::class), $this->createMock(EntityManager::class), $this->createMock(RequestStack::class), $this->createMock(Router::class), $this->createMock(TranslatorInterface::class), $this->createMock(Logger::class), $this->createMock(EncryptionHelper::class), $this->createMock(LeadModel::class), $this->createMock(CompanyModel::class), $this->createMock(PathsHelper::class), $this->createMock(NotificationModel::class), $this->createMock(FieldModel::class), $this->createMock(IntegrationEntityModel::class), $this->createMock(DoNotContactModel::class), $this->createMock(FieldsWithUniqueIdentifier::class)) extends AbstractIntegration {
|
||||
public function getName(): string
|
||||
{
|
||||
return 'double';
|
||||
}
|
||||
|
||||
public function getAuthenticationType(): string
|
||||
{
|
||||
return 'none';
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Auth\Provider\ApiKey;
|
||||
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\ApiKey\Credentials\HeaderCredentialsInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\ApiKey\Credentials\ParameterCredentialsInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\ApiKey\HttpFactory;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\AuthCredentialsInterface;
|
||||
use Mautic\IntegrationsBundle\Exception\InvalidCredentialsException;
|
||||
use Mautic\IntegrationsBundle\Exception\PluginNotConfiguredException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class HttpFactoryTest extends TestCase
|
||||
{
|
||||
public function testType(): void
|
||||
{
|
||||
$this->assertEquals('api_key', (new HttpFactory())->getAuthType());
|
||||
}
|
||||
|
||||
public function testInvalidCredentialsThrowsException(): void
|
||||
{
|
||||
$this->expectException(InvalidCredentialsException::class);
|
||||
|
||||
$credentials = new class implements AuthCredentialsInterface {
|
||||
};
|
||||
|
||||
(new HttpFactory())->getClient($credentials);
|
||||
}
|
||||
|
||||
public function testMissingCredentialsThrowsException(): void
|
||||
{
|
||||
$this->expectException(PluginNotConfiguredException::class);
|
||||
|
||||
$credentials = new class implements HeaderCredentialsInterface {
|
||||
public function getApiKey(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getKeyName(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
(new HttpFactory())->getClient($credentials);
|
||||
}
|
||||
|
||||
public function testInstantiatedClientIsReturned(): void
|
||||
{
|
||||
$credentials = new class implements HeaderCredentialsInterface {
|
||||
public function getApiKey(): string
|
||||
{
|
||||
return 'abc';
|
||||
}
|
||||
|
||||
public function getKeyName(): string
|
||||
{
|
||||
return '123';
|
||||
}
|
||||
};
|
||||
|
||||
$factory = new HttpFactory();
|
||||
|
||||
$client1 = $factory->getClient($credentials);
|
||||
$client2 = $factory->getClient($credentials);
|
||||
$this->assertTrue($client1 === $client2);
|
||||
|
||||
$credential2 = new class implements HeaderCredentialsInterface {
|
||||
public function getApiKey(): string
|
||||
{
|
||||
return '123';
|
||||
}
|
||||
|
||||
public function getKeyName(): string
|
||||
{
|
||||
return 'abc';
|
||||
}
|
||||
};
|
||||
|
||||
$client3 = $factory->getClient($credential2);
|
||||
$this->assertFalse($client1 === $client3);
|
||||
}
|
||||
|
||||
public function testHeaderCredentialsSetsHeader(): void
|
||||
{
|
||||
$credentials = new class implements HeaderCredentialsInterface {
|
||||
public function getApiKey(): string
|
||||
{
|
||||
return '123';
|
||||
}
|
||||
|
||||
public function getKeyName(): string
|
||||
{
|
||||
return 'abc';
|
||||
}
|
||||
};
|
||||
|
||||
$factory = new HttpFactory();
|
||||
|
||||
$client = $factory->getClient($credentials);
|
||||
$headers = $client->getConfig('headers'); /** @phpstan-ignore-line Deprecated. Must be refactored for Guzzle 8 */
|
||||
$this->assertArrayHasKey('abc', $headers);
|
||||
$this->assertEquals('123', $headers['abc']);
|
||||
}
|
||||
|
||||
public function testParameterCredentialsAppendsToken(): void
|
||||
{
|
||||
$credentials = new class implements ParameterCredentialsInterface {
|
||||
public function getApiKey(): string
|
||||
{
|
||||
return '123';
|
||||
}
|
||||
|
||||
public function getKeyName(): string
|
||||
{
|
||||
return 'abc';
|
||||
}
|
||||
};
|
||||
|
||||
$factory = new HttpFactory();
|
||||
$client = $factory->getClient($credentials);
|
||||
|
||||
try {
|
||||
// Triggering an exception so we can extract the request
|
||||
$client->request('get', 'foobar');
|
||||
} catch (ConnectException $exception) {
|
||||
$query = $exception->getRequest()->getUri()->getQuery();
|
||||
$this->assertEquals('abc=123', $query);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Auth\Provider\BasicAuth;
|
||||
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\BasicAuth\CredentialsInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\BasicAuth\HttpFactory;
|
||||
use Mautic\IntegrationsBundle\Exception\PluginNotConfiguredException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class HttpFactoryTest extends TestCase
|
||||
{
|
||||
public function testType(): void
|
||||
{
|
||||
$this->assertEquals('basic_auth', (new HttpFactory())->getAuthType());
|
||||
}
|
||||
|
||||
public function testMissingUsernameThrowsException(): void
|
||||
{
|
||||
$this->expectException(PluginNotConfiguredException::class);
|
||||
|
||||
$credentials = new class implements CredentialsInterface {
|
||||
public function getUsername(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return '123';
|
||||
}
|
||||
};
|
||||
|
||||
(new HttpFactory())->getClient($credentials);
|
||||
}
|
||||
|
||||
public function testMissingPasswordThrowsException(): void
|
||||
{
|
||||
$this->expectException(PluginNotConfiguredException::class);
|
||||
|
||||
$credentials = new class implements CredentialsInterface {
|
||||
public function getUsername(): string
|
||||
{
|
||||
return '123';
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
(new HttpFactory())->getClient($credentials);
|
||||
}
|
||||
|
||||
public function testInstantiatedClientIsReturned(): void
|
||||
{
|
||||
$credentials = new class implements CredentialsInterface {
|
||||
public function getUsername(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
};
|
||||
|
||||
$factory = new HttpFactory();
|
||||
|
||||
$client1 = $factory->getClient($credentials);
|
||||
$client2 = $factory->getClient($credentials);
|
||||
$this->assertTrue($client1 === $client2);
|
||||
|
||||
$credentials2 = new class implements CredentialsInterface {
|
||||
public function getUsername(): string
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
};
|
||||
|
||||
$client3 = $factory->getClient($credentials2);
|
||||
$this->assertFalse($client1 === $client3);
|
||||
}
|
||||
|
||||
public function testHeaderIsSet(): void
|
||||
{
|
||||
$credentials = new class implements CredentialsInterface {
|
||||
public function getUsername(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
};
|
||||
|
||||
$factory = new HttpFactory();
|
||||
|
||||
$client = $factory->getClient($credentials);
|
||||
|
||||
try {
|
||||
// Triggering an exception so we can extract the request
|
||||
$client->request('get', 'foobar');
|
||||
} catch (ConnectException $exception) {
|
||||
$headers = $exception->getRequest()->getHeaders();
|
||||
$this->assertArrayHasKey('Authorization', $headers);
|
||||
|
||||
$this->assertEquals('Basic '.base64_encode('foo:bar'), $headers['Authorization'][0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Auth\Provider\Oauth1aTwoLegged;
|
||||
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\Oauth1aTwoLegged\CredentialsInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\Oauth1aTwoLegged\HttpFactory;
|
||||
use Mautic\IntegrationsBundle\Exception\PluginNotConfiguredException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class HttpFactoryTest extends TestCase
|
||||
{
|
||||
public function testType(): void
|
||||
{
|
||||
$this->assertEquals('oauth1a_two_legged', (new HttpFactory())->getAuthType());
|
||||
}
|
||||
|
||||
public function testGetClientWithEmptyCredentials(): void
|
||||
{
|
||||
$credentials = $this->createMock(CredentialsInterface::class);
|
||||
$httpFactory = new HttpFactory();
|
||||
$this->expectException(PluginNotConfiguredException::class);
|
||||
$httpFactory->getClient($credentials);
|
||||
}
|
||||
|
||||
public function testGetClientWithFullCredentials(): void
|
||||
{
|
||||
$credentials = $this->createMock(CredentialsInterface::class);
|
||||
$credentials->method('getConsumerKey')->willReturn('ConsumerKeyValue');
|
||||
$credentials->method('getConsumerSecret')->willReturn('ConsumerSecretValue');
|
||||
$credentials->method('getToken')->willReturn('TokenValue');
|
||||
$credentials->method('getTokenSecret')->willReturn('TokenSecretValue');
|
||||
$credentials->method('getAuthUrl')->willReturn('AuthUrlValue');
|
||||
$httpFactory = new HttpFactory();
|
||||
$client = $httpFactory->getClient($credentials);
|
||||
$config = $client->getConfig(); /** @phpstan-ignore-line Deprecated. Must be refactored for Guzzle 8 */
|
||||
$this->assertSame('oauth', $config['auth']);
|
||||
$this->assertSame('AuthUrlValue', $config['base_uri']->getPath());
|
||||
$this->assertTrue($config['handler']->hasHandler());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,388 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Auth\Provider\Oauth2ThreeLegged;
|
||||
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use kamermans\OAuth2\OAuth2Middleware;
|
||||
use kamermans\OAuth2\Persistence\TokenPersistenceInterface as KamermansTokenPersistenceInterface;
|
||||
use kamermans\OAuth2\Signer\AccessToken\SignerInterface as AccessTokenSigner;
|
||||
use kamermans\OAuth2\Signer\ClientCredentials\SignerInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\Oauth2ThreeLegged\Credentials\CodeInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\Oauth2ThreeLegged\Credentials\CredentialsInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\Oauth2ThreeLegged\Credentials\RedirectUriInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\Oauth2ThreeLegged\Credentials\ScopeInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\Oauth2ThreeLegged\HttpFactory;
|
||||
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\ConfigAccess\ConfigCredentialsSignerInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\ConfigAccess\ConfigTokenPersistenceInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\ConfigAccess\ConfigTokenSignerInterface;
|
||||
use Mautic\IntegrationsBundle\Exception\PluginNotConfiguredException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class HttpFactoryTest extends TestCase
|
||||
{
|
||||
public function testType(): void
|
||||
{
|
||||
$this->assertEquals('oauth2_three_legged', (new HttpFactory())->getAuthType());
|
||||
}
|
||||
|
||||
public function testMissingAuthorizationUrlThrowsException(): void
|
||||
{
|
||||
$this->expectException(PluginNotConfiguredException::class);
|
||||
|
||||
$credentials = new class implements CredentialsInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getTokenUrl(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
(new HttpFactory())->getClient($credentials);
|
||||
}
|
||||
|
||||
public function testMissingTokenUrlThrowsException(): void
|
||||
{
|
||||
$this->expectException(PluginNotConfiguredException::class);
|
||||
|
||||
$credentials = new class implements CredentialsInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://auth.url';
|
||||
}
|
||||
|
||||
public function getTokenUrl(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
(new HttpFactory())->getClient($credentials);
|
||||
}
|
||||
|
||||
public function testBaseURISetOnBaseUriAwareCredentials(): void
|
||||
{
|
||||
$credentials = new class implements CredentialsInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://auth.url';
|
||||
}
|
||||
|
||||
public function getTokenUrl(): string
|
||||
{
|
||||
return 'http://token.url';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
public function getCode(): string
|
||||
{
|
||||
return 'auth_code';
|
||||
}
|
||||
|
||||
public function getRedirectUri(): string
|
||||
{
|
||||
return 'http://redirect.url';
|
||||
}
|
||||
|
||||
public function getScope(): string
|
||||
{
|
||||
return 'scope';
|
||||
}
|
||||
|
||||
public function getBaseUri(): string
|
||||
{
|
||||
return 'https://mautic.com';
|
||||
}
|
||||
};
|
||||
|
||||
$client = (new HttpFactory())->getClient($credentials);
|
||||
/**
|
||||
* Even though the method getConfig is deprecated it won't get deprecated
|
||||
* https://github.com/guzzle/guzzle/issues/3114#issuecomment-1627228395.
|
||||
*/
|
||||
/** @phpstan-ignore-next-line */
|
||||
$this->assertEquals('https://mautic.com', (string) $client->getConfig('base_uri'));
|
||||
}
|
||||
|
||||
public function testMissingClientIdThrowsException(): void
|
||||
{
|
||||
$this->expectException(PluginNotConfiguredException::class);
|
||||
|
||||
$credentials = new class implements CredentialsInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://auth.url';
|
||||
}
|
||||
|
||||
public function getTokenUrl(): string
|
||||
{
|
||||
return 'http://token.url';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
(new HttpFactory())->getClient($credentials);
|
||||
}
|
||||
|
||||
public function testMissingClientSecretThrowsException(): void
|
||||
{
|
||||
$this->expectException(PluginNotConfiguredException::class);
|
||||
|
||||
$credentials = new class implements CredentialsInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://auth.url';
|
||||
}
|
||||
|
||||
public function getTokenUrl(): string
|
||||
{
|
||||
return 'http://token.url';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
(new HttpFactory())->getClient($credentials);
|
||||
}
|
||||
|
||||
public function testInstantiatedClientIsReturned(): void
|
||||
{
|
||||
$credentials = new class implements CredentialsInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://auth.url';
|
||||
}
|
||||
|
||||
public function getTokenUrl(): string
|
||||
{
|
||||
return 'http://token.url';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
};
|
||||
|
||||
$factory = new HttpFactory();
|
||||
|
||||
$client1 = $factory->getClient($credentials);
|
||||
$client2 = $factory->getClient($credentials);
|
||||
$this->assertTrue($client1 === $client2);
|
||||
|
||||
$credentials2 = new class implements CredentialsInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://auth.url';
|
||||
}
|
||||
|
||||
public function getTokenUrl(): string
|
||||
{
|
||||
return 'http://token.url';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
};
|
||||
|
||||
$client3 = $factory->getClient($credentials2);
|
||||
$this->assertFalse($client1 === $client3);
|
||||
}
|
||||
|
||||
public function testReAuthClientConfiguration(): void
|
||||
{
|
||||
$credentials = $this->getCredentials();
|
||||
|
||||
$client = (new HttpFactory())->getClient($credentials);
|
||||
|
||||
$middleware = $this->extractMiddleware($client);
|
||||
|
||||
$reflectedMiddleware = new \ReflectionClass($middleware);
|
||||
$grantType = $this->getProperty($reflectedMiddleware, $middleware, 'grantType');
|
||||
|
||||
$reflectedGrantType = new \ReflectionClass($grantType);
|
||||
$reauthConfig = $this->getProperty($reflectedGrantType, $grantType, 'config');
|
||||
|
||||
$expectedConfig = [
|
||||
'client_id' => $credentials->getClientId(),
|
||||
'client_secret' => $credentials->getClientSecret(),
|
||||
'code' => $credentials->getCode(),
|
||||
'redirect_uri' => $credentials->getRedirectUri(),
|
||||
'scope' => $credentials->getScope(),
|
||||
];
|
||||
|
||||
$this->assertEquals($expectedConfig, $reauthConfig->toArray());
|
||||
}
|
||||
|
||||
public function testClientConfiguration(): void
|
||||
{
|
||||
$credentials = $this->getCredentials();
|
||||
$signerInterface = $this->createMock(SignerInterface::class);
|
||||
$kamermansTokenPersistence = $this->createMock(KamermansTokenPersistenceInterface::class);
|
||||
$accessTokenSigner = $this->createMock(AccessTokenSigner::class);
|
||||
|
||||
$clientCredentialSigner = $this->createMock(ConfigCredentialsSignerInterface::class);
|
||||
$clientCredentialSigner->expects($this->once())
|
||||
->method('getCredentialsSigner')
|
||||
->willReturn($signerInterface);
|
||||
|
||||
$client = (new HttpFactory())->getClient($credentials, $clientCredentialSigner);
|
||||
$middleware = $this->extractMiddleware($client);
|
||||
$reflectedMiddleware = new \ReflectionClass($middleware);
|
||||
$this->assertTrue($this->getProperty($reflectedMiddleware, $middleware, 'clientCredentialsSigner') === $signerInterface);
|
||||
|
||||
$tokenPersistence = $this->createMock(ConfigTokenPersistenceInterface::class);
|
||||
$tokenPersistence->expects($this->once())
|
||||
->method('getTokenPersistence')
|
||||
->willReturn($kamermansTokenPersistence);
|
||||
|
||||
$client = (new HttpFactory())->getClient($credentials, $tokenPersistence);
|
||||
$middleware = $this->extractMiddleware($client);
|
||||
$reflectedMiddleware = new \ReflectionClass($middleware);
|
||||
$this->assertTrue($this->getProperty($reflectedMiddleware, $middleware, 'tokenPersistence') === $kamermansTokenPersistence);
|
||||
|
||||
$tokenPersistence = $this->createMock(ConfigTokenSignerInterface::class);
|
||||
$tokenPersistence->expects($this->once())
|
||||
->method('getTokenSigner')
|
||||
->willReturn($accessTokenSigner);
|
||||
|
||||
$client = (new HttpFactory())->getClient($credentials, $tokenPersistence);
|
||||
$middleware = $this->extractMiddleware($client);
|
||||
$reflectedMiddleware = new \ReflectionClass($middleware);
|
||||
$this->assertTrue($this->getProperty($reflectedMiddleware, $middleware, 'accessTokenSigner') === $accessTokenSigner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
private function extractMiddleware(ClientInterface $client): OAuth2Middleware
|
||||
{
|
||||
/** @phpstan-ignore-next-line */
|
||||
$handler = $client->getConfig()['handler'];
|
||||
|
||||
$reflection = new \ReflectionClass($handler);
|
||||
$property = $reflection->getProperty('stack');
|
||||
$property->setAccessible(true);
|
||||
|
||||
$stack = $property->getValue($handler);
|
||||
|
||||
/** @var OAuth2Middleware $oauthMiddleware */
|
||||
$oauthMiddleware = array_pop($stack);
|
||||
|
||||
return $oauthMiddleware[0];
|
||||
}
|
||||
|
||||
private function getProperty(\ReflectionClass $reflection, $object, string $name)
|
||||
{
|
||||
$property = $reflection->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
|
||||
return $property->getValue($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CredentialsInterface|CodeInterface|RedirectUriInterface|ScopeInterface
|
||||
*/
|
||||
private function getCredentials(): CredentialsInterface
|
||||
{
|
||||
return new class implements CredentialsInterface, CodeInterface, RedirectUriInterface, ScopeInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://auth.url';
|
||||
}
|
||||
|
||||
public function getTokenUrl(): string
|
||||
{
|
||||
return 'http://token.url';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
public function getCode(): string
|
||||
{
|
||||
return 'auth_code';
|
||||
}
|
||||
|
||||
public function getRedirectUri(): string
|
||||
{
|
||||
return 'http://redirect.url';
|
||||
}
|
||||
|
||||
public function getScope(): string
|
||||
{
|
||||
return 'scope';
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,432 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Auth\Provider\Oauth2TwoLegged;
|
||||
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use kamermans\OAuth2\GrantType\ClientCredentials;
|
||||
use kamermans\OAuth2\GrantType\PasswordCredentials;
|
||||
use kamermans\OAuth2\OAuth2Middleware;
|
||||
use kamermans\OAuth2\Persistence\TokenPersistenceInterface as KamermansTokenPersistenceInterface;
|
||||
use kamermans\OAuth2\Signer\AccessToken\SignerInterface as AccessTokenSigner;
|
||||
use kamermans\OAuth2\Signer\ClientCredentials\SignerInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\AuthCredentialsInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\Oauth2ThreeLegged\Credentials\CredentialsInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\Oauth2TwoLegged\Credentials\ClientCredentialsGrantInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\Oauth2TwoLegged\Credentials\PasswordCredentialsGrantInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\Oauth2TwoLegged\Credentials\ScopeInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\Oauth2TwoLegged\Credentials\StateInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Provider\Oauth2TwoLegged\HttpFactory;
|
||||
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\ConfigAccess\ConfigCredentialsSignerInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\ConfigAccess\ConfigTokenPersistenceInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\ConfigAccess\ConfigTokenSignerInterface;
|
||||
use Mautic\IntegrationsBundle\Exception\InvalidCredentialsException;
|
||||
use Mautic\IntegrationsBundle\Exception\PluginNotConfiguredException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class HttpFactoryTest extends TestCase
|
||||
{
|
||||
public function testType(): void
|
||||
{
|
||||
$this->assertEquals('oauth2_two_legged', (new HttpFactory())->getAuthType());
|
||||
}
|
||||
|
||||
public function testInvalidCredentialsThrowsException(): void
|
||||
{
|
||||
$this->expectException(InvalidCredentialsException::class);
|
||||
|
||||
$credentials = new class implements AuthCredentialsInterface {
|
||||
};
|
||||
|
||||
(new HttpFactory())->getClient($credentials);
|
||||
}
|
||||
|
||||
public function testMissingAuthorizationUrlThrowsException(): void
|
||||
{
|
||||
$this->expectException(PluginNotConfiguredException::class);
|
||||
|
||||
$credentials = new class implements ClientCredentialsGrantInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
(new HttpFactory())->getClient($credentials);
|
||||
}
|
||||
|
||||
public function testMissingClientIdThrowsException(): void
|
||||
{
|
||||
$this->expectException(PluginNotConfiguredException::class);
|
||||
|
||||
$credentials = new class implements ClientCredentialsGrantInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://test.com';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
(new HttpFactory())->getClient($credentials);
|
||||
}
|
||||
|
||||
public function testMissingClientSecretIdThrowsException(): void
|
||||
{
|
||||
$this->expectException(PluginNotConfiguredException::class);
|
||||
|
||||
$credentials = new class implements ClientCredentialsGrantInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://test.com';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
(new HttpFactory())->getClient($credentials);
|
||||
}
|
||||
|
||||
public function testMissingUsernameThrowsException(): void
|
||||
{
|
||||
$this->expectException(PluginNotConfiguredException::class);
|
||||
|
||||
$credentials = new class implements PasswordCredentialsGrantInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://test.com';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
|
||||
public function getUsername(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
(new HttpFactory())->getClient($credentials);
|
||||
}
|
||||
|
||||
public function testMissingPasswordThrowsException(): void
|
||||
{
|
||||
$this->expectException(PluginNotConfiguredException::class);
|
||||
|
||||
$credentials = new class implements PasswordCredentialsGrantInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://test.com';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
|
||||
public function getUsername(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
(new HttpFactory())->getClient($credentials);
|
||||
}
|
||||
|
||||
public function testInstantiatedClientIsReturned(): void
|
||||
{
|
||||
$credentials = new class implements ClientCredentialsGrantInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://test.com';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
};
|
||||
|
||||
$factory = new HttpFactory();
|
||||
|
||||
$client1 = $factory->getClient($credentials);
|
||||
$client2 = $factory->getClient($credentials);
|
||||
$this->assertTrue($client1 === $client2);
|
||||
|
||||
$credentials2 = new class implements ClientCredentialsGrantInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://test.com';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
};
|
||||
|
||||
$client3 = $factory->getClient($credentials2);
|
||||
$this->assertFalse($client1 === $client3);
|
||||
}
|
||||
|
||||
public function testReAuthClientConfiguration(): void
|
||||
{
|
||||
$credentials = $this->getCredentials();
|
||||
|
||||
$client = (new HttpFactory())->getClient($credentials);
|
||||
|
||||
$middleware = $this->extractMiddleware($client);
|
||||
|
||||
$reflectedMiddleware = new \ReflectionClass($middleware);
|
||||
$grantType = $this->getProperty($reflectedMiddleware, $middleware, 'grantType');
|
||||
|
||||
$reflectedGrantType = new \ReflectionClass($grantType);
|
||||
$reauthConfig = $this->getProperty($reflectedGrantType, $grantType, 'config');
|
||||
|
||||
$expectedConfig = [
|
||||
'client_id' => $credentials->getClientId(),
|
||||
'client_secret' => $credentials->getClientSecret(),
|
||||
'scope' => $credentials->getScope(),
|
||||
'state' => $credentials->getState(),
|
||||
'username' => $credentials->getUsername(),
|
||||
'password' => $credentials->getPassword(),
|
||||
];
|
||||
|
||||
$this->assertEquals($expectedConfig, $reauthConfig->toArray());
|
||||
}
|
||||
|
||||
public function testPasswordGrantTypeIsUsed(): void
|
||||
{
|
||||
$credentials = new class implements PasswordCredentialsGrantInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://test.com';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
|
||||
public function getUsername(): string
|
||||
{
|
||||
return 'username';
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return 'password';
|
||||
}
|
||||
};
|
||||
|
||||
$client = (new HttpFactory())->getClient($credentials);
|
||||
$middleware = $this->extractMiddleware($client);
|
||||
$reflectedMiddleware = new \ReflectionClass($middleware);
|
||||
$grantType = $this->getProperty($reflectedMiddleware, $middleware, 'grantType');
|
||||
|
||||
$this->assertInstanceOf(PasswordCredentials::class, $grantType);
|
||||
}
|
||||
|
||||
public function testClientCredentialsGrantTypeIsUsed(): void
|
||||
{
|
||||
$credentials = new class implements ClientCredentialsGrantInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://test.com';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
};
|
||||
|
||||
$client = (new HttpFactory())->getClient($credentials);
|
||||
$middleware = $this->extractMiddleware($client);
|
||||
$reflectedMiddleware = new \ReflectionClass($middleware);
|
||||
$grantType = $this->getProperty($reflectedMiddleware, $middleware, 'grantType');
|
||||
|
||||
$this->assertInstanceOf(ClientCredentials::class, $grantType);
|
||||
}
|
||||
|
||||
public function testClientConfiguration(): void
|
||||
{
|
||||
$credentials = $this->getCredentials();
|
||||
$signerInterface = $this->createMock(SignerInterface::class);
|
||||
$kamermansTokenPersistence = $this->createMock(KamermansTokenPersistenceInterface::class);
|
||||
$accessTokenSigner = $this->createMock(AccessTokenSigner::class);
|
||||
|
||||
$clientCredentialSigner = $this->createMock(ConfigCredentialsSignerInterface::class);
|
||||
$clientCredentialSigner->expects($this->once())
|
||||
->method('getCredentialsSigner')
|
||||
->willReturn($signerInterface);
|
||||
|
||||
$client = (new \Mautic\IntegrationsBundle\Auth\Provider\Oauth2ThreeLegged\HttpFactory())->getClient($credentials, $clientCredentialSigner);
|
||||
$middleware = $this->extractMiddleware($client);
|
||||
$reflectedMiddleware = new \ReflectionClass($middleware);
|
||||
$this->assertTrue($this->getProperty($reflectedMiddleware, $middleware, 'clientCredentialsSigner') === $signerInterface);
|
||||
|
||||
$tokenPersistence = $this->createMock(ConfigTokenPersistenceInterface::class);
|
||||
$tokenPersistence->expects($this->once())
|
||||
->method('getTokenPersistence')
|
||||
->willReturn($kamermansTokenPersistence);
|
||||
|
||||
$client = (new HttpFactory())->getClient($credentials, $tokenPersistence);
|
||||
$middleware = $this->extractMiddleware($client);
|
||||
$reflectedMiddleware = new \ReflectionClass($middleware);
|
||||
$this->assertTrue($this->getProperty($reflectedMiddleware, $middleware, 'tokenPersistence') === $kamermansTokenPersistence);
|
||||
|
||||
$tokenPersistence = $this->createMock(ConfigTokenSignerInterface::class);
|
||||
$tokenPersistence->expects($this->once())
|
||||
->method('getTokenSigner')
|
||||
->willReturn($accessTokenSigner);
|
||||
|
||||
$client = (new HttpFactory())->getClient($credentials, $tokenPersistence);
|
||||
$middleware = $this->extractMiddleware($client);
|
||||
$reflectedMiddleware = new \ReflectionClass($middleware);
|
||||
$this->assertTrue($this->getProperty($reflectedMiddleware, $middleware, 'accessTokenSigner') === $accessTokenSigner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
private function extractMiddleware(ClientInterface $client): OAuth2Middleware
|
||||
{
|
||||
$handler = $client->getConfig()['handler']; /** @phpstan-ignore-line Deprecated. Must be refactored for Guzzle 8 */
|
||||
$reflection = new \ReflectionClass($handler);
|
||||
$property = $reflection->getProperty('stack');
|
||||
$property->setAccessible(true);
|
||||
|
||||
$stack = $property->getValue($handler);
|
||||
|
||||
/** @var OAuth2Middleware $oauthMiddleware */
|
||||
$oauthMiddleware = array_pop($stack);
|
||||
|
||||
return $oauthMiddleware[0];
|
||||
}
|
||||
|
||||
private function getProperty(\ReflectionClass $reflection, $object, string $name)
|
||||
{
|
||||
$property = $reflection->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
|
||||
return $property->getValue($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PasswordCredentialsGrantInterface|StateInterface|ScopeInterface
|
||||
*/
|
||||
private function getCredentials(): PasswordCredentialsGrantInterface
|
||||
{
|
||||
return new class implements PasswordCredentialsGrantInterface, StateInterface, ScopeInterface, CredentialsInterface {
|
||||
public function getAuthorizationUrl(): string
|
||||
{
|
||||
return 'http://test.com';
|
||||
}
|
||||
|
||||
public function getClientId(): string
|
||||
{
|
||||
return 'bar';
|
||||
}
|
||||
|
||||
public function getUsername(): string
|
||||
{
|
||||
return 'username';
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return 'password';
|
||||
}
|
||||
|
||||
public function getState(): string
|
||||
{
|
||||
return 'state';
|
||||
}
|
||||
|
||||
public function getScope(): string
|
||||
{
|
||||
return 'scope';
|
||||
}
|
||||
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return 'secret';
|
||||
}
|
||||
|
||||
public function getTokenUrl(): string
|
||||
{
|
||||
return 'tokenurl';
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Auth\Support\Oauth2\Token;
|
||||
|
||||
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\Token\IntegrationToken;
|
||||
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\Token\IntegrationTokenFactory;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class IntegrationTokenFactoryTest extends TestCase
|
||||
{
|
||||
public function testTokenGeneratedWithExpiresIn(): void
|
||||
{
|
||||
$factory = new IntegrationTokenFactory();
|
||||
$data = [
|
||||
'access_token' => '123',
|
||||
'refresh_token' => '456',
|
||||
'expires_in' => 10,
|
||||
];
|
||||
|
||||
$token = $factory($data);
|
||||
|
||||
$this->assertEquals($data['access_token'], $token->getAccessToken());
|
||||
$this->assertEquals($data['refresh_token'], $token->getRefreshToken());
|
||||
$this->assertFalse($token->isExpired());
|
||||
$this->assertEquals(time() + 10, $token->getExpiresAt());
|
||||
}
|
||||
|
||||
public function testTokenGeneratedWithExpiresAt(): void
|
||||
{
|
||||
$factory = new IntegrationTokenFactory();
|
||||
$data = [
|
||||
'access_token' => '123',
|
||||
'refresh_token' => '456',
|
||||
'expires_at' => time() + 10,
|
||||
];
|
||||
|
||||
$token = $factory($data);
|
||||
|
||||
$this->assertEquals($data['access_token'], $token->getAccessToken());
|
||||
$this->assertEquals($data['refresh_token'], $token->getRefreshToken());
|
||||
$this->assertFalse($token->isExpired());
|
||||
$this->assertEquals($data['expires_at'], $token->getExpiresAt());
|
||||
}
|
||||
|
||||
public function testTokenGeneratedWithExpires(): void
|
||||
{
|
||||
$factory = new IntegrationTokenFactory();
|
||||
$data = [
|
||||
'access_token' => '123',
|
||||
'refresh_token' => '456',
|
||||
'expires' => 10,
|
||||
];
|
||||
|
||||
$token = $factory($data);
|
||||
|
||||
$this->assertEquals($data['access_token'], $token->getAccessToken());
|
||||
$this->assertEquals($data['refresh_token'], $token->getRefreshToken());
|
||||
$this->assertFalse($token->isExpired());
|
||||
$this->assertEquals(time() + 10, $token->getExpiresAt());
|
||||
}
|
||||
|
||||
public function testTokenGeneratedWithDefaultExpires(): void
|
||||
{
|
||||
$factory = new IntegrationTokenFactory([], 100);
|
||||
$data = [
|
||||
'access_token' => '123',
|
||||
'refresh_token' => '456',
|
||||
];
|
||||
|
||||
$token = $factory($data);
|
||||
|
||||
$this->assertEquals($data['access_token'], $token->getAccessToken());
|
||||
$this->assertEquals($data['refresh_token'], $token->getRefreshToken());
|
||||
$this->assertFalse($token->isExpired());
|
||||
$this->assertEquals(time() + 100, $token->getExpiresAt());
|
||||
}
|
||||
|
||||
public function testTokenGeneratedWithUnexpiredTokenByDefault(): void
|
||||
{
|
||||
$factory = new IntegrationTokenFactory();
|
||||
$data = [
|
||||
'access_token' => '123',
|
||||
'refresh_token' => '456',
|
||||
];
|
||||
|
||||
$token = $factory($data);
|
||||
|
||||
$this->assertEquals($data['access_token'], $token->getAccessToken());
|
||||
$this->assertEquals($data['refresh_token'], $token->getRefreshToken());
|
||||
$this->assertFalse($token->isExpired());
|
||||
$this->assertEquals(0, $token->getExpiresAt());
|
||||
}
|
||||
|
||||
public function testTokenGeneratedWithPreviousRefreshToken(): void
|
||||
{
|
||||
$factory = new IntegrationTokenFactory();
|
||||
$data = [
|
||||
'access_token' => '123',
|
||||
];
|
||||
|
||||
$previousToken = new IntegrationToken('789', '456');
|
||||
$token = $factory($data, $previousToken);
|
||||
|
||||
$this->assertEquals($data['access_token'], $token->getAccessToken());
|
||||
$this->assertEquals($previousToken->getRefreshToken(), $token->getRefreshToken());
|
||||
$this->assertFalse($token->isExpired());
|
||||
}
|
||||
|
||||
public function testTokenGeneratedWithExtraData(): void
|
||||
{
|
||||
$factory = new IntegrationTokenFactory(['foo']);
|
||||
$data = [
|
||||
'access_token' => '123',
|
||||
'refresh_token' => '456',
|
||||
'foo' => 'bar',
|
||||
'bar' => 'foo',
|
||||
];
|
||||
|
||||
$token = $factory($data);
|
||||
|
||||
$this->assertEquals($data['access_token'], $token->getAccessToken());
|
||||
$this->assertEquals($data['refresh_token'], $token->getRefreshToken());
|
||||
$this->assertFalse($token->isExpired());
|
||||
$this->assertEquals(['foo' => 'bar'], $token->getExtraData());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Auth\Support\Oauth2\Token;
|
||||
|
||||
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\Token\IntegrationToken;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class IntegrationTokenTest extends TestCase
|
||||
{
|
||||
public function testGetters(): void
|
||||
{
|
||||
$expires = time() + 100;
|
||||
$extraData = ['foo' => 'bar'];
|
||||
$token = new IntegrationToken('accessToken', 'refreshToken', $expires, $extraData);
|
||||
|
||||
$this->assertEquals('accessToken', $token->getAccessToken());
|
||||
$this->assertEquals('refreshToken', $token->getRefreshToken());
|
||||
$this->assertEquals($expires, $token->getExpiresAt());
|
||||
$this->assertEquals($extraData, $token->getExtraData());
|
||||
}
|
||||
|
||||
public function testIsExpired(): void
|
||||
{
|
||||
$token = new IntegrationToken('accessToken', 'refreshToken', time() - 100);
|
||||
|
||||
$this->assertTrue($token->isExpired());
|
||||
}
|
||||
|
||||
public function testIsExpiredIfAccessTokenIsMissing(): void
|
||||
{
|
||||
$token = new IntegrationToken('', 'refreshToken');
|
||||
|
||||
$this->assertTrue($token->isExpired());
|
||||
}
|
||||
|
||||
public function testIsNotExpired(): void
|
||||
{
|
||||
$token = new IntegrationToken('accessToken', 'refreshToken', time() + 100);
|
||||
|
||||
$this->assertFalse($token->isExpired());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Auth\Support\Oauth2\Token;
|
||||
|
||||
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\Token\TokenPersistenceFactory;
|
||||
use Mautic\IntegrationsBundle\Helper\IntegrationsHelper;
|
||||
use Mautic\PluginBundle\Entity\Integration;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class TokenPersistenceFactoryTest extends TestCase
|
||||
{
|
||||
private \PHPUnit\Framework\MockObject\MockObject $integrationsHelper;
|
||||
|
||||
private \PHPUnit\Framework\MockObject\MockObject $integration;
|
||||
|
||||
public function setup(): void
|
||||
{
|
||||
$this->integrationsHelper = $this->createMock(IntegrationsHelper::class);
|
||||
$this->integration = $this->createMock(Integration::class);
|
||||
}
|
||||
|
||||
public function testCreate(): void
|
||||
{
|
||||
$accessToken = 'access_token';
|
||||
$refreshToken = 'refresh_token';
|
||||
$expiresAt = 10;
|
||||
$apiKeys = [
|
||||
'access_token' => $accessToken,
|
||||
'refresh_token' => $refreshToken,
|
||||
'expires_at' => $expiresAt,
|
||||
];
|
||||
|
||||
$this->integration->expects($this->any())
|
||||
->method('getApiKeys')
|
||||
->willReturn($apiKeys);
|
||||
|
||||
$factory = new TokenPersistenceFactory($this->integrationsHelper);
|
||||
$tokenPersistence = $factory->create($this->integration);
|
||||
$this->assertTrue($tokenPersistence->hasToken());
|
||||
}
|
||||
|
||||
public function testCreateWithInvalidToken(): void
|
||||
{
|
||||
$accessToken = null;
|
||||
$refreshToken = 'refresh_token';
|
||||
$expiresAt = 10;
|
||||
$apiKeys = [
|
||||
'access_token' => $accessToken,
|
||||
'refresh_token' => $refreshToken,
|
||||
'expires_at' => $expiresAt,
|
||||
];
|
||||
|
||||
$this->integration->expects($this->any())
|
||||
->method('getApiKeys')
|
||||
->willReturn($apiKeys);
|
||||
|
||||
$factory = new TokenPersistenceFactory($this->integrationsHelper);
|
||||
$tokenPersistence = $factory->create($this->integration);
|
||||
$this->assertFalse($tokenPersistence->hasToken());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Auth\Support\Oauth2\Token;
|
||||
|
||||
use kamermans\OAuth2\Token\RawToken;
|
||||
use kamermans\OAuth2\Token\RawTokenFactory;
|
||||
use kamermans\OAuth2\Token\TokenInterface;
|
||||
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\Token\IntegrationToken;
|
||||
use Mautic\IntegrationsBundle\Auth\Support\Oauth2\Token\TokenPersistence;
|
||||
use Mautic\IntegrationsBundle\Exception\IntegrationNotSetException;
|
||||
use Mautic\IntegrationsBundle\Helper\IntegrationsHelper;
|
||||
use Mautic\PluginBundle\Entity\Integration;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class TokenPersistenceTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var MockObject|IntegrationsHelper
|
||||
*/
|
||||
private MockObject $integrationsHelper;
|
||||
|
||||
private TokenPersistence $tokenPersistence;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->integrationsHelper = $this->createMock(IntegrationsHelper::class);
|
||||
$this->tokenPersistence = new TokenPersistence($this->integrationsHelper);
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testIntegrationNotSetRestoreToken(): void
|
||||
{
|
||||
$this->expectException(IntegrationNotSetException::class);
|
||||
|
||||
$token = $this->createMock(TokenInterface::class);
|
||||
$this->tokenPersistence->restoreToken($token);
|
||||
}
|
||||
|
||||
public function testRestoreToken(): void
|
||||
{
|
||||
$accessToken = 'access_token';
|
||||
$refreshToken = 'refresh_token';
|
||||
$expiresAt = 10;
|
||||
$apiKeys = [
|
||||
'access_token' => $accessToken,
|
||||
'refresh_token' => $refreshToken,
|
||||
'expires_at' => $expiresAt,
|
||||
];
|
||||
|
||||
$factory = new RawTokenFactory();
|
||||
$tokenFromApi = $factory([
|
||||
'access_token' => $accessToken,
|
||||
'refresh_token' => $refreshToken,
|
||||
'expires_at' => $expiresAt,
|
||||
]);
|
||||
|
||||
$integration = $this->createMock(Integration::class);
|
||||
$integration->expects($this->once())
|
||||
->method('getApiKeys')
|
||||
->willReturn($apiKeys);
|
||||
|
||||
$this->tokenPersistence->setIntegration($integration);
|
||||
|
||||
$newToken = $this->tokenPersistence->restoreToken($tokenFromApi);
|
||||
|
||||
$this->assertSame($tokenFromApi->getAccessToken(), $newToken->getAccessToken());
|
||||
$this->assertSame($tokenFromApi->getRefreshToken(), $newToken->getRefreshToken());
|
||||
}
|
||||
|
||||
public function testIntegrationNotSetSaveToken(): void
|
||||
{
|
||||
$this->expectException(IntegrationNotSetException::class);
|
||||
|
||||
$token = $this->createMock(TokenInterface::class);
|
||||
$this->tokenPersistence->saveToken($token);
|
||||
}
|
||||
|
||||
public function testSaveToken(): void
|
||||
{
|
||||
$oldApiKeys = [
|
||||
'access_token' => 'old_access_token',
|
||||
'something' => 'something',
|
||||
];
|
||||
|
||||
$newApiKeys = [
|
||||
'access_token' => 'access_token',
|
||||
'refresh_token' => 'refresh_token',
|
||||
'expires_at' => '0',
|
||||
];
|
||||
|
||||
$extraData = [
|
||||
'instance_url' => 'abc.123.com',
|
||||
];
|
||||
|
||||
$token = new IntegrationToken($newApiKeys['access_token'], $newApiKeys['refresh_token'], $newApiKeys['expires_at'], $extraData);
|
||||
$integration = $this->createMock(Integration::class);
|
||||
$newApiKeys = array_merge($oldApiKeys, $extraData, $newApiKeys);
|
||||
|
||||
$integration->expects($this->exactly(2))
|
||||
->method('getApiKeys')
|
||||
->willReturnOnConsecutiveCalls($oldApiKeys, $newApiKeys);
|
||||
|
||||
$integration->expects($this->once())
|
||||
->method('setApiKeys')
|
||||
->with($newApiKeys);
|
||||
|
||||
$this->tokenPersistence->setIntegration($integration);
|
||||
|
||||
$this->integrationsHelper->expects($this->once())
|
||||
->method('saveIntegrationConfiguration');
|
||||
|
||||
$this->tokenPersistence->saveToken($token);
|
||||
|
||||
$this->assertTrue($this->tokenPersistence->hasToken());
|
||||
}
|
||||
|
||||
public function testIntegrationNotSetDeleteToken(): void
|
||||
{
|
||||
$this->expectException(IntegrationNotSetException::class);
|
||||
|
||||
$token = $this->createMock(TokenInterface::class);
|
||||
$this->tokenPersistence->saveToken($token);
|
||||
}
|
||||
|
||||
public function testDeleteToken(): void
|
||||
{
|
||||
$accessToken = 'access_token';
|
||||
$refreshToken = 'refresh_token';
|
||||
$expiresAt = 10;
|
||||
$token = new RawToken($accessToken, $refreshToken, $expiresAt);
|
||||
$expected = [
|
||||
'leaveMe' => 'something',
|
||||
];
|
||||
$apiKeys = array_merge(
|
||||
[
|
||||
'access_token' => $accessToken,
|
||||
'refresh_token' => $refreshToken,
|
||||
'expires_at' => $expiresAt,
|
||||
],
|
||||
$expected
|
||||
);
|
||||
|
||||
$integration = new Integration();
|
||||
$integration->setApiKeys($apiKeys);
|
||||
|
||||
$this->tokenPersistence->setIntegration($integration);
|
||||
|
||||
$this->integrationsHelper->expects($this->exactly(2))
|
||||
->method('saveIntegrationConfiguration');
|
||||
$this->tokenPersistence->saveToken($token);
|
||||
|
||||
$this->assertTrue($this->tokenPersistence->hasToken());
|
||||
|
||||
$this->tokenPersistence->deleteToken();
|
||||
$this->assertFalse($this->tokenPersistence->hasToken());
|
||||
|
||||
$apiKeys = $integration->getApiKeys();
|
||||
$this->assertFalse(isset($apiKeys['access_token']));
|
||||
$this->assertFalse(isset($apiKeys['expires_in']));
|
||||
|
||||
$newToken = $this->tokenPersistence->restoreToken($token);
|
||||
$this->assertTrue($newToken->isExpired());
|
||||
$this->assertEmpty($newToken->getAccessToken());
|
||||
}
|
||||
|
||||
public function testHasToken(): void
|
||||
{
|
||||
$accessToken = 'access_token';
|
||||
$refreshToken = 'refresh_token';
|
||||
$expiresAt = 10;
|
||||
|
||||
$apiKeys = [
|
||||
'access_token' => $accessToken,
|
||||
'refresh_token' => $refreshToken,
|
||||
'expires_at' => $expiresAt,
|
||||
];
|
||||
|
||||
$integration = $this->createMock(Integration::class);
|
||||
$integration->method('getApiKeys')
|
||||
->willReturnOnConsecutiveCalls(null, $apiKeys, ['access_token' => $accessToken], null, null);
|
||||
|
||||
$this->tokenPersistence->setIntegration($integration);
|
||||
$this->assertFalse($this->tokenPersistence->hasToken());
|
||||
$token = new RawToken($accessToken, $refreshToken, $expiresAt);
|
||||
$this->tokenPersistence->saveToken($token);
|
||||
$this->assertTrue($this->tokenPersistence->hasToken());
|
||||
|
||||
$token = new RawToken();
|
||||
$this->tokenPersistence->saveToken($token);
|
||||
$this->assertFalse($this->tokenPersistence->hasToken());
|
||||
}
|
||||
|
||||
public function testRestoreTokenSetsExpirationIfKnown(): void
|
||||
{
|
||||
$accessToken = 'access_token';
|
||||
$refreshToken = 'refresh_token';
|
||||
$expiresAt = time() + 100;
|
||||
$apiKeys = [
|
||||
'access_token' => $accessToken,
|
||||
'refresh_token' => $refreshToken,
|
||||
'expires_at' => $expiresAt,
|
||||
];
|
||||
|
||||
$factory = new RawTokenFactory();
|
||||
$tokenFromApi = $factory([
|
||||
'access_token' => $accessToken,
|
||||
'refresh_token' => $refreshToken,
|
||||
'expires_at' => $expiresAt,
|
||||
]);
|
||||
|
||||
$integration = $this->createMock(Integration::class);
|
||||
$integration->expects($this->once())
|
||||
->method('getApiKeys')
|
||||
->willReturn($apiKeys);
|
||||
|
||||
$this->tokenPersistence->setIntegration($integration);
|
||||
|
||||
$newToken = $this->tokenPersistence->restoreToken($tokenFromApi);
|
||||
|
||||
$this->assertSame($apiKeys['expires_at'], $newToken->getExpiresAt());
|
||||
$this->assertFalse($newToken->isExpired());
|
||||
}
|
||||
|
||||
public function testRestoreTokenRestoresExpirationToNotExpiredWhenNotExplicitlyDefined(): void
|
||||
{
|
||||
$accessToken = 'access_token';
|
||||
$refreshToken = 'refresh_token';
|
||||
$apiKeys = [
|
||||
'access_token' => $accessToken,
|
||||
'refresh_token' => $refreshToken,
|
||||
];
|
||||
|
||||
$factory = new RawTokenFactory();
|
||||
$tokenFromApi = $factory([
|
||||
'access_token' => $accessToken,
|
||||
'refresh_token' => $refreshToken,
|
||||
]);
|
||||
|
||||
$integration = $this->createMock(Integration::class);
|
||||
$integration->expects($this->once())
|
||||
->method('getApiKeys')
|
||||
->willReturn($apiKeys);
|
||||
|
||||
$this->tokenPersistence->setIntegration($integration);
|
||||
|
||||
$newToken = $this->tokenPersistence->restoreToken($tokenFromApi);
|
||||
|
||||
$this->assertSame(0, $newToken->getExpiresAt());
|
||||
$this->assertFalse($newToken->isExpired());
|
||||
}
|
||||
|
||||
public function testRestoreTokenExpiresTokenIfApplicable(): void
|
||||
{
|
||||
$accessToken = 'access_token';
|
||||
$refreshToken = 'refresh_token';
|
||||
$expiresAt = time() - 100;
|
||||
$apiKeys = [
|
||||
'access_token' => $accessToken,
|
||||
'refresh_token' => $refreshToken,
|
||||
'expires_at' => $expiresAt,
|
||||
];
|
||||
|
||||
$factory = new RawTokenFactory();
|
||||
$tokenFromApi = $factory([
|
||||
'access_token' => $accessToken,
|
||||
'refresh_token' => $refreshToken,
|
||||
'expires_at' => $expiresAt,
|
||||
]);
|
||||
|
||||
$integration = $this->createMock(Integration::class);
|
||||
$integration->expects($this->once())
|
||||
->method('getApiKeys')
|
||||
->willReturn($apiKeys);
|
||||
|
||||
$this->tokenPersistence->setIntegration($integration);
|
||||
|
||||
$newToken = $this->tokenPersistence->restoreToken($tokenFromApi);
|
||||
|
||||
$this->assertSame($apiKeys['expires_at'], $newToken->getExpiresAt());
|
||||
$this->assertTrue($newToken->isExpired());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Command;
|
||||
|
||||
use Mautic\CoreBundle\Test\IsolatedTestTrait;
|
||||
use Mautic\IntegrationsBundle\Command\SyncCommand;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\InputOptionsDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncService\SyncServiceInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
|
||||
class SyncCommandTest extends TestCase
|
||||
{
|
||||
use IsolatedTestTrait;
|
||||
|
||||
private const INTEGRATION_NAME = 'Test';
|
||||
|
||||
/**
|
||||
* @var SyncServiceInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $syncService;
|
||||
|
||||
private CommandTester $commandTester;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->syncService = $this->createMock(SyncServiceInterface::class);
|
||||
$application = new Application();
|
||||
|
||||
$application->addCommand(new SyncCommand($this->syncService));
|
||||
|
||||
// env is global option. Must be defined.
|
||||
$application->getDefinition()->addOption(
|
||||
new InputOption(
|
||||
'--env',
|
||||
'-e',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'The environment to operate in.',
|
||||
'DEV'
|
||||
)
|
||||
);
|
||||
|
||||
$this->commandTester = new CommandTester(
|
||||
$application->find(SyncCommand::NAME)
|
||||
);
|
||||
}
|
||||
|
||||
public function testExecuteWithoutIntetrationName(): void
|
||||
{
|
||||
$this->assertSame(1, $this->commandTester->execute([]));
|
||||
}
|
||||
|
||||
#[\PHPUnit\Framework\Attributes\PreserveGlobalState(false)]
|
||||
#[\PHPUnit\Framework\Attributes\RunInSeparateProcess]
|
||||
public function testExecuteWithSomeOptions(): void
|
||||
{
|
||||
$this->syncService->expects($this->once())
|
||||
->method('processIntegrationSync')
|
||||
->with($this->callback(function (InputOptionsDAO $inputOptionsDAO) {
|
||||
$this->assertSame(self::INTEGRATION_NAME, $inputOptionsDAO->getIntegration());
|
||||
$this->assertSame(['123', '345'], $inputOptionsDAO->getMauticObjectIds()->getObjectIdsFor(Contact::NAME));
|
||||
$this->assertNull($inputOptionsDAO->getIntegrationObjectIds());
|
||||
$this->assertTrue($inputOptionsDAO->pullIsEnabled());
|
||||
$this->assertFalse($inputOptionsDAO->pushIsEnabled());
|
||||
|
||||
return true;
|
||||
}));
|
||||
|
||||
$code = $this->commandTester->execute([
|
||||
'integration' => self::INTEGRATION_NAME,
|
||||
'--disable-push' => true,
|
||||
'--mautic-object-id' => ['contact:123', 'contact:345'],
|
||||
]);
|
||||
|
||||
$this->assertSame(0, $code);
|
||||
}
|
||||
|
||||
#[\PHPUnit\Framework\Attributes\PreserveGlobalState(false)]
|
||||
#[\PHPUnit\Framework\Attributes\RunInSeparateProcess]
|
||||
public function testExecuteWhenSyncThrowsException(): void
|
||||
{
|
||||
$this->syncService->expects($this->once())
|
||||
->method('processIntegrationSync')
|
||||
->with($this->callback(function (InputOptionsDAO $inputOptionsDAO) {
|
||||
$this->assertSame(self::INTEGRATION_NAME, $inputOptionsDAO->getIntegration());
|
||||
|
||||
return true;
|
||||
}))
|
||||
->will($this->throwException(new \Exception()));
|
||||
|
||||
$code = $this->commandTester->execute(['integration' => self::INTEGRATION_NAME]);
|
||||
|
||||
$this->assertSame(1, $code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Mautic\IntegrationsBundle\DTO\Note;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class NoteTest extends TestCase
|
||||
{
|
||||
public function testGetterFunctions(): void
|
||||
{
|
||||
$note = 'This is note';
|
||||
$type = Note::TYPE_WARNING;
|
||||
|
||||
$noteObject = new Note($note, $type);
|
||||
|
||||
$this->assertSame($note, $noteObject->getNote());
|
||||
$this->assertSame($type, $noteObject->getType());
|
||||
}
|
||||
|
||||
public function testGetterFunctionsThrowsException(): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage(sprintf('Type value can be either "%s" or "%s".', Note::TYPE_INFO, Note::TYPE_WARNING));
|
||||
|
||||
$noteObject = new Note('Notes', 'randomType');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Entity;
|
||||
|
||||
use Doctrine\DBAL\Query\QueryBuilder;
|
||||
use Mautic\CoreBundle\Test\Doctrine\RepositoryConfiguratorTrait;
|
||||
use Mautic\IntegrationsBundle\Entity\FieldChange;
|
||||
use Mautic\IntegrationsBundle\Entity\FieldChangeRepository;
|
||||
use Mautic\LeadBundle\Entity\Company;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class FieldChangeRepositoryTest extends TestCase
|
||||
{
|
||||
use RepositoryConfiguratorTrait;
|
||||
|
||||
private FieldChangeRepository $repository;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->repository = $this->configureRepository(FieldChange::class);
|
||||
$this->connection->method('createQueryBuilder')->willReturnCallback(fn () => new QueryBuilder($this->connection));
|
||||
}
|
||||
|
||||
public function testWhereQueryPartForFindingChangesForSingleObject(): void
|
||||
{
|
||||
$integration = 'test';
|
||||
$objectType = 'foobar';
|
||||
$objectId = 5;
|
||||
|
||||
$this->connection->expects($this->once())
|
||||
->method('executeQuery')
|
||||
->with(
|
||||
'SELECT * FROM '.MAUTIC_TABLE_PREFIX.'sync_object_field_change_report f WHERE (f.integration = :integration) AND (f.object_type = :objectType) AND (f.object_id = :objectId) ORDER BY f.modified_at ASC',
|
||||
[
|
||||
'integration' => $integration,
|
||||
'objectType' => $objectType,
|
||||
'objectId' => $objectId,
|
||||
]
|
||||
);
|
||||
|
||||
$this->repository->findChangesForObject($integration, $objectType, $objectId);
|
||||
}
|
||||
|
||||
public function testDeleteEntitiesForObject(): void
|
||||
{
|
||||
$this->connection->expects($this->once())
|
||||
->method('executeStatement')
|
||||
->with(
|
||||
'DELETE FROM '.MAUTIC_TABLE_PREFIX.'sync_object_field_change_report WHERE (object_type = :objectType) AND (object_id = :objectId)',
|
||||
[
|
||||
'objectType' => Company::class,
|
||||
'objectId' => 123,
|
||||
]
|
||||
)->willReturn(1);
|
||||
|
||||
$this->repository->deleteEntitiesForObject(123, Company::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Entity;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\AbstractQuery;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Mautic\CoreBundle\Test\Doctrine\RepositoryConfiguratorTrait;
|
||||
use Mautic\IntegrationsBundle\Entity\ObjectMapping;
|
||||
use Mautic\IntegrationsBundle\Entity\ObjectMappingRepository;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class ObjectMappingRepositoryTest extends TestCase
|
||||
{
|
||||
use RepositoryConfiguratorTrait;
|
||||
|
||||
/**
|
||||
* @var MockObject&AbstractQuery<mixed>
|
||||
*/
|
||||
private MockObject $query;
|
||||
|
||||
private ObjectMappingRepository $repository;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->repository = $this->configureRepository(ObjectMapping::class);
|
||||
|
||||
$this->entityManager->method('createQueryBuilder')->willReturnCallback(fn () => new QueryBuilder($this->entityManager));
|
||||
|
||||
// This is terrible, but the Query class is final and AbstractQuery doesn't have some methods used.
|
||||
$this->query = $this->getMockBuilder(Query::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['setParameters', 'getSingleResult', 'getSQL', '_doExecute', 'setFirstResult', 'setMaxResults'])
|
||||
->getMock();
|
||||
|
||||
$this->query->expects($this->once())
|
||||
->method('setFirstResult')
|
||||
->willReturnSelf();
|
||||
|
||||
$this->query->expects($this->once())
|
||||
->method('setMaxResults')
|
||||
->willReturnSelf();
|
||||
}
|
||||
|
||||
public function testDeleteEntitiesForObject(): void
|
||||
{
|
||||
$this->entityManager->expects($this->once())
|
||||
->method('createQuery')
|
||||
->with('DELETE Mautic\IntegrationsBundle\Entity\ObjectMapping m WHERE m.internalObjectName = :internalObject AND m.internalObjectId = :internalObjectId')
|
||||
->willReturn($this->query);
|
||||
|
||||
$this->query->expects($this->once())
|
||||
->method('setParameters')
|
||||
->with($this->callback(function (ArrayCollection $collection) {
|
||||
/** @var Parameter $parameter */
|
||||
$parameter = $collection[0];
|
||||
$this->assertSame('internalObject', $parameter->getName());
|
||||
$this->assertSame('company', $parameter->getValue());
|
||||
|
||||
/** @var Parameter $parameter */
|
||||
$parameter = $collection[1];
|
||||
$this->assertSame('internalObjectId', $parameter->getName());
|
||||
$this->assertSame(123, $parameter->getValue());
|
||||
|
||||
return true;
|
||||
}))
|
||||
->willReturnSelf();
|
||||
|
||||
// // Stopping early to avoid Mocking hell. We have what we needed.
|
||||
$this->query->expects($this->once())
|
||||
->method('_doExecute')
|
||||
->willReturn(0);
|
||||
|
||||
$this->repository->deleteEntitiesForObject(123, 'company');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Entity;
|
||||
|
||||
use Mautic\IntegrationsBundle\Entity\ObjectMapping;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ObjectMappingTest extends TestCase
|
||||
{
|
||||
private \DateTime $dateCreated;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->dateCreated = new \DateTime();
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testConstruct(): void
|
||||
{
|
||||
$objectMapping = new ObjectMapping($this->dateCreated);
|
||||
$this->assertEquals($this->dateCreated, $objectMapping->getDateCreated());
|
||||
}
|
||||
|
||||
public function testSetAndGetIntegrationReferenceId(): void
|
||||
{
|
||||
$objectMapping = new ObjectMapping($this->dateCreated);
|
||||
$objectMapping->setIntegrationReferenceId('ref');
|
||||
$this->assertEquals('ref', $objectMapping->getIntegrationReferenceId());
|
||||
}
|
||||
|
||||
public function testLoadMetadata(): void
|
||||
{
|
||||
$metadata = new \Doctrine\ORM\Mapping\ClassMetadata(ObjectMapping::class);
|
||||
ObjectMapping::loadMetadata($metadata);
|
||||
|
||||
$expectedFieldNames = [
|
||||
'id',
|
||||
'dateCreated',
|
||||
'integration',
|
||||
'internalObjectName',
|
||||
'internalObjectId',
|
||||
'integrationObjectName',
|
||||
'integrationObjectId',
|
||||
'lastSyncDate',
|
||||
'internalStorage',
|
||||
'isDeleted',
|
||||
'integrationReferenceId',
|
||||
];
|
||||
$this->assertEquals($expectedFieldNames, $metadata->getFieldNames());
|
||||
|
||||
$referenceIdMapping = $metadata->table['indexes']['integration_reference'];
|
||||
$this->assertEquals(
|
||||
[
|
||||
'integration',
|
||||
'integration_object_name',
|
||||
'integration_reference_id',
|
||||
'integration_object_id',
|
||||
],
|
||||
$referenceIdMapping['columns'],
|
||||
'Required index is not being created.'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Event;
|
||||
|
||||
use Mautic\IntegrationsBundle\Event\CompletedSyncIterationEvent;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\MappingManualDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\InputOptionsDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\OrderResultsDAO;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class CompletedSyncIterationEventTest extends TestCase
|
||||
{
|
||||
public function testGetters(): void
|
||||
{
|
||||
$mappingManual = new MappingManualDAO('foobar');
|
||||
$orderResults = new OrderResultsDAO([], [], [], []);
|
||||
$iteration = 1;
|
||||
$inputOptions = new InputOptionsDAO(['integration' => 'foobar']);
|
||||
|
||||
$event = new CompletedSyncIterationEvent($orderResults, $iteration, $inputOptions, $mappingManual);
|
||||
|
||||
Assert::assertSame($mappingManual->getIntegration(), $event->getIntegration());
|
||||
Assert::assertSame($orderResults, $event->getOrderResults());
|
||||
Assert::assertSame($iteration, $event->getIteration());
|
||||
Assert::assertSame($inputOptions, $event->getInputOptions());
|
||||
Assert::assertSame($mappingManual, $event->getMappingManual());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Event;
|
||||
|
||||
use Mautic\IntegrationsBundle\Event\ConfigSaveEvent;
|
||||
use Mautic\PluginBundle\Entity\Integration;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ConfigSaveEventTest extends TestCase
|
||||
{
|
||||
public function testGetters(): void
|
||||
{
|
||||
$name = 'name';
|
||||
$integration = $this->createMock(Integration::class);
|
||||
$event = new ConfigSaveEvent($integration);
|
||||
|
||||
$integration->expects(self::once())
|
||||
->method('getName')
|
||||
->willReturn($name);
|
||||
|
||||
self::assertSame($integration, $event->getIntegrationConfiguration());
|
||||
self::assertSame($name, $event->getIntegration());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Event;
|
||||
|
||||
use Mautic\IntegrationsBundle\Event\KeysSaveEvent;
|
||||
use Mautic\PluginBundle\Entity\Integration;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class KeysSaveEventTest extends TestCase
|
||||
{
|
||||
public function testGetters(): void
|
||||
{
|
||||
$integration = $this->createMock(Integration::class);
|
||||
$keys = ['apikey' => 'test'];
|
||||
$integration->expects(self::once())
|
||||
->method('getApiKeys')
|
||||
->willReturn($keys);
|
||||
|
||||
$event = new KeysSaveEvent($integration, $keys);
|
||||
|
||||
self::assertSame($integration, $event->getIntegrationConfiguration());
|
||||
self::assertSame($keys, $event->getOldKeys());
|
||||
self::assertSame($keys, $event->getNewKeys());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Event;
|
||||
|
||||
use Mautic\IntegrationsBundle\Event\MauticSyncFieldsLoadEvent;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class MauticSyncFieldsLoadEventTest extends TestCase
|
||||
{
|
||||
public function testWorkflow(): void
|
||||
{
|
||||
$objectName = 'object';
|
||||
$fields = [
|
||||
'fieldKey' => 'fieldName',
|
||||
];
|
||||
|
||||
$newFieldKey = 'newFieldKey';
|
||||
$newFieldValue = 'newFieldValue';
|
||||
|
||||
$event = new MauticSyncFieldsLoadEvent($objectName, $fields);
|
||||
$this->assertSame($objectName, $event->getObjectName());
|
||||
$this->assertSame($fields, $event->getFields());
|
||||
$event->addField($newFieldKey, $newFieldValue);
|
||||
$this->assertSame(
|
||||
array_merge($fields, [$newFieldKey => $newFieldValue]),
|
||||
$event->getFields()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\EventListener;
|
||||
|
||||
use Mautic\IntegrationsBundle\Entity\ObjectMapping;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectCreateEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectFindByIdEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectFindEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectOwnerEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectRouteEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectUpdateEvent;
|
||||
use Mautic\IntegrationsBundle\EventListener\CompanyObjectSubscriber;
|
||||
use Mautic\IntegrationsBundle\IntegrationEvents;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\DateRange;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\UpdatedObjectMappingDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\ObjectChangeDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Company;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ObjectHelper\CompanyObjectHelper;
|
||||
use Mautic\LeadBundle\Entity\Company as CompanyEntity;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Routing\Router;
|
||||
|
||||
class CompanyObjectSubscriberTest extends TestCase
|
||||
{
|
||||
private CompanyObjectHelper|MockObject $companyObjectHelper;
|
||||
|
||||
private Router|MockObject $router;
|
||||
|
||||
private CompanyObjectSubscriber $subscriber;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->companyObjectHelper = $this->createMock(CompanyObjectHelper::class);
|
||||
$this->router = $this->createMock(Router::class);
|
||||
$this->subscriber = new CompanyObjectSubscriber(
|
||||
$this->companyObjectHelper,
|
||||
$this->router
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetSubscribedEvents(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
[
|
||||
IntegrationEvents::INTEGRATION_COLLECT_INTERNAL_OBJECTS => ['collectInternalObjects', 0],
|
||||
IntegrationEvents::INTEGRATION_UPDATE_INTERNAL_OBJECTS => ['updateCompanies', 0],
|
||||
IntegrationEvents::INTEGRATION_CREATE_INTERNAL_OBJECTS => ['createCompanies', 0],
|
||||
IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORDS => [
|
||||
['findCompaniesByIds', 0],
|
||||
['findCompaniesByDateRange', 0],
|
||||
['findCompaniesByFieldValues', 0],
|
||||
],
|
||||
IntegrationEvents::INTEGRATION_FIND_OWNER_IDS => ['findOwnerIdsForCompanies', 0],
|
||||
IntegrationEvents::INTEGRATION_BUILD_INTERNAL_OBJECT_ROUTE => ['buildCompanyRoute', 0],
|
||||
IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORD => ['findCompanyById', 0],
|
||||
],
|
||||
CompanyObjectSubscriber::getSubscribedEvents()
|
||||
);
|
||||
}
|
||||
|
||||
public function testCollectInternalObjects(): void
|
||||
{
|
||||
$event = new InternalObjectEvent();
|
||||
|
||||
$this->subscriber->collectInternalObjects($event);
|
||||
|
||||
$this->assertCount(1, $event->getObjects());
|
||||
$this->assertInstanceOf(
|
||||
Company::class,
|
||||
$event->getObjects()[0]
|
||||
);
|
||||
}
|
||||
|
||||
public function testUpdateCompaniesWithWrongObject(): void
|
||||
{
|
||||
$event = new InternalObjectUpdateEvent(new Contact(), [], []);
|
||||
|
||||
$this->companyObjectHelper->expects($this->never())
|
||||
->method('update');
|
||||
|
||||
$this->subscriber->updateCompanies($event);
|
||||
|
||||
$this->assertSame([], $event->getUpdatedObjectMappings());
|
||||
}
|
||||
|
||||
public function testUpdateCompaniesWithRightObject(): void
|
||||
{
|
||||
$objectChangeDAO = new ObjectChangeDAO('integration', 'object', 'objectId', 'mappedObject', 'mappedId');
|
||||
|
||||
$event = new InternalObjectUpdateEvent(new Company(), [123], [$objectChangeDAO]);
|
||||
|
||||
$objectMapping = $this->createMock(UpdatedObjectMappingDAO::class);
|
||||
$this->companyObjectHelper->expects($this->once())
|
||||
->method('update')
|
||||
->with([123], [$objectChangeDAO])
|
||||
->willReturn([$objectMapping]);
|
||||
|
||||
$this->subscriber->updateCompanies($event);
|
||||
|
||||
$this->assertSame([$objectMapping], $event->getUpdatedObjectMappings());
|
||||
}
|
||||
|
||||
public function testCreateCompaniesWithWrongObject(): void
|
||||
{
|
||||
$event = new InternalObjectCreateEvent(new Contact(), []);
|
||||
|
||||
$this->companyObjectHelper->expects($this->never())
|
||||
->method('create');
|
||||
|
||||
$this->subscriber->createCompanies($event);
|
||||
|
||||
$this->assertSame([], $event->getObjectMappings());
|
||||
}
|
||||
|
||||
public function testCreateCompaniesWithRightObject(): void
|
||||
{
|
||||
$event = new InternalObjectCreateEvent(new Company(), [['somefield' => 'somevalue']]);
|
||||
|
||||
$objectMapping = $this->createMock(ObjectMapping::class);
|
||||
$this->companyObjectHelper->expects($this->once())
|
||||
->method('create')
|
||||
->with([['somefield' => 'somevalue']])
|
||||
->willReturn([$objectMapping]);
|
||||
|
||||
$this->subscriber->createCompanies($event);
|
||||
|
||||
$this->assertSame([$objectMapping], $event->getObjectMappings());
|
||||
}
|
||||
|
||||
public function testFindCompaniesByIdsWithWrongObject(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Contact());
|
||||
|
||||
$this->companyObjectHelper->expects($this->never())
|
||||
->method('findObjectsByIds');
|
||||
|
||||
$this->subscriber->findCompaniesByIds($event);
|
||||
|
||||
$this->assertSame([], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindCompaniesByIdsWithNoIds(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Company());
|
||||
|
||||
$this->companyObjectHelper->expects($this->never())
|
||||
->method('findObjectsByIds');
|
||||
|
||||
$this->subscriber->findCompaniesByIds($event);
|
||||
|
||||
$this->assertSame([], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindCompaniesByIdsWithRightObject(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Company());
|
||||
|
||||
$event->setIds([123]);
|
||||
|
||||
$this->companyObjectHelper->expects($this->once())
|
||||
->method('findObjectsByIds')
|
||||
->with([123])
|
||||
->willReturn([['object_1']]);
|
||||
|
||||
$this->subscriber->findCompaniesByIds($event);
|
||||
|
||||
$this->assertSame([['object_1']], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindCompaniesByDateRangeWithWrongObject(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Contact());
|
||||
|
||||
$this->companyObjectHelper->expects($this->never())
|
||||
->method('findObjectsBetweenDates');
|
||||
|
||||
$this->subscriber->findCompaniesByDateRange($event);
|
||||
|
||||
$this->assertSame([], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindCompaniesByDateRangeWithNoDateRange(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Company());
|
||||
|
||||
$this->companyObjectHelper->expects($this->never())
|
||||
->method('findObjectsBetweenDates');
|
||||
|
||||
$this->subscriber->findCompaniesByDateRange($event);
|
||||
|
||||
$this->assertSame([], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindCompaniesByDateRangeWithRightObject(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Company());
|
||||
$fromDate = new \DateTimeImmutable();
|
||||
$toDate = new \DateTimeImmutable();
|
||||
$dateRange = new DateRange($fromDate, $toDate);
|
||||
$start = 0;
|
||||
$limit = 10;
|
||||
|
||||
$event->setDateRange($dateRange);
|
||||
$event->setStart($start);
|
||||
$event->setLimit($limit);
|
||||
|
||||
$this->companyObjectHelper->expects($this->once())
|
||||
->method('findObjectsBetweenDates')
|
||||
->with(
|
||||
$fromDate,
|
||||
$toDate,
|
||||
$start,
|
||||
$limit
|
||||
)
|
||||
->willReturn([['object_1']]);
|
||||
|
||||
$this->subscriber->findCompaniesByDateRange($event);
|
||||
|
||||
$this->assertSame([['object_1']], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindCompaniesByFieldValuesWithWrongObject(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Contact());
|
||||
|
||||
$this->companyObjectHelper->expects($this->never())
|
||||
->method('findObjectsByFieldValues');
|
||||
|
||||
$this->subscriber->findCompaniesByFieldValues($event);
|
||||
|
||||
$this->assertSame([], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindCompaniesByFieldValuesWithNoIds(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Company());
|
||||
|
||||
$this->companyObjectHelper->expects($this->never())
|
||||
->method('findObjectsByFieldValues');
|
||||
|
||||
$this->subscriber->findCompaniesByFieldValues($event);
|
||||
|
||||
$this->assertSame([], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindCompaniesByFieldValuesWithRightObject(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Company());
|
||||
|
||||
$event->setFieldValues(['field_a' => 123]);
|
||||
|
||||
$this->companyObjectHelper->expects($this->once())
|
||||
->method('findObjectsByFieldValues')
|
||||
->with(['field_a' => 123])
|
||||
->willReturn([['object_1']]);
|
||||
|
||||
$this->subscriber->findCompaniesByFieldValues($event);
|
||||
|
||||
$this->assertSame([['object_1']], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindOwnerIdsForCompaniesWithWrongObject(): void
|
||||
{
|
||||
$event = new InternalObjectOwnerEvent(new Contact(), []);
|
||||
|
||||
$this->companyObjectHelper->expects($this->never())
|
||||
->method('findOwnerIds');
|
||||
|
||||
$this->subscriber->findOwnerIdsForCompanies($event);
|
||||
|
||||
$this->assertSame([], $event->getOwners());
|
||||
}
|
||||
|
||||
public function testFindOwnerIdsForCompaniesWithRightObject(): void
|
||||
{
|
||||
$event = new InternalObjectOwnerEvent(new Company(), [567]);
|
||||
|
||||
$this->companyObjectHelper->expects($this->once())
|
||||
->method('findOwnerIds')
|
||||
->with([567])
|
||||
->willReturn([['object_1']]);
|
||||
|
||||
$this->subscriber->findOwnerIdsForCompanies($event);
|
||||
|
||||
$this->assertSame([['object_1']], $event->getOwners());
|
||||
}
|
||||
|
||||
public function testBuildCompanyRouteWithWrongObject(): void
|
||||
{
|
||||
$event = new InternalObjectRouteEvent(new Contact(), 123);
|
||||
|
||||
$this->router->expects($this->never())
|
||||
->method('generate');
|
||||
|
||||
$this->subscriber->buildCompanyRoute($event);
|
||||
|
||||
$this->assertNull($event->getRoute());
|
||||
}
|
||||
|
||||
public function testBuildCompanyRouteWithRightObject(): void
|
||||
{
|
||||
$event = new InternalObjectRouteEvent(new Company(), 123);
|
||||
|
||||
$this->router->expects($this->once())
|
||||
->method('generate')
|
||||
->with(
|
||||
'mautic_company_action',
|
||||
[
|
||||
'objectAction' => 'view',
|
||||
'objectId' => 123,
|
||||
]
|
||||
)
|
||||
->willReturn('some/route');
|
||||
|
||||
$this->subscriber->buildCompanyRoute($event);
|
||||
|
||||
$this->assertSame('some/route', $event->getRoute());
|
||||
}
|
||||
|
||||
public function testFindCompanyById(): void
|
||||
{
|
||||
$event = new InternalObjectFindByIdEvent(new Company());
|
||||
$event->setId(1);
|
||||
$companyObj = $this->createMock(CompanyEntity::class);
|
||||
$this->companyObjectHelper->expects($this->once())
|
||||
->method('findObjectById')
|
||||
->with(1)
|
||||
->willReturn($companyObj);
|
||||
$this->subscriber->findCompanyById($event);
|
||||
self::assertSame($companyObj, $event->getEntity());
|
||||
}
|
||||
|
||||
public function testFindCompanyByIdWithNoIdSet(): void
|
||||
{
|
||||
$event = new InternalObjectFindByIdEvent(new Company());
|
||||
$this->companyObjectHelper->expects($this->never())
|
||||
->method('findObjectById');
|
||||
$this->subscriber->findCompanyById($event);
|
||||
self::assertNull($event->getEntity());
|
||||
}
|
||||
|
||||
public function testFindCompanyByIdWithNoCompany(): void
|
||||
{
|
||||
$event = new InternalObjectFindByIdEvent(new Company());
|
||||
$event->setId(1);
|
||||
$this->companyObjectHelper->expects($this->once())
|
||||
->method('findObjectById')
|
||||
->with(1)
|
||||
->willReturn(null);
|
||||
$this->subscriber->findCompanyById($event);
|
||||
self::assertNull($event->getEntity());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,375 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\EventListener;
|
||||
|
||||
use Mautic\IntegrationsBundle\Entity\ObjectMapping;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectCreateEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectFindByIdEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectFindEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectOwnerEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectRouteEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectUpdateEvent;
|
||||
use Mautic\IntegrationsBundle\EventListener\ContactObjectSubscriber;
|
||||
use Mautic\IntegrationsBundle\IntegrationEvents;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\DateRange;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\UpdatedObjectMappingDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\ObjectChangeDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Company;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ObjectHelper\ContactObjectHelper;
|
||||
use Mautic\LeadBundle\Entity\Lead;
|
||||
use Mautic\LeadBundle\Exception\ImportFailedException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Routing\Router;
|
||||
|
||||
class ContactObjectSubscriberTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var ContactObjectHelper|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $contactObjectHelper;
|
||||
|
||||
/**
|
||||
* @var Router|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $router;
|
||||
|
||||
private ContactObjectSubscriber $subscriber;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->contactObjectHelper = $this->createMock(ContactObjectHelper::class);
|
||||
$this->router = $this->createMock(Router::class);
|
||||
$this->subscriber = new ContactObjectSubscriber(
|
||||
$this->contactObjectHelper,
|
||||
$this->router
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetSubscribedEvents(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
[
|
||||
IntegrationEvents::INTEGRATION_COLLECT_INTERNAL_OBJECTS => ['collectInternalObjects', 0],
|
||||
IntegrationEvents::INTEGRATION_UPDATE_INTERNAL_OBJECTS => ['updateContacts', 0],
|
||||
IntegrationEvents::INTEGRATION_CREATE_INTERNAL_OBJECTS => ['createContacts', 0],
|
||||
IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORDS => [
|
||||
['findContactsByIds', 0],
|
||||
['findContactsByDateRange', 0],
|
||||
['findContactsByFieldValues', 0],
|
||||
],
|
||||
IntegrationEvents::INTEGRATION_FIND_OWNER_IDS => ['findOwnerIdsForContacts', 0],
|
||||
IntegrationEvents::INTEGRATION_BUILD_INTERNAL_OBJECT_ROUTE => ['buildContactRoute', 0],
|
||||
IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORD => ['findContactById', 0],
|
||||
],
|
||||
ContactObjectSubscriber::getSubscribedEvents()
|
||||
);
|
||||
}
|
||||
|
||||
public function testCollectInternalObjects(): void
|
||||
{
|
||||
$event = new InternalObjectEvent();
|
||||
|
||||
$this->subscriber->collectInternalObjects($event);
|
||||
|
||||
$this->assertCount(1, $event->getObjects());
|
||||
$this->assertInstanceOf(
|
||||
Contact::class,
|
||||
$event->getObjects()[0]
|
||||
);
|
||||
}
|
||||
|
||||
public function testUpdateContactsWithWrongObject(): void
|
||||
{
|
||||
$event = new InternalObjectUpdateEvent(new Company(), [], []);
|
||||
|
||||
$this->contactObjectHelper->expects($this->never())
|
||||
->method('update');
|
||||
|
||||
$this->subscriber->updateContacts($event);
|
||||
|
||||
$this->assertSame([], $event->getUpdatedObjectMappings());
|
||||
}
|
||||
|
||||
public function testUpdateContactsWithRightObject(): void
|
||||
{
|
||||
$objectChangeDAO = new ObjectChangeDAO('integration', 'object', 'objectId', 'mappedObject', 'mappedId');
|
||||
|
||||
$event = new InternalObjectUpdateEvent(new Contact(), [123], [$objectChangeDAO]);
|
||||
|
||||
$objectMapping = $this->createMock(UpdatedObjectMappingDAO::class);
|
||||
$this->contactObjectHelper->expects($this->once())
|
||||
->method('update')
|
||||
->with([123], [$objectChangeDAO])
|
||||
->willReturn([$objectMapping]);
|
||||
|
||||
$this->subscriber->updateContacts($event);
|
||||
|
||||
$this->assertSame([$objectMapping], $event->getUpdatedObjectMappings());
|
||||
}
|
||||
|
||||
public function testCreateContactsWithWrongObject(): void
|
||||
{
|
||||
$event = new InternalObjectCreateEvent(new Company(), []);
|
||||
|
||||
$this->contactObjectHelper->expects($this->never())
|
||||
->method('create');
|
||||
|
||||
$this->subscriber->createContacts($event);
|
||||
|
||||
$this->assertSame([], $event->getObjectMappings());
|
||||
}
|
||||
|
||||
public function testCreateContactsWithRightObject(): void
|
||||
{
|
||||
$event = new InternalObjectCreateEvent(new Contact(), [['somefield' => 'somevalue']]);
|
||||
|
||||
$objectMapping = $this->createMock(ObjectMapping::class);
|
||||
$this->contactObjectHelper->expects($this->once())
|
||||
->method('create')
|
||||
->with([['somefield' => 'somevalue']])
|
||||
->willReturn([$objectMapping]);
|
||||
|
||||
$this->subscriber->createContacts($event);
|
||||
|
||||
$this->assertSame([$objectMapping], $event->getObjectMappings());
|
||||
}
|
||||
|
||||
public function testFindContactsByIdsWithWrongObject(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Company());
|
||||
|
||||
$this->contactObjectHelper->expects($this->never())
|
||||
->method('findObjectsByIds');
|
||||
|
||||
$this->subscriber->findContactsByIds($event);
|
||||
|
||||
$this->assertSame([], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindContactsByIdsWithNoIds(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Contact());
|
||||
|
||||
$this->contactObjectHelper->expects($this->never())
|
||||
->method('findObjectsByIds');
|
||||
|
||||
$this->subscriber->findContactsByIds($event);
|
||||
|
||||
$this->assertSame([], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindContactsByIdsWithRightObject(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Contact());
|
||||
|
||||
$event->setIds([123]);
|
||||
|
||||
$this->contactObjectHelper->expects($this->once())
|
||||
->method('findObjectsByIds')
|
||||
->with([123])
|
||||
->willReturn([['object_1']]);
|
||||
|
||||
$this->subscriber->findContactsByIds($event);
|
||||
|
||||
$this->assertSame([['object_1']], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindContactsByDateRangeWithWrongObject(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Company());
|
||||
|
||||
$this->contactObjectHelper->expects($this->never())
|
||||
->method('findObjectsBetweenDates');
|
||||
|
||||
$this->subscriber->findContactsByDateRange($event);
|
||||
|
||||
$this->assertSame([], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindContactsByDateRangeWithNoDateRange(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Contact());
|
||||
|
||||
$this->contactObjectHelper->expects($this->never())
|
||||
->method('findObjectsBetweenDates');
|
||||
|
||||
$this->subscriber->findContactsByDateRange($event);
|
||||
|
||||
$this->assertSame([], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindContactsByDateRangeWithRightObject(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Contact());
|
||||
$fromDate = new \DateTimeImmutable();
|
||||
$toDate = new \DateTimeImmutable();
|
||||
$dateRange = new DateRange($fromDate, $toDate);
|
||||
$start = 0;
|
||||
$limit = 10;
|
||||
|
||||
$event->setDateRange($dateRange);
|
||||
$event->setStart($start);
|
||||
$event->setLimit($limit);
|
||||
|
||||
$this->contactObjectHelper->expects($this->once())
|
||||
->method('findObjectsBetweenDates')
|
||||
->with(
|
||||
$fromDate,
|
||||
$toDate,
|
||||
$start,
|
||||
$limit
|
||||
)
|
||||
->willReturn([['object_1']]);
|
||||
|
||||
$this->subscriber->findContactsByDateRange($event);
|
||||
|
||||
$this->assertSame([['object_1']], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindContactsByFieldValuesWithWrongObject(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Company());
|
||||
|
||||
$this->contactObjectHelper->expects($this->never())
|
||||
->method('findObjectsByFieldValues');
|
||||
|
||||
$this->subscriber->findContactsByFieldValues($event);
|
||||
|
||||
$this->assertSame([], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindContactsByFieldValuesWithNoIds(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Contact());
|
||||
|
||||
$this->contactObjectHelper->expects($this->never())
|
||||
->method('findObjectsByFieldValues');
|
||||
|
||||
$this->subscriber->findContactsByFieldValues($event);
|
||||
|
||||
$this->assertSame([], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindContactsByFieldValuesWithRightObject(): void
|
||||
{
|
||||
$event = new InternalObjectFindEvent(new Contact());
|
||||
|
||||
$event->setFieldValues(['field_a' => 123]);
|
||||
|
||||
$this->contactObjectHelper->expects($this->once())
|
||||
->method('findObjectsByFieldValues')
|
||||
->with(['field_a' => 123])
|
||||
->willReturn([['object_1']]);
|
||||
|
||||
$this->subscriber->findContactsByFieldValues($event);
|
||||
|
||||
$this->assertSame([['object_1']], $event->getFoundObjects());
|
||||
}
|
||||
|
||||
public function testFindOwnerIdsForContactsWithWrongObject(): void
|
||||
{
|
||||
$event = new InternalObjectOwnerEvent(new Company(), []);
|
||||
|
||||
$this->contactObjectHelper->expects($this->never())
|
||||
->method('findOwnerIds');
|
||||
|
||||
$this->subscriber->findOwnerIdsForContacts($event);
|
||||
|
||||
$this->assertSame([], $event->getOwners());
|
||||
}
|
||||
|
||||
public function testFindOwnerIdsForContactsWithRightObject(): void
|
||||
{
|
||||
$event = new InternalObjectOwnerEvent(new Contact(), [567]);
|
||||
|
||||
$this->contactObjectHelper->expects($this->once())
|
||||
->method('findOwnerIds')
|
||||
->with([567])
|
||||
->willReturn([['object_1']]);
|
||||
|
||||
$this->subscriber->findOwnerIdsForContacts($event);
|
||||
|
||||
$this->assertSame([['object_1']], $event->getOwners());
|
||||
}
|
||||
|
||||
public function testBuildContactRouteWithWrongObject(): void
|
||||
{
|
||||
$event = new InternalObjectRouteEvent(new Company(), 123);
|
||||
|
||||
$this->router->expects($this->never())
|
||||
->method('generate');
|
||||
|
||||
$this->subscriber->buildContactRoute($event);
|
||||
|
||||
$this->assertNull($event->getRoute());
|
||||
}
|
||||
|
||||
public function testBuildContactRouteWithRightObject(): void
|
||||
{
|
||||
$event = new InternalObjectRouteEvent(new Contact(), 123);
|
||||
|
||||
$this->router->expects($this->once())
|
||||
->method('generate')
|
||||
->with(
|
||||
'mautic_contact_action',
|
||||
[
|
||||
'objectAction' => 'view',
|
||||
'objectId' => 123,
|
||||
]
|
||||
)
|
||||
->willReturn('some/route');
|
||||
|
||||
$this->subscriber->buildContactRoute($event);
|
||||
|
||||
$this->assertSame('some/route', $event->getRoute());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ImportFailedException
|
||||
*/
|
||||
public function testFindContactById(): void
|
||||
{
|
||||
$event = new InternalObjectFindByIdEvent(new Contact());
|
||||
$event->setId(1);
|
||||
$contactObj = $this->createMock(Lead::class);
|
||||
$this->contactObjectHelper->expects($this->once())
|
||||
->method('findObjectById')
|
||||
->with(1)
|
||||
->willReturn($contactObj);
|
||||
$this->subscriber->findContactById($event);
|
||||
self::assertSame($contactObj, $event->getEntity());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ImportFailedException
|
||||
*/
|
||||
public function testFindContactByIdWithNoIdSet(): void
|
||||
{
|
||||
$event = new InternalObjectFindByIdEvent(new Contact());
|
||||
$this->contactObjectHelper->expects($this->never())
|
||||
->method('findObjectById');
|
||||
$this->subscriber->findContactById($event);
|
||||
self::assertNull($event->getEntity());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ImportFailedException
|
||||
*/
|
||||
public function testFindContactByIdWithNoContact(): void
|
||||
{
|
||||
$event = new InternalObjectFindByIdEvent(new Contact());
|
||||
$event->setId(1);
|
||||
$this->contactObjectHelper->expects($this->once())
|
||||
->method('findObjectById')
|
||||
->with(1)
|
||||
->willReturn(null);
|
||||
$this->subscriber->findContactById($event);
|
||||
self::assertNull($event->getEntity());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,512 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\EventListener;
|
||||
|
||||
use Mautic\IntegrationsBundle\Entity\FieldChangeRepository;
|
||||
use Mautic\IntegrationsBundle\Entity\ObjectMappingRepository;
|
||||
use Mautic\IntegrationsBundle\EventListener\LeadSubscriber;
|
||||
use Mautic\IntegrationsBundle\Exception\IntegrationNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Helper\SyncIntegrationsHelper;
|
||||
use Mautic\IntegrationsBundle\IntegrationEvents;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\EncodedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\MauticSyncDataExchange;
|
||||
use Mautic\IntegrationsBundle\Sync\VariableExpresser\VariableExpresserHelperInterface;
|
||||
use Mautic\LeadBundle\Entity\Company;
|
||||
use Mautic\LeadBundle\Entity\Lead;
|
||||
use Mautic\LeadBundle\Event\CompanyEvent;
|
||||
use Mautic\LeadBundle\Event\LeadEvent;
|
||||
use Mautic\LeadBundle\LeadEvents;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class LeadSubscriberTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var MockObject|FieldChangeRepository
|
||||
*/
|
||||
private MockObject $fieldChangeRepository;
|
||||
|
||||
/**
|
||||
* @var MockObject|ObjectMappingRepository
|
||||
*/
|
||||
private MockObject $objectMappingRepository;
|
||||
|
||||
/**
|
||||
* @var MockObject|VariableExpresserHelperInterface
|
||||
*/
|
||||
private MockObject $variableExpresserHelper;
|
||||
|
||||
/**
|
||||
* @var MockObject|SyncIntegrationsHelper
|
||||
*/
|
||||
private MockObject $syncIntegrationsHelper;
|
||||
|
||||
/**
|
||||
* @var MockObject|CompanyEvent
|
||||
*/
|
||||
private MockObject $companyEvent;
|
||||
|
||||
private LeadSubscriber $subscriber;
|
||||
|
||||
/**
|
||||
* @var MockObject|EventDispatcherInterface
|
||||
*/
|
||||
private MockObject $eventDispatcherInterfaceMock;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->fieldChangeRepository = $this->createMock(FieldChangeRepository::class);
|
||||
$this->objectMappingRepository = $this->createMock(ObjectMappingRepository::class);
|
||||
$this->variableExpresserHelper = $this->createMock(VariableExpresserHelperInterface::class);
|
||||
$this->syncIntegrationsHelper = $this->createMock(SyncIntegrationsHelper::class);
|
||||
$this->companyEvent = $this->createMock(CompanyEvent::class);
|
||||
$this->eventDispatcherInterfaceMock = $this->createMock(EventDispatcherInterface::class);
|
||||
$this->subscriber = new LeadSubscriber(
|
||||
$this->fieldChangeRepository,
|
||||
$this->objectMappingRepository,
|
||||
$this->variableExpresserHelper,
|
||||
$this->syncIntegrationsHelper,
|
||||
$this->eventDispatcherInterfaceMock
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetSubscribedEvents(): void
|
||||
{
|
||||
Assert::assertEquals(
|
||||
[
|
||||
LeadEvents::LEAD_POST_SAVE => ['onLeadPostSave', 0],
|
||||
LeadEvents::LEAD_POST_DELETE => ['onLeadPostDelete', 255],
|
||||
LeadEvents::COMPANY_POST_SAVE => ['onCompanyPostSave', 0],
|
||||
LeadEvents::COMPANY_POST_DELETE => ['onCompanyPostDelete', 255],
|
||||
LeadEvents::LEAD_COMPANY_CHANGE => ['onLeadCompanyChange', 128],
|
||||
],
|
||||
LeadSubscriber::getSubscribedEvents()
|
||||
);
|
||||
}
|
||||
|
||||
public function testOnLeadPostSaveAnonymousLead(): void
|
||||
{
|
||||
$lead = $this->createMock(Lead::class);
|
||||
$lead->expects($this->once())
|
||||
->method('isAnonymous')
|
||||
->willReturn(true);
|
||||
$lead->expects($this->never())
|
||||
->method('getChanges');
|
||||
|
||||
$this->syncIntegrationsHelper->expects($this->never())
|
||||
->method('hasObjectSyncEnabled');
|
||||
|
||||
$this->subscriber->onLeadPostSave(new LeadEvent($lead));
|
||||
}
|
||||
|
||||
public function testOnLeadPostSaveLeadObjectSyncNotEnabled(): void
|
||||
{
|
||||
$lead = $this->createMock(Lead::class);
|
||||
$lead->expects($this->once())
|
||||
->method('isAnonymous')
|
||||
->willReturn(false);
|
||||
$lead->expects($this->never())
|
||||
->method('getChanges');
|
||||
|
||||
$this->syncIntegrationsHelper->expects($this->once())
|
||||
->method('hasObjectSyncEnabled')
|
||||
->with(Contact::NAME)
|
||||
->willReturn(false);
|
||||
|
||||
$this->subscriber->onLeadPostSave(new LeadEvent($lead));
|
||||
}
|
||||
|
||||
public function testOnLeadPostSaveNoAction(): void
|
||||
{
|
||||
$fieldChanges = [];
|
||||
|
||||
$lead = $this->createMock(Lead::class);
|
||||
$lead->expects($this->once())
|
||||
->method('isAnonymous')
|
||||
->willReturn(false);
|
||||
$lead->expects($this->once())
|
||||
->method('getChanges')
|
||||
->willReturn($fieldChanges);
|
||||
|
||||
$this->syncIntegrationsHelper->expects($this->once())
|
||||
->method('hasObjectSyncEnabled')
|
||||
->with(Contact::NAME)
|
||||
->willReturn(true);
|
||||
|
||||
$this->subscriber->onLeadPostSave(new LeadEvent($lead));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IntegrationNotFoundException
|
||||
* @throws ObjectNotFoundException
|
||||
*/
|
||||
public function testOnLeadPostSaveRecordChanges(): void
|
||||
{
|
||||
$fieldName = 'fieldName';
|
||||
$oldValue = 'oldValue';
|
||||
$newValue = 'newValue';
|
||||
$fieldChanges = [
|
||||
'fields' => [
|
||||
$fieldName => [
|
||||
$oldValue,
|
||||
$newValue,
|
||||
],
|
||||
],
|
||||
];
|
||||
$objectId = 1;
|
||||
|
||||
$lead = $this->createLeadMock($fieldChanges, $objectId);
|
||||
|
||||
$this->syncIntegrationsHelper->expects($this->once())
|
||||
->method('hasObjectSyncEnabled')
|
||||
->with(Contact::NAME)
|
||||
->willReturn(true);
|
||||
|
||||
$this->handleRecordFieldChanges($fieldChanges['fields'], $objectId, Lead::class);
|
||||
|
||||
$this->eventDispatcherInterfaceMock
|
||||
->method('hasListeners')
|
||||
->with(IntegrationEvents::INTEGRATION_BEFORE_CONTACT_FIELD_CHANGES)
|
||||
->willReturn(true);
|
||||
|
||||
$this->subscriber->onLeadPostSave(new LeadEvent($lead));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IntegrationNotFoundException
|
||||
* @throws ObjectNotFoundException
|
||||
*/
|
||||
public function testOnLeadPostSaveRecordChangesWithOwnerChange(): void
|
||||
{
|
||||
$newOwnerId = 5;
|
||||
$fieldChanges = [
|
||||
'owner' => [
|
||||
2,
|
||||
$newOwnerId,
|
||||
],
|
||||
];
|
||||
$objectId = 1;
|
||||
|
||||
$lead = $this->createLeadMock($fieldChanges, $objectId);
|
||||
|
||||
$this->syncIntegrationsHelper->expects($this->once())
|
||||
->method('hasObjectSyncEnabled')
|
||||
->with(Contact::NAME)
|
||||
->willReturn(true);
|
||||
|
||||
$fieldChanges['fields']['owner_id'] = $fieldChanges['owner'];
|
||||
|
||||
$this->handleRecordFieldChanges($fieldChanges['fields'], $objectId, Lead::class);
|
||||
|
||||
$this->eventDispatcherInterfaceMock
|
||||
->method('hasListeners')
|
||||
->with(IntegrationEvents::INTEGRATION_BEFORE_CONTACT_FIELD_CHANGES)
|
||||
->willReturn(true);
|
||||
|
||||
$this->subscriber->onLeadPostSave(new LeadEvent($lead));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IntegrationNotFoundException
|
||||
* @throws ObjectNotFoundException
|
||||
*/
|
||||
public function testOnLeadPostSaveRecordChangesWithPointChange(): void
|
||||
{
|
||||
$newPointCount = 5;
|
||||
$fieldChanges = [
|
||||
'points' => [
|
||||
2,
|
||||
$newPointCount,
|
||||
],
|
||||
];
|
||||
$objectId = 1;
|
||||
|
||||
$lead = $this->createLeadMock($fieldChanges, $objectId);
|
||||
|
||||
$this->syncIntegrationsHelper->expects($this->once())
|
||||
->method('hasObjectSyncEnabled')
|
||||
->with(Contact::NAME)
|
||||
->willReturn(true);
|
||||
|
||||
$fieldChanges['fields']['points'] = $fieldChanges['points'];
|
||||
|
||||
$this->handleRecordFieldChanges($fieldChanges['fields'], $objectId, Lead::class);
|
||||
|
||||
$this->eventDispatcherInterfaceMock
|
||||
->method('hasListeners')
|
||||
->with(IntegrationEvents::INTEGRATION_BEFORE_CONTACT_FIELD_CHANGES)
|
||||
->willReturn(true);
|
||||
|
||||
$this->subscriber->onLeadPostSave(new LeadEvent($lead));
|
||||
}
|
||||
|
||||
public function testOnLeadPostDelete(): void
|
||||
{
|
||||
$deletedId = 5;
|
||||
$lead = new Lead();
|
||||
$lead->deletedId = $deletedId;
|
||||
$lead->setEmail('john@doe.email');
|
||||
|
||||
$this->fieldChangeRepository->expects($this->once())
|
||||
->method('deleteEntitiesForObject')
|
||||
->with((int) $deletedId, Lead::class);
|
||||
|
||||
$this->objectMappingRepository->expects($this->once())
|
||||
->method('deleteEntitiesForObject')
|
||||
->with((int) $deletedId, MauticSyncDataExchange::OBJECT_CONTACT);
|
||||
|
||||
$this->subscriber->onLeadPostDelete(new LeadEvent($lead));
|
||||
}
|
||||
|
||||
public function testOnLeadPostDeleteForAnonymousLeads(): void
|
||||
{
|
||||
$deletedId = 5;
|
||||
$lead = new Lead();
|
||||
$lead->deletedId = $deletedId;
|
||||
|
||||
$this->fieldChangeRepository->expects($this->never())
|
||||
->method('deleteEntitiesForObject');
|
||||
|
||||
$this->objectMappingRepository->expects($this->never())
|
||||
->method('deleteEntitiesForObject');
|
||||
|
||||
$this->subscriber->onLeadPostDelete(new LeadEvent($lead));
|
||||
}
|
||||
|
||||
public function testOnCompanyPostSaveSyncNotEnabled(): void
|
||||
{
|
||||
$this->syncIntegrationsHelper->expects($this->once())
|
||||
->method('hasObjectSyncEnabled')
|
||||
->with(MauticSyncDataExchange::OBJECT_COMPANY)
|
||||
->willReturn(false);
|
||||
|
||||
$this->companyEvent->expects($this->never())
|
||||
->method('getCompany');
|
||||
|
||||
$this->subscriber->onCompanyPostSave($this->companyEvent);
|
||||
}
|
||||
|
||||
public function testOnCompanyPostSaveSyncNoAction(): void
|
||||
{
|
||||
$fieldChanges = [];
|
||||
|
||||
$company = $this->createCompanyMock($fieldChanges, 1);
|
||||
|
||||
$this->companyEvent->expects($this->once())
|
||||
->method('getCompany')
|
||||
->willReturn($company);
|
||||
|
||||
$this->syncIntegrationsHelper->expects($this->once())
|
||||
->method('hasObjectSyncEnabled')
|
||||
->with(MauticSyncDataExchange::OBJECT_COMPANY)
|
||||
->willReturn(true);
|
||||
|
||||
$this->subscriber->onCompanyPostSave($this->companyEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IntegrationNotFoundException
|
||||
* @throws ObjectNotFoundException
|
||||
*/
|
||||
public function testOnCompanyPostSaveSyncRecordChanges(): void
|
||||
{
|
||||
$fieldName = 'fieldName';
|
||||
$oldValue = 'oldValue';
|
||||
$newValue = 'newValue';
|
||||
$fieldChanges = [
|
||||
'fields' => [
|
||||
$fieldName => [
|
||||
$oldValue,
|
||||
$newValue,
|
||||
],
|
||||
],
|
||||
];
|
||||
$objectId = 1;
|
||||
|
||||
$company = $this->createCompanyMock($fieldChanges, $objectId);
|
||||
|
||||
$this->companyEvent->expects($this->once())
|
||||
->method('getCompany')
|
||||
->willReturn($company);
|
||||
|
||||
$this->syncIntegrationsHelper->expects($this->once())
|
||||
->method('hasObjectSyncEnabled')
|
||||
->with(MauticSyncDataExchange::OBJECT_COMPANY)
|
||||
->willReturn(true);
|
||||
|
||||
$this->handleRecordFieldChanges($fieldChanges['fields'], $objectId, Company::class);
|
||||
|
||||
$this->eventDispatcherInterfaceMock
|
||||
->method('hasListeners')
|
||||
->with(IntegrationEvents::INTEGRATION_BEFORE_COMPANY_FIELD_CHANGES)
|
||||
->willReturn(true);
|
||||
|
||||
$this->subscriber->onCompanyPostSave($this->companyEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IntegrationNotFoundException
|
||||
* @throws ObjectNotFoundException
|
||||
*/
|
||||
public function testOnCompanyPostSaveRecordChangesWithOwnerChange(): void
|
||||
{
|
||||
$newOwnerId = 5;
|
||||
$fieldChanges = [
|
||||
'owner' => [
|
||||
2,
|
||||
$newOwnerId,
|
||||
],
|
||||
];
|
||||
$objectId = 1;
|
||||
|
||||
$company = $this->createCompanyMock($fieldChanges, $objectId);
|
||||
|
||||
$this->companyEvent->expects($this->once())
|
||||
->method('getCompany')
|
||||
->willReturn($company);
|
||||
|
||||
$this->syncIntegrationsHelper->expects($this->once())
|
||||
->method('hasObjectSyncEnabled')
|
||||
->with(MauticSyncDataExchange::OBJECT_COMPANY)
|
||||
->willReturn(true);
|
||||
|
||||
$fieldChanges['fields']['owner_id'] = $fieldChanges['owner'];
|
||||
|
||||
$this->handleRecordFieldChanges($fieldChanges['fields'], $objectId, Company::class);
|
||||
|
||||
$this->eventDispatcherInterfaceMock
|
||||
->method('hasListeners')
|
||||
->with(IntegrationEvents::INTEGRATION_BEFORE_COMPANY_FIELD_CHANGES)
|
||||
->willReturn(true);
|
||||
|
||||
$this->subscriber->onCompanyPostSave($this->companyEvent);
|
||||
}
|
||||
|
||||
public function testOnCompanyPostDelete(): void
|
||||
{
|
||||
$deletedId = 5;
|
||||
$lead = new Company();
|
||||
$lead->deletedId = $deletedId;
|
||||
|
||||
$this->companyEvent->expects($this->exactly(2))
|
||||
->method('getCompany')
|
||||
->willReturn($lead);
|
||||
|
||||
$this->fieldChangeRepository->expects($this->once())
|
||||
->method('deleteEntitiesForObject')
|
||||
->with((int) $deletedId, Company::class);
|
||||
|
||||
$this->objectMappingRepository->expects($this->once())
|
||||
->method('deleteEntitiesForObject')
|
||||
->with((int) $deletedId, MauticSyncDataExchange::OBJECT_COMPANY);
|
||||
|
||||
$this->subscriber->onCompanyPostDelete($this->companyEvent);
|
||||
}
|
||||
|
||||
private function handleRecordFieldChanges(array $fieldChanges, int $objectId, string $objectType): void
|
||||
{
|
||||
$integrationName = 'testIntegration';
|
||||
$enabledIntegrations = [$integrationName];
|
||||
|
||||
$this->syncIntegrationsHelper->expects($this->any())
|
||||
->method('getEnabledIntegrations')
|
||||
->willReturn($enabledIntegrations);
|
||||
|
||||
$fieldNames = [];
|
||||
$values = [];
|
||||
$valueDAOs = [];
|
||||
$i = 0;
|
||||
|
||||
foreach ($fieldChanges as $fieldName => [$oldValue, $newValue]) {
|
||||
$values[] = [$newValue];
|
||||
$valueDAOs[] = new EncodedValueDAO($objectType, (string) $newValue);
|
||||
$fieldNames[] = $fieldName;
|
||||
}
|
||||
$matcher = $this->exactly(1);
|
||||
|
||||
$this->variableExpresserHelper->expects($matcher)->method('encodeVariable')
|
||||
->willReturnCallback(function (...$parameters) use ($matcher, $values, $valueDAOs) {
|
||||
$this->assertSame($values[$matcher->numberOfInvocations() - 1], $parameters);
|
||||
|
||||
return $valueDAOs[0];
|
||||
});
|
||||
|
||||
$this->fieldChangeRepository->expects($this->once())
|
||||
->method('deleteEntitiesForObjectByColumnName')
|
||||
->with($objectId, $objectType, $fieldNames);
|
||||
|
||||
$this->fieldChangeRepository->expects($this->once())
|
||||
->method('saveEntities');
|
||||
|
||||
$this->fieldChangeRepository->expects($this->once())
|
||||
->method('detachEntities');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $fieldChanges
|
||||
*/
|
||||
private function createLeadMock(array $fieldChanges, int $objectId): Lead
|
||||
{
|
||||
return new class($fieldChanges, $objectId) extends Lead {
|
||||
/**
|
||||
* @param mixed[] $fieldChanges
|
||||
*/
|
||||
public function __construct(
|
||||
private array $fieldChanges,
|
||||
private int $objectId,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function isAnonymous(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getChanges($includePast = false): array
|
||||
{
|
||||
return $this->fieldChanges;
|
||||
}
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->objectId;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $fieldChanges
|
||||
*/
|
||||
private function createCompanyMock(array $fieldChanges, int $objectId): Company
|
||||
{
|
||||
return new class($fieldChanges, $objectId) extends Company {
|
||||
/**
|
||||
* @param mixed[] $fieldChanges
|
||||
*/
|
||||
public function __construct(
|
||||
private array $fieldChanges,
|
||||
private int $objectId,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getChanges($includePast = false): array
|
||||
{
|
||||
return $this->fieldChanges;
|
||||
}
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->objectId;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Form\Type;
|
||||
|
||||
use Mautic\IntegrationsBundle\Exception\InvalidFormOptionException;
|
||||
use Mautic\IntegrationsBundle\Form\Type\IntegrationSyncSettingsObjectFieldType;
|
||||
use Mautic\IntegrationsBundle\Mapping\MappedFieldInfoInterface;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\ObjectMappingDAO;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
final class IntegrationSyncSettingsObjectFieldTypeTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
/**
|
||||
* @var MockObject|FormBuilderInterface
|
||||
*/
|
||||
private MockObject $formBuilder;
|
||||
|
||||
private IntegrationSyncSettingsObjectFieldType $form;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->formBuilder = $this->createMock(FormBuilderInterface::class);
|
||||
$this->form = new IntegrationSyncSettingsObjectFieldType();
|
||||
}
|
||||
|
||||
public function testBuildFormForWrongField(): void
|
||||
{
|
||||
$options = ['field' => 'unicorn'];
|
||||
$this->expectException(InvalidFormOptionException::class);
|
||||
$this->form->buildForm($this->formBuilder, $options);
|
||||
}
|
||||
|
||||
public function testBuildFormForMappedField(): void
|
||||
{
|
||||
$field = $this->createMock(MappedFieldInfoInterface::class);
|
||||
$options = [
|
||||
'field' => $field,
|
||||
'placeholder' => 'Placeholder ABC',
|
||||
'object' => 'Object A',
|
||||
'integration' => 'Integration A',
|
||||
'mauticFields' => [
|
||||
'mautic_field_a' => 'Mautic Field A',
|
||||
'mautic_field_b' => 'Mautic Field B',
|
||||
],
|
||||
];
|
||||
|
||||
$field->method('showAsRequired')->willReturn(true);
|
||||
$field->method('getName')->willReturn('Integration Field A');
|
||||
$field->method('isBidirectionalSyncEnabled')->willReturn(false);
|
||||
$field->method('isToIntegrationSyncEnabled')->willReturn(true);
|
||||
$field->method('isToMauticSyncEnabled')->willReturn(true);
|
||||
$matcher = $this->exactly(2);
|
||||
|
||||
$this->formBuilder->expects($matcher)
|
||||
->method('add')->willReturnCallback(function (...$parameters) use ($matcher, $options) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('mappedField', $parameters[0]);
|
||||
$this->assertSame(ChoiceType::class, $parameters[1]);
|
||||
$this->assertSame([
|
||||
'label' => false,
|
||||
'choices' => [
|
||||
'Mautic Field A' => 'mautic_field_a',
|
||||
'Mautic Field B' => 'mautic_field_b',
|
||||
],
|
||||
'required' => true,
|
||||
'placeholder' => '',
|
||||
'error_bubbling' => false,
|
||||
'attr' => [
|
||||
'class' => 'form-control integration-mapped-field',
|
||||
'data-placeholder' => $options['placeholder'],
|
||||
'data-object' => $options['object'],
|
||||
'data-integration' => $options['integration'],
|
||||
'data-field' => 'Integration Field A',
|
||||
],
|
||||
], $parameters[2]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('syncDirection', $parameters[0]);
|
||||
$this->assertSame(ChoiceType::class, $parameters[1]);
|
||||
$this->assertSame([
|
||||
'choices' => [
|
||||
'mautic.integration.sync_direction_integration' => ObjectMappingDAO::SYNC_TO_INTEGRATION,
|
||||
'mautic.integration.sync_direction_mautic' => ObjectMappingDAO::SYNC_TO_MAUTIC,
|
||||
],
|
||||
'label' => false,
|
||||
'empty_data' => ObjectMappingDAO::SYNC_TO_INTEGRATION,
|
||||
'attr' => [
|
||||
'class' => 'integration-sync-direction',
|
||||
'data-object' => 'Object A',
|
||||
'data-integration' => 'Integration A',
|
||||
'data-field' => 'Integration Field A',
|
||||
],
|
||||
], $parameters[2]);
|
||||
}
|
||||
|
||||
return $this->formBuilder;
|
||||
});
|
||||
|
||||
$this->form->buildForm($this->formBuilder, $options);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Exception\IntegrationNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Helper\BuilderIntegrationsHelper;
|
||||
use Mautic\IntegrationsBundle\Helper\IntegrationsHelper;
|
||||
use Mautic\IntegrationsBundle\Integration\Interfaces\BuilderInterface;
|
||||
use Mautic\PluginBundle\Entity\Integration;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class BuilderIntegrationsHelperTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var IntegrationsHelper|MockObject
|
||||
*/
|
||||
private MockObject $integrationsHelper;
|
||||
|
||||
private BuilderIntegrationsHelper $builderIntegrationsHelper;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->integrationsHelper = $this->createMock(IntegrationsHelper::class);
|
||||
$this->builderIntegrationsHelper = new BuilderIntegrationsHelper($this->integrationsHelper);
|
||||
}
|
||||
|
||||
public function testBuilderNotFoundIfFeatureSupportedButNotEnabled(): void
|
||||
{
|
||||
$builder = $this->createMock(BuilderInterface::class);
|
||||
$integration = new Integration();
|
||||
|
||||
$builder->expects($this->once())
|
||||
->method('isSupported')
|
||||
->with('page')
|
||||
->willReturn(true);
|
||||
|
||||
$builder->expects($this->once())
|
||||
->method('getIntegrationConfiguration')
|
||||
->willReturn($integration);
|
||||
|
||||
$this->builderIntegrationsHelper->addIntegration($builder);
|
||||
|
||||
$this->expectException(IntegrationNotFoundException::class);
|
||||
|
||||
$this->builderIntegrationsHelper->getBuilder('page');
|
||||
}
|
||||
|
||||
public function testBuilderNotFoundIfFeatureIsNotSupported(): void
|
||||
{
|
||||
$builder = $this->createMock(BuilderInterface::class);
|
||||
$builder->expects($this->once())
|
||||
->method('isSupported')
|
||||
->with('page')
|
||||
->willReturn(false);
|
||||
|
||||
$builder->expects($this->never())
|
||||
->method('getIntegrationConfiguration');
|
||||
|
||||
$this->builderIntegrationsHelper->addIntegration($builder);
|
||||
|
||||
$this->expectException(IntegrationNotFoundException::class);
|
||||
|
||||
$this->builderIntegrationsHelper->getBuilder('page');
|
||||
}
|
||||
|
||||
public function testBuilderFoundIfFeatureIsSupportedAndBuilderEnabled(): void
|
||||
{
|
||||
$builder = $this->createMock(BuilderInterface::class);
|
||||
|
||||
$integration = new Integration();
|
||||
$integration->setIsPublished(true);
|
||||
|
||||
$builder->expects($this->once())
|
||||
->method('isSupported')
|
||||
->with('page')
|
||||
->willReturn(true);
|
||||
|
||||
$builder->expects($this->once())
|
||||
->method('getIntegrationConfiguration')
|
||||
->willReturn($integration);
|
||||
|
||||
$this->builderIntegrationsHelper->addIntegration($builder);
|
||||
|
||||
$foundBuilder = $this->builderIntegrationsHelper->getBuilder('page');
|
||||
|
||||
Assert::assertSame($builder, $foundBuilder);
|
||||
}
|
||||
|
||||
public function testBuilderNamesAreReturned(): void
|
||||
{
|
||||
$builder1 = $this->createMock(BuilderInterface::class);
|
||||
$builder1->expects($this->exactly(2))
|
||||
->method('getName')
|
||||
->willReturn('builder1');
|
||||
$builder1->expects($this->once())
|
||||
->method('getDisplayName')
|
||||
->willReturn('Builder One');
|
||||
$this->builderIntegrationsHelper->addIntegration($builder1);
|
||||
|
||||
$builder2 = $this->createMock(BuilderInterface::class);
|
||||
$builder2->expects($this->exactly(2))
|
||||
->method('getName')
|
||||
->willReturn('builder2');
|
||||
$builder2->expects($this->once())
|
||||
->method('getDisplayName')
|
||||
->willReturn('Builder Two');
|
||||
$this->builderIntegrationsHelper->addIntegration($builder2);
|
||||
|
||||
Assert::assertSame(
|
||||
[
|
||||
'builder1' => 'Builder One',
|
||||
'builder2' => 'Builder Two',
|
||||
],
|
||||
$this->builderIntegrationsHelper->getBuilderNames()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Helper\FieldFilterHelper;
|
||||
use Mautic\IntegrationsBundle\Integration\Interfaces\ConfigFormSyncInterface;
|
||||
use Mautic\IntegrationsBundle\Mapping\MappedFieldInfoInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class FieldFilterHelperTest extends TestCase
|
||||
{
|
||||
public function testFieldsFilteredByPage(): void
|
||||
{
|
||||
$integrationObject = $this->getIntegrationObject();
|
||||
$fieldFilterHelper = new FieldFilterHelper($integrationObject);
|
||||
|
||||
$fieldFilterHelper->filterFieldsByPage('test', 2, 3);
|
||||
$this->assertEquals(5, $fieldFilterHelper->getTotalFieldCount());
|
||||
$filteredFields = $fieldFilterHelper->getFilteredFields();
|
||||
|
||||
$this->assertFalse(isset($filteredFields['field1']));
|
||||
$this->assertFalse(isset($filteredFields['field2']));
|
||||
$this->assertFalse(isset($filteredFields['field3']));
|
||||
$this->assertTrue(isset($filteredFields['field4']));
|
||||
$this->assertTrue(isset($filteredFields['field5']));
|
||||
}
|
||||
|
||||
public function testFieldsFilteredByKeyword(): void
|
||||
{
|
||||
$integrationObject = $this->getIntegrationObject();
|
||||
$fieldFilterHelper = new FieldFilterHelper($integrationObject);
|
||||
|
||||
$fieldFilterHelper->filterFieldsByKeyword('test', 'three', 1);
|
||||
$this->assertEquals(1, $fieldFilterHelper->getTotalFieldCount());
|
||||
$filteredFields = $fieldFilterHelper->getFilteredFields();
|
||||
|
||||
$this->assertFalse(isset($filteredFields['field1']));
|
||||
$this->assertFalse(isset($filteredFields['field2']));
|
||||
$this->assertTrue(isset($filteredFields['field3']));
|
||||
$this->assertFalse(isset($filteredFields['field4']));
|
||||
$this->assertFalse(isset($filteredFields['field5']));
|
||||
}
|
||||
|
||||
public function testFieldsFilteredByKeywordAndPage(): void
|
||||
{
|
||||
$integrationObject = $this->getIntegrationObject();
|
||||
$fieldFilterHelper = new FieldFilterHelper($integrationObject);
|
||||
|
||||
$fieldFilterHelper->filterFieldsByKeyword('test', 'field', 2, 3);
|
||||
$this->assertEquals(5, $fieldFilterHelper->getTotalFieldCount());
|
||||
$filteredFields = $fieldFilterHelper->getFilteredFields();
|
||||
|
||||
$this->assertFalse(isset($filteredFields['field1']));
|
||||
$this->assertFalse(isset($filteredFields['field2']));
|
||||
$this->assertFalse(isset($filteredFields['field3']));
|
||||
$this->assertTrue(isset($filteredFields['field4']));
|
||||
$this->assertTrue(isset($filteredFields['field5']));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \PHPUnit\Framework\MockObject\MockObject|ConfigFormSyncInterface
|
||||
*/
|
||||
private function getIntegrationObject()
|
||||
{
|
||||
$field1 = $this->createMock(MappedFieldInfoInterface::class);
|
||||
$field1->method('getLabel')
|
||||
->willReturn('field one');
|
||||
$field2 = $this->createMock(MappedFieldInfoInterface::class);
|
||||
$field2->method('getLabel')
|
||||
->willReturn('field two');
|
||||
$field3 = $this->createMock(MappedFieldInfoInterface::class);
|
||||
$field3->method('getLabel')
|
||||
->willReturn('field three');
|
||||
$field4 = $this->createMock(MappedFieldInfoInterface::class);
|
||||
$field4->method('getLabel')
|
||||
->willReturn('field four');
|
||||
$field5 = $this->createMock(MappedFieldInfoInterface::class);
|
||||
$field5->method('getLabel')
|
||||
->willReturn('field five');
|
||||
|
||||
$integrationObject = $this->createMock(ConfigFormSyncInterface::class);
|
||||
$integrationObject->method('getAllFieldsForMapping')
|
||||
->willReturn(
|
||||
[
|
||||
'field1' => $field1,
|
||||
'field2' => $field2,
|
||||
'field3' => $field3,
|
||||
'field4' => $field4,
|
||||
'field5' => $field5,
|
||||
]
|
||||
);
|
||||
|
||||
return $integrationObject;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,483 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Exception\InvalidFormOptionException;
|
||||
use Mautic\IntegrationsBundle\Helper\FieldMergerHelper;
|
||||
use Mautic\IntegrationsBundle\Integration\Interfaces\ConfigFormSyncInterface;
|
||||
use Mautic\IntegrationsBundle\Mapping\MappedFieldInfoInterface;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\ObjectMappingDAO;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class FieldMergerHelperTest extends TestCase
|
||||
{
|
||||
public function testNonExistingFieldsAreRemoved(): void
|
||||
{
|
||||
$fields = $this->getCurrentFieldMappings();
|
||||
|
||||
$integrationObject = $this->getIntegrationObject(true);
|
||||
$fieldMergerHelper = new FieldMergerHelper($integrationObject, $fields);
|
||||
|
||||
$updatedFieldMappings = [
|
||||
'field1' => [
|
||||
'mappedField' => 'mautic_test_field',
|
||||
'syncDirection' => 'bidirectional',
|
||||
],
|
||||
];
|
||||
|
||||
$fieldMergerHelper->mergeSyncFieldMapping('Lead', $updatedFieldMappings);
|
||||
$mergedFieldMappings = $fieldMergerHelper->getFieldMappings();
|
||||
|
||||
$this->assertFalse(isset($mergedFieldMappings['Lead']['field1']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field2']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field3']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field4']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field5']));
|
||||
}
|
||||
|
||||
public function testFieldUnsetIfMappingIsDeleted(): void
|
||||
{
|
||||
$fields = $this->getCurrentFieldMappings();
|
||||
unset($fields['Lead']['field1']);
|
||||
|
||||
$integrationObject = $this->getIntegrationObject();
|
||||
$fieldMergerHelper = new FieldMergerHelper($integrationObject, $fields);
|
||||
|
||||
$updatedFieldMappings = [
|
||||
'field1' => [],
|
||||
];
|
||||
|
||||
$fieldMergerHelper->mergeSyncFieldMapping('Lead', $updatedFieldMappings);
|
||||
$mergedFieldMappings = $fieldMergerHelper->getFieldMappings();
|
||||
|
||||
$this->assertFalse(isset($mergedFieldMappings['Lead']['field1']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field2']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field3']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field4']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field5']));
|
||||
}
|
||||
|
||||
public function testCurrentFieldMappingsAreMerged(): void
|
||||
{
|
||||
$fields = $this->getCurrentFieldMappings();
|
||||
$integrationObject = $this->getIntegrationObject();
|
||||
$fieldMergerHelper = new FieldMergerHelper($integrationObject, $fields);
|
||||
|
||||
$updatedFieldMappings = [
|
||||
'field1' => [
|
||||
'mappedField' => 'mautic_test_field',
|
||||
'syncDirection' => 'mautic',
|
||||
],
|
||||
];
|
||||
|
||||
$integrationFields = $integrationObject->getAllFieldsForMapping('Lead');
|
||||
/** @var MappedFieldInfoInterface|\PHPUnit\Framework\MockObject\MockObject $field1 */
|
||||
$field1 = $integrationFields['field1'];
|
||||
$field1->expects($this->once())
|
||||
->method('isBidirectionalSyncEnabled')
|
||||
->willReturn(true);
|
||||
$field1->expects($this->once())
|
||||
->method('isToIntegrationSyncEnabled')
|
||||
->willReturn(true);
|
||||
$field1->expects($this->once())
|
||||
->method('isToMauticSyncEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$fieldMergerHelper->mergeSyncFieldMapping('Lead', $updatedFieldMappings);
|
||||
$mergedFieldMappings = $fieldMergerHelper->getFieldMappings();
|
||||
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field1']));
|
||||
$this->assertEquals($updatedFieldMappings['field1']['mappedField'], $mergedFieldMappings['Lead']['field1']['mappedField']);
|
||||
$this->assertEquals($updatedFieldMappings['field1']['syncDirection'], $mergedFieldMappings['Lead']['field1']['syncDirection']);
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field2']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field3']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field4']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field5']));
|
||||
}
|
||||
|
||||
public function testCurrentFieldMappingsAreMergedWithJustMappedFieldUpdated(): void
|
||||
{
|
||||
$fields = $this->getCurrentFieldMappings();
|
||||
$integrationObject = $this->getIntegrationObject();
|
||||
$fieldMergerHelper = new FieldMergerHelper($integrationObject, $fields);
|
||||
|
||||
$updatedFieldMappings = [
|
||||
'field4' => [
|
||||
'mappedField' => 'mautic_test_field',
|
||||
],
|
||||
];
|
||||
|
||||
$integrationFields = $integrationObject->getAllFieldsForMapping('Lead');
|
||||
/** @var MappedFieldInfoInterface|\PHPUnit\Framework\MockObject\MockObject $field4 */
|
||||
$field4 = $integrationFields['field4'];
|
||||
$field4->expects($this->once())
|
||||
->method('isBidirectionalSyncEnabled')
|
||||
->willReturn(false);
|
||||
$field4->expects($this->once())
|
||||
->method('isToIntegrationSyncEnabled')
|
||||
->willReturn(false);
|
||||
$field4->expects($this->once())
|
||||
->method('isToMauticSyncEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$fieldMergerHelper->mergeSyncFieldMapping('Lead', $updatedFieldMappings);
|
||||
$mergedFieldMappings = $fieldMergerHelper->getFieldMappings();
|
||||
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field1']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field2']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field3']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field4']));
|
||||
$this->assertEquals($updatedFieldMappings['field4']['mappedField'], $mergedFieldMappings['Lead']['field4']['mappedField']);
|
||||
$this->assertEquals(ObjectMappingDAO::SYNC_TO_MAUTIC, $mergedFieldMappings['Lead']['field4']['syncDirection']);
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field5']));
|
||||
}
|
||||
|
||||
public function testCurrentFieldMappingsAreMergedWithJustSyncDirectionUpdated(): void
|
||||
{
|
||||
$fields = $this->getCurrentFieldMappings();
|
||||
$integrationObject = $this->getIntegrationObject();
|
||||
$fieldMergerHelper = new FieldMergerHelper($integrationObject, $fields);
|
||||
|
||||
$updatedFieldMappings = [
|
||||
'field4' => [
|
||||
'syncDirection' => ObjectMappingDAO::SYNC_TO_INTEGRATION,
|
||||
],
|
||||
];
|
||||
|
||||
$integrationFields = $integrationObject->getAllFieldsForMapping('Lead');
|
||||
/** @var MappedFieldInfoInterface|\PHPUnit\Framework\MockObject\MockObject $field1 */
|
||||
$field4 = $integrationFields['field4'];
|
||||
$field4->expects($this->once())
|
||||
->method('isBidirectionalSyncEnabled')
|
||||
->willReturn(false);
|
||||
$field4->expects($this->once())
|
||||
->method('isToIntegrationSyncEnabled')
|
||||
->willReturn(true);
|
||||
$field4->expects($this->once())
|
||||
->method('isToMauticSyncEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$fieldMergerHelper->mergeSyncFieldMapping('Lead', $updatedFieldMappings);
|
||||
$mergedFieldMappings = $fieldMergerHelper->getFieldMappings();
|
||||
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field1']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field2']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field3']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field4']));
|
||||
$this->assertEquals($fields['Lead']['field4']['mappedField'], $mergedFieldMappings['Lead']['field4']['mappedField']);
|
||||
$this->assertEquals($updatedFieldMappings['field4']['syncDirection'], $mergedFieldMappings['Lead']['field4']['syncDirection']);
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field5']));
|
||||
}
|
||||
|
||||
public function testFieldUnsetIfDirectionIsUpdatedWithoutMappedField(): void
|
||||
{
|
||||
$fields = $this->getCurrentFieldMappings();
|
||||
unset($fields['Lead']['field1']);
|
||||
|
||||
$integrationObject = $this->getIntegrationObject();
|
||||
$fieldMergerHelper = new FieldMergerHelper($integrationObject, $fields);
|
||||
|
||||
$updatedFieldMappings = [
|
||||
'field1' => [
|
||||
'mappedField' => '',
|
||||
'syncDirection' => 'bidirectional',
|
||||
],
|
||||
];
|
||||
|
||||
$fieldMergerHelper->mergeSyncFieldMapping('Lead', $updatedFieldMappings);
|
||||
$mergedFieldMappings = $fieldMergerHelper->getFieldMappings();
|
||||
|
||||
$this->assertFalse(isset($mergedFieldMappings['Lead']['field1']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field2']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field3']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field4']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field5']));
|
||||
}
|
||||
|
||||
public function testDefaultSyncDirectionSetWithExisting(): void
|
||||
{
|
||||
$fields = $this->getCurrentFieldMappings();
|
||||
|
||||
$integrationObject = $this->getIntegrationObject();
|
||||
$integrationFields = $integrationObject->getAllFieldsForMapping('Lead');
|
||||
/** @var MappedFieldInfoInterface|\PHPUnit\Framework\MockObject\MockObject $field1 */
|
||||
$field4 = $integrationFields['field4'];
|
||||
$field4->expects($this->once())
|
||||
->method('isBidirectionalSyncEnabled')
|
||||
->willReturn(true);
|
||||
$field4->expects($this->once())
|
||||
->method('isToIntegrationSyncEnabled')
|
||||
->willReturn(true);
|
||||
$field4->expects($this->once())
|
||||
->method('isToMauticSyncEnabled')
|
||||
->willReturn(true);
|
||||
$fieldMergerHelper = new FieldMergerHelper($integrationObject, $fields);
|
||||
|
||||
$updatedFieldMappings = [
|
||||
'field4' => [
|
||||
'mappedField' => 'mautic_test_field',
|
||||
],
|
||||
];
|
||||
|
||||
$fieldMergerHelper->mergeSyncFieldMapping('Lead', $updatedFieldMappings);
|
||||
$mergedFieldMappings = $fieldMergerHelper->getFieldMappings();
|
||||
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field1']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field2']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field3']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field4']));
|
||||
$this->assertEquals(ObjectMappingDAO::SYNC_TO_MAUTIC, $mergedFieldMappings['Lead']['field4']['syncDirection']);
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field5']));
|
||||
}
|
||||
|
||||
public function testDefaultSyncDirectionSetWithBidirectionalSupported(): void
|
||||
{
|
||||
$fields = $this->getCurrentFieldMappings();
|
||||
|
||||
$integrationObject = $this->getIntegrationObject();
|
||||
$integrationFields = $integrationObject->getAllFieldsForMapping('Lead');
|
||||
|
||||
/** @var MappedFieldInfoInterface|\PHPUnit\Framework\MockObject\MockObject $field1 */
|
||||
$field1 = $integrationFields['field1'];
|
||||
$field1->expects($this->once())
|
||||
->method('isBidirectionalSyncEnabled')
|
||||
->willReturn(true);
|
||||
$field1->expects($this->once())
|
||||
->method('isToIntegrationSyncEnabled')
|
||||
->willReturn(true);
|
||||
$field1->expects($this->once())
|
||||
->method('isToMauticSyncEnabled')
|
||||
->willReturn(true);
|
||||
$fieldMergerHelper = new FieldMergerHelper($integrationObject, $fields);
|
||||
|
||||
$updatedFieldMappings = [
|
||||
'field1' => [
|
||||
'mappedField' => 'mautic_test_field',
|
||||
],
|
||||
];
|
||||
|
||||
$fieldMergerHelper->mergeSyncFieldMapping('Lead', $updatedFieldMappings);
|
||||
$mergedFieldMappings = $fieldMergerHelper->getFieldMappings();
|
||||
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field1']));
|
||||
$this->assertEquals(ObjectMappingDAO::SYNC_BIDIRECTIONALLY, $mergedFieldMappings['Lead']['field1']['syncDirection']);
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field2']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field3']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field4']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field5']));
|
||||
}
|
||||
|
||||
public function testDefaultSyncDirectionSetWithIntegrationDirectionalSupported(): void
|
||||
{
|
||||
$fields = $this->getCurrentFieldMappings();
|
||||
unset($fields['Lead']['field1']);
|
||||
|
||||
$integrationObject = $this->getIntegrationObject();
|
||||
$integrationFields = $integrationObject->getAllFieldsForMapping('Lead');
|
||||
/** @var MappedFieldInfoInterface|\PHPUnit\Framework\MockObject\MockObject $field1 */
|
||||
$field1 = $integrationFields['field1'];
|
||||
$field1->expects($this->once())
|
||||
->method('isBidirectionalSyncEnabled')
|
||||
->willReturn(false);
|
||||
$field1->expects($this->once())
|
||||
->method('isToIntegrationSyncEnabled')
|
||||
->willReturn(true);
|
||||
$field1->expects($this->once())
|
||||
->method('isToMauticSyncEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$fieldMergerHelper = new FieldMergerHelper($integrationObject, $fields);
|
||||
|
||||
$updatedFieldMappings = [
|
||||
'field1' => [
|
||||
'mappedField' => 'mautic_test_field',
|
||||
],
|
||||
];
|
||||
|
||||
$fieldMergerHelper->mergeSyncFieldMapping('Lead', $updatedFieldMappings);
|
||||
$mergedFieldMappings = $fieldMergerHelper->getFieldMappings();
|
||||
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field1']));
|
||||
$this->assertEquals(ObjectMappingDAO::SYNC_TO_INTEGRATION, $mergedFieldMappings['Lead']['field1']['syncDirection']);
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field2']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field3']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field4']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field5']));
|
||||
}
|
||||
|
||||
public function testDefaultSyncDirectionSetWithMauticDirectionalSupported(): void
|
||||
{
|
||||
$fields = $this->getCurrentFieldMappings();
|
||||
unset($fields['Lead']['field1']);
|
||||
|
||||
$integrationObject = $this->getIntegrationObject();
|
||||
$integrationFields = $integrationObject->getAllFieldsForMapping('Lead');
|
||||
/** @var MappedFieldInfoInterface|\PHPUnit\Framework\MockObject\MockObject $field1 */
|
||||
$field1 = $integrationFields['field1'];
|
||||
$field1->expects($this->once())
|
||||
->method('isBidirectionalSyncEnabled')
|
||||
->willReturn(false);
|
||||
$field1->expects($this->once())
|
||||
->method('isToIntegrationSyncEnabled')
|
||||
->willReturn(false);
|
||||
$field1->expects($this->once())
|
||||
->method('isToMauticSyncEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$fieldMergerHelper = new FieldMergerHelper($integrationObject, $fields);
|
||||
|
||||
$updatedFieldMappings = [
|
||||
'field1' => [
|
||||
'mappedField' => 'mautic_test_field',
|
||||
],
|
||||
];
|
||||
|
||||
$fieldMergerHelper->mergeSyncFieldMapping('Lead', $updatedFieldMappings);
|
||||
$mergedFieldMappings = $fieldMergerHelper->getFieldMappings();
|
||||
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field1']));
|
||||
$this->assertEquals(ObjectMappingDAO::SYNC_TO_MAUTIC, $mergedFieldMappings['Lead']['field1']['syncDirection']);
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field2']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field3']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field4']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field5']));
|
||||
}
|
||||
|
||||
public function testCurrentSyncDirectionOverwrittenWithSupportedDirectionalSync(): void
|
||||
{
|
||||
$fields = $this->getCurrentFieldMappings();
|
||||
|
||||
$integrationObject = $this->getIntegrationObject();
|
||||
$integrationFields = $integrationObject->getAllFieldsForMapping('Lead');
|
||||
/** @var MappedFieldInfoInterface|\PHPUnit\Framework\MockObject\MockObject $field1 */
|
||||
$field1 = $integrationFields['field1'];
|
||||
$field1->expects($this->once())
|
||||
->method('isBidirectionalSyncEnabled')
|
||||
->willReturn(false);
|
||||
$field1->expects($this->once())
|
||||
->method('isToIntegrationSyncEnabled')
|
||||
->willReturn(false);
|
||||
$field1->expects($this->once())
|
||||
->method('isToMauticSyncEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$fieldMergerHelper = new FieldMergerHelper($integrationObject, $fields);
|
||||
|
||||
$updatedFieldMappings = [
|
||||
'field1' => [
|
||||
'mappedField' => 'mautic_test_field',
|
||||
],
|
||||
];
|
||||
|
||||
$fieldMergerHelper->mergeSyncFieldMapping('Lead', $updatedFieldMappings);
|
||||
$mergedFieldMappings = $fieldMergerHelper->getFieldMappings();
|
||||
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field1']));
|
||||
$this->assertEquals(ObjectMappingDAO::SYNC_TO_MAUTIC, $mergedFieldMappings['Lead']['field1']['syncDirection']);
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field2']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field3']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field4']));
|
||||
$this->assertTrue(isset($mergedFieldMappings['Lead']['field5']));
|
||||
}
|
||||
|
||||
public function testDefaultSyncDirectionThrowsExceptionIfFieldDoesNotHaveSyncDirectionSupportDefined(): void
|
||||
{
|
||||
$this->expectException(InvalidFormOptionException::class);
|
||||
|
||||
$fields = $this->getCurrentFieldMappings();
|
||||
unset($fields['Lead']['field1']);
|
||||
|
||||
$integrationObject = $this->getIntegrationObject();
|
||||
$integrationFields = $integrationObject->getAllFieldsForMapping('Lead');
|
||||
/** @var MappedFieldInfoInterface|\PHPUnit\Framework\MockObject\MockObject $field1 */
|
||||
$field1 = $integrationFields['field1'];
|
||||
$field1->expects($this->once())
|
||||
->method('isBidirectionalSyncEnabled')
|
||||
->willReturn(false);
|
||||
$field1->expects($this->once())
|
||||
->method('isToIntegrationSyncEnabled')
|
||||
->willReturn(false);
|
||||
$field1->expects($this->once())
|
||||
->method('isToMauticSyncEnabled')
|
||||
->willReturn(false);
|
||||
$fieldMergerHelper = new FieldMergerHelper($integrationObject, $fields);
|
||||
|
||||
$updatedFieldMappings = [
|
||||
'field1' => [
|
||||
'mappedField' => 'mautic_test_field',
|
||||
],
|
||||
];
|
||||
|
||||
$fieldMergerHelper->mergeSyncFieldMapping('Lead', $updatedFieldMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \PHPUnit\Framework\MockObject\MockObject|ConfigFormSyncInterface
|
||||
*/
|
||||
private function getIntegrationObject(bool $removeFirstField = false): ConfigFormSyncInterface
|
||||
{
|
||||
$field1 = $this->createMock(MappedFieldInfoInterface::class);
|
||||
$field1->method('getName')
|
||||
->willReturn('field one');
|
||||
$field2 = $this->createMock(MappedFieldInfoInterface::class);
|
||||
$field2->method('getName')
|
||||
->willReturn('field two');
|
||||
$field3 = $this->createMock(MappedFieldInfoInterface::class);
|
||||
$field3->method('getName')
|
||||
->willReturn('field three');
|
||||
$field4 = $this->createMock(MappedFieldInfoInterface::class);
|
||||
$field4->method('getName')
|
||||
->willReturn('field four');
|
||||
$field5 = $this->createMock(MappedFieldInfoInterface::class);
|
||||
$field5->method('getName')
|
||||
->willReturn('field five');
|
||||
|
||||
$fields = [
|
||||
'field1' => $field1,
|
||||
'field2' => $field2,
|
||||
'field3' => $field3,
|
||||
'field4' => $field4,
|
||||
'field5' => $field5,
|
||||
];
|
||||
|
||||
if ($removeFirstField) {
|
||||
unset($fields['field1']);
|
||||
}
|
||||
|
||||
$integrationObject = $this->createMock(ConfigFormSyncInterface::class);
|
||||
$integrationObject->method('getAllFieldsForMapping')
|
||||
->willReturn($fields);
|
||||
|
||||
return $integrationObject;
|
||||
}
|
||||
|
||||
private function getCurrentFieldMappings(): array
|
||||
{
|
||||
return [
|
||||
'Lead' => [
|
||||
'field1' => [
|
||||
'mappedField' => 'mautic_field1',
|
||||
'syncDirection' => ObjectMappingDAO::SYNC_BIDIRECTIONALLY,
|
||||
],
|
||||
'field2' => [
|
||||
'mappedField' => 'mautic_field2',
|
||||
'syncDirection' => ObjectMappingDAO::SYNC_BIDIRECTIONALLY,
|
||||
],
|
||||
'field3' => [
|
||||
'mappedField' => 'mautic_field3',
|
||||
'syncDirection' => ObjectMappingDAO::SYNC_BIDIRECTIONALLY,
|
||||
],
|
||||
'field4' => [
|
||||
'mappedField' => 'mautic_field4',
|
||||
'syncDirection' => ObjectMappingDAO::SYNC_TO_MAUTIC,
|
||||
],
|
||||
'field5' => [
|
||||
'mappedField' => 'mautic_field5',
|
||||
'syncDirection' => ObjectMappingDAO::SYNC_TO_INTEGRATION,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Integration;
|
||||
|
||||
use Mautic\IntegrationsBundle\DTO\Note;
|
||||
use Mautic\IntegrationsBundle\Integration\ConfigFormNotesTrait;
|
||||
use Mautic\IntegrationsBundle\Integration\Interfaces\ConfigFormNotesInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ConfigFormNotesTraitTest extends TestCase
|
||||
{
|
||||
public function testConfigFormNotesTraitFormDefaultValues(): void
|
||||
{
|
||||
$configFormNotes = new class implements ConfigFormNotesInterface {
|
||||
use ConfigFormNotesTrait;
|
||||
};
|
||||
|
||||
$this->assertNull($configFormNotes->getAuthorizationNote());
|
||||
$this->assertNull($configFormNotes->getFeaturesNote());
|
||||
$this->assertNull($configFormNotes->getFieldMappingNote());
|
||||
}
|
||||
|
||||
public function testConfigFormNotesTraitFormForCustomValues(): void
|
||||
{
|
||||
$configFormNotes = new class implements ConfigFormNotesInterface {
|
||||
use ConfigFormNotesTrait;
|
||||
|
||||
public function getAuthorizationNote(): Note
|
||||
{
|
||||
return new Note('Authorisation', Note::TYPE_WARNING);
|
||||
}
|
||||
|
||||
public function getFeaturesNote(): Note
|
||||
{
|
||||
return new Note('Features', Note::TYPE_INFO);
|
||||
}
|
||||
|
||||
public function getFieldMappingNote(): Note
|
||||
{
|
||||
return new Note('Field Mapping', Note::TYPE_WARNING);
|
||||
}
|
||||
};
|
||||
|
||||
$this->assertInstanceOf(Note::class, $configFormNotes->getAuthorizationNote());
|
||||
$this->assertSame(Note::TYPE_WARNING, $configFormNotes->getAuthorizationNote()->getType());
|
||||
$this->assertSame('Authorisation', $configFormNotes->getAuthorizationNote()->getNote());
|
||||
|
||||
$this->assertInstanceOf(Note::class, $configFormNotes->getFeaturesNote());
|
||||
$this->assertSame(Note::TYPE_INFO, $configFormNotes->getFeaturesNote()->getType());
|
||||
$this->assertSame('Features', $configFormNotes->getFeaturesNote()->getNote());
|
||||
|
||||
$this->assertInstanceOf(Note::class, $configFormNotes->getFieldMappingNote());
|
||||
$this->assertSame(Note::TYPE_WARNING, $configFormNotes->getFieldMappingNote()->getType());
|
||||
$this->assertSame('Field Mapping', $configFormNotes->getFieldMappingNote()->getNote());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\DAO;
|
||||
|
||||
use Mautic\IntegrationsBundle\Exception\InvalidValueException;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\InputOptionsDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\ObjectIdsDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\MauticSyncDataExchange;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class InputOptionsDAOTest extends TestCase
|
||||
{
|
||||
public function testWorkflowFromCliWithAllValuesSet(): void
|
||||
{
|
||||
$inputOptionsDAO = new InputOptionsDAO(
|
||||
[
|
||||
'integration' => 'Magento',
|
||||
'first-time-sync' => true,
|
||||
'disable-push' => false,
|
||||
'disable-pull' => true,
|
||||
'disable-activity-push' => true,
|
||||
'mautic-object-id' => ['contact:12', 'contact:13', 'company:45'],
|
||||
'integration-object-id' => ['Lead:hfskjdhf', 'Lead:hfskjdhr'],
|
||||
'start-datetime' => '2019-09-12T12:01:20',
|
||||
'end-datetime' => '2019-10-12T12:01:20',
|
||||
'option' => ['custom1:1', 'custom2:2'],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertSame('Magento', $inputOptionsDAO->getIntegration());
|
||||
$this->assertTrue($inputOptionsDAO->isFirstTimeSync());
|
||||
$this->assertFalse($inputOptionsDAO->pullIsEnabled());
|
||||
$this->assertTrue($inputOptionsDAO->pushIsEnabled());
|
||||
$this->assertFalse($inputOptionsDAO->activityPushIsEnabled());
|
||||
$this->assertSame(['12', '13'], $inputOptionsDAO->getMauticObjectIds()->getObjectIdsFor(Contact::NAME));
|
||||
$this->assertSame(['45'], $inputOptionsDAO->getMauticObjectIds()->getObjectIdsFor(MauticSyncDataExchange::OBJECT_COMPANY));
|
||||
$this->assertSame(['hfskjdhf', 'hfskjdhr'], $inputOptionsDAO->getIntegrationObjectIds()->getObjectIdsFor('Lead'));
|
||||
$this->assertSame('2019-09-12T12:01:20+00:00', $inputOptionsDAO->getStartDateTime()->format(DATE_ATOM));
|
||||
$this->assertSame('2019-10-12T12:01:20+00:00', $inputOptionsDAO->getEndDateTime()->format(DATE_ATOM));
|
||||
$this->assertSame(['custom1' => '1', 'custom2' => '2'], $inputOptionsDAO->getOptions());
|
||||
}
|
||||
|
||||
public function testWorkflowFromCliWithNoValuesSet(): void
|
||||
{
|
||||
$this->expectException(InvalidValueException::class);
|
||||
new InputOptionsDAO([]);
|
||||
}
|
||||
|
||||
public function testWorkflowFromCliWithOnlyIntegrationValuesSet(): void
|
||||
{
|
||||
$inputOptionsDAO = new InputOptionsDAO(['integration' => 'Magento']);
|
||||
$this->assertSame('Magento', $inputOptionsDAO->getIntegration());
|
||||
$this->assertFalse($inputOptionsDAO->isFirstTimeSync());
|
||||
$this->assertTrue($inputOptionsDAO->pullIsEnabled());
|
||||
$this->assertTrue($inputOptionsDAO->pushIsEnabled());
|
||||
$this->assertTrue($inputOptionsDAO->activityPushIsEnabled());
|
||||
$this->assertNull($inputOptionsDAO->getMauticObjectIds());
|
||||
$this->assertNull($inputOptionsDAO->getIntegrationObjectIds());
|
||||
$this->assertNull($inputOptionsDAO->getStartDateTime());
|
||||
$this->assertNull($inputOptionsDAO->getEndDateTime());
|
||||
$this->assertEmpty($inputOptionsDAO->getOptions());
|
||||
}
|
||||
|
||||
public function testWorkflowFromServiceWithAllValuesSet(): void
|
||||
{
|
||||
$mauticObjectIds = new ObjectIdsDAO();
|
||||
$integrationObjectIds = new ObjectIdsDAO();
|
||||
$start = new \DateTimeImmutable('2019-09-12T12:01:20', new \DateTimeZone('UTC'));
|
||||
$end = new \DateTimeImmutable('2019-10-12T12:01:20', new \DateTimeZone('UTC'));
|
||||
$options = ['custom1' => 1, 'custom2' => 2];
|
||||
$inputOptionsDAO = new InputOptionsDAO(
|
||||
[
|
||||
'integration' => 'Magento',
|
||||
'first-time-sync' => true,
|
||||
'disable-push' => false,
|
||||
'disable-pull' => true,
|
||||
'disable-activity-push' => false,
|
||||
'mautic-object-id' => $mauticObjectIds,
|
||||
'integration-object-id' => $integrationObjectIds,
|
||||
'start-datetime' => $start,
|
||||
'end-datetime' => $end,
|
||||
'options' => $options,
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertSame('Magento', $inputOptionsDAO->getIntegration());
|
||||
$this->assertTrue($inputOptionsDAO->isFirstTimeSync());
|
||||
$this->assertFalse($inputOptionsDAO->pullIsEnabled());
|
||||
$this->assertTrue($inputOptionsDAO->pushIsEnabled());
|
||||
$this->assertTrue($inputOptionsDAO->activityPushIsEnabled());
|
||||
$this->assertSame($mauticObjectIds, $inputOptionsDAO->getMauticObjectIds());
|
||||
$this->assertSame($integrationObjectIds, $inputOptionsDAO->getIntegrationObjectIds());
|
||||
$this->assertSame($start, $inputOptionsDAO->getStartDateTime());
|
||||
$this->assertSame($end, $inputOptionsDAO->getEndDateTime());
|
||||
$this->assertSame($options, $inputOptionsDAO->getOptions());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\DAO\Mapping;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\MappingManualDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\ObjectMappingDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class MappingManualDAOTest extends TestCase
|
||||
{
|
||||
private $integrationName = 'Test';
|
||||
|
||||
private $integrationObjectName = 'Contact';
|
||||
|
||||
public function testMappedIntegrationNamesAreReturnedBasedOnInternalObjectName(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
[$this->integrationObjectName],
|
||||
$this->getMappingManualDAO()->getIntegrationObjectNames(Contact::NAME)
|
||||
);
|
||||
}
|
||||
|
||||
public function testMappedInternalNamesAreReturnedBasedOnIntegrationObjectName(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
[Contact::NAME],
|
||||
$this->getMappingManualDAO()->getInternalObjectNames($this->integrationObjectName)
|
||||
);
|
||||
}
|
||||
|
||||
public function testThatOneWayInternalObjectFieldsAreNotReturnedWhenNotRequired(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
[
|
||||
'email', // required and bidirectional
|
||||
'country', // bidirectional
|
||||
'firstname', // sync from mautic to integration
|
||||
],
|
||||
$this->getMappingManualDAO()->getInternalObjectFieldsToSyncToIntegration(Contact::NAME)
|
||||
);
|
||||
}
|
||||
|
||||
public function testThatRequiredInternalObjectFieldsAreReturned(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
['email'],
|
||||
$this->getMappingManualDAO()->getInternalObjectRequiredFieldNames(Contact::NAME)
|
||||
);
|
||||
}
|
||||
|
||||
public function testThatOneWayIntegrationObjectFieldsAreNotReturnedWhenNotRequired(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
[
|
||||
'email', // required and bidirectional
|
||||
'country', // bidirectional
|
||||
'last_name', // sync from mautic to integration
|
||||
],
|
||||
$this->getMappingManualDAO()->getIntegrationObjectFieldsToSyncToMautic($this->integrationObjectName)
|
||||
);
|
||||
}
|
||||
|
||||
public function testThatRequiredIntegrationObjectFieldsAreReturned(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
['email'],
|
||||
$this->getMappingManualDAO()->getIntegrationObjectRequiredFieldNames($this->integrationObjectName)
|
||||
);
|
||||
}
|
||||
|
||||
public function testMappedIntegrationFieldIsReturned(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
'last_name',
|
||||
$this->getMappingManualDAO()->getIntegrationMappedField(
|
||||
$this->integrationObjectName,
|
||||
Contact::NAME,
|
||||
'lastname'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function testMappedInternalFieldIsReturned(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
'lastname',
|
||||
$this->getMappingManualDAO()->getInternalMappedField(
|
||||
Contact::NAME,
|
||||
$this->integrationObjectName,
|
||||
'last_name'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function getMappingManualDAO()
|
||||
{
|
||||
$mappingManual = new MappingManualDAO($this->integrationName);
|
||||
$objectMapping = new ObjectMappingDAO(Contact::NAME, $this->integrationObjectName);
|
||||
$objectMapping->addFieldMapping('email', 'email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$objectMapping->addFieldMapping('country', 'country', ObjectMappingDAO::SYNC_BIDIRECTIONALLY);
|
||||
$objectMapping->addFieldMapping('firstname', 'first_name', ObjectMappingDAO::SYNC_TO_INTEGRATION);
|
||||
$objectMapping->addFieldMapping('lastname', 'last_name', ObjectMappingDAO::SYNC_TO_MAUTIC);
|
||||
|
||||
$mappingManual->addObjectMapping($objectMapping);
|
||||
|
||||
return $mappingManual;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\DAO;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\ObjectIdsDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotFoundException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ObjectIdsDAOTest extends TestCase
|
||||
{
|
||||
public function testWorkflow(): void
|
||||
{
|
||||
$objectIdsDAO = ObjectIdsDAO::createFromCliOptions(
|
||||
[
|
||||
'contact:123',
|
||||
'contact:124',
|
||||
'company:12',
|
||||
'company:13',
|
||||
'Lead:sowiern',
|
||||
'Lead:sowie4n',
|
||||
]
|
||||
);
|
||||
|
||||
$objectIdsDAO->addObjectId('company', '234');
|
||||
|
||||
$this->assertSame(['123', '124'], $objectIdsDAO->getObjectIdsFor('contact'));
|
||||
$this->assertSame(['12', '13', '234'], $objectIdsDAO->getObjectIdsFor('company'));
|
||||
$this->assertSame(['sowiern', 'sowie4n'], $objectIdsDAO->getObjectIdsFor('Lead'));
|
||||
|
||||
$this->expectException(ObjectNotFoundException::class);
|
||||
$objectIdsDAO->getObjectIdsFor('Unicorn');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\DAO;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\RelationsDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\RelationDAO;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class RelationsDAOTest extends TestCase
|
||||
{
|
||||
public function testAddRelations(): void
|
||||
{
|
||||
$relationsDAO = new RelationsDAO();
|
||||
$integrationObjectId = 'IntegrationId-123';
|
||||
$integrationRelObjectId = 'IntegrationId-456';
|
||||
$objectName = 'Contact';
|
||||
$relObjectName = 'Account';
|
||||
$relationObject = new RelationDAO(
|
||||
$objectName,
|
||||
$relObjectName,
|
||||
$relObjectName,
|
||||
$integrationObjectId,
|
||||
$integrationRelObjectId
|
||||
);
|
||||
|
||||
$relations = ['AccountId' => $relationObject];
|
||||
|
||||
$relationsDAO->addRelations($relations);
|
||||
|
||||
$this->assertEquals($relationsDAO->current(), $relationObject);
|
||||
$this->assertEquals($relationsDAO->current()->getObjectName(), $objectName);
|
||||
$this->assertEquals($relationsDAO->current()->getRelObjectName(), $relObjectName);
|
||||
$this->assertEquals($relationsDAO->current()->getObjectIntegrationId(), $integrationObjectId);
|
||||
$this->assertEquals($relationsDAO->current()->getRelObjectIntegrationId(), $integrationRelObjectId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\DAO\Sync\Order;
|
||||
|
||||
use Mautic\IntegrationsBundle\Entity\ObjectMapping;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\FieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\ObjectChangeDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\FieldDAO as ReportFieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ObjectChangeDAOTest extends TestCase
|
||||
{
|
||||
public function testGetUnchangedFields(): void
|
||||
{
|
||||
$fieldDAO = new FieldDAO('email', new NormalizedValueDAO('email', 'test@test.com'));
|
||||
|
||||
$objectChangeDAO = new ObjectChangeDAO('foo', 'bar', 1, 'contact', 1);
|
||||
$objectChangeDAO->addField($fieldDAO, ReportFieldDAO::FIELD_UNCHANGED);
|
||||
|
||||
$unchangedFields = $objectChangeDAO->getUnchangedFields();
|
||||
Assert::assertCount(1, $unchangedFields);
|
||||
Assert::assertArrayHasKey('email', $unchangedFields);
|
||||
Assert::assertSame($fieldDAO, $unchangedFields['email']);
|
||||
}
|
||||
|
||||
public function testSetAndGetObjectMapping(): void
|
||||
{
|
||||
$objectChangeDAO = new ObjectChangeDAO('foo', 'bar', 1, 'contact', 1);
|
||||
$objectMapping = new ObjectMapping();
|
||||
|
||||
$objectChangeDAO->setObjectMapping($objectMapping);
|
||||
|
||||
Assert::assertSame($objectMapping, $objectChangeDAO->getObjectMapping());
|
||||
}
|
||||
|
||||
public function testThatFieldCanBeRemoved(): void
|
||||
{
|
||||
$objectChangeDAO = new ObjectChangeDAO('foo', 'bar', 1, 'contact', 1);
|
||||
$value = new NormalizedValueDAO('type', 1);
|
||||
$field = new FieldDAO('fieldName', $value);
|
||||
|
||||
Assert::assertCount(0, $objectChangeDAO->getFields());
|
||||
$objectChangeDAO->addField($field);
|
||||
Assert::assertCount(1, $objectChangeDAO->getFields());
|
||||
$objectChangeDAO->removeField('fieldName');
|
||||
Assert::assertCount(0, $objectChangeDAO->getFields());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\DAO\Sync\Order;
|
||||
|
||||
use Mautic\IntegrationsBundle\Entity\ObjectMapping;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\ObjectMappingsDAO;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ObjectMappingsDAOTest extends TestCase
|
||||
{
|
||||
public function testGetters(): void
|
||||
{
|
||||
$objectMappings = new ObjectMappingsDAO();
|
||||
|
||||
$objectMappings->addNewObjectMapping((new ObjectMapping())->setIntegrationObjectName('foonew'));
|
||||
$objectMappings->addNewObjectMapping((new ObjectMapping())->setIntegrationObjectName('barnew'));
|
||||
$mappings = $objectMappings->getNewMappings();
|
||||
Assert::assertCount(2, $mappings);
|
||||
Assert::assertEquals('foonew', $mappings[0]->getIntegrationObjectName());
|
||||
Assert::assertEquals('barnew', $mappings[1]->getIntegrationObjectName());
|
||||
|
||||
$objectMappings->addUpdatedObjectMapping((new ObjectMapping())->setIntegrationObjectName('fooupdate'));
|
||||
$objectMappings->addUpdatedObjectMapping((new ObjectMapping())->setIntegrationObjectName('barupdate'));
|
||||
$mappings = $objectMappings->getUpdatedMappings();
|
||||
Assert::assertCount(2, $mappings);
|
||||
Assert::assertEquals('fooupdate', $mappings[0]->getIntegrationObjectName());
|
||||
Assert::assertEquals('barupdate', $mappings[1]->getIntegrationObjectName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\DAO\Sync\Order;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\ObjectChangeDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\OrderDAO;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class OrderDAOTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Test that the retry object is removed from the synced objects and the success object is present.
|
||||
*/
|
||||
public function testGetSuccessfullySyncedObjects(): void
|
||||
{
|
||||
$orderDAO = new OrderDAO(new \DateTimeImmutable(), false, 'IntegrationA');
|
||||
$successObject = new ObjectChangeDAO('IntegrationA', 'Contact', 'integration-id-1', 'lead', 123);
|
||||
$retryObject = new ObjectChangeDAO('IntegrationA', 'Contact', 'integration-id-2', 'lead', 456);
|
||||
|
||||
$orderDAO->addObjectChange($successObject);
|
||||
$orderDAO->addObjectChange($retryObject);
|
||||
$orderDAO->retrySyncLater($retryObject);
|
||||
|
||||
Assert::assertSame(
|
||||
[$successObject],
|
||||
$orderDAO->getSuccessfullySyncedObjects()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\DAO\Sync\Order;
|
||||
|
||||
use Mautic\IntegrationsBundle\Entity\ObjectMapping;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\RemappedObjectDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\ObjectChangeDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\OrderResultsDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotFoundException;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class OrderResultsDAOTest extends TestCase
|
||||
{
|
||||
public function testObjectsOrganizedByObjectName(): void
|
||||
{
|
||||
$newObjectMapping1 = new ObjectMapping();
|
||||
$newObjectMapping1->setIntegrationObjectName('foo');
|
||||
$newObjectMapping1->setIntegrationObjectId('abc');
|
||||
$newObjectMapping2 = new ObjectMapping();
|
||||
$newObjectMapping2->setIntegrationObjectName('bar');
|
||||
$newObjectMapping2->setIntegrationObjectId('efg');
|
||||
$newObjectMappings = [$newObjectMapping1, $newObjectMapping2];
|
||||
|
||||
$updatedObjectMapping1 = new ObjectMapping();
|
||||
$updatedObjectMapping1->setIntegrationObjectName('foo');
|
||||
$updatedObjectMapping1->setIntegrationObjectId('hij');
|
||||
$updatedObjectMapping2 = new ObjectMapping();
|
||||
$updatedObjectMapping2->setIntegrationObjectName('bar');
|
||||
$updatedObjectMapping1->setIntegrationObjectId('klm');
|
||||
$updatedObjectMappings = [$updatedObjectMapping1, $updatedObjectMapping2];
|
||||
|
||||
$remappedObjects = [
|
||||
new RemappedObjectDAO('foobar', 'oldfoo', 'oldfoo1', 'foo', 'foo1'),
|
||||
new RemappedObjectDAO('foobar', 'oldbar', 'oldbar1', 'bar', 'bar1'),
|
||||
];
|
||||
|
||||
$deletedObjects = [
|
||||
new ObjectChangeDAO('foobar', 'foo', 'foo1', 'contact', 1),
|
||||
new ObjectChangeDAO('foobar', 'bar', 'bar1', 'company', 1),
|
||||
];
|
||||
|
||||
$orderResults = new OrderResultsDAO($newObjectMappings, $updatedObjectMappings, $remappedObjects, $deletedObjects);
|
||||
|
||||
$fooNewObjectMappings = $orderResults->getNewObjectMappings('foo');
|
||||
Assert::assertCount(1, $fooNewObjectMappings);
|
||||
Assert::assertEquals('abc', $fooNewObjectMappings[0]->getIntegrationObjectId());
|
||||
|
||||
$barNewObjectMappings = $orderResults->getNewObjectMappings('bar');
|
||||
Assert::assertCount(1, $barNewObjectMappings);
|
||||
Assert::assertEquals('efg', $barNewObjectMappings[0]->getIntegrationObjectId());
|
||||
|
||||
$fooRemappedObjects = $orderResults->getRemappedObjects('foo');
|
||||
Assert::assertCount(1, $fooRemappedObjects);
|
||||
Assert::assertEquals('foo1', $fooRemappedObjects[0]->getNewObjectId());
|
||||
|
||||
$barRemappedObjects = $orderResults->getRemappedObjects('bar');
|
||||
Assert::assertCount(1, $barRemappedObjects);
|
||||
Assert::assertEquals('bar1', $barRemappedObjects[0]->getNewObjectId());
|
||||
|
||||
$fooDeletedObjects = $orderResults->getDeletedObjects('foo');
|
||||
Assert::assertCount(1, $fooDeletedObjects);
|
||||
Assert::assertEquals('foo1', $fooDeletedObjects[0]->getObjectId());
|
||||
|
||||
$barDeletedObjects = $orderResults->getDeletedObjects('bar');
|
||||
Assert::assertCount(1, $barDeletedObjects);
|
||||
Assert::assertEquals('bar1', $barDeletedObjects[0]->getObjectId());
|
||||
}
|
||||
|
||||
public function testExceptionThrownIfObjectNotFoundForNewObjectMappings(): void
|
||||
{
|
||||
$this->expectException(ObjectNotFoundException::class);
|
||||
|
||||
$orderResults = new OrderResultsDAO([], [], [], []);
|
||||
$orderResults->getNewObjectMappings('foo');
|
||||
}
|
||||
|
||||
public function testExceptionThrownIfObjectNotFoundForUpdatedObjectMappings(): void
|
||||
{
|
||||
$this->expectException(ObjectNotFoundException::class);
|
||||
|
||||
$orderResults = new OrderResultsDAO([], [], [], []);
|
||||
$orderResults->getUpdatedObjectMappings('foo');
|
||||
}
|
||||
|
||||
public function testExceptionThrownIfObjectNotFoundForRemappedObjects(): void
|
||||
{
|
||||
$this->expectException(ObjectNotFoundException::class);
|
||||
|
||||
$orderResults = new OrderResultsDAO([], [], [], []);
|
||||
$orderResults->getRemappedObjects('foo');
|
||||
}
|
||||
|
||||
public function testExceptionThrownIfObjectNotFoundForDeletedObjects(): void
|
||||
{
|
||||
$this->expectException(ObjectNotFoundException::class);
|
||||
|
||||
$orderResults = new OrderResultsDAO([], [], [], []);
|
||||
$orderResults->getDeletedObjects('foo');
|
||||
}
|
||||
|
||||
public function testGetObjectMappingsReturnsMergedNewAndUpdated(): void
|
||||
{
|
||||
$newObjectMapping = new ObjectMapping();
|
||||
$newObjectMapping->setIntegrationObjectName('foo');
|
||||
$newObjectMapping->setIntegrationObjectId('abc');
|
||||
|
||||
$updatedObjectMapping = new ObjectMapping();
|
||||
$updatedObjectMapping->setIntegrationObjectName('foo');
|
||||
$updatedObjectMapping->setIntegrationObjectId('hij');
|
||||
|
||||
$orderResults = new OrderResultsDAO([$newObjectMapping], [$updatedObjectMapping], [], []);
|
||||
|
||||
$objectMappings = $orderResults->getObjectMappings('foo');
|
||||
Assert::assertCount(2, $objectMappings);
|
||||
Assert::assertEquals('abc', $objectMappings[0]->getIntegrationObjectId());
|
||||
Assert::assertEquals('hij', $objectMappings[1]->getIntegrationObjectId());
|
||||
|
||||
$objectMappings = $orderResults->getObjectMappings('bar');
|
||||
Assert::assertEmpty($objectMappings);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Entity\ObjectMapping;
|
||||
use Mautic\IntegrationsBundle\Entity\ObjectMappingRepository;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectFindEvent;
|
||||
use Mautic\IntegrationsBundle\IntegrationEvents;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\MappingManualDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\UpdatedObjectMappingDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\FieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\ObjectDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectDeletedException;
|
||||
use Mautic\IntegrationsBundle\Sync\Helper\MappingHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Company;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ObjectProvider;
|
||||
use Mautic\LeadBundle\Field\FieldsWithUniqueIdentifier;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class MappingHelperTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var MockObject&FieldsWithUniqueIdentifier
|
||||
*/
|
||||
private MockObject $fieldsWithUniqueIdentifier;
|
||||
|
||||
/**
|
||||
* @var ObjectProvider&MockObject
|
||||
*/
|
||||
private MockObject $objectProvider;
|
||||
|
||||
/**
|
||||
* @var EventDispatcherInterface&MockObject
|
||||
*/
|
||||
private MockObject $dispatcher;
|
||||
|
||||
/**
|
||||
* @var ObjectMappingRepository&MockObject
|
||||
*/
|
||||
private MockObject $objectMappingRepository;
|
||||
|
||||
private MappingHelper $mappingHelper;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->objectProvider = $this->createMock(ObjectProvider::class);
|
||||
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||
$this->objectMappingRepository = $this->createMock(ObjectMappingRepository::class);
|
||||
$this->fieldsWithUniqueIdentifier = $this->createMock(FieldsWithUniqueIdentifier::class);
|
||||
$this->mappingHelper = new MappingHelper(
|
||||
$this->fieldsWithUniqueIdentifier,
|
||||
$this->objectMappingRepository,
|
||||
$this->objectProvider,
|
||||
$this->dispatcher
|
||||
);
|
||||
}
|
||||
|
||||
public function testObjectReturnedIfKnownMappingExists(): void
|
||||
{
|
||||
$mappingManual = new MappingManualDAO('test');
|
||||
$integrationObjectDAO = new ObjectDAO('Object', 1);
|
||||
|
||||
$internalObjectDAO = [
|
||||
'internal_object_id' => 1,
|
||||
'last_sync_date' => '2018-10-01 00:00:00',
|
||||
'is_deleted' => 0,
|
||||
];
|
||||
|
||||
$this->objectMappingRepository->expects($this->once())
|
||||
->method('getInternalObject')
|
||||
->willReturn($internalObjectDAO);
|
||||
|
||||
$internalObjectName = 'Contact';
|
||||
$foundInternalObject = $this->mappingHelper->findMauticObject($mappingManual, $internalObjectName, $integrationObjectDAO);
|
||||
|
||||
Assert::assertEquals($internalObjectName, $foundInternalObject->getObject());
|
||||
Assert::assertEquals($internalObjectDAO['internal_object_id'], $foundInternalObject->getObjectId());
|
||||
Assert::assertEquals($internalObjectDAO['last_sync_date'], $foundInternalObject->getChangeDateTime()->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
public function testMauticObjectSearchedAndEmptyObjectReturnedIfNoIdentifierFieldsAreMapped(): void
|
||||
{
|
||||
$this->fieldsWithUniqueIdentifier->expects($this->once())
|
||||
->method('getFieldsWithUniqueIdentifier')
|
||||
->willReturn([]);
|
||||
|
||||
$mappingManual = $this->createMock(MappingManualDAO::class);
|
||||
$internalObjectName = 'Contact';
|
||||
$integrationObjectDAO = new ObjectDAO('Object', 1);
|
||||
|
||||
$foundInternalObject = $this->mappingHelper->findMauticObject($mappingManual, $internalObjectName, $integrationObjectDAO);
|
||||
|
||||
Assert::assertEquals($internalObjectName, $foundInternalObject->getObject());
|
||||
Assert::assertEquals(null, $foundInternalObject->getObjectId());
|
||||
}
|
||||
|
||||
public function testEmptyObjectIsReturnedWhenMauticContactIsNotFound(): void
|
||||
{
|
||||
$this->fieldsWithUniqueIdentifier->expects($this->once())
|
||||
->method('getFieldsWithUniqueIdentifier')
|
||||
->willReturn(
|
||||
[
|
||||
'email' => 'Email',
|
||||
]
|
||||
);
|
||||
|
||||
$internalObject = new Contact();
|
||||
$internalObjectName = Contact::NAME;
|
||||
$integrationObjectDAO = new ObjectDAO('Object', 1);
|
||||
$integrationObjectDAO->addField(new FieldDAO('integration_email', new NormalizedValueDAO('email', 'test@test.com')));
|
||||
|
||||
$mappingManual = $this->createMock(MappingManualDAO::class);
|
||||
$mappingManual->expects($this->once())
|
||||
->method('getIntegrationMappedField')
|
||||
->with($integrationObjectDAO->getObject(), $internalObjectName, 'email')
|
||||
->willReturn('integration_email');
|
||||
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByName')
|
||||
->with($internalObjectName)
|
||||
->willReturn($internalObject);
|
||||
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->callback(
|
||||
function (InternalObjectFindEvent $event) use ($internalObject) {
|
||||
Assert::assertSame($internalObject, $event->getObject());
|
||||
Assert::assertSame(['email' => 'test@test.com'], $event->getFieldValues());
|
||||
|
||||
return true;
|
||||
}
|
||||
),
|
||||
IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORDS
|
||||
);
|
||||
|
||||
$foundInternalObject = $this->mappingHelper->findMauticObject($mappingManual, $internalObjectName, $integrationObjectDAO);
|
||||
|
||||
Assert::assertEquals($internalObjectName, $foundInternalObject->getObject());
|
||||
Assert::assertEquals(null, $foundInternalObject->getObjectId());
|
||||
}
|
||||
|
||||
public function testMauticContactIsFoundAndReturnedAsObjectDAO(): void
|
||||
{
|
||||
$this->fieldsWithUniqueIdentifier->expects($this->once())
|
||||
->method('getFieldsWithUniqueIdentifier')
|
||||
->willReturn(
|
||||
[
|
||||
'email' => 'Email',
|
||||
]
|
||||
);
|
||||
|
||||
$internalObject = new Contact();
|
||||
$internalObjectName = Contact::NAME;
|
||||
$changeDateTime = new \DateTime();
|
||||
$integrationObjectDAO = new ObjectDAO('Object', 1, $changeDateTime);
|
||||
$integrationObjectDAO->addField(new FieldDAO('integration_email', new NormalizedValueDAO('email', 'test@test.com')));
|
||||
|
||||
$mappingManual = $this->createMock(MappingManualDAO::class);
|
||||
$mappingManual->expects($this->once())
|
||||
->method('getIntegrationMappedField')
|
||||
->with($integrationObjectDAO->getObject(), $internalObjectName, 'email')
|
||||
->willReturn('integration_email');
|
||||
$mappingManual->expects($this->exactly(2))
|
||||
->method('getIntegration')
|
||||
->willReturn('Test');
|
||||
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByName')
|
||||
->with($internalObjectName)
|
||||
->willReturn($internalObject);
|
||||
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->callback(
|
||||
function (InternalObjectFindEvent $event) use ($internalObject) {
|
||||
Assert::assertSame($internalObject, $event->getObject());
|
||||
Assert::assertSame(['email' => 'test@test.com'], $event->getFieldValues());
|
||||
|
||||
// Mock a subscriber.
|
||||
$event->setFoundObjects(
|
||||
[
|
||||
[
|
||||
'id' => 3,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
),
|
||||
IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORDS
|
||||
);
|
||||
|
||||
$foundInternalObject = $this->mappingHelper->findMauticObject($mappingManual, $internalObjectName, $integrationObjectDAO);
|
||||
|
||||
Assert::assertEquals($internalObjectName, $foundInternalObject->getObject());
|
||||
Assert::assertEquals(3, $foundInternalObject->getObjectId());
|
||||
}
|
||||
|
||||
public function testMauticCompanyIsFoundAndReturnedAsObjectDAO(): void
|
||||
{
|
||||
$this->fieldsWithUniqueIdentifier->expects($this->once())
|
||||
->method('getFieldsWithUniqueIdentifier')
|
||||
->willReturn(
|
||||
[
|
||||
'email' => 'Email',
|
||||
]
|
||||
);
|
||||
|
||||
$internalObject = new Company();
|
||||
$internalObjectName = Company::NAME;
|
||||
$changeDateTime = new \DateTime();
|
||||
$integrationObjectDAO = new ObjectDAO('Object', 1, $changeDateTime);
|
||||
$integrationObjectDAO->addField(new FieldDAO('integration_email', new NormalizedValueDAO('email', 'test@test.com')));
|
||||
|
||||
$mappingManual = $this->createMock(MappingManualDAO::class);
|
||||
$mappingManual->expects($this->once())
|
||||
->method('getIntegrationMappedField')
|
||||
->with($integrationObjectDAO->getObject(), $internalObjectName, 'email')
|
||||
->willReturn('integration_email');
|
||||
$mappingManual->expects($this->exactly(2))
|
||||
->method('getIntegration')
|
||||
->willReturn('Test');
|
||||
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByName')
|
||||
->with($internalObjectName)
|
||||
->willReturn($internalObject);
|
||||
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->callback(
|
||||
function (InternalObjectFindEvent $event) use ($internalObject) {
|
||||
Assert::assertSame($internalObject, $event->getObject());
|
||||
Assert::assertSame(['email' => 'test@test.com'], $event->getFieldValues());
|
||||
|
||||
// Mock a subscriber.
|
||||
$event->setFoundObjects(
|
||||
[
|
||||
[
|
||||
'id' => 3,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
),
|
||||
IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORDS
|
||||
);
|
||||
|
||||
$foundInternalObject = $this->mappingHelper->findMauticObject(
|
||||
$mappingManual,
|
||||
$internalObjectName,
|
||||
$integrationObjectDAO
|
||||
);
|
||||
|
||||
Assert::assertEquals($internalObjectName, $foundInternalObject->getObject());
|
||||
Assert::assertEquals(3, $foundInternalObject->getObjectId());
|
||||
}
|
||||
|
||||
public function testIntegrationObjectReturnedIfMapped(): void
|
||||
{
|
||||
$objectName = 'Object';
|
||||
$objectId = 1;
|
||||
$changeDateTime = '2018-10-08 00:00:00';
|
||||
|
||||
$this->objectMappingRepository->expects($this->once())
|
||||
->method('getIntegrationObject')
|
||||
->willReturn(
|
||||
[
|
||||
'is_deleted' => false,
|
||||
'integration_object_id' => $objectId,
|
||||
'last_sync_date' => $changeDateTime,
|
||||
]
|
||||
);
|
||||
|
||||
$foundIntegrationObject = $this->mappingHelper->findIntegrationObject('Test', $objectName, new ObjectDAO('Contact', 1));
|
||||
|
||||
Assert::assertEquals($objectName, $foundIntegrationObject->getObject());
|
||||
Assert::assertEquals($objectId, $foundIntegrationObject->getObjectId());
|
||||
Assert::assertEquals($changeDateTime, $foundIntegrationObject->getChangeDateTime()->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
public function testEmptyIntegrationObjectReturnedIfNotMapped(): void
|
||||
{
|
||||
$objectName = 'Object';
|
||||
$this->objectMappingRepository->expects($this->once())
|
||||
->method('getIntegrationObject')
|
||||
->willReturn([]);
|
||||
|
||||
$foundIntegrationObject = $this->mappingHelper->findIntegrationObject('Test', $objectName, new ObjectDAO('Contact', 1));
|
||||
|
||||
Assert::assertEquals($objectName, $foundIntegrationObject->getObject());
|
||||
Assert::assertEquals(null, $foundIntegrationObject->getObjectId());
|
||||
Assert::assertEquals(null, $foundIntegrationObject->getChangeDateTime());
|
||||
}
|
||||
|
||||
public function testDeletedExceptionThrownIfIntegrationObjectHasBeenNotedAsDeleted(): void
|
||||
{
|
||||
$this->expectException(ObjectDeletedException::class);
|
||||
|
||||
$objectName = 'Object';
|
||||
$objectId = 1;
|
||||
$changeDateTime = '2018-10-08 00:00:00';
|
||||
|
||||
$this->objectMappingRepository->expects($this->once())
|
||||
->method('getIntegrationObject')
|
||||
->willReturn(
|
||||
[
|
||||
'is_deleted' => true,
|
||||
'integration_object_id' => $objectId,
|
||||
'last_sync_date' => $changeDateTime,
|
||||
]
|
||||
);
|
||||
|
||||
$this->mappingHelper->findIntegrationObject('Test', $objectName, new ObjectDAO('Contact', 1));
|
||||
}
|
||||
|
||||
public function testObjectMappingIsInjectedIntoUpdatedObjectMappingDAO(): void
|
||||
{
|
||||
$objectMapping = new ObjectMapping();
|
||||
$objectMapping->setIntegration('foobar');
|
||||
$objectMapping->setIntegrationObjectName('foo');
|
||||
$objectMapping->setIntegrationObjectId('1');
|
||||
|
||||
$this->objectMappingRepository->expects($this->once())
|
||||
->method('findOneBy')
|
||||
->with(
|
||||
[
|
||||
'integration' => $objectMapping->getIntegration(),
|
||||
'integrationObjectName' => $objectMapping->getIntegrationObjectName(),
|
||||
'integrationObjectId' => $objectMapping->getIntegrationObjectId(),
|
||||
]
|
||||
)
|
||||
->willReturn($objectMapping);
|
||||
|
||||
$updatedObjectMappingDAO = new UpdatedObjectMappingDAO('foobar', 'foo', 1, new \DateTime());
|
||||
|
||||
$this->mappingHelper->updateObjectMappings([$updatedObjectMappingDAO]);
|
||||
|
||||
Assert::assertSame($objectMapping, $updatedObjectMappingDAO->getObjectMapping());
|
||||
}
|
||||
|
||||
public function testObjectMappingIsNotSetIfObjectMappingNotFoundWhenAttemptingToUpdate(): void
|
||||
{
|
||||
$this->objectMappingRepository->expects($this->once())
|
||||
->method('findOneBy')
|
||||
->with(
|
||||
[
|
||||
'integration' => 'foobar',
|
||||
'integrationObjectName' => 'foo',
|
||||
'integrationObjectId' => 1,
|
||||
]
|
||||
);
|
||||
|
||||
$updatedObjectMappingDAO = new UpdatedObjectMappingDAO('foobar', 'foo', 1, new \DateTime());
|
||||
|
||||
$this->mappingHelper->updateObjectMappings([$updatedObjectMappingDAO]);
|
||||
|
||||
Assert::assertEmpty($updatedObjectMappingDAO->getObjectMapping());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\MappingManualDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\RelationsDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\FieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\ObjectDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\RelationDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\ReportDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\ReferenceValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Helper\MappingHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\Helper\RelationsHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\MauticSyncDataExchange;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class RelationsHelperTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var MappingHelper|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $mappingHelper;
|
||||
|
||||
private RelationsHelper $relationsHelper;
|
||||
|
||||
/**
|
||||
* @var ReportDAO|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $syncReport;
|
||||
|
||||
/**
|
||||
* @var MappingManualDAO|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $mappingManual;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->mappingHelper = $this->createMock(MappingHelper::class);
|
||||
$this->relationsHelper = new RelationsHelper($this->mappingHelper);
|
||||
$this->syncReport = $this->createMock(ReportDAO::class);
|
||||
$this->mappingManual = $this->createMock(MappingManualDAO::class);
|
||||
}
|
||||
|
||||
public function testProcessRelationsWithUnsychronisedObjects(): void
|
||||
{
|
||||
$integrationObjectId = 'IntegrationId-123';
|
||||
$integrationRelObjectId = 'IntegrationId-456';
|
||||
$relObjectName = 'Account';
|
||||
|
||||
$relationObject = new RelationDAO(
|
||||
'Contact',
|
||||
'AccountId',
|
||||
$relObjectName,
|
||||
$integrationObjectId,
|
||||
$integrationRelObjectId
|
||||
);
|
||||
|
||||
$relationsObject = new RelationsDAO();
|
||||
$relationsObject->addRelation($relationObject);
|
||||
|
||||
$this->syncReport->expects($this->once())
|
||||
->method('getRelations')
|
||||
->willReturn($relationsObject);
|
||||
|
||||
$this->mappingManual->expects($this->any())
|
||||
->method('getMappedInternalObjectsNames')
|
||||
->willReturn(['company']);
|
||||
|
||||
$internalObject = new ObjectDAO('company', null);
|
||||
|
||||
$this->mappingHelper->expects($this->once())
|
||||
->method('findMauticObject')
|
||||
->willReturn($internalObject);
|
||||
|
||||
$this->relationsHelper->processRelations($this->mappingManual, $this->syncReport);
|
||||
|
||||
$objectsToSynchronize = $this->relationsHelper->getObjectsToSynchronize();
|
||||
|
||||
$this->assertCount(1, $objectsToSynchronize);
|
||||
|
||||
$this->assertEquals($objectsToSynchronize[0]->getObjectId(), $integrationRelObjectId);
|
||||
$this->assertEquals($objectsToSynchronize[0]->getObject(), $relObjectName);
|
||||
}
|
||||
|
||||
public function testProcessRelationsWithSychronisedObjects(): void
|
||||
{
|
||||
$integrationObjectId = 'IntegrationId-123';
|
||||
$integrationRelObjectId = 'IntegrationId-456';
|
||||
$internalRelObjectId = 13;
|
||||
$relObjectName = 'Account';
|
||||
$relFieldName = 'AccountId';
|
||||
|
||||
$referenceVlaue = new ReferenceValueDAO();
|
||||
$normalizedValue = new NormalizedValueDAO(NormalizedValueDAO::REFERENCE_TYPE, $integrationRelObjectId, $referenceVlaue);
|
||||
|
||||
$fieldDao = new FieldDAO('AccountId', $normalizedValue);
|
||||
$objectDao = new ObjectDAO('Contact', 1);
|
||||
$objectDao->addField($fieldDao);
|
||||
|
||||
$relationObject = new RelationDAO(
|
||||
'Contact',
|
||||
$relFieldName,
|
||||
$relObjectName,
|
||||
$integrationObjectId,
|
||||
$integrationRelObjectId
|
||||
);
|
||||
|
||||
$relationsObject = new RelationsDAO();
|
||||
$relationsObject->addRelation($relationObject);
|
||||
|
||||
$this->syncReport->expects($this->once())
|
||||
->method('getRelations')
|
||||
->willReturn($relationsObject);
|
||||
|
||||
$this->syncReport->expects($this->once())
|
||||
->method('getObject')
|
||||
->willReturn($objectDao);
|
||||
|
||||
$this->mappingManual->expects($this->any())
|
||||
->method('getMappedInternalObjectsNames')
|
||||
->willReturn(['company']);
|
||||
|
||||
$internalObject = new ObjectDAO(MauticSyncDataExchange::OBJECT_COMPANY, $internalRelObjectId);
|
||||
|
||||
$this->mappingHelper->expects($this->once())
|
||||
->method('findMauticObject')
|
||||
->willReturn($internalObject);
|
||||
|
||||
$this->relationsHelper->processRelations($this->mappingManual, $this->syncReport);
|
||||
|
||||
$objectsToSynchronize = $this->relationsHelper->getObjectsToSynchronize();
|
||||
|
||||
$this->assertCount(0, $objectsToSynchronize);
|
||||
$this->assertEquals($internalRelObjectId, $objectDao->getField($relFieldName)->getValue()->getNormalizedValue()->getValue());
|
||||
$this->assertEquals(MauticSyncDataExchange::OBJECT_COMPANY, $objectDao->getField($relFieldName)->getValue()->getNormalizedValue()->getType());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\Helper\SyncDateHelper;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class SyncDateHelperTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var SyncDateHelper|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $syncDateHelper;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->syncDateHelper = $this->getMockBuilder(SyncDateHelper::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['getLastSyncDateForObject'])
|
||||
->getMock();
|
||||
}
|
||||
|
||||
public function testSpecifiedFromDateTimeIsReturned(): void
|
||||
{
|
||||
$syncFromDateTime = new \DateTimeImmutable('2018-10-08 00:00:00');
|
||||
|
||||
$this->syncDateHelper->setSyncDateTimes($syncFromDateTime);
|
||||
|
||||
Assert::assertEquals($syncFromDateTime, $this->syncDateHelper->getSyncFromDateTime('Test', 'Object'));
|
||||
}
|
||||
|
||||
public function testLastSyncDateForIntegrationSyncObjectIsReturned(): void
|
||||
{
|
||||
$objectLastSyncDate = new \DateTimeImmutable('2018-10-08 00:00:00');
|
||||
|
||||
$this->syncDateHelper->method('getLastSyncDateForObject')
|
||||
->willReturn($objectLastSyncDate);
|
||||
|
||||
Assert::assertEquals($objectLastSyncDate, $this->syncDateHelper->getSyncFromDateTime('Test', 'Object'));
|
||||
}
|
||||
|
||||
public function testSyncToDateTimeIsReturnedIfSpecified(): void
|
||||
{
|
||||
$syncToDateTime = new \DateTimeImmutable('2018-10-08 00:00:00');
|
||||
|
||||
$this->syncDateHelper->setSyncDateTimes(null, $syncToDateTime);
|
||||
|
||||
Assert::assertEquals($syncToDateTime, $this->syncDateHelper->getSyncToDateTime());
|
||||
}
|
||||
|
||||
public function testSyncDateTimeIsReturnedForSyncToDateTimeIfNotSpecified(): void
|
||||
{
|
||||
$this->syncDateHelper->setSyncDateTimes();
|
||||
|
||||
Assert::assertInstanceOf(\DateTimeImmutable::class, $this->syncDateHelper->getSyncToDateTime());
|
||||
}
|
||||
|
||||
public function testThatSetInternalSyncStartDateTimeMethodUsesSyncToDateValueIfItIsEarlier(): void
|
||||
{
|
||||
// Although $fiveSecondsBefore value is expected to be in UTC timezone let's use another timezone
|
||||
// to check how the method handles such cases.
|
||||
$fiveSecondsBefore = new \DateTime('-5 seconds', new \DateTimeZone('Etc/GMT-5'));
|
||||
$this->syncDateHelper->setSyncDateTimes(null, $fiveSecondsBefore);
|
||||
$this->syncDateHelper->setInternalSyncStartDateTime();
|
||||
$internalSyncStartDateTime = $this->syncDateHelper->getInternalSyncStartDateTime();
|
||||
Assert::assertSame($fiveSecondsBefore->getTimestamp(), $internalSyncStartDateTime->getTimestamp());
|
||||
}
|
||||
|
||||
public function testThatSetInternalSyncStartDateTimeMethodUsesNowIfItIsEarlier(): void
|
||||
{
|
||||
// Although $fiveSecondsAfter value is expected to be in UTC timezone let's use another timezone
|
||||
// to check how the method handles such cases.
|
||||
$fiveSecondsAfter = new \DateTime('+5 seconds', new \DateTimeZone('Etc/GMT+5'));
|
||||
$this->syncDateHelper->setSyncDateTimes(null, $fiveSecondsAfter);
|
||||
$this->syncDateHelper->setInternalSyncStartDateTime();
|
||||
$now = new \DateTime('now', new \DateTimeZone('UTC'));
|
||||
$internalSyncStartDateTime = $this->syncDateHelper->getInternalSyncStartDateTime();
|
||||
$difference = $internalSyncStartDateTime->getTimestamp() - $now->getTimestamp();
|
||||
|
||||
// Add a 1 second buffer in case there is some delay
|
||||
Assert::assertTrue((1 >= $difference) && (-1 < $difference));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\Notification\Handler;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\HandlerNotSupportedException;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Handler\HandlerContainer;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Handler\HandlerInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class HandlerContainerTest extends TestCase
|
||||
{
|
||||
public function testExceptionThrownIfIntegrationNotFound(): void
|
||||
{
|
||||
$this->expectException(HandlerNotSupportedException::class);
|
||||
|
||||
$handler = new HandlerContainer();
|
||||
$handler->getHandler('foo', 'bar');
|
||||
}
|
||||
|
||||
public function testExceptionThrownIfObjectNotFound(): void
|
||||
{
|
||||
$this->expectException(HandlerNotSupportedException::class);
|
||||
|
||||
$handler = new HandlerContainer();
|
||||
|
||||
$mockHandler = $this->createMock(HandlerInterface::class);
|
||||
$mockHandler->method('getIntegration')
|
||||
->willReturn('foo');
|
||||
$mockHandler->method('getSupportedObject')
|
||||
->willReturn('bogus');
|
||||
|
||||
$handler->registerHandler($mockHandler);
|
||||
|
||||
$handler->getHandler('foo', 'bar');
|
||||
}
|
||||
|
||||
public function testHandlerIsRegistered(): void
|
||||
{
|
||||
$handler = new HandlerContainer();
|
||||
|
||||
$mockHandler = $this->createMock(HandlerInterface::class);
|
||||
$mockHandler->method('getIntegration')
|
||||
->willReturn('foo');
|
||||
$mockHandler->method('getSupportedObject')
|
||||
->willReturn('bar');
|
||||
|
||||
$handler->registerHandler($mockHandler);
|
||||
|
||||
$returnedHandler = $handler->getHandler('foo', 'bar');
|
||||
|
||||
$this->assertEquals($mockHandler, $returnedHandler);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\Notification\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectOwnerEvent;
|
||||
use Mautic\IntegrationsBundle\IntegrationEvents;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotSupportedException;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Helper\OwnerProvider;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ObjectProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class OwnerProviderTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var ObjectProvider|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $objectProvider;
|
||||
|
||||
/**
|
||||
* @var EventDispatcherInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $dispatcher;
|
||||
|
||||
private OwnerProvider $ownerProvider;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->objectProvider = $this->createMock(ObjectProvider::class);
|
||||
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||
$this->ownerProvider = new OwnerProvider($this->dispatcher, $this->objectProvider);
|
||||
}
|
||||
|
||||
public function testGetOwnersForObjectIdsWithoutIds(): void
|
||||
{
|
||||
$this->objectProvider->expects($this->never())
|
||||
->method('getObjectByName');
|
||||
|
||||
$this->assertSame([], $this->ownerProvider->getOwnersForObjectIds(Contact::NAME, []));
|
||||
}
|
||||
|
||||
public function testGetOwnersForObjectIdsWithUnknownObject(): void
|
||||
{
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByName')
|
||||
->with('Unicorn')
|
||||
->willThrowException(new ObjectNotFoundException('Unicorn'));
|
||||
|
||||
$this->expectException(ObjectNotSupportedException::class);
|
||||
|
||||
$this->ownerProvider->getOwnersForObjectIds('Unicorn', [123]);
|
||||
}
|
||||
|
||||
public function testGetOwnersForObjectIdsWithKnownObject(): void
|
||||
{
|
||||
$internalObject = new Contact();
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByName')
|
||||
->with(Contact::NAME)
|
||||
->willReturn($internalObject);
|
||||
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->callback(function (InternalObjectOwnerEvent $event) use ($internalObject) {
|
||||
$this->assertSame($internalObject, $event->getObject());
|
||||
$this->assertSame([123], $event->getObjectIds());
|
||||
|
||||
// Simulate a subscriber. Format: [object_id => owner_id].
|
||||
$event->setOwners([$event->getObjectIds()[0] => 456]);
|
||||
|
||||
return true;
|
||||
}),
|
||||
IntegrationEvents::INTEGRATION_FIND_OWNER_IDS
|
||||
);
|
||||
|
||||
$this->assertSame([123 => 456], $this->ownerProvider->getOwnersForObjectIds(Contact::NAME, [123]));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\Notification\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectRouteEvent;
|
||||
use Mautic\IntegrationsBundle\IntegrationEvents;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotSupportedException;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Helper\RouteHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Company;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ObjectProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class RouteHelperTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var ObjectProvider|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $objectProvider;
|
||||
|
||||
/**
|
||||
* @var EventDispatcherInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $dispatcher;
|
||||
|
||||
private RouteHelper $routeHelper;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->objectProvider = $this->createMock(ObjectProvider::class);
|
||||
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||
$this->routeHelper = new RouteHelper($this->objectProvider, $this->dispatcher);
|
||||
}
|
||||
|
||||
public function testContactRoute(): void
|
||||
{
|
||||
$internalObject = new Contact();
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByName')
|
||||
->with(Contact::NAME)
|
||||
->willReturn($internalObject);
|
||||
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->callback(function (InternalObjectRouteEvent $event) use ($internalObject) {
|
||||
$this->assertSame($internalObject, $event->getObject());
|
||||
$this->assertSame(1, $event->getId());
|
||||
|
||||
// Mock a subscriber.
|
||||
$event->setRoute('route/for/id/1');
|
||||
|
||||
return true;
|
||||
}),
|
||||
IntegrationEvents::INTEGRATION_BUILD_INTERNAL_OBJECT_ROUTE
|
||||
);
|
||||
|
||||
$this->routeHelper->getRoute(Contact::NAME, 1);
|
||||
}
|
||||
|
||||
public function testCompanyRoute(): void
|
||||
{
|
||||
$internalObject = new Company();
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByName')
|
||||
->with(Company::NAME)
|
||||
->willReturn($internalObject);
|
||||
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->callback(function (InternalObjectRouteEvent $event) use ($internalObject) {
|
||||
$this->assertSame($internalObject, $event->getObject());
|
||||
$this->assertSame(1, $event->getId());
|
||||
|
||||
// Mock a subscriber.
|
||||
$event->setRoute('route/for/id/1');
|
||||
|
||||
return true;
|
||||
}),
|
||||
IntegrationEvents::INTEGRATION_BUILD_INTERNAL_OBJECT_ROUTE
|
||||
);
|
||||
|
||||
$this->routeHelper->getRoute(Company::NAME, 1);
|
||||
}
|
||||
|
||||
public function testExceptionThrownWithUnsupportedObject(): void
|
||||
{
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByName')
|
||||
->with('FooBar')
|
||||
->willThrowException(new ObjectNotFoundException('FooBar object not found'));
|
||||
|
||||
$this->dispatcher->expects($this->never())->method('dispatch');
|
||||
|
||||
$this->expectException(ObjectNotSupportedException::class);
|
||||
|
||||
$this->routeHelper->getRoute('FooBar', 1);
|
||||
}
|
||||
|
||||
public function testLink(): void
|
||||
{
|
||||
$internalObject = new Contact();
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByName')
|
||||
->with(Contact::NAME)
|
||||
->willReturn($internalObject);
|
||||
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->callback(function (InternalObjectRouteEvent $event) use ($internalObject) {
|
||||
$this->assertSame($internalObject, $event->getObject());
|
||||
$this->assertSame(1, $event->getId());
|
||||
|
||||
// Mock a subscriber.
|
||||
$event->setRoute('route/for/id/1');
|
||||
|
||||
return true;
|
||||
}),
|
||||
IntegrationEvents::INTEGRATION_BUILD_INTERNAL_OBJECT_ROUTE
|
||||
);
|
||||
|
||||
$link = $this->routeHelper->getLink(Contact::NAME, 1, 'Hello');
|
||||
$this->assertEquals('<a href="route/for/id/1">Hello</a>', $link);
|
||||
}
|
||||
|
||||
public function testLinkCsv(): void
|
||||
{
|
||||
$internalObject = new Contact();
|
||||
$this->objectProvider->expects($this->exactly(2))
|
||||
->method('getObjectByName')
|
||||
->with(Contact::NAME)
|
||||
->willReturn($internalObject);
|
||||
$matcher = $this->exactly(2);
|
||||
|
||||
$this->dispatcher->expects($matcher)
|
||||
->method('dispatch')->willReturnCallback(function (...$parameters) use ($matcher, $internalObject) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectRouteEvent $event) use ($internalObject) {
|
||||
$this->assertSame($internalObject, $event->getObject());
|
||||
$this->assertSame(1, $event->getId());
|
||||
|
||||
// Mock a subscriber.
|
||||
$event->setRoute('route/for/id/1');
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_BUILD_INTERNAL_OBJECT_ROUTE, $parameters[1]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectRouteEvent $event) use ($internalObject) {
|
||||
$this->assertSame($internalObject, $event->getObject());
|
||||
$this->assertSame(2, $event->getId());
|
||||
|
||||
// Mock a subscriber.
|
||||
$event->setRoute('route/for/id/2');
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_BUILD_INTERNAL_OBJECT_ROUTE, $parameters[1]);
|
||||
}
|
||||
|
||||
return $parameters[0];
|
||||
});
|
||||
|
||||
$csv = $this->routeHelper->getLinkCsv(Contact::NAME, [1, 2]);
|
||||
$this->assertEquals('[<a href="route/for/id/1">1</a>], [<a href="route/for/id/2">2</a>]', $csv);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\Notification\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Helper\OwnerProvider;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Helper\RouteHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Helper\UserHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Helper\UserNotificationBuilder;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Helper\UserNotificationHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Writer;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class UserNotificationHelperTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var Writer|MockObject
|
||||
*/
|
||||
private MockObject $writer;
|
||||
|
||||
/**
|
||||
* @var UserHelper|MockObject
|
||||
*/
|
||||
private MockObject $userHelper;
|
||||
|
||||
/**
|
||||
* @var OwnerProvider|MockObject
|
||||
*/
|
||||
private MockObject $ownerProvider;
|
||||
|
||||
/**
|
||||
* @var RouteHelper|MockObject
|
||||
*/
|
||||
private MockObject $routeHelper;
|
||||
|
||||
/**
|
||||
* @var TranslatorInterface|MockObject
|
||||
*/
|
||||
private MockObject $translator;
|
||||
|
||||
private UserNotificationHelper $helper;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->writer = $this->createMock(Writer::class);
|
||||
$this->userHelper = $this->createMock(UserHelper::class);
|
||||
$this->ownerProvider = $this->createMock(OwnerProvider::class);
|
||||
$this->routeHelper = $this->createMock(RouteHelper::class);
|
||||
$this->translator = $this->createMock(TranslatorInterface::class);
|
||||
|
||||
$userNotificationBuilder = new UserNotificationBuilder($this->userHelper,
|
||||
$this->ownerProvider,
|
||||
$this->routeHelper,
|
||||
$this->translator
|
||||
);
|
||||
$this->helper = new UserNotificationHelper($this->writer, $userNotificationBuilder);
|
||||
}
|
||||
|
||||
public function testNotificationSentToOwner(): void
|
||||
{
|
||||
$this->ownerProvider->expects($this->once())
|
||||
->method('getOwnersForObjectIds')
|
||||
->with(Contact::NAME, [1])
|
||||
->willReturn([['owner_id' => 1, 'id' => 1]]);
|
||||
|
||||
$this->userHelper->expects($this->never())
|
||||
->method('getAdminUsers');
|
||||
$matcher = $this->exactly(2);
|
||||
|
||||
$this->translator->expects($matcher)
|
||||
->method('trans')->willReturnCallback(function (...$parameters) use ($matcher) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('mautic.integration.sync.user_notification.header', $parameters[0]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('mautic.integration.sync.user_notification.sync_error', $parameters[0]);
|
||||
}
|
||||
|
||||
return 'test';
|
||||
});
|
||||
|
||||
$this->writer->expects($this->once())
|
||||
->method('writeUserNotification');
|
||||
|
||||
$this->routeHelper->expects($this->once())
|
||||
->method('getLink');
|
||||
|
||||
$this->helper->writeNotification('test', 'test', 'test', Contact::NAME, 1, 'foobar');
|
||||
}
|
||||
|
||||
public function testNotificationSentToAdmins(): void
|
||||
{
|
||||
$this->ownerProvider->expects($this->once())
|
||||
->method('getOwnersForObjectIds')
|
||||
->with(Contact::NAME, [1])
|
||||
->willReturn([]);
|
||||
|
||||
$this->userHelper->expects($this->once())
|
||||
->method('getAdminUsers')
|
||||
->willReturn([1]);
|
||||
$matcher = $this->exactly(2);
|
||||
|
||||
$this->translator->expects($matcher)
|
||||
->method('trans')->willReturnCallback(function (...$parameters) use ($matcher) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('mautic.integration.sync.user_notification.header', $parameters[0]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('mautic.integration.sync.user_notification.sync_error', $parameters[0]);
|
||||
}
|
||||
|
||||
return 'test';
|
||||
});
|
||||
|
||||
$this->writer->expects($this->once())
|
||||
->method('writeUserNotification');
|
||||
|
||||
$this->routeHelper->expects($this->once())
|
||||
->method('getLink');
|
||||
|
||||
$this->helper->writeNotification('test', 'test', 'test', Contact::NAME, 1, 'foobar');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\Notification\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Helper\OwnerProvider;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Helper\RouteHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Helper\UserHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Helper\UserSummaryNotificationHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Writer;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class UserSummaryNotificationHelperTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var Writer|MockObject
|
||||
*/
|
||||
private MockObject $writer;
|
||||
|
||||
/**
|
||||
* @var UserHelper|MockObject
|
||||
*/
|
||||
private MockObject $userHelper;
|
||||
|
||||
/**
|
||||
* @var OwnerProvider|MockObject
|
||||
*/
|
||||
private MockObject $ownerProvider;
|
||||
|
||||
/**
|
||||
* @var RouteHelper|MockObject
|
||||
*/
|
||||
private MockObject $routeHelper;
|
||||
|
||||
/**
|
||||
* @var TranslatorInterface|MockObject
|
||||
*/
|
||||
private MockObject $translator;
|
||||
|
||||
private UserSummaryNotificationHelper $helper;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->writer = $this->createMock(Writer::class);
|
||||
$this->userHelper = $this->createMock(UserHelper::class);
|
||||
$this->ownerProvider = $this->createMock(OwnerProvider::class);
|
||||
$this->routeHelper = $this->createMock(RouteHelper::class);
|
||||
$this->translator = $this->createMock(TranslatorInterface::class);
|
||||
$this->helper = new UserSummaryNotificationHelper(
|
||||
$this->writer,
|
||||
$this->userHelper,
|
||||
$this->ownerProvider,
|
||||
$this->routeHelper,
|
||||
$this->translator
|
||||
);
|
||||
}
|
||||
|
||||
public function testNotificationSentToOwner(): void
|
||||
{
|
||||
$this->helper->storeSummaryNotification('Foo', 'Bar', 1);
|
||||
$this->helper->storeSummaryNotification('Bar', 'Foo', 2);
|
||||
$matcher = $this->exactly(2);
|
||||
|
||||
$this->ownerProvider->expects($matcher)
|
||||
->method('getOwnersForObjectIds')->willReturnCallback(function (...$parameters) use ($matcher) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(Contact::NAME, $parameters[0]);
|
||||
$this->assertSame([1 => 1], $parameters[1]);
|
||||
|
||||
return [['owner_id' => 1, 'id' => 1]];
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(Contact::NAME, $parameters[0]);
|
||||
$this->assertSame([2 => 2], $parameters[1]);
|
||||
|
||||
return [['owner_id' => 2, 'id' => 2]];
|
||||
}
|
||||
});
|
||||
|
||||
$this->userHelper->expects($this->never())
|
||||
->method('getAdminUsers');
|
||||
$matcher = $this->exactly(4);
|
||||
|
||||
$this->translator->expects($matcher)
|
||||
->method('trans')->willReturnCallback(function (...$parameters) use ($matcher) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('mautic.integration.sync.user_notification.header', $parameters[0]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('test', $parameters[0]);
|
||||
}
|
||||
if (3 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('mautic.integration.sync.user_notification.header', $parameters[0]);
|
||||
}
|
||||
if (4 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('test', $parameters[0]);
|
||||
}
|
||||
|
||||
return 'test';
|
||||
});
|
||||
|
||||
$this->writer->expects($this->exactly(2))
|
||||
->method('writeUserNotification');
|
||||
|
||||
$this->routeHelper->expects($this->exactly(2))
|
||||
->method('getLinkCsv');
|
||||
|
||||
$this->helper->writeNotifications(Contact::NAME, 'test');
|
||||
}
|
||||
|
||||
public function testNotificationSentToAdmins(): void
|
||||
{
|
||||
$this->helper->storeSummaryNotification('Foo', 'Bar', 1);
|
||||
$this->helper->storeSummaryNotification('Bar', 'Foo', 2);
|
||||
$matcher = $this->exactly(2);
|
||||
|
||||
$this->ownerProvider->expects($matcher)
|
||||
->method('getOwnersForObjectIds')->willReturnCallback(function (...$parameters) use ($matcher) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(Contact::NAME, $parameters[0]);
|
||||
$this->assertSame([1 => 1], $parameters[1]);
|
||||
|
||||
return [];
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(Contact::NAME, $parameters[0]);
|
||||
$this->assertSame([2 => 2], $parameters[1]);
|
||||
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
$this->userHelper->expects($this->exactly(2))
|
||||
->method('getAdminUsers')
|
||||
->willReturn([1]);
|
||||
$matcher = $this->exactly(4);
|
||||
|
||||
$this->translator->expects($matcher)
|
||||
->method('trans')->willReturnCallback(function (...$parameters) use ($matcher) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('mautic.integration.sync.user_notification.header', $parameters[0]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('test', $parameters[0]);
|
||||
}
|
||||
if (3 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('mautic.integration.sync.user_notification.header', $parameters[0]);
|
||||
}
|
||||
if (4 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('test', $parameters[0]);
|
||||
}
|
||||
|
||||
return 'test';
|
||||
});
|
||||
|
||||
$this->writer->expects($this->exactly(2))
|
||||
->method('writeUserNotification');
|
||||
|
||||
$this->routeHelper->expects($this->exactly(2))
|
||||
->method('getLinkCsv');
|
||||
|
||||
$this->helper->writeNotifications(Contact::NAME, 'test');
|
||||
}
|
||||
|
||||
public function testMoreThan25ObjectsResultInCountMessage(): void
|
||||
{
|
||||
$counter = 1;
|
||||
$withIds = [];
|
||||
do {
|
||||
$this->helper->storeSummaryNotification('Foo', 'Bar', $counter);
|
||||
$withIds[$counter] = $counter;
|
||||
++$counter;
|
||||
} while ($counter <= 26);
|
||||
|
||||
$this->ownerProvider->expects($this->once())
|
||||
->method('getOwnersForObjectIds')
|
||||
->with(Contact::NAME, $withIds)
|
||||
->willReturn([]);
|
||||
|
||||
$this->userHelper->expects($this->once())
|
||||
->method('getAdminUsers')
|
||||
->willReturn([1]);
|
||||
|
||||
$this->translator->expects($this->exactly(2))
|
||||
->method('trans')
|
||||
->willReturnCallback(
|
||||
function ($string, $params) {
|
||||
$expectedStrings = [
|
||||
'mautic.integration.sync.user_notification.header',
|
||||
'mautic.integration.sync.user_notification.count_message',
|
||||
];
|
||||
|
||||
if (!in_array($string, $expectedStrings)) {
|
||||
$this->fail($string.' is not an expected translation key');
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
);
|
||||
|
||||
$this->writer->expects($this->exactly(1))
|
||||
->method('writeUserNotification');
|
||||
|
||||
$this->routeHelper->expects($this->never())
|
||||
->method('getLinkCsv');
|
||||
|
||||
$this->helper->writeNotifications(Contact::NAME, 'test');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncDataExchange\Helper;
|
||||
|
||||
use Mautic\ChannelBundle\Helper\ChannelListHelper;
|
||||
use Mautic\IntegrationsBundle\Event\MauticSyncFieldsLoadEvent;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Helper\FieldHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ObjectProvider;
|
||||
use Mautic\IntegrationsBundle\Sync\VariableExpresser\VariableExpresserHelperInterface;
|
||||
use Mautic\LeadBundle\Field\FieldsWithUniqueIdentifier;
|
||||
use Mautic\LeadBundle\Model\FieldModel;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class FieldHelperTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var FieldModel&MockObject
|
||||
*/
|
||||
private MockObject $fieldModel;
|
||||
|
||||
/**
|
||||
* @var MockObject&FieldsWithUniqueIdentifier
|
||||
*/
|
||||
private MockObject $fieldsWithUniqueIdentifier;
|
||||
|
||||
/**
|
||||
* @var VariableExpresserHelperInterface&MockObject
|
||||
*/
|
||||
private MockObject $variableExpresserHelper;
|
||||
|
||||
/**
|
||||
* @var ChannelListHelper&MockObject
|
||||
*/
|
||||
private MockObject $channelListHelper;
|
||||
|
||||
private MockObject $eventDispatcher;
|
||||
|
||||
/**
|
||||
* @var MauticSyncFieldsLoadEvent&MockObject
|
||||
*/
|
||||
private MockObject $mauticSyncFieldsLoadEvent;
|
||||
|
||||
/**
|
||||
* @var ObjectProvider&MockObject
|
||||
*/
|
||||
private MockObject $objectProvider;
|
||||
|
||||
private FieldHelper $fieldHelper;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->fieldModel = $this->createMock(FieldModel::class);
|
||||
$this->variableExpresserHelper = $this->createMock(VariableExpresserHelperInterface::class);
|
||||
$this->channelListHelper = $this->createMock(ChannelListHelper::class);
|
||||
$this->objectProvider = $this->createMock(ObjectProvider::class);
|
||||
$this->channelListHelper->method('getFeatureChannels')
|
||||
->willReturn(['Email' => 'email']);
|
||||
|
||||
$this->mauticSyncFieldsLoadEvent = $this->createMock(MauticSyncFieldsLoadEvent::class);
|
||||
$this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||
$this->eventDispatcher->method('dispatch')
|
||||
->willReturn($this->mauticSyncFieldsLoadEvent);
|
||||
|
||||
$this->fieldsWithUniqueIdentifier = $this->createMock(FieldsWithUniqueIdentifier::class);
|
||||
|
||||
$this->fieldHelper = new FieldHelper(
|
||||
$this->fieldModel,
|
||||
$this->fieldsWithUniqueIdentifier,
|
||||
$this->variableExpresserHelper,
|
||||
$this->channelListHelper,
|
||||
$this->createMock(TranslatorInterface::class),
|
||||
$this->eventDispatcher,
|
||||
$this->objectProvider
|
||||
);
|
||||
}
|
||||
|
||||
public function testContactSyncFieldsReturned(): void
|
||||
{
|
||||
$objectName = Contact::NAME;
|
||||
$syncFields = ['email' => 'Email'];
|
||||
|
||||
$this->mauticSyncFieldsLoadEvent->method('getObjectName')
|
||||
->willReturn($objectName);
|
||||
$this->mauticSyncFieldsLoadEvent->method('getFields')
|
||||
->willReturn($syncFields);
|
||||
|
||||
$this->fieldModel->method('getFieldList')
|
||||
->willReturn($syncFields);
|
||||
|
||||
$fields = $this->fieldHelper->getSyncFields($objectName);
|
||||
|
||||
$this->assertEquals(
|
||||
[
|
||||
'email',
|
||||
'mautic_internal_contact_timeline',
|
||||
'mautic_internal_dnc_email',
|
||||
'mautic_internal_id',
|
||||
],
|
||||
array_keys($fields)
|
||||
);
|
||||
}
|
||||
|
||||
public function testCompanySyncFieldsReturned(): void
|
||||
{
|
||||
$objectName = Contact::NAME;
|
||||
$syncFields = ['email' => 'Email'];
|
||||
|
||||
$this->mauticSyncFieldsLoadEvent->method('getObjectName')
|
||||
->willReturn($objectName);
|
||||
$this->mauticSyncFieldsLoadEvent->method('getFields')
|
||||
->willReturn($syncFields);
|
||||
|
||||
$this->fieldModel->method('getFieldList')
|
||||
->willReturn($syncFields);
|
||||
|
||||
$fields = $this->fieldHelper->getSyncFields($objectName);
|
||||
|
||||
$this->assertEquals(
|
||||
[
|
||||
'email',
|
||||
'mautic_internal_contact_timeline',
|
||||
'mautic_internal_dnc_email',
|
||||
'mautic_internal_id',
|
||||
],
|
||||
array_keys($fields)
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetRequiredFieldsForContact(): void
|
||||
{
|
||||
$this->fieldModel->expects($this->once())
|
||||
->method('getFieldList')
|
||||
->willReturn(['some fields']);
|
||||
|
||||
$this->fieldsWithUniqueIdentifier->expects($this->once())
|
||||
->method('getFieldsWithUniqueIdentifier')
|
||||
->willReturn(['some unique fields']);
|
||||
|
||||
$this->assertSame(
|
||||
['some fields', 'some unique fields'],
|
||||
$this->fieldHelper->getRequiredFields('lead')
|
||||
);
|
||||
|
||||
// Call it for the second time to ensure the result was cached,
|
||||
$this->assertSame(
|
||||
['some fields', 'some unique fields'],
|
||||
$this->fieldHelper->getRequiredFields('lead')
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetRequiredFieldsForCompany(): void
|
||||
{
|
||||
$this->fieldModel->expects($this->once())
|
||||
->method('getFieldList')
|
||||
->willReturn(['some fields']);
|
||||
|
||||
$this->fieldsWithUniqueIdentifier->expects($this->never())
|
||||
->method('getFieldsWithUniqueIdentifier');
|
||||
|
||||
$this->assertSame(
|
||||
['some fields'],
|
||||
$this->fieldHelper->getRequiredFields('company')
|
||||
);
|
||||
|
||||
// Call it for the second time to ensure the result was cached,
|
||||
$this->assertSame(
|
||||
['some fields'],
|
||||
$this->fieldHelper->getRequiredFields('company')
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetFieldObjectName(): void
|
||||
{
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByName')
|
||||
->with(Contact::NAME)
|
||||
->willReturn(new Contact());
|
||||
|
||||
$this->assertSame(
|
||||
Contact::ENTITY,
|
||||
$this->fieldHelper->getFieldObjectName(Contact::NAME)
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetNormalizedFieldType(): void
|
||||
{
|
||||
$this->assertEquals(NormalizedValueDAO::BOOLEAN_TYPE, $this->fieldHelper->getNormalizedFieldType('boolean'));
|
||||
$this->assertEquals(NormalizedValueDAO::DATETIME_TYPE, $this->fieldHelper->getNormalizedFieldType('date'));
|
||||
$this->assertEquals(NormalizedValueDAO::DATETIME_TYPE, $this->fieldHelper->getNormalizedFieldType('datetime'));
|
||||
$this->assertEquals(NormalizedValueDAO::DATETIME_TYPE, $this->fieldHelper->getNormalizedFieldType('time'));
|
||||
$this->assertEquals(NormalizedValueDAO::FLOAT_TYPE, $this->fieldHelper->getNormalizedFieldType('number'));
|
||||
$this->assertEquals(NormalizedValueDAO::SELECT_TYPE, $this->fieldHelper->getNormalizedFieldType('select'));
|
||||
$this->assertEquals(NormalizedValueDAO::MULTISELECT_TYPE, $this->fieldHelper->getNormalizedFieldType('multiselect'));
|
||||
$this->assertEquals(NormalizedValueDAO::STRING_TYPE, $this->fieldHelper->getNormalizedFieldType('default'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncDataExchange\Internal\Executioner\Exception;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Executioner\Exception\FieldSchemaNotFoundException;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class FieldSchemaNotFoundExceptionTest extends TestCase
|
||||
{
|
||||
public function testMessage(): void
|
||||
{
|
||||
$object = 'SomeObject';
|
||||
$alias = 'SomeAlias';
|
||||
$exception = new FieldSchemaNotFoundException($object, $alias);
|
||||
$expected = sprintf('Schema for alias "%s" of object "%s" not found', $alias, $object);
|
||||
Assert::assertSame($expected, $exception->getMessage());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncDataExchange\Internal\Executioner;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\FieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\ObjectChangeDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\BulkNotification;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Executioner\FieldValidator;
|
||||
use Mautic\LeadBundle\Entity\LeadFieldRepository;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class FieldValidatorTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var LeadFieldRepository&MockObject
|
||||
*/
|
||||
private MockObject $leadFieldRepository;
|
||||
|
||||
/**
|
||||
* @var BulkNotification&MockObject
|
||||
*/
|
||||
private MockObject $bulkNotification;
|
||||
|
||||
private FieldValidator $fieldValidator;
|
||||
|
||||
protected function setup(): void
|
||||
{
|
||||
$this->leadFieldRepository = $this->createMock(LeadFieldRepository::class);
|
||||
$this->bulkNotification = $this->createMock(BulkNotification::class);
|
||||
$this->fieldValidator = new FieldValidator($this->leadFieldRepository, $this->bulkNotification);
|
||||
}
|
||||
|
||||
public function testValidateFields(): void
|
||||
{
|
||||
$this->leadFieldRepository->method('getFieldSchemaData')
|
||||
->willReturn([
|
||||
'company' => [
|
||||
'alias' => 'company',
|
||||
'label' => 'Company',
|
||||
'type' => 'text',
|
||||
'isUniqueIdentifer' => false,
|
||||
'charLengthLimit' => 5,
|
||||
],
|
||||
'email' => [
|
||||
'alias' => 'email',
|
||||
'label' => 'Email',
|
||||
'type' => 'email',
|
||||
'isUniqueIdentifer' => true,
|
||||
'charLengthLimit' => 64,
|
||||
],
|
||||
'date' => [
|
||||
'alias' => 'date',
|
||||
'label' => 'Date',
|
||||
'type' => 'date',
|
||||
'isUniqueIdentifer' => false,
|
||||
'charLengthLimit' => null,
|
||||
],
|
||||
'time' => [
|
||||
'alias' => 'time',
|
||||
'label' => 'Time',
|
||||
'type' => 'time',
|
||||
'isUniqueIdentifer' => false,
|
||||
'charLengthLimit' => null,
|
||||
],
|
||||
'bool' => [
|
||||
'alias' => 'bool',
|
||||
'label' => 'Bool',
|
||||
'type' => 'boolean',
|
||||
'isUniqueIdentifer' => false,
|
||||
'charLengthLimit' => null,
|
||||
],
|
||||
'number' => [
|
||||
'alias' => 'number',
|
||||
'label' => 'Number',
|
||||
'type' => 'number',
|
||||
'isUniqueIdentifer' => false,
|
||||
'charLengthLimit' => null,
|
||||
],
|
||||
]);
|
||||
|
||||
$firstChangedObject = (new ObjectChangeDAO('integration', 'lead', '1', 'Lead', '00Q4H00000juXes'))
|
||||
->addField(new FieldDAO('company', new NormalizedValueDAO('string', 'Some company', 'Some company')))
|
||||
->addField(new FieldDAO('email', new NormalizedValueDAO('string', 'email@domain.tld', 'email@domain.tld')))
|
||||
->addField(new FieldDAO('unknown', new NormalizedValueDAO('string', 'something', 'something')));
|
||||
$secondChangedObject = (new ObjectChangeDAO('integration', 'lead', '1', 'Lead', '00Q4H00000juXes'))
|
||||
->addField(new FieldDAO('date', new NormalizedValueDAO('date', '2020-09-08 10:05:35', '2020-09-08 10:05:35')))
|
||||
->addField(new FieldDAO('time', new NormalizedValueDAO('date', '2020-09-08', '2020-09-08')))
|
||||
->addField(new FieldDAO('number', new NormalizedValueDAO('url', 'https://url', 'https://url')))
|
||||
->addField(new FieldDAO('bool', new NormalizedValueDAO('boolean', 1, true)));
|
||||
$changedObjects = [
|
||||
$firstChangedObject,
|
||||
$secondChangedObject,
|
||||
];
|
||||
|
||||
$matcher = $this->exactly(3);
|
||||
|
||||
$this->bulkNotification->expects($matcher)
|
||||
->method('addNotification')
|
||||
->willReturnCallback(function (...$parameters) use ($matcher, $firstChangedObject, $secondChangedObject) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->getNotificationAssertion($parameters, "Custom field 'Company' with value 'Some company' exceeded maximum allowed length and was ignored during the sync. Your integration integration plugin may be configured improperly.", $firstChangedObject, 'company', 'length');
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->getNotificationAssertion($parameters, "Custom field 'Time' of type 'time' did not match integration type 'date' and was ignored during the sync. Your integration integration plugin may be configured improperly.", $secondChangedObject, 'time', 'type');
|
||||
}
|
||||
if (3 === $matcher->numberOfInvocations()) {
|
||||
$this->getNotificationAssertion($parameters, "Custom field 'Number' of type 'number' did not match integration type 'url' and was ignored during the sync. Your integration integration plugin may be configured improperly.", $secondChangedObject, 'number', 'type');
|
||||
}
|
||||
});
|
||||
|
||||
$this->bulkNotification->expects($this->once())
|
||||
->method('flush');
|
||||
|
||||
$this->fieldValidator->validateFields('lead', $changedObjects);
|
||||
|
||||
Assert::assertNull($firstChangedObject->getField('company'));
|
||||
Assert::assertInstanceOf(FieldDAO::class, $firstChangedObject->getField('email'));
|
||||
Assert::assertInstanceOf(FieldDAO::class, $firstChangedObject->getField('unknown'));
|
||||
Assert::assertInstanceOf(FieldDAO::class, $secondChangedObject->getField('date'));
|
||||
Assert::assertNull($secondChangedObject->getField('time'));
|
||||
Assert::assertNull($secondChangedObject->getField('number'));
|
||||
Assert::assertInstanceOf(FieldDAO::class, $secondChangedObject->getField('bool'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $parameters
|
||||
*/
|
||||
private function getNotificationAssertion(array $parameters, string $message, ObjectChangeDAO $changedObject, string $fieldName, string $type): void
|
||||
{
|
||||
Assert::assertSame($parameters[0], $changedObject->getIntegration().'-'.$changedObject->getObject().'-'.$fieldName.'-'.$type);
|
||||
Assert::assertSame($parameters[1], $message);
|
||||
Assert::assertSame($parameters[2], $changedObject->getIntegration());
|
||||
Assert::assertSame($parameters[3], sprintf('%s %s', $changedObject->getMappedObjectId(), $changedObject->getObject()));
|
||||
Assert::assertSame($parameters[4], $changedObject->getObject());
|
||||
Assert::assertSame($parameters[5], 0);
|
||||
Assert::assertSame($parameters[6], sprintf('%s %s %s', $changedObject->getIntegration(), $changedObject->getObject(), $changedObject->getMappedObjectId()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,440 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncDataExchange\Internal\Executioner;
|
||||
|
||||
use Mautic\IntegrationsBundle\Entity\ObjectMapping;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectCreateEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectUpdateEvent;
|
||||
use Mautic\IntegrationsBundle\IntegrationEvents;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\UpdatedObjectMappingDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\ObjectChangeDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\OrderDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Sync\Helper\MappingHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Executioner\FieldValidatorInterface;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Executioner\OrderExecutioner;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Executioner\ReferenceResolverInterface;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Company;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\ObjectInterface;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ObjectProvider;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class OrderExecutionerTest extends TestCase
|
||||
{
|
||||
private const INTEGRATION_NAME = 'Test';
|
||||
|
||||
/**
|
||||
* @var MappingHelper|MockObject
|
||||
*/
|
||||
private MockObject $mappingHelper;
|
||||
|
||||
/**
|
||||
* @var EventDispatcherInterface|MockObject
|
||||
*/
|
||||
private MockObject $dispatcher;
|
||||
|
||||
/**
|
||||
* @var ObjectProvider|MockObject
|
||||
*/
|
||||
private MockObject $objectProvider;
|
||||
|
||||
private OrderExecutioner $orderExecutioner;
|
||||
|
||||
/**
|
||||
* @var ReferenceResolverInterface|MockObject
|
||||
*/
|
||||
private MockObject $referenceResolver;
|
||||
|
||||
/**
|
||||
* @var FieldValidatorInterface|MockObject
|
||||
*/
|
||||
private MockObject $fieldValidator;
|
||||
|
||||
protected function setup(): void
|
||||
{
|
||||
$this->mappingHelper = $this->createMock(MappingHelper::class);
|
||||
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||
$this->objectProvider = $this->createMock(ObjectProvider::class);
|
||||
$this->referenceResolver = $this->createMock(ReferenceResolverInterface::class);
|
||||
$this->fieldValidator = $this->createMock(FieldValidatorInterface::class);
|
||||
$this->orderExecutioner = new OrderExecutioner(
|
||||
$this->mappingHelper,
|
||||
$this->dispatcher,
|
||||
$this->objectProvider,
|
||||
$this->referenceResolver,
|
||||
$this->fieldValidator
|
||||
);
|
||||
}
|
||||
|
||||
public function testContactsAreUpdatedAndCreated(): void
|
||||
{
|
||||
$this->objectProvider->expects($this->exactly(2))
|
||||
->method('getObjectByName')
|
||||
->with(Contact::NAME)
|
||||
->willReturn(new Contact());
|
||||
$matcher = $this->exactly(2);
|
||||
|
||||
$this->dispatcher->expects($matcher)
|
||||
->method('dispatch')->willReturnCallback(function (...$parameters) use ($matcher) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectUpdateEvent $event) {
|
||||
Assert::assertSame(Contact::NAME, $event->getObject()->getName());
|
||||
Assert::assertSame([1, 2], $event->getIdentifiedObjectIds());
|
||||
Assert::assertCount(2, $event->getUpdateObjects());
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_UPDATE_INTERNAL_OBJECTS, $parameters[1]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectCreateEvent $event) {
|
||||
Assert::assertSame(Contact::NAME, $event->getObject()->getName());
|
||||
Assert::assertCount(1, $event->getCreateObjects());
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_CREATE_INTERNAL_OBJECTS, $parameters[1]);
|
||||
}
|
||||
|
||||
return $parameters[0];
|
||||
});
|
||||
|
||||
$this->mappingHelper->expects($this->exactly(1))
|
||||
->method('updateObjectMappings');
|
||||
|
||||
$this->mappingHelper->expects($this->exactly(1))
|
||||
->method('saveObjectMappings');
|
||||
|
||||
$this->referenceResolver->expects($this->exactly(2))
|
||||
->method('resolveReferences');
|
||||
|
||||
$this->fieldValidator->expects($this->exactly(2))
|
||||
->method('validateFields');
|
||||
|
||||
$this->orderExecutioner->execute($this->getSyncOrder(Contact::NAME));
|
||||
}
|
||||
|
||||
public function testUpdatedObjectsWithoutAnObjectMappingDoesNotGetAddedToObjectMappingsDAO(): void
|
||||
{
|
||||
$this->objectProvider->expects($this->exactly(2))
|
||||
->method('getObjectByName')
|
||||
->with(Contact::NAME)
|
||||
->willReturn(new Contact());
|
||||
$matcher = $this->exactly(2);
|
||||
|
||||
$this->dispatcher->expects($matcher)
|
||||
->method('dispatch')->willReturnCallback(function (...$parameters) use ($matcher) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectUpdateEvent $event) {
|
||||
Assert::assertSame(Contact::NAME, $event->getObject()->getName());
|
||||
Assert::assertSame([1, 2], $event->getIdentifiedObjectIds());
|
||||
Assert::assertCount(2, $event->getUpdateObjects());
|
||||
|
||||
$updatedObjectMappings = [];
|
||||
foreach ($event->getUpdateObjects() as $key => $updateObject) {
|
||||
$updatedObjectMappings[] = $updatedObjectMapping = new UpdatedObjectMappingDAO(
|
||||
$updateObject->getIntegration(),
|
||||
$updateObject->getObject(),
|
||||
$updateObject->getObjectId(),
|
||||
new \DateTime()
|
||||
);
|
||||
|
||||
if (0 !== $key) {
|
||||
// Only inject an object mapping for one of the objects
|
||||
break;
|
||||
}
|
||||
|
||||
$objectMapping = new ObjectMapping();
|
||||
$objectMapping->setIntegration($updateObject->getIntegration());
|
||||
$objectMapping->setIntegrationObjectName($updateObject->getObject());
|
||||
$objectMapping->setIntegrationObjectId($updateObject->getObjectId());
|
||||
$updatedObjectMapping->setObjectMapping($objectMapping);
|
||||
}
|
||||
|
||||
$event->setUpdatedObjectMappings($updatedObjectMappings);
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_UPDATE_INTERNAL_OBJECTS, $parameters[1]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectCreateEvent $event) {
|
||||
Assert::assertSame(Contact::NAME, $event->getObject()->getName());
|
||||
Assert::assertCount(1, $event->getCreateObjects());
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_CREATE_INTERNAL_OBJECTS, $parameters[1]);
|
||||
}
|
||||
|
||||
return $parameters[0];
|
||||
});
|
||||
|
||||
$this->mappingHelper->expects($this->exactly(1))
|
||||
->method('updateObjectMappings');
|
||||
|
||||
$this->mappingHelper->expects($this->exactly(1))
|
||||
->method('saveObjectMappings');
|
||||
|
||||
$this->referenceResolver->expects($this->exactly(2))
|
||||
->method('resolveReferences');
|
||||
|
||||
$this->fieldValidator->expects($this->exactly(2))
|
||||
->method('validateFields');
|
||||
|
||||
$this->orderExecutioner->execute($this->getSyncOrder(Contact::NAME));
|
||||
}
|
||||
|
||||
public function testCompaniesAreUpdatedAndCreated(): void
|
||||
{
|
||||
$this->objectProvider->expects($this->exactly(2))
|
||||
->method('getObjectByName')
|
||||
->with(Company::NAME)
|
||||
->willReturn(new Company());
|
||||
$matcher = $this->exactly(2);
|
||||
|
||||
$this->dispatcher->expects($matcher)
|
||||
->method('dispatch')->willReturnCallback(function (...$parameters) use ($matcher) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectUpdateEvent $event) {
|
||||
Assert::assertSame(Company::NAME, $event->getObject()->getName());
|
||||
Assert::assertSame([1, 2], $event->getIdentifiedObjectIds());
|
||||
Assert::assertCount(2, $event->getUpdateObjects());
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_UPDATE_INTERNAL_OBJECTS, $parameters[1]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectCreateEvent $event) {
|
||||
Assert::assertSame(Company::NAME, $event->getObject()->getName());
|
||||
Assert::assertCount(1, $event->getCreateObjects());
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_CREATE_INTERNAL_OBJECTS, $parameters[1]);
|
||||
}
|
||||
|
||||
return $parameters[0];
|
||||
});
|
||||
|
||||
$this->mappingHelper->expects($this->exactly(1))
|
||||
->method('updateObjectMappings');
|
||||
|
||||
$this->mappingHelper->expects($this->exactly(1))
|
||||
->method('saveObjectMappings');
|
||||
|
||||
$this->referenceResolver->expects($this->exactly(2))
|
||||
->method('resolveReferences');
|
||||
|
||||
$this->fieldValidator->expects($this->exactly(2))
|
||||
->method('validateFields');
|
||||
|
||||
$syncOrder = $this->getSyncOrder(Company::NAME);
|
||||
$this->orderExecutioner->execute($syncOrder);
|
||||
}
|
||||
|
||||
public function testMixedObjectsAreUpdatedAndCreated(): void
|
||||
{
|
||||
$matcher = $this->exactly(4);
|
||||
$this->objectProvider->expects($matcher)
|
||||
->method('getObjectByName')->willReturnCallback(function (...$parameters) use ($matcher) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(Contact::NAME, $parameters[0]);
|
||||
|
||||
return new Contact();
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(Company::NAME, $parameters[0]);
|
||||
|
||||
return new Company();
|
||||
}
|
||||
if (3 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(Contact::NAME, $parameters[0]);
|
||||
|
||||
return new Contact();
|
||||
}
|
||||
if (4 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(Company::NAME, $parameters[0]);
|
||||
|
||||
return new Company();
|
||||
}
|
||||
});
|
||||
$matcher = $this->exactly(4);
|
||||
|
||||
$this->dispatcher->expects($matcher)
|
||||
->method('dispatch')->willReturnCallback(function (...$parameters) use ($matcher) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectUpdateEvent $event) {
|
||||
Assert::assertSame(Contact::NAME, $event->getObject()->getName());
|
||||
|
||||
$updatedObjectMappings = [];
|
||||
foreach ($event->getUpdateObjects() as $updateObject) {
|
||||
$updatedObjectMappings[] = $updatedObjectMapping = new UpdatedObjectMappingDAO(
|
||||
$updateObject->getIntegration(),
|
||||
$updateObject->getObject(),
|
||||
$updateObject->getObjectId(),
|
||||
new \DateTime()
|
||||
);
|
||||
|
||||
$objectMapping = new ObjectMapping();
|
||||
$objectMapping->setIntegration($updateObject->getIntegration());
|
||||
$objectMapping->setIntegrationObjectName($updateObject->getObject());
|
||||
$objectMapping->setIntegrationObjectId($updateObject->getObjectId());
|
||||
$updatedObjectMapping->setObjectMapping($objectMapping);
|
||||
}
|
||||
$event->setUpdatedObjectMappings($updatedObjectMappings);
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_UPDATE_INTERNAL_OBJECTS, $parameters[1]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectUpdateEvent $event) {
|
||||
Assert::assertSame(Company::NAME, $event->getObject()->getName());
|
||||
|
||||
$updatedObjectMappings = [];
|
||||
foreach ($event->getUpdateObjects() as $updateObject) {
|
||||
$updatedObjectMappings[] = $updatedObjectMapping = new UpdatedObjectMappingDAO(
|
||||
$updateObject->getIntegration(),
|
||||
$updateObject->getObject(),
|
||||
$updateObject->getObjectId(),
|
||||
new \DateTime()
|
||||
);
|
||||
|
||||
$objectMapping = new ObjectMapping();
|
||||
$objectMapping->setIntegration($updateObject->getIntegration());
|
||||
$objectMapping->setIntegrationObjectName($updateObject->getObject());
|
||||
$objectMapping->setIntegrationObjectId($updateObject->getObjectId());
|
||||
$updatedObjectMapping->setObjectMapping($objectMapping);
|
||||
}
|
||||
|
||||
$event->setUpdatedObjectMappings($updatedObjectMappings);
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_UPDATE_INTERNAL_OBJECTS, $parameters[1]);
|
||||
}
|
||||
if (3 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectCreateEvent $event) {
|
||||
Assert::assertSame(Contact::NAME, $event->getObject()->getName());
|
||||
|
||||
$createdObjectMappings = [];
|
||||
foreach ($event->getCreateObjects() as $createObject) {
|
||||
$objectMapping = new ObjectMapping();
|
||||
$objectMapping->setIntegration($createObject->getIntegration());
|
||||
$objectMapping->setIntegrationObjectName($createObject->getObject());
|
||||
$objectMapping->setIntegrationObjectId($createObject->getObjectId());
|
||||
|
||||
$createdObjectMappings[] = $objectMapping;
|
||||
}
|
||||
$event->setObjectMappings($createdObjectMappings);
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_CREATE_INTERNAL_OBJECTS, $parameters[1]);
|
||||
}
|
||||
if (4 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectCreateEvent $event) {
|
||||
Assert::assertSame(Company::NAME, $event->getObject()->getName());
|
||||
|
||||
$createdObjectMappings = [];
|
||||
foreach ($event->getCreateObjects() as $createObject) {
|
||||
$objectMapping = new ObjectMapping();
|
||||
$objectMapping->setIntegration($createObject->getIntegration());
|
||||
$objectMapping->setIntegrationObjectName($createObject->getObject());
|
||||
$objectMapping->setIntegrationObjectId($createObject->getObjectId());
|
||||
|
||||
$createdObjectMappings[] = $objectMapping;
|
||||
}
|
||||
$event->setObjectMappings($createdObjectMappings);
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_CREATE_INTERNAL_OBJECTS, $parameters[1]);
|
||||
}
|
||||
|
||||
return $parameters[0];
|
||||
});
|
||||
|
||||
$this->mappingHelper->expects($this->exactly(2))
|
||||
->method('updateObjectMappings');
|
||||
|
||||
$this->mappingHelper->expects($this->exactly(2))
|
||||
->method('saveObjectMappings');
|
||||
|
||||
// Merge companies and contacts for the test
|
||||
$syncOrder = $this->getSyncOrder(Contact::NAME);
|
||||
$companySyncOrder = $this->getSyncOrder(Company::NAME);
|
||||
foreach ($companySyncOrder->getChangedObjectsByObjectType(Company::NAME) as $objectChange) {
|
||||
$syncOrder->addObjectChange($objectChange);
|
||||
}
|
||||
|
||||
$orderMappings = $this->orderExecutioner->execute($syncOrder);
|
||||
Assert::assertCount(4, $orderMappings->getUpdatedMappings());
|
||||
Assert::assertCount(2, $orderMappings->getNewMappings());
|
||||
}
|
||||
|
||||
public function testEmptyObjectsForUpdateDoesNothing(): void
|
||||
{
|
||||
$syncOrder = new OrderDAO(new \DateTimeImmutable(), false, self::INTEGRATION_NAME);
|
||||
$syncOrder->addObjectChange(new ObjectChangeDAO(self::INTEGRATION_NAME, 'bar', null, 'bar', 4));
|
||||
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with($this->isInstanceOf(InternalObjectCreateEvent::class), IntegrationEvents::INTEGRATION_CREATE_INTERNAL_OBJECTS);
|
||||
|
||||
$this->orderExecutioner->execute($syncOrder);
|
||||
}
|
||||
|
||||
public function testEmptyObjectsForCreateDoesNothing(): void
|
||||
{
|
||||
$syncOrder = new OrderDAO(new \DateTimeImmutable(), false, self::INTEGRATION_NAME);
|
||||
$syncOrder->addObjectChange(new ObjectChangeDAO(self::INTEGRATION_NAME, 'bar', 4, 'bar', 4));
|
||||
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with($this->isInstanceOf(InternalObjectUpdateEvent::class), IntegrationEvents::INTEGRATION_UPDATE_INTERNAL_OBJECTS);
|
||||
|
||||
$this->orderExecutioner->execute($syncOrder);
|
||||
}
|
||||
|
||||
public function testObjectNotFoundExceptionIsLoggedAndNothingElse(): void
|
||||
{
|
||||
$syncOrder = $this->getSyncOrder('foo');
|
||||
$syncOrder->addObjectChange(new ObjectChangeDAO(self::INTEGRATION_NAME, 'bar', 4, 'bar', 4));
|
||||
$syncOrder->addObjectChange(new ObjectChangeDAO(self::INTEGRATION_NAME, 'bar', null, 'bar', 4));
|
||||
|
||||
// update and create per object
|
||||
$this->objectProvider->expects($this->exactly(4))
|
||||
->method('getObjectByName')
|
||||
->willReturnCallback(
|
||||
function (string $objectName) {
|
||||
if ('bar' === $objectName) {
|
||||
throw new ObjectNotFoundException($objectName);
|
||||
}
|
||||
|
||||
return $this->createMock(ObjectInterface::class);
|
||||
}
|
||||
);
|
||||
|
||||
// only foo should recognized and processed
|
||||
$this->dispatcher->expects($this->exactly(2))
|
||||
->method('dispatch');
|
||||
|
||||
$this->orderExecutioner->execute($syncOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function getSyncOrder(string $objectName): OrderDAO
|
||||
{
|
||||
$syncOrder = new OrderDAO(new \DateTimeImmutable(), false, self::INTEGRATION_NAME);
|
||||
|
||||
// Two updates
|
||||
$syncOrder->addObjectChange(new ObjectChangeDAO(self::INTEGRATION_NAME, $objectName, 1, $objectName, 1));
|
||||
$syncOrder->addObjectChange(new ObjectChangeDAO(self::INTEGRATION_NAME, $objectName, 2, $objectName, 2));
|
||||
|
||||
// One create
|
||||
$syncOrder->addObjectChange(new ObjectChangeDAO(self::INTEGRATION_NAME, $objectName, null, $objectName, 3));
|
||||
|
||||
return $syncOrder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncDataExchange\Internal\Executioner;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Query\QueryBuilder;
|
||||
use Doctrine\DBAL\Result;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\FieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\ObjectChangeDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\ReferenceValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Executioner\ReferenceResolver;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ReferenceResolverTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var Connection|MockObject
|
||||
*/
|
||||
private MockObject $connection;
|
||||
|
||||
private ReferenceResolver $referenceResolver;
|
||||
|
||||
protected function setup(): void
|
||||
{
|
||||
$this->connection = $this->createMock(Connection::class);
|
||||
$this->referenceResolver = new ReferenceResolver($this->connection);
|
||||
}
|
||||
|
||||
public function testResolveLeadReferences(): void
|
||||
{
|
||||
$this->connection->method('createQueryBuilder')
|
||||
->willReturn($this->createQueryBuilder('Company name', false));
|
||||
|
||||
$companyReference = $this->createReference('company', 3);
|
||||
$userReference = $this->createReference('user', 4);
|
||||
$notFoundReference = $this->createReference('company', 5);
|
||||
|
||||
$changedObject = (new ObjectChangeDAO('integration', 'lead', '1', 'Lead', '00Q4H00000juXes'))
|
||||
->addField(new FieldDAO('company', new NormalizedValueDAO('reference', $companyReference, $companyReference)))
|
||||
->addField(new FieldDAO('user', new NormalizedValueDAO('reference', $userReference, $userReference)))
|
||||
->addField(new FieldDAO('city', new NormalizedValueDAO('text', 'Some city', 'Some city')))
|
||||
->addField(new FieldDAO('manager', new NormalizedValueDAO('reference', $notFoundReference, $notFoundReference)));
|
||||
|
||||
$this->referenceResolver->resolveReferences('lead', [$changedObject]);
|
||||
|
||||
$companyField = $changedObject->getField('company');
|
||||
Assert::assertInstanceOf(FieldDAO::class, $companyField);
|
||||
Assert::assertSame('Company name', $companyField->getValue()->getOriginalValue());
|
||||
Assert::assertSame('Company name', $companyField->getValue()->getNormalizedValue());
|
||||
|
||||
$userField = $changedObject->getField('user');
|
||||
Assert::assertInstanceOf(FieldDAO::class, $userField);
|
||||
Assert::assertNull($userField->getValue()->getOriginalValue());
|
||||
Assert::assertNull($userField->getValue()->getNormalizedValue());
|
||||
|
||||
$cityField = $changedObject->getField('city');
|
||||
Assert::assertInstanceOf(FieldDAO::class, $cityField);
|
||||
Assert::assertSame('Some city', $cityField->getValue()->getOriginalValue());
|
||||
Assert::assertSame('Some city', $cityField->getValue()->getNormalizedValue());
|
||||
|
||||
$managerField = $changedObject->getField('manager');
|
||||
Assert::assertInstanceOf(FieldDAO::class, $managerField);
|
||||
Assert::assertNull($managerField->getValue()->getOriginalValue());
|
||||
Assert::assertNull($managerField->getValue()->getNormalizedValue());
|
||||
}
|
||||
|
||||
public function testResolveCompanyReferences(): void
|
||||
{
|
||||
$this->connection->method('createQueryBuilder')
|
||||
->willReturn($this->createQueryBuilder('Company name'));
|
||||
|
||||
$companyReference = $this->createReference('company', 3);
|
||||
|
||||
$changedObject = (new ObjectChangeDAO('integration', 'company', '1', 'Lead', '00Q4H00000juXes'))
|
||||
->addField(new FieldDAO('company', new NormalizedValueDAO('reference', $companyReference, $companyReference)));
|
||||
|
||||
$this->referenceResolver->resolveReferences('company', [$changedObject]);
|
||||
|
||||
$companyField = $changedObject->getField('company');
|
||||
Assert::assertInstanceOf(FieldDAO::class, $companyField);
|
||||
Assert::assertSame($companyReference, $companyField->getValue()->getOriginalValue());
|
||||
Assert::assertSame($companyReference, $companyField->getValue()->getNormalizedValue());
|
||||
}
|
||||
|
||||
private function createReference(string $type, int $value): ReferenceValueDAO
|
||||
{
|
||||
$reference = new ReferenceValueDAO();
|
||||
$reference->setType($type);
|
||||
$reference->setValue($value);
|
||||
|
||||
return $reference;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed ...$returnValues
|
||||
*
|
||||
* @return QueryBuilder|MockObject
|
||||
*/
|
||||
private function createQueryBuilder(...$returnValues)
|
||||
{
|
||||
$result = $this->createMock(Result::class);
|
||||
$result->method('fetchOne')
|
||||
->willReturnOnConsecutiveCalls(...$returnValues);
|
||||
|
||||
$queryBuilder = $this->createMock(QueryBuilder::class);
|
||||
$queryBuilder->method('executeQuery')
|
||||
->willReturn($result);
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncDataExchange\Internal\ObjectHelper;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\FieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\ObjectChangeDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Company as CompanyObject;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ObjectHelper\CompanyObjectHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\MauticSyncDataExchange;
|
||||
use Mautic\LeadBundle\Entity\Company;
|
||||
use Mautic\LeadBundle\Entity\CompanyRepository;
|
||||
use Mautic\LeadBundle\Field\FieldsWithUniqueIdentifier;
|
||||
use Mautic\LeadBundle\Model\CompanyModel;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class CompanyObjectHelperTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var CompanyModel&MockObject
|
||||
*/
|
||||
private MockObject $model;
|
||||
|
||||
/**
|
||||
* @var CompanyRepository&MockObject
|
||||
*/
|
||||
private MockObject $repository;
|
||||
|
||||
/**
|
||||
* @var Connection&MockObject
|
||||
*/
|
||||
private MockObject $connection;
|
||||
|
||||
/**
|
||||
* @var FieldsWithUniqueIdentifier&MockObject
|
||||
*/
|
||||
private MockObject $fieldsWithUniqueIdentifier;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->model = $this->createMock(CompanyModel::class);
|
||||
$this->repository = $this->createMock(CompanyRepository::class);
|
||||
$this->connection = $this->createMock(Connection::class);
|
||||
$this->fieldsWithUniqueIdentifier = $this->createMock(FieldsWithUniqueIdentifier::class);
|
||||
|
||||
$this->fieldsWithUniqueIdentifier->method('getFieldsWithUniqueIdentifier')
|
||||
->with(['object' => CompanyObject::NAME])
|
||||
->willReturn(
|
||||
[
|
||||
'companyemail' => [],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function testCreateWithDuplicateUniqueIdentifiers(): void
|
||||
{
|
||||
$idMap = [
|
||||
'email1@email.com' => 127,
|
||||
'email2@email.com' => 128,
|
||||
];
|
||||
|
||||
$this->model->expects($this->exactly(3))
|
||||
->method('saveEntity')
|
||||
->with(
|
||||
$this->callback(function (Company $company) use ($idMap): bool {
|
||||
// Set ID
|
||||
$reflection = new \ReflectionClass($company);
|
||||
$property = $reflection->getProperty('id');
|
||||
$property->setAccessible(true);
|
||||
$property->setValue($company, $idMap[$company->getEmail()]);
|
||||
|
||||
return true;
|
||||
})
|
||||
);
|
||||
|
||||
$this->repository->expects($this->exactly(2))
|
||||
->method('detachEntity');
|
||||
|
||||
// Test that two objects with the same unique identifier are merged into one
|
||||
$object1 = $this->getObject(1, ['companyemail' => 'email1@email.com']);
|
||||
$object2 = $this->getObject(2, ['companyemail' => 'email2@email.com']);
|
||||
$object3 = $this->getObject(3, ['companyemail' => 'email1@email.com']);
|
||||
|
||||
$objects = [$object1, $object2, $object3];
|
||||
|
||||
$objectMappings = $this->getObjectHelper()->create($objects);
|
||||
|
||||
foreach ($objectMappings as $key => $objectMapping) {
|
||||
$this->assertEquals('Test', $objectMapping->getIntegration());
|
||||
$this->assertEquals(CompanyObject::NAME, $objectMapping->getInternalObjectName());
|
||||
$this->assertEquals('MappedObject', $objectMapping->getIntegrationObjectName());
|
||||
$this->assertEquals($objects[$key]->getMappedObjectId(), $objectMapping->getIntegrationObjectId());
|
||||
|
||||
// Test that mapped ID matches internal ID
|
||||
switch ($objects[$key]->getMappedObjectId()) {
|
||||
case 1:
|
||||
case 3:
|
||||
Assert::assertSame(127, $objectMapping->getInternalObjectId());
|
||||
break;
|
||||
case 2:
|
||||
Assert::assertSame(128, $objectMapping->getInternalObjectId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testCreateWithOneWithoutUniqueIdentifier(): void
|
||||
{
|
||||
$idMap = [
|
||||
'email1@email.com' => 127,
|
||||
'email2@email.com' => 128,
|
||||
'' => 129,
|
||||
];
|
||||
|
||||
$this->model->expects($this->exactly(4))
|
||||
->method('saveEntity')
|
||||
->with(
|
||||
$this->callback(function (Company $company) use ($idMap): bool {
|
||||
// Set ID
|
||||
$reflection = new \ReflectionClass($company);
|
||||
$property = $reflection->getProperty('id');
|
||||
$property->setAccessible(true);
|
||||
$property->setValue($company, $idMap[$company->getEmail()]);
|
||||
|
||||
return true;
|
||||
})
|
||||
);
|
||||
|
||||
$this->repository->expects($this->exactly(3))
|
||||
->method('detachEntity');
|
||||
|
||||
// Test that two objects with the same unique identifier are merged into one
|
||||
$object1 = $this->getObject(1, ['companyemail' => 'email1@email.com']);
|
||||
$object2 = $this->getObject(2, ['companyemail' => 'email2@email.com']);
|
||||
$object3 = $this->getObject(3, ['companyemail' => 'email1@email.com']);
|
||||
$object4 = $this->getObject(4, ['companyname' => 'Some Biz']);
|
||||
|
||||
$objects = [$object1, $object2, $object3, $object4];
|
||||
|
||||
$objectMappings = $this->getObjectHelper()->create($objects);
|
||||
|
||||
foreach ($objectMappings as $key => $objectMapping) {
|
||||
$this->assertEquals('Test', $objectMapping->getIntegration());
|
||||
$this->assertEquals(CompanyObject::NAME, $objectMapping->getInternalObjectName());
|
||||
$this->assertEquals('MappedObject', $objectMapping->getIntegrationObjectName());
|
||||
$this->assertEquals($objects[$key]->getMappedObjectId(), $objectMapping->getIntegrationObjectId());
|
||||
|
||||
// Test that mapped ID matches internal ID
|
||||
switch ($objects[$key]->getMappedObjectId()) {
|
||||
case 1:
|
||||
case 3:
|
||||
Assert::assertSame(127, $objectMapping->getInternalObjectId());
|
||||
break;
|
||||
case 2:
|
||||
Assert::assertSame(128, $objectMapping->getInternalObjectId());
|
||||
break;
|
||||
case 4:
|
||||
Assert::assertSame(129, $objectMapping->getInternalObjectId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testUpdate(): void
|
||||
{
|
||||
$this->model->expects($this->exactly(2))
|
||||
->method('saveEntity');
|
||||
$this->repository->expects($this->exactly(2))
|
||||
->method('detachEntity');
|
||||
|
||||
$objects = [
|
||||
0 => new ObjectChangeDAO('Test', MauticSyncDataExchange::OBJECT_COMPANY, 0, 'MappedObject', 0, new \DateTime()),
|
||||
1 => new ObjectChangeDAO('Test', MauticSyncDataExchange::OBJECT_COMPANY, 1, 'MappedObject', 1, new \DateTime()),
|
||||
];
|
||||
|
||||
$company1 = $this->createMock(Company::class);
|
||||
$company1->method('getId')
|
||||
->willReturn(0);
|
||||
$company2 = $this->createMock(Company::class);
|
||||
$company2->method('getId')
|
||||
->willReturn(1);
|
||||
$this->model->expects($this->once())
|
||||
->method('getEntities')
|
||||
->willReturn(
|
||||
[
|
||||
$company1,
|
||||
$company2,
|
||||
]
|
||||
);
|
||||
$objectMappings = $this->getObjectHelper()->update([3, 4], $objects);
|
||||
|
||||
foreach ($objectMappings as $objectMapping) {
|
||||
$this->assertEquals('Test', $objectMapping->getIntegration());
|
||||
$this->assertEquals('MappedObject', $objectMapping->getIntegrationObjectName());
|
||||
$this->assertTrue(isset($objects[$objectMapping->getIntegrationObjectId()]));
|
||||
$this->assertEquals($objects[$objectMapping->getIntegrationObjectId()]->getMappedObjectId(), $objectMapping->getIntegrationObjectId());
|
||||
}
|
||||
}
|
||||
|
||||
public function testFindObjectById(): void
|
||||
{
|
||||
$company = new Company();
|
||||
$this->repository->expects(self::once())
|
||||
->method('getEntity')
|
||||
->with(1)
|
||||
->willReturn($company);
|
||||
|
||||
self::assertSame($company, $this->getObjectHelper()->findObjectById(1));
|
||||
}
|
||||
|
||||
public function testFindObjectByIdReturnsNull(): void
|
||||
{
|
||||
$this->repository->expects(self::once())
|
||||
->method('getEntity')
|
||||
->with(1);
|
||||
|
||||
self::assertNull($this->getObjectHelper()->findObjectById(1));
|
||||
}
|
||||
|
||||
public function testSetFieldValues(): void
|
||||
{
|
||||
$company = new Company();
|
||||
$this->model->expects(self::once())
|
||||
->method('setFieldValues')
|
||||
->with($company, []);
|
||||
$this->getObjectHelper()->setFieldValues($company);
|
||||
}
|
||||
|
||||
public function testUpdateEmpty(): void
|
||||
{
|
||||
$this->model->expects($this->never())
|
||||
->method('getEntities');
|
||||
|
||||
$objectMappings = $this->getObjectHelper()->update([], []);
|
||||
|
||||
Assert::assertSame([], $objectMappings);
|
||||
}
|
||||
|
||||
private function getObjectHelper(): CompanyObjectHelper
|
||||
{
|
||||
return new CompanyObjectHelper($this->model, $this->repository, $this->connection, $this->fieldsWithUniqueIdentifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,string> $fieldValues
|
||||
*/
|
||||
private function getObject(int $mappedId, array $fieldValues): ObjectChangeDAO
|
||||
{
|
||||
$object = new ObjectChangeDAO(
|
||||
'Test',
|
||||
CompanyObject::NAME,
|
||||
null,
|
||||
'MappedObject',
|
||||
$mappedId,
|
||||
new \DateTime()
|
||||
);
|
||||
|
||||
foreach ($fieldValues as $name => $value) {
|
||||
$object->addField(
|
||||
new FieldDAO($name, new NormalizedValueDAO('string', $value))
|
||||
);
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncDataExchange\Internal\ObjectHelper;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\FieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\ObjectChangeDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\ReferenceValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ObjectHelper\ContactObjectHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\MauticSyncDataExchange;
|
||||
use Mautic\LeadBundle\DataObject\LeadManipulator;
|
||||
use Mautic\LeadBundle\Entity\Lead;
|
||||
use Mautic\LeadBundle\Entity\LeadRepository;
|
||||
use Mautic\LeadBundle\Exception\ImportFailedException;
|
||||
use Mautic\LeadBundle\Field\FieldList;
|
||||
use Mautic\LeadBundle\Field\FieldsWithUniqueIdentifier;
|
||||
use Mautic\LeadBundle\Model\DoNotContact;
|
||||
use Mautic\LeadBundle\Model\LeadModel;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ContactObjectHelperTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var LeadModel&MockObject
|
||||
*/
|
||||
private MockObject $model;
|
||||
|
||||
/**
|
||||
* @var LeadRepository&MockObject
|
||||
*/
|
||||
private MockObject $repository;
|
||||
|
||||
/**
|
||||
* @var Connection&MockObject
|
||||
*/
|
||||
private MockObject $connection;
|
||||
|
||||
/**
|
||||
* @var DoNotContact&MockObject
|
||||
*/
|
||||
private MockObject $doNotContactModel;
|
||||
|
||||
/**
|
||||
* @var FieldList&MockObject
|
||||
*/
|
||||
private MockObject $fieldList;
|
||||
|
||||
/**
|
||||
* @var FieldsWithUniqueIdentifier&MockObject
|
||||
*/
|
||||
private MockObject $fieldsWithUniqueIdentifier;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->model = $this->createMock(LeadModel::class);
|
||||
$this->repository = $this->createMock(LeadRepository::class);
|
||||
$this->connection = $this->createMock(Connection::class);
|
||||
$this->doNotContactModel = $this->createMock(DoNotContact::class);
|
||||
$this->fieldList = $this->createMock(FieldList::class);
|
||||
$this->fieldsWithUniqueIdentifier = $this->createMock(FieldsWithUniqueIdentifier::class);
|
||||
|
||||
$this->fieldList->method('getFieldList')
|
||||
->willReturn(
|
||||
[
|
||||
'email' => [],
|
||||
'company' => [],
|
||||
]
|
||||
);
|
||||
|
||||
$this->fieldsWithUniqueIdentifier->method('getFieldsWithUniqueIdentifier')
|
||||
->with(['object' => Contact::NAME])
|
||||
->willReturn(
|
||||
[
|
||||
'email' => [],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function testCreateWithDuplicateUniqueIdentifiers(): void
|
||||
{
|
||||
$idMap = [
|
||||
'email1@email.com' => 127,
|
||||
'email2@email.com' => 128,
|
||||
];
|
||||
|
||||
$this->model->expects($this->exactly(3))
|
||||
->method('saveEntity')
|
||||
->with(
|
||||
$this->callback(function (Lead $lead) use ($idMap): bool {
|
||||
$this->assertManipulator($lead, 'create');
|
||||
|
||||
// Set contact ID
|
||||
$reflection = new \ReflectionClass($lead);
|
||||
$property = $reflection->getProperty('id');
|
||||
$property->setAccessible(true);
|
||||
$property->setValue($lead, $idMap[$lead->getEmail()]);
|
||||
|
||||
return true;
|
||||
})
|
||||
);
|
||||
$this->repository->expects($this->exactly(2))
|
||||
->method('detachEntity');
|
||||
|
||||
// Test that two objects with the same unique identifier are merged into one
|
||||
$object1 = $this->getObject(1, ['email' => 'email1@email.com']);
|
||||
$object2 = $this->getObject(2, ['email' => 'email2@email.com']);
|
||||
$object3 = $this->getObject(3, ['email' => 'email1@email.com']);
|
||||
|
||||
$objects = [$object1, $object2, $object3];
|
||||
|
||||
$objectMappings = $this->getObjectHelper()->create($objects);
|
||||
|
||||
foreach ($objectMappings as $key => $objectMapping) {
|
||||
$this->assertEquals('Test', $objectMapping->getIntegration());
|
||||
$this->assertEquals(Contact::NAME, $objectMapping->getInternalObjectName());
|
||||
$this->assertEquals('MappedObject', $objectMapping->getIntegrationObjectName());
|
||||
$this->assertEquals($objects[$key]->getMappedObjectId(), $objectMapping->getIntegrationObjectId());
|
||||
|
||||
// Test that mapped ID matches internal ID
|
||||
switch ($objects[$key]->getMappedObjectId()) {
|
||||
case 1:
|
||||
case 3:
|
||||
Assert::assertSame(127, $objectMapping->getInternalObjectId());
|
||||
break;
|
||||
case 2:
|
||||
Assert::assertSame(128, $objectMapping->getInternalObjectId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testCreateWithOneWithoutUniqueIdentifier(): void
|
||||
{
|
||||
$idMap = [
|
||||
'email1@email.com' => 127,
|
||||
'email2@email.com' => 128,
|
||||
'' => 129,
|
||||
];
|
||||
|
||||
$this->model->expects($this->exactly(4))
|
||||
->method('saveEntity')
|
||||
->with(
|
||||
$this->callback(function (Lead $lead) use ($idMap): bool {
|
||||
$this->assertManipulator($lead, 'create');
|
||||
|
||||
// Set contact ID
|
||||
$reflection = new \ReflectionClass($lead);
|
||||
$property = $reflection->getProperty('id');
|
||||
$property->setAccessible(true);
|
||||
$property->setValue($lead, $idMap[$lead->getEmail()]);
|
||||
|
||||
return true;
|
||||
})
|
||||
);
|
||||
|
||||
$this->repository->expects($this->exactly(3))
|
||||
->method('detachEntity');
|
||||
|
||||
// Test that two objects with the same unique identifier are merged into one
|
||||
$object1 = $this->getObject(1, ['email' => 'email1@email.com']);
|
||||
$object2 = $this->getObject(2, ['email' => 'email2@email.com']);
|
||||
$object3 = $this->getObject(3, ['email' => 'email1@email.com']);
|
||||
$object4 = $this->getObject(4, ['firstname' => 'Somebody']);
|
||||
|
||||
$objects = [$object1, $object2, $object3, $object4];
|
||||
|
||||
$objectMappings = $this->getObjectHelper()->create($objects);
|
||||
|
||||
foreach ($objectMappings as $key => $objectMapping) {
|
||||
$this->assertEquals('Test', $objectMapping->getIntegration());
|
||||
$this->assertEquals(Contact::NAME, $objectMapping->getInternalObjectName());
|
||||
$this->assertEquals('MappedObject', $objectMapping->getIntegrationObjectName());
|
||||
$this->assertEquals($objects[$key]->getMappedObjectId(), $objectMapping->getIntegrationObjectId());
|
||||
|
||||
// Test that mapped ID matches internal ID
|
||||
switch ($objects[$key]->getMappedObjectId()) {
|
||||
case 1:
|
||||
case 3:
|
||||
Assert::assertSame(127, $objectMapping->getInternalObjectId());
|
||||
break;
|
||||
case 2:
|
||||
Assert::assertSame(128, $objectMapping->getInternalObjectId());
|
||||
break;
|
||||
case 4:
|
||||
Assert::assertSame(129, $objectMapping->getInternalObjectId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testUpdate(): void
|
||||
{
|
||||
$this->model->expects($this->exactly(2))
|
||||
->method('saveEntity');
|
||||
$this->repository->expects($this->exactly(2))
|
||||
->method('detachEntity');
|
||||
|
||||
$objectChangeDaoA = new ObjectChangeDAO('Test', Contact::NAME, 0, 'MappedObject', 0, new \DateTime());
|
||||
$objectChangeDaoB = new ObjectChangeDAO('Test', Contact::NAME, 1, 'MappedObject', 1, new \DateTime());
|
||||
$objects = [$objectChangeDaoA, $objectChangeDaoB];
|
||||
$companyId = 1234;
|
||||
$companyValue = new ReferenceValueDAO();
|
||||
$companyValue->setValue($companyId);
|
||||
$companyValue->setType(MauticSyncDataExchange::OBJECT_COMPANY);
|
||||
|
||||
$emailField = new FieldDAO('email', new NormalizedValueDAO('email', 'john@doe.com'));
|
||||
$companyField = new FieldDAO(
|
||||
MauticSyncDataExchange::OBJECT_COMPANY,
|
||||
new NormalizedValueDAO('reference', $companyValue, 'Company A')
|
||||
);
|
||||
|
||||
$objectChangeDaoA->addField($emailField);
|
||||
$objectChangeDaoA->addField($companyField);
|
||||
|
||||
$contact1 = $this->createPartialMock(Lead::class, ['getId', 'addUpdatedField']);
|
||||
$contact1->method('getId')
|
||||
->willReturn(0);
|
||||
$contact2 = $this->createPartialMock(Lead::class, ['getId']);
|
||||
$contact2->method('getId')
|
||||
->willReturn(1);
|
||||
$this->model->expects($this->once())
|
||||
->method('getEntities')
|
||||
->willReturn(
|
||||
[
|
||||
$contact1,
|
||||
$contact2,
|
||||
]
|
||||
);
|
||||
$matcher = $this->exactly(2);
|
||||
|
||||
$contact1->expects($matcher)
|
||||
->method('addUpdatedField')->willReturnCallback(function (...$parameters) use ($matcher) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('email', $parameters[0]);
|
||||
$this->assertSame('john@doe.com', $parameters[1]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(MauticSyncDataExchange::OBJECT_COMPANY, $parameters[0]);
|
||||
$this->assertSame('Company A', $parameters[1]);
|
||||
}
|
||||
});
|
||||
|
||||
$objectMappings = $this->getObjectHelper()->update([3, 4], $objects);
|
||||
|
||||
foreach ($objectMappings as $objectMapping) {
|
||||
$this->assertEquals('Test', $objectMapping->getIntegration());
|
||||
$this->assertEquals('MappedObject', $objectMapping->getIntegrationObjectName());
|
||||
$this->assertTrue(isset($objects[$objectMapping->getIntegrationObjectId()]));
|
||||
$this->assertEquals($objects[$objectMapping->getIntegrationObjectId()]->getMappedObjectId(), $objectMapping->getIntegrationObjectId());
|
||||
}
|
||||
|
||||
$this->assertManipulator($contact1, 'update');
|
||||
$this->assertManipulator($contact2, 'update');
|
||||
}
|
||||
|
||||
public function testDoNotContactIsAdded(): void
|
||||
{
|
||||
$this->doNotContactModel->expects($this->once())
|
||||
->method('addDncForContact')
|
||||
->with(1, 'email', 1, 'Test', true, true, true);
|
||||
|
||||
$objectChangeDAO = new ObjectChangeDAO('Test', Contact::NAME, 1, 'MappedObject', 1, new \DateTime());
|
||||
$objectChangeDAO->addField(new FieldDAO('mautic_internal_dnc_email', new NormalizedValueDAO(NormalizedValueDAO::INT_TYPE, 1)));
|
||||
|
||||
$objects = [
|
||||
1 => $objectChangeDAO,
|
||||
];
|
||||
|
||||
$contact1 = $this->createMock(Lead::class);
|
||||
$contact1->method('getId')
|
||||
->willReturn(1);
|
||||
|
||||
$this->model->expects($this->once())
|
||||
->method('getEntities')
|
||||
->willReturn([$contact1]);
|
||||
$this->getObjectHelper()->update([1], $objects);
|
||||
}
|
||||
|
||||
public function testDoNotContactIsRemoved(): void
|
||||
{
|
||||
$this->doNotContactModel->expects($this->once())
|
||||
->method('removeDncForContact')
|
||||
->with(1, 'email');
|
||||
|
||||
$objectChangeDAO = new ObjectChangeDAO('Test', Contact::NAME, 1, 'MappedObject', 1, new \DateTime());
|
||||
$objectChangeDAO->addField(new FieldDAO('mautic_internal_dnc_email', new NormalizedValueDAO(NormalizedValueDAO::INT_TYPE, 0)));
|
||||
|
||||
$objects = [
|
||||
1 => $objectChangeDAO,
|
||||
];
|
||||
|
||||
$contact1 = $this->createMock(Lead::class);
|
||||
$contact1->method('getId')
|
||||
->willReturn(1);
|
||||
|
||||
$this->model->expects($this->once())
|
||||
->method('getEntities')
|
||||
->willReturn([$contact1]);
|
||||
$this->getObjectHelper()->update([1], $objects);
|
||||
}
|
||||
|
||||
public function testUnrecognizedDoNotContactDefaultsToManualDNC(): void
|
||||
{
|
||||
$this->doNotContactModel->expects($this->once())
|
||||
->method('addDncForContact')
|
||||
->with(1, 'email', 3, 'Test', true, true, true);
|
||||
|
||||
$objectChangeDAO = new ObjectChangeDAO('Test', Contact::NAME, 1, 'MappedObject', 1, new \DateTime());
|
||||
$objectChangeDAO->addField(new FieldDAO('mautic_internal_dnc_email', new NormalizedValueDAO(NormalizedValueDAO::INT_TYPE, 4)));
|
||||
|
||||
$objects = [
|
||||
1 => $objectChangeDAO,
|
||||
];
|
||||
|
||||
$contact1 = $this->createMock(Lead::class);
|
||||
$contact1->method('getId')
|
||||
->willReturn(1);
|
||||
|
||||
$this->model->expects($this->once())
|
||||
->method('getEntities')
|
||||
->willReturn([$contact1]);
|
||||
$this->getObjectHelper()->update([1], $objects);
|
||||
}
|
||||
|
||||
public function testFindObjectById(): void
|
||||
{
|
||||
$contact = new Lead();
|
||||
$this->repository->expects(self::once())
|
||||
->method('getEntity')
|
||||
->with(1)
|
||||
->willReturn($contact);
|
||||
|
||||
self::assertSame($contact, $this->getObjectHelper()->findObjectById(1));
|
||||
}
|
||||
|
||||
public function testFindObjectByIdReturnsNull(): void
|
||||
{
|
||||
$this->repository->expects(self::once())
|
||||
->method('getEntity')
|
||||
->with(1);
|
||||
|
||||
self::assertNull($this->getObjectHelper()->findObjectById(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ImportFailedException
|
||||
*/
|
||||
public function testSetFieldValues(): void
|
||||
{
|
||||
$contact = new Lead();
|
||||
$this->model->expects(self::once())
|
||||
->method('setFieldValues')
|
||||
->with($contact, []);
|
||||
$this->getObjectHelper()->setFieldValues($contact);
|
||||
}
|
||||
|
||||
private function getObjectHelper(): ContactObjectHelper
|
||||
{
|
||||
return new ContactObjectHelper($this->model, $this->repository, $this->connection, $this->doNotContactModel, $this->fieldList, $this->fieldsWithUniqueIdentifier);
|
||||
}
|
||||
|
||||
private function assertManipulator(Lead $lead, string $objectName): void
|
||||
{
|
||||
$manipulator = $lead->getManipulator();
|
||||
$this->assertInstanceOf(LeadManipulator::class, $manipulator);
|
||||
$this->assertSame('integrations', $manipulator->getBundleName());
|
||||
$this->assertSame($objectName, $manipulator->getObjectName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,string> $fieldValues
|
||||
*/
|
||||
private function getObject(int $mappedId, array $fieldValues): ObjectChangeDAO
|
||||
{
|
||||
$object = new ObjectChangeDAO('Test', Contact::NAME, null, 'MappedObject', $mappedId, new \DateTime());
|
||||
|
||||
foreach ($fieldValues as $name => $value) {
|
||||
$object->addField(
|
||||
new FieldDAO($name, new NormalizedValueDAO('string', $value))
|
||||
);
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncDataExchange\Internal;
|
||||
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectEvent;
|
||||
use Mautic\IntegrationsBundle\IntegrationEvents;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ObjectProvider;
|
||||
use Mautic\LeadBundle\Entity\Lead;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class ObjectProviderTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var EventDispatcherInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $dispatcher;
|
||||
|
||||
private ObjectProvider $objectProvider;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||
$this->objectProvider = new ObjectProvider($this->dispatcher);
|
||||
}
|
||||
|
||||
public function testGetObjectByNameIfItDoesNotExist(): void
|
||||
{
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->isInstanceOf(InternalObjectEvent::class),
|
||||
IntegrationEvents::INTEGRATION_COLLECT_INTERNAL_OBJECTS
|
||||
);
|
||||
|
||||
$this->expectException(ObjectNotFoundException::class);
|
||||
$this->objectProvider->getObjectByName('Unicorn');
|
||||
}
|
||||
|
||||
public function testGetObjectByNameIfItExists(): void
|
||||
{
|
||||
$contact = new Contact();
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->callback(function (InternalObjectEvent $e) use ($contact) {
|
||||
// Fake a subscriber.
|
||||
$e->addObject($contact);
|
||||
|
||||
return true;
|
||||
}),
|
||||
IntegrationEvents::INTEGRATION_COLLECT_INTERNAL_OBJECTS
|
||||
);
|
||||
|
||||
$this->assertSame($contact, $this->objectProvider->getObjectByName(Contact::NAME));
|
||||
}
|
||||
|
||||
public function testGetObjectByEntityNameIfItDoesNotExist(): void
|
||||
{
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->isInstanceOf(InternalObjectEvent::class),
|
||||
IntegrationEvents::INTEGRATION_COLLECT_INTERNAL_OBJECTS,
|
||||
);
|
||||
|
||||
$this->expectException(ObjectNotFoundException::class);
|
||||
$this->objectProvider->getObjectByEntityName('Unicorn');
|
||||
}
|
||||
|
||||
public function testGetObjectByEntityNameIfItExists(): void
|
||||
{
|
||||
$contact = new Contact();
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->callback(function (InternalObjectEvent $e) use ($contact) {
|
||||
// Fake a subscriber.
|
||||
$e->addObject($contact);
|
||||
|
||||
return true;
|
||||
}),
|
||||
IntegrationEvents::INTEGRATION_COLLECT_INTERNAL_OBJECTS
|
||||
);
|
||||
|
||||
$this->assertSame($contact, $this->objectProvider->getObjectByEntityName(Lead::class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncDataExchange\Internal\ReportBuilder;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\FieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Request\ObjectDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\FieldNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Helper\FieldHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ObjectHelper\ContactObjectHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ReportBuilder\FieldBuilder;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Routing\Router;
|
||||
|
||||
class FieldBuilderTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var Router|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $router;
|
||||
|
||||
/**
|
||||
* @var FieldHelper|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $fieldHelper;
|
||||
|
||||
/**
|
||||
* @var ContactObjectHelper|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $contactObjectHelper;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->router = $this->createMock(Router::class);
|
||||
$this->fieldHelper = $this->getMockBuilder(FieldHelper::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['getFieldList'])
|
||||
->getMock();
|
||||
$this->contactObjectHelper = $this->createMock(ContactObjectHelper::class);
|
||||
}
|
||||
|
||||
public function testIdFieldIsAdded(): void
|
||||
{
|
||||
$field = $this->getFieldBuilder()->buildObjectField('mautic_internal_id', ['id' => 1], new ObjectDAO('Test'), 'Test');
|
||||
$this->assertEquals('mautic_internal_id', $field->getName());
|
||||
$this->assertEquals(FieldDAO::FIELD_CHANGED, $field->getState());
|
||||
$this->assertEquals(1, $field->getValue()->getNormalizedValue());
|
||||
}
|
||||
|
||||
public function testOwnerIdFieldIsAdded(): void
|
||||
{
|
||||
$field = $this->getFieldBuilder()->buildObjectField(
|
||||
'owner_id',
|
||||
['id' => 1, 'owner_id' => 123],
|
||||
new ObjectDAO('Test'),
|
||||
'Test'
|
||||
);
|
||||
|
||||
$this->assertEquals('owner_id', $field->getName());
|
||||
$this->assertEquals(FieldDAO::FIELD_CHANGED, $field->getState());
|
||||
$this->assertEquals(123, $field->getValue()->getNormalizedValue());
|
||||
}
|
||||
|
||||
public function testDoNotContactFieldIsAdded(): void
|
||||
{
|
||||
$this->contactObjectHelper->expects($this->once())
|
||||
->method('getDoNotContactStatus')
|
||||
->with(1, 'email')
|
||||
->willReturn(0);
|
||||
|
||||
$field = $this->getFieldBuilder()->buildObjectField('mautic_internal_dnc_email', ['id' => 1], new ObjectDAO('Test'), 'Test');
|
||||
|
||||
$this->assertEquals('mautic_internal_dnc_email', $field->getName());
|
||||
$this->assertEquals(FieldDAO::FIELD_CHANGED, $field->getState());
|
||||
$this->assertEquals(0, $field->getValue()->getNormalizedValue());
|
||||
}
|
||||
|
||||
public function testTimelineFieldIsAdded(): void
|
||||
{
|
||||
$this->router->expects($this->once())
|
||||
->method('generate')
|
||||
->with(
|
||||
'mautic_plugin_timeline_view',
|
||||
[
|
||||
'integration' => 'Test',
|
||||
'leadId' => 1,
|
||||
],
|
||||
UrlGeneratorInterface::ABSOLUTE_URL
|
||||
);
|
||||
|
||||
$field = $this->getFieldBuilder()->buildObjectField('mautic_internal_contact_timeline', ['id' => 1], new ObjectDAO('Test'), 'Test');
|
||||
|
||||
$this->assertEquals('mautic_internal_contact_timeline', $field->getName());
|
||||
$this->assertEquals(FieldDAO::FIELD_CHANGED, $field->getState());
|
||||
$this->assertEquals('', $field->getValue()->getNormalizedValue());
|
||||
}
|
||||
|
||||
public function testCustomFieldsAreAdded(): void
|
||||
{
|
||||
$this->fieldHelper->expects($this->once())
|
||||
->method('getFieldList')
|
||||
->with('Test')
|
||||
->willReturn(
|
||||
[
|
||||
'email' => [
|
||||
'type' => 'email',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$objectDAO = new ObjectDAO('Test');
|
||||
$objectDAO->setRequiredFields(['email']);
|
||||
|
||||
$field = $this->getFieldBuilder()->buildObjectField('email', ['id' => 1, 'email' => 'test@test.com'], $objectDAO, 'Test');
|
||||
|
||||
$this->assertEquals('email', $field->getName());
|
||||
$this->assertEquals(FieldDAO::FIELD_REQUIRED, $field->getState());
|
||||
$this->assertEquals('test@test.com', $field->getValue()->getNormalizedValue());
|
||||
}
|
||||
|
||||
public function testUnrecognizedFieldThrowsException(): void
|
||||
{
|
||||
$this->fieldHelper->expects($this->once())
|
||||
->method('getFieldList')
|
||||
->with('Test')
|
||||
->willReturn(
|
||||
[
|
||||
'email' => [
|
||||
'type' => 'email',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->expectException(FieldNotFoundException::class);
|
||||
|
||||
$this->getFieldBuilder()->buildObjectField('badfield', ['id' => 1, 'email' => 'test@test.com'], new ObjectDAO('Test'), 'Test');
|
||||
}
|
||||
|
||||
public function getFieldBuilder()
|
||||
{
|
||||
return new FieldBuilder($this->router, $this->fieldHelper, $this->contactObjectHelper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,381 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncDataExchange\Internal\ReportBuilder;
|
||||
|
||||
use Mautic\IntegrationsBundle\Event\InternalCompanyEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalContactEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectFindByIdEvent;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectFindEvent;
|
||||
use Mautic\IntegrationsBundle\Exception\InvalidValueException;
|
||||
use Mautic\IntegrationsBundle\IntegrationEvents;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\InputOptionsDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\FieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Request\ObjectDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Request\RequestDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\FieldNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Company;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ObjectProvider;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ReportBuilder\FieldBuilder;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ReportBuilder\FullObjectReportBuilder;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\MauticSyncDataExchange;
|
||||
use Mautic\LeadBundle\Entity\Company as CompanyEntity;
|
||||
use Mautic\LeadBundle\Entity\Lead;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class FullObjectReportBuilderTest extends TestCase
|
||||
{
|
||||
private const INTEGRATION_NAME = 'Test';
|
||||
|
||||
private const TEST_EMAIL = 'test@test.com';
|
||||
|
||||
/**
|
||||
* @var ObjectProvider|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $objectProvider;
|
||||
|
||||
/**
|
||||
* @var EventDispatcherInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $dispatcher;
|
||||
|
||||
/**
|
||||
* @var FieldBuilder|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $fieldBuilder;
|
||||
|
||||
private FullObjectReportBuilder $reportBuilder;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->objectProvider = $this->createMock(ObjectProvider::class);
|
||||
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||
$this->fieldBuilder = $this->createMock(FieldBuilder::class);
|
||||
$this->reportBuilder = new FullObjectReportBuilder(
|
||||
$this->fieldBuilder,
|
||||
$this->objectProvider,
|
||||
$this->dispatcher
|
||||
);
|
||||
}
|
||||
|
||||
public function testBuildingContactReport(): void
|
||||
{
|
||||
$requestDAO = new RequestDAO(self::INTEGRATION_NAME, 1, new InputOptionsDAO(['integration' => self::INTEGRATION_NAME]));
|
||||
$fromDateTime = new \DateTimeImmutable('2018-10-08 00:00:00');
|
||||
$toDateTime = new \DateTimeImmutable('2018-10-08 00:01:00');
|
||||
$requestObject = new ObjectDAO(Contact::NAME, $fromDateTime, $toDateTime);
|
||||
$requestObject->addField('email');
|
||||
$requestDAO->addObject($requestObject);
|
||||
|
||||
$this->fieldBuilder->expects($this->once())
|
||||
->method('buildObjectField')
|
||||
->with('email', $this->anything(), $requestObject, $requestDAO->getSyncToIntegration())
|
||||
->willReturn(
|
||||
new FieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, self::TEST_EMAIL))
|
||||
);
|
||||
|
||||
$internalObject = new Contact();
|
||||
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByName')
|
||||
->with(Contact::NAME)
|
||||
->willReturn($internalObject);
|
||||
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->callback(function (InternalObjectFindEvent $event) use ($internalObject, $fromDateTime, $toDateTime) {
|
||||
$this->assertSame($internalObject, $event->getObject());
|
||||
$this->assertSame($fromDateTime, $event->getDateRange()->getFromDate());
|
||||
$this->assertSame($toDateTime, $event->getDateRange()->getToDate());
|
||||
$this->assertSame(0, $event->getStart());
|
||||
$this->assertSame(200, $event->getLimit());
|
||||
|
||||
// Mock a subscriber:
|
||||
$event->setFoundObjects([
|
||||
[
|
||||
'id' => 1,
|
||||
'email' => self::TEST_EMAIL,
|
||||
'date_modified' => '2018-10-08 00:30:00',
|
||||
],
|
||||
]);
|
||||
|
||||
return true;
|
||||
}),
|
||||
IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORDS
|
||||
);
|
||||
|
||||
$report = $this->reportBuilder->buildReport($requestDAO);
|
||||
$objects = $report->getObjects(Contact::NAME);
|
||||
|
||||
$this->assertTrue(isset($objects[1]));
|
||||
$this->assertEquals(self::TEST_EMAIL, $objects[1]->getField('email')->getValue()->getNormalizedValue());
|
||||
}
|
||||
|
||||
public function testBuildingCompanyReport(): void
|
||||
{
|
||||
$requestDAO = new RequestDAO(self::INTEGRATION_NAME, 1, new InputOptionsDAO(['integration' => self::INTEGRATION_NAME]));
|
||||
$fromDateTime = new \DateTimeImmutable('2018-10-08 00:00:00');
|
||||
$toDateTime = new \DateTimeImmutable('2018-10-08 00:01:00');
|
||||
$requestObject = new ObjectDAO(MauticSyncDataExchange::OBJECT_COMPANY, $fromDateTime, $toDateTime);
|
||||
$requestObject->addField('email');
|
||||
$requestDAO->addObject($requestObject);
|
||||
|
||||
$this->fieldBuilder->expects($this->once())
|
||||
->method('buildObjectField')
|
||||
->with('email', $this->anything(), $requestObject, $requestDAO->getSyncToIntegration())
|
||||
->willReturn(
|
||||
new FieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, self::TEST_EMAIL))
|
||||
);
|
||||
|
||||
$internalObject = new Company();
|
||||
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByName')
|
||||
->with(Company::NAME)
|
||||
->willReturn($internalObject);
|
||||
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->callback(function (InternalObjectFindEvent $event) use ($internalObject, $fromDateTime, $toDateTime) {
|
||||
$this->assertSame($internalObject, $event->getObject());
|
||||
$this->assertSame($fromDateTime, $event->getDateRange()->getFromDate());
|
||||
$this->assertSame($toDateTime, $event->getDateRange()->getToDate());
|
||||
$this->assertSame(0, $event->getStart());
|
||||
$this->assertSame(200, $event->getLimit());
|
||||
|
||||
// Mock a subscriber:
|
||||
$event->setFoundObjects([
|
||||
[
|
||||
'id' => 1,
|
||||
'email' => self::TEST_EMAIL,
|
||||
'date_modified' => '2018-10-08 00:30:00',
|
||||
],
|
||||
]);
|
||||
|
||||
return true;
|
||||
}),
|
||||
IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORDS
|
||||
);
|
||||
|
||||
$report = $this->reportBuilder->buildReport($requestDAO);
|
||||
$objects = $report->getObjects(MauticSyncDataExchange::OBJECT_COMPANY);
|
||||
|
||||
$this->assertTrue(isset($objects[1]));
|
||||
$this->assertEquals(self::TEST_EMAIL, $objects[1]->getField('email')->getValue()->getNormalizedValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FieldNotFoundException
|
||||
* @throws InvalidValueException
|
||||
*/
|
||||
public function testBuildingContactReportWithFindInternalRecordEvent(): void
|
||||
{
|
||||
$requestDAO = new RequestDAO(self::INTEGRATION_NAME, 1, new InputOptionsDAO(['integration' => self::INTEGRATION_NAME]));
|
||||
$fromDateTime = new \DateTimeImmutable('2018-10-08 00:00:00');
|
||||
$toDateTime = new \DateTimeImmutable('2018-10-08 00:01:00');
|
||||
$requestObject = new ObjectDAO(Contact::NAME, $fromDateTime, $toDateTime);
|
||||
$requestObject->addField('email');
|
||||
$requestDAO->addObject($requestObject);
|
||||
|
||||
$this->fieldBuilder->expects($this->once())
|
||||
->method('buildObjectField')
|
||||
->with('email', $this->anything(), $requestObject, $requestDAO->getSyncToIntegration())
|
||||
->willReturn(
|
||||
new FieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, self::TEST_EMAIL))
|
||||
);
|
||||
|
||||
$internalObject = new Contact();
|
||||
|
||||
$this->objectProvider->expects($this->exactly(2))
|
||||
->method('getObjectByName')
|
||||
->with(Contact::NAME)
|
||||
->willReturn($internalObject);
|
||||
$matcher = $this->exactly(2);
|
||||
|
||||
$this->dispatcher->expects($matcher)
|
||||
->method('hasListeners')->willReturnCallback(function (...$parameters) use ($matcher) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORD, $parameters[0]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_BEFORE_FULL_CONTACT_REPORT_BUILD, $parameters[0]);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
$contactEntity = new class extends Lead {
|
||||
public function getId(): int
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
$matcher = $this->exactly(3);
|
||||
|
||||
$this->dispatcher->expects($matcher)
|
||||
->method('dispatch')->willReturnCallback(function (...$parameters) use ($matcher, $internalObject, $fromDateTime, $toDateTime, $contactEntity) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectFindEvent $event) use (
|
||||
$internalObject,
|
||||
$fromDateTime,
|
||||
$toDateTime
|
||||
) {
|
||||
$this->assertSame($internalObject, $event->getObject());
|
||||
$this->assertSame($fromDateTime, $event->getDateRange()->getFromDate());
|
||||
$this->assertSame($toDateTime, $event->getDateRange()->getToDate());
|
||||
$this->assertSame(0, $event->getStart());
|
||||
$this->assertSame(200, $event->getLimit());
|
||||
|
||||
// Mock a subscriber:
|
||||
$event->setFoundObjects(
|
||||
[
|
||||
[
|
||||
'id' => 1,
|
||||
'email' => self::TEST_EMAIL,
|
||||
'date_modified' => '2018-10-08 00:30:00',
|
||||
],
|
||||
]
|
||||
);
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORDS, $parameters[1]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectFindByIdEvent $event) use ($internalObject, $contactEntity) {
|
||||
$this->assertSame($internalObject, $event->getObject());
|
||||
$event->setId($contactEntity->getId());
|
||||
$event->setEntity($contactEntity);
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORD, $parameters[1]);
|
||||
}
|
||||
if (3 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalContactEvent $event) use ($contactEntity) {
|
||||
$this->assertSame($contactEntity, $event->getContact());
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_BEFORE_FULL_CONTACT_REPORT_BUILD, $parameters[1]);
|
||||
}
|
||||
|
||||
return $parameters[0];
|
||||
});
|
||||
|
||||
$report = $this->reportBuilder->buildReport($requestDAO);
|
||||
$objects = $report->getObjects(Contact::NAME);
|
||||
|
||||
$this->assertTrue(isset($objects[1]));
|
||||
$this->assertEquals(self::TEST_EMAIL, $objects[1]->getField('email')->getValue()->getNormalizedValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FieldNotFoundException
|
||||
* @throws InvalidValueException
|
||||
*/
|
||||
public function testBuildingCompanyReportWithFindInternalRecordEvent(): void
|
||||
{
|
||||
$requestDAO = new RequestDAO(self::INTEGRATION_NAME, 1, new InputOptionsDAO(['integration' => self::INTEGRATION_NAME]));
|
||||
$fromDateTime = new \DateTimeImmutable('2018-10-08 00:00:00');
|
||||
$toDateTime = new \DateTimeImmutable('2018-10-08 00:01:00');
|
||||
$requestObject = new ObjectDAO(MauticSyncDataExchange::OBJECT_COMPANY, $fromDateTime, $toDateTime);
|
||||
$requestObject->addField('email');
|
||||
$requestDAO->addObject($requestObject);
|
||||
|
||||
$this->fieldBuilder->expects($this->once())
|
||||
->method('buildObjectField')
|
||||
->with('email', $this->anything(), $requestObject, $requestDAO->getSyncToIntegration())
|
||||
->willReturn(
|
||||
new FieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, self::TEST_EMAIL))
|
||||
);
|
||||
|
||||
$internalObject = new Company();
|
||||
|
||||
$this->objectProvider->expects($this->exactly(2))
|
||||
->method('getObjectByName')
|
||||
->with(Company::NAME)
|
||||
->willReturn($internalObject);
|
||||
$matcher = $this->exactly(2);
|
||||
|
||||
$this->dispatcher->expects($matcher)
|
||||
->method('hasListeners')->willReturnCallback(function (...$parameters) use ($matcher) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORD, $parameters[0]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_BEFORE_FULL_COMPANY_REPORT_BUILD, $parameters[0]);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
$companyEntity = new class extends CompanyEntity {
|
||||
public function getId(): int
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
$matcher = $this->exactly(3);
|
||||
|
||||
$this->dispatcher->expects($matcher)
|
||||
->method('dispatch')->willReturnCallback(function (...$parameters) use ($matcher, $internalObject,
|
||||
$fromDateTime,
|
||||
$toDateTime,
|
||||
$companyEntity) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectFindEvent $event) use (
|
||||
$internalObject,
|
||||
$fromDateTime,
|
||||
$toDateTime
|
||||
) {
|
||||
$this->assertSame($internalObject, $event->getObject());
|
||||
$this->assertSame($fromDateTime, $event->getDateRange()->getFromDate());
|
||||
$this->assertSame($toDateTime, $event->getDateRange()->getToDate());
|
||||
$this->assertSame(0, $event->getStart());
|
||||
$this->assertSame(200, $event->getLimit());
|
||||
|
||||
// Mock a subscriber:
|
||||
$event->setFoundObjects(
|
||||
[
|
||||
[
|
||||
'id' => 1,
|
||||
'email' => self::TEST_EMAIL,
|
||||
'date_modified' => '2018-10-08 00:30:00',
|
||||
],
|
||||
]
|
||||
);
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORDS, $parameters[1]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalObjectFindByIdEvent $event) use ($internalObject, $companyEntity) {
|
||||
$this->assertSame($internalObject, $event->getObject());
|
||||
$event->setId($companyEntity->getId());
|
||||
$event->setEntity($companyEntity);
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORD, $parameters[1]);
|
||||
}
|
||||
if (3 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (InternalCompanyEvent $event) use ($companyEntity) {
|
||||
$this->assertSame($companyEntity, $event->getCompany());
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_BEFORE_FULL_COMPANY_REPORT_BUILD, $parameters[1]);
|
||||
}
|
||||
|
||||
return $parameters[0];
|
||||
});
|
||||
|
||||
$report = $this->reportBuilder->buildReport($requestDAO);
|
||||
$objects = $report->getObjects(MauticSyncDataExchange::OBJECT_COMPANY);
|
||||
|
||||
$this->assertTrue(isset($objects[1]));
|
||||
$this->assertEquals(self::TEST_EMAIL, $objects[1]->getField('email')->getValue()->getNormalizedValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncDataExchange\Internal\ReportBuilder;
|
||||
|
||||
use Mautic\IntegrationsBundle\Entity\FieldChangeRepository;
|
||||
use Mautic\IntegrationsBundle\Event\InternalObjectFindEvent;
|
||||
use Mautic\IntegrationsBundle\IntegrationEvents;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\InputOptionsDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\FieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Request\ObjectDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Request\RequestDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\EncodedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\FieldNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Helper\FieldHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Company as InternalCompany;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ObjectProvider;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ReportBuilder\FieldBuilder;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ReportBuilder\PartialObjectReportBuilder;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\MauticSyncDataExchange;
|
||||
use Mautic\LeadBundle\Entity\Company;
|
||||
use Mautic\LeadBundle\Entity\Lead;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class PartialObjectReportBuilderTest extends TestCase
|
||||
{
|
||||
private const INTEGRATION_NAME = 'Test';
|
||||
|
||||
/**
|
||||
* @var FieldChangeRepository|MockObject
|
||||
*/
|
||||
private MockObject $fieldChangeRepository;
|
||||
|
||||
/**
|
||||
* @var FieldHelper|MockObject
|
||||
*/
|
||||
private MockObject $fieldHelper;
|
||||
|
||||
/**
|
||||
* @var EventDispatcherInterface|MockObject
|
||||
*/
|
||||
private MockObject $dispatcher;
|
||||
|
||||
/**
|
||||
* @var FieldBuilder|MockObject
|
||||
*/
|
||||
private MockObject $fieldBuilder;
|
||||
|
||||
/**
|
||||
* @var ObjectProvider|MockObject
|
||||
*/
|
||||
private MockObject $objectProvider;
|
||||
|
||||
private PartialObjectReportBuilder $reportBuilder;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->fieldChangeRepository = $this->createMock(FieldChangeRepository::class);
|
||||
$this->fieldHelper = $this->getMockBuilder(FieldHelper::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['getFieldChangeObject', 'getFieldObjectName'])
|
||||
->getMock();
|
||||
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||
$this->fieldBuilder = $this->createMock(FieldBuilder::class);
|
||||
$this->objectProvider = $this->createMock(ObjectProvider::class);
|
||||
$this->reportBuilder = new PartialObjectReportBuilder(
|
||||
$this->fieldChangeRepository,
|
||||
$this->fieldHelper,
|
||||
$this->fieldBuilder,
|
||||
$this->objectProvider,
|
||||
$this->dispatcher
|
||||
);
|
||||
}
|
||||
|
||||
public function testTrackedContactChanges(): void
|
||||
{
|
||||
$requestDAO = new RequestDAO(self::INTEGRATION_NAME, 1, new InputOptionsDAO(['integration' => self::INTEGRATION_NAME]));
|
||||
$fromDateTime = new \DateTimeImmutable('2018-10-08 00:00:00');
|
||||
$toDateTime = new \DateTimeImmutable('2018-10-08 00:01:00');
|
||||
$requestObject = new ObjectDAO(Contact::NAME, $fromDateTime, $toDateTime);
|
||||
$requestObject->addField('email');
|
||||
$requestObject->addField('firstname');
|
||||
$requestDAO->addObject($requestObject);
|
||||
|
||||
$this->fieldBuilder->expects($this->once())
|
||||
->method('buildObjectField')
|
||||
->with('email', $this->anything(), $requestObject, self::INTEGRATION_NAME)
|
||||
->willReturn(
|
||||
new FieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'test@test.com'))
|
||||
);
|
||||
|
||||
$fieldChange = [
|
||||
'object_type' => Lead::class,
|
||||
'object_id' => 1,
|
||||
'modified_at' => '2018-10-08 00:30:00',
|
||||
'column_name' => 'firstname',
|
||||
'column_type' => EncodedValueDAO::STRING_TYPE,
|
||||
'column_value' => 'Bob',
|
||||
];
|
||||
|
||||
$this->fieldHelper->expects($this->once())
|
||||
->method('getFieldChangeObject')
|
||||
->with($fieldChange)
|
||||
->willReturn(
|
||||
new FieldDAO('firstname', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob'))
|
||||
);
|
||||
|
||||
$this->fieldHelper->expects($this->once())
|
||||
->method('getFieldObjectName')
|
||||
->with(Contact::NAME)
|
||||
->willReturn(Lead::class);
|
||||
|
||||
// Find and return tracked changes
|
||||
$this->fieldChangeRepository->expects($this->once())
|
||||
->method('findChangesBefore')
|
||||
->with(
|
||||
'Test',
|
||||
Lead::class,
|
||||
$toDateTime,
|
||||
0
|
||||
)
|
||||
->willReturn([$fieldChange]);
|
||||
|
||||
$internalObject = new Contact();
|
||||
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByEntityName')
|
||||
->with(Lead::class)
|
||||
->willReturn($internalObject);
|
||||
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByName')
|
||||
->with(Contact::NAME)
|
||||
->willReturn($internalObject);
|
||||
|
||||
// Find the complete object
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->callback(function (InternalObjectFindEvent $event) use ($internalObject) {
|
||||
$this->assertSame($internalObject, $event->getObject());
|
||||
$this->assertSame([1], $event->getIds());
|
||||
|
||||
// Mock a subscriber:
|
||||
$event->setFoundObjects([
|
||||
[
|
||||
'id' => 1,
|
||||
'email' => 'test@test.com',
|
||||
'firstname' => 'Bob and Cat',
|
||||
],
|
||||
]);
|
||||
|
||||
return true;
|
||||
}),
|
||||
IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORDS
|
||||
);
|
||||
|
||||
$report = $this->reportBuilder->buildReport($requestDAO);
|
||||
$objects = $report->getObjects(Contact::NAME);
|
||||
|
||||
$this->assertTrue(isset($objects[1]));
|
||||
$this->assertEquals('test@test.com', $objects[1]->getField('email')->getValue()->getNormalizedValue());
|
||||
$this->assertEquals('Bob', $objects[1]->getField('firstname')->getValue()->getNormalizedValue());
|
||||
}
|
||||
|
||||
public function testTrackedCompanyChanges(): void
|
||||
{
|
||||
$requestDAO = new RequestDAO(self::INTEGRATION_NAME, 1, new InputOptionsDAO(['integration' => self::INTEGRATION_NAME]));
|
||||
$fromDateTime = new \DateTimeImmutable('2018-10-08 00:00:00');
|
||||
$toDateTime = new \DateTimeImmutable('2018-10-08 00:01:00');
|
||||
$requestObject = new ObjectDAO(MauticSyncDataExchange::OBJECT_COMPANY, $fromDateTime, $toDateTime);
|
||||
$requestObject->addField('email');
|
||||
$requestObject->addField('companyname');
|
||||
$requestDAO->addObject($requestObject);
|
||||
|
||||
$this->fieldBuilder->expects($this->once())
|
||||
->method('buildObjectField')
|
||||
->with('email', $this->anything(), $requestObject, self::INTEGRATION_NAME)
|
||||
->willReturn(
|
||||
new FieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'test@test.com'))
|
||||
);
|
||||
|
||||
$fieldChange = [
|
||||
'object_type' => Company::class,
|
||||
'object_id' => 1,
|
||||
'modified_at' => '2018-10-08 00:30:00',
|
||||
'column_name' => 'firstname',
|
||||
'column_type' => EncodedValueDAO::STRING_TYPE,
|
||||
'column_value' => 'Bob',
|
||||
];
|
||||
|
||||
$this->fieldHelper->expects($this->once())
|
||||
->method('getFieldChangeObject')
|
||||
->with($fieldChange)
|
||||
->willReturn(
|
||||
new FieldDAO('companyname', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob and Cat'))
|
||||
);
|
||||
|
||||
$this->fieldHelper->expects($this->once())
|
||||
->method('getFieldObjectName')
|
||||
->with(InternalCompany::NAME)
|
||||
->willReturn(Company::class);
|
||||
|
||||
// Find and return tracked changes
|
||||
$this->fieldChangeRepository->expects($this->once())
|
||||
->method('findChangesBefore')
|
||||
->with(
|
||||
'Test',
|
||||
Company::class,
|
||||
$toDateTime,
|
||||
0
|
||||
)
|
||||
->willReturn([$fieldChange]);
|
||||
|
||||
$internalObject = new InternalCompany();
|
||||
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByEntityName')
|
||||
->with(Company::class)
|
||||
->willReturn($internalObject);
|
||||
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByName')
|
||||
->with(InternalCompany::NAME)
|
||||
->willReturn($internalObject);
|
||||
|
||||
// Find the complete object
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->callback(function (InternalObjectFindEvent $event) use ($internalObject) {
|
||||
$this->assertSame([1], $event->getIds());
|
||||
$this->assertSame($internalObject, $event->getObject());
|
||||
|
||||
// Mock a subscriber:
|
||||
$event->setFoundObjects([
|
||||
[
|
||||
'id' => 1,
|
||||
'email' => 'test@test.com',
|
||||
'companyname' => 'Bob and Cat',
|
||||
],
|
||||
]);
|
||||
|
||||
return true;
|
||||
}),
|
||||
IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORDS
|
||||
);
|
||||
|
||||
$report = $this->reportBuilder->buildReport($requestDAO);
|
||||
$objects = $report->getObjects(InternalCompany::NAME);
|
||||
|
||||
$this->assertTrue(isset($objects[1]));
|
||||
$this->assertEquals('test@test.com', $objects[1]->getField('email')->getValue()->getNormalizedValue());
|
||||
$this->assertEquals('Bob and Cat', $objects[1]->getField('companyname')->getValue()->getNormalizedValue());
|
||||
}
|
||||
|
||||
public function testTrackedContactChangesThrowsObjectNotFoundException(): void
|
||||
{
|
||||
$requestDAO = new RequestDAO(self::INTEGRATION_NAME, 1, new InputOptionsDAO(['integration' => self::INTEGRATION_NAME]));
|
||||
$fromDateTime = new \DateTimeImmutable('2018-10-08 00:00:00');
|
||||
$toDateTime = new \DateTimeImmutable('2018-10-08 00:01:00');
|
||||
$requestObject = new ObjectDAO(Contact::NAME, $fromDateTime, $toDateTime);
|
||||
$requestObject->addField('email');
|
||||
$requestObject->addField('firstname');
|
||||
$requestDAO->addObject($requestObject);
|
||||
|
||||
$fieldChange = [
|
||||
'object_type' => Lead::class,
|
||||
'object_id' => 1,
|
||||
'modified_at' => '2018-10-08 00:30:00',
|
||||
'column_name' => 'firstname',
|
||||
'column_type' => EncodedValueDAO::STRING_TYPE,
|
||||
'column_value' => 'Bob',
|
||||
];
|
||||
|
||||
$this->fieldHelper->expects($this->once())
|
||||
->method('getFieldObjectName')
|
||||
->with(Contact::NAME)
|
||||
->willReturn(Lead::class);
|
||||
|
||||
// Find and return tracked changes
|
||||
$this->fieldChangeRepository->expects($this->once())
|
||||
->method('findChangesBefore')
|
||||
->with(
|
||||
'Test',
|
||||
Lead::class,
|
||||
$toDateTime,
|
||||
0
|
||||
)
|
||||
->willReturn([$fieldChange]);
|
||||
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByEntityName')
|
||||
->with(Lead::class)
|
||||
->willThrowException(new ObjectNotFoundException(Contact::NAME));
|
||||
|
||||
$report = $this->reportBuilder->buildReport($requestDAO);
|
||||
$objects = $report->getObjects(Contact::NAME);
|
||||
|
||||
$this->assertEmpty($objects);
|
||||
}
|
||||
|
||||
public function testTrackedContactChangesFieldNotFoundException(): void
|
||||
{
|
||||
$exception = new FieldNotFoundException('email', 'company');
|
||||
$this->expectExceptionObject($exception);
|
||||
|
||||
$requestDAO = new RequestDAO(self::INTEGRATION_NAME, 1, new InputOptionsDAO(['integration' => self::INTEGRATION_NAME]));
|
||||
$fromDateTime = new \DateTimeImmutable('2018-10-08 00:00:00');
|
||||
$toDateTime = new \DateTimeImmutable('2018-10-08 00:01:00');
|
||||
$requestObject = new ObjectDAO(MauticSyncDataExchange::OBJECT_COMPANY, $fromDateTime, $toDateTime);
|
||||
$requestObject->addField('email');
|
||||
$requestObject->addField('companyname');
|
||||
$requestDAO->addObject($requestObject);
|
||||
|
||||
$this->fieldBuilder->expects($this->once())
|
||||
->method('buildObjectField')
|
||||
->with('email', $this->anything(), $requestObject, self::INTEGRATION_NAME)
|
||||
->willThrowException(new FieldNotFoundException('email', $requestObject->getObject()));
|
||||
|
||||
$fieldChange = [
|
||||
'object_type' => Company::class,
|
||||
'object_id' => 1,
|
||||
'modified_at' => '2018-10-08 00:30:00',
|
||||
'column_name' => 'firstname',
|
||||
'column_type' => EncodedValueDAO::STRING_TYPE,
|
||||
'column_value' => 'Bob',
|
||||
];
|
||||
|
||||
$this->fieldHelper->expects($this->once())
|
||||
->method('getFieldChangeObject')
|
||||
->with($fieldChange)
|
||||
->willReturn(
|
||||
new FieldDAO('companyname', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob and Cat'))
|
||||
);
|
||||
|
||||
$this->fieldHelper->expects($this->once())
|
||||
->method('getFieldObjectName')
|
||||
->with(InternalCompany::NAME)
|
||||
->willReturn(Company::class);
|
||||
|
||||
// Find and return tracked changes
|
||||
$this->fieldChangeRepository->expects($this->once())
|
||||
->method('findChangesBefore')
|
||||
->with(
|
||||
'Test',
|
||||
Company::class,
|
||||
$toDateTime,
|
||||
0
|
||||
)
|
||||
->willReturn([$fieldChange]);
|
||||
|
||||
$internalObject = new InternalCompany();
|
||||
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByEntityName')
|
||||
->with(Company::class)
|
||||
->willReturn($internalObject);
|
||||
|
||||
$this->objectProvider->expects($this->once())
|
||||
->method('getObjectByName')
|
||||
->with(InternalCompany::NAME)
|
||||
->willReturn($internalObject);
|
||||
|
||||
// Find the complete object
|
||||
$this->dispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(
|
||||
$this->callback(function (InternalObjectFindEvent $event) use ($internalObject) {
|
||||
$this->assertSame([1], $event->getIds());
|
||||
$this->assertSame($internalObject, $event->getObject());
|
||||
|
||||
// Mock a subscriber:
|
||||
$event->setFoundObjects([
|
||||
[
|
||||
'id' => 1,
|
||||
'email' => 'test@test.com',
|
||||
'companyname' => 'Bob and Cat',
|
||||
],
|
||||
]);
|
||||
|
||||
return true;
|
||||
}),
|
||||
IntegrationEvents::INTEGRATION_FIND_INTERNAL_RECORDS
|
||||
);
|
||||
|
||||
$report = $this->reportBuilder->buildReport($requestDAO);
|
||||
$objects = $report->getObjects(InternalCompany::NAME);
|
||||
|
||||
$this->assertTrue(isset($objects[1]));
|
||||
// trying to access non-existent object
|
||||
$objects[1]->getField('email');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncDataExchange;
|
||||
|
||||
use Mautic\IntegrationsBundle\Entity\FieldChangeRepository;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\MappingManualDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\InputOptionsDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\FieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\ObjectDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Request\RequestDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Helper\MappingHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\Helper\SyncDateHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Helper\FieldHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Executioner\OrderExecutioner;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ReportBuilder\FullObjectReportBuilder;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ReportBuilder\PartialObjectReportBuilder;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\MauticSyncDataExchange;
|
||||
use Mautic\LeadBundle\Entity\Lead;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class MauticSyncDataExchangeTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var MockObject|FieldChangeRepository
|
||||
*/
|
||||
private MockObject $fieldChangeRepository;
|
||||
|
||||
/**
|
||||
* @var MockObject|FieldHelper
|
||||
*/
|
||||
private MockObject $fieldHelper;
|
||||
|
||||
/**
|
||||
* @var MockObject|MappingHelper
|
||||
*/
|
||||
private MockObject $mappingHelper;
|
||||
|
||||
/**
|
||||
* @var MockObject|FullObjectReportBuilder
|
||||
*/
|
||||
private MockObject $fullObjectReportBuilder;
|
||||
|
||||
/**
|
||||
* @var MockObject|PartialObjectReportBuilder
|
||||
*/
|
||||
private MockObject $partialObjectReportBuilder;
|
||||
|
||||
/**
|
||||
* @var MockObject|OrderExecutioner
|
||||
*/
|
||||
private MockObject $orderExecutioner;
|
||||
|
||||
private MauticSyncDataExchange $mauticSyncDataExchange;
|
||||
|
||||
/**
|
||||
* @var SyncDateHelper&MockObject
|
||||
*/
|
||||
private MockObject $syncDateHelper;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->fieldChangeRepository = $this->createMock(FieldChangeRepository::class);
|
||||
$this->fieldHelper = $this->createMock(FieldHelper::class);
|
||||
$this->mappingHelper = $this->createMock(MappingHelper::class);
|
||||
$this->fullObjectReportBuilder = $this->createMock(FullObjectReportBuilder::class);
|
||||
$this->partialObjectReportBuilder = $this->createMock(PartialObjectReportBuilder::class);
|
||||
$this->orderExecutioner = $this->createMock(OrderExecutioner::class);
|
||||
$this->syncDateHelper = $this->createMock(SyncDateHelper::class);
|
||||
|
||||
$this->mauticSyncDataExchange = new MauticSyncDataExchange(
|
||||
$this->fieldChangeRepository,
|
||||
$this->fieldHelper,
|
||||
$this->mappingHelper,
|
||||
$this->fullObjectReportBuilder,
|
||||
$this->partialObjectReportBuilder,
|
||||
$this->orderExecutioner,
|
||||
$this->syncDateHelper
|
||||
);
|
||||
}
|
||||
|
||||
public function testFirstTimeSyncUsesFullObjectBuilder(): void
|
||||
{
|
||||
$inputOptionsDAO = new InputOptionsDAO(
|
||||
[
|
||||
'integration' => 'foobar',
|
||||
'first-time-sync' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$requestDAO = new RequestDAO('foobar', 1, $inputOptionsDAO);
|
||||
|
||||
$this->fullObjectReportBuilder->expects($this->once())
|
||||
->method('buildReport')
|
||||
->with($requestDAO);
|
||||
|
||||
$this->partialObjectReportBuilder->expects($this->never())
|
||||
->method('buildReport')
|
||||
->with($requestDAO);
|
||||
|
||||
$this->mauticSyncDataExchange->getSyncReport($requestDAO);
|
||||
}
|
||||
|
||||
public function testSyncingSpecificMauticIdsUseFullObjectBuilder(): void
|
||||
{
|
||||
$inputOptionsDAO = new InputOptionsDAO(
|
||||
[
|
||||
'integration' => 'foobar',
|
||||
'mautic-object-id' => [1, 2, 3],
|
||||
]
|
||||
);
|
||||
|
||||
$requestDAO = new RequestDAO('foobar', 1, $inputOptionsDAO);
|
||||
|
||||
$this->fullObjectReportBuilder->expects($this->once())
|
||||
->method('buildReport')
|
||||
->with($requestDAO);
|
||||
|
||||
$this->partialObjectReportBuilder->expects($this->never())
|
||||
->method('buildReport')
|
||||
->with($requestDAO);
|
||||
|
||||
$this->mauticSyncDataExchange->getSyncReport($requestDAO);
|
||||
}
|
||||
|
||||
public function testUseOfPartialObjectBuilder(): void
|
||||
{
|
||||
$inputOptionsDAO = new InputOptionsDAO(
|
||||
[
|
||||
'integration' => 'foobar',
|
||||
]
|
||||
);
|
||||
|
||||
$requestDAO = new RequestDAO('foobar', 1, $inputOptionsDAO);
|
||||
|
||||
$this->fullObjectReportBuilder->expects($this->never())
|
||||
->method('buildReport')
|
||||
->with($requestDAO);
|
||||
|
||||
$this->partialObjectReportBuilder->expects($this->once())
|
||||
->method('buildReport')
|
||||
->with($requestDAO);
|
||||
|
||||
$this->mauticSyncDataExchange->getSyncReport($requestDAO);
|
||||
}
|
||||
|
||||
public function testGetConflictedInternalObjectWithNoObjectId(): void
|
||||
{
|
||||
$mappingManualDao = new MappingManualDAO('IntegrationA');
|
||||
$integrationObjectDao = new ObjectDAO('Lead', 'some-SF-ID');
|
||||
|
||||
$this->mappingHelper->expects($this->once())
|
||||
->method('findMauticObject')
|
||||
->with($mappingManualDao, 'lead', $integrationObjectDao)
|
||||
->willReturn(new ObjectDAO('lead', null));
|
||||
|
||||
// No need to make the DB query when ID is null.
|
||||
$this->fieldChangeRepository->expects($this->never())
|
||||
->method('findChangesForObject');
|
||||
|
||||
$internalObjectDao = $this->mauticSyncDataExchange->getConflictedInternalObject($mappingManualDao, 'lead', $integrationObjectDao);
|
||||
|
||||
Assert::assertSame('lead', $internalObjectDao->getObject());
|
||||
Assert::assertNull($internalObjectDao->getObjectId());
|
||||
}
|
||||
|
||||
public function testGetConflictedInternalObjectWithObjectId(): void
|
||||
{
|
||||
$mappingManualDao = new MappingManualDAO('IntegrationA');
|
||||
$integrationObjectDao = new ObjectDAO('Lead', 'some-SF-ID');
|
||||
$fieldChange = [
|
||||
'modified_at' => '2020-08-25 17:20:00',
|
||||
'column_type' => 'text',
|
||||
'column_value' => 'some-field-value',
|
||||
'column_name' => 'some-field-name',
|
||||
];
|
||||
|
||||
$this->mappingHelper->expects($this->once())
|
||||
->method('findMauticObject')
|
||||
->with($mappingManualDao, 'lead', $integrationObjectDao)
|
||||
->willReturn(new ObjectDAO('lead', 123));
|
||||
|
||||
$this->mappingHelper->method('getMauticEntityClassName')
|
||||
->with('lead')
|
||||
->willReturn(Lead::class);
|
||||
|
||||
$this->fieldHelper->method('getFieldChangeObject')
|
||||
->with($fieldChange)
|
||||
->willReturn(new FieldDAO('some-field-name', new NormalizedValueDAO('type', 'some-field-value')));
|
||||
|
||||
$this->fieldChangeRepository->expects($this->once())
|
||||
->method('findChangesForObject')
|
||||
->with('IntegrationA', Lead::class, 123)
|
||||
->willReturn([$fieldChange]);
|
||||
|
||||
$internalObjectDao = $this->mauticSyncDataExchange->getConflictedInternalObject($mappingManualDao, 'lead', $integrationObjectDao);
|
||||
|
||||
Assert::assertSame('lead', $internalObjectDao->getObject());
|
||||
Assert::assertSame(123, $internalObjectDao->getObjectId());
|
||||
Assert::assertCount(1, $internalObjectDao->getFields());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncJudge\Modes;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\InformationChangeRequestDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ConflictUnresolvedException;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncJudge\Modes\BestEvidence;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class BestEvidenceTest extends TestCase
|
||||
{
|
||||
public function testLeftWinnerWithCertainChangeDateTime(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$winner = BestEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
|
||||
$this->assertEquals($leftChangeRequest, $winner);
|
||||
}
|
||||
|
||||
public function testRightWinnerWithCertainChangeDateTime(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$winner = BestEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
|
||||
$this->assertEquals($rightChangeRequest, $winner);
|
||||
}
|
||||
|
||||
public function testLeftWinnerWithPossibleChangeDateTime(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$winner = BestEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
|
||||
$this->assertEquals($leftChangeRequest, $winner);
|
||||
}
|
||||
|
||||
public function testRightWinnerWithPossibleChangeDateTime(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$winner = BestEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
|
||||
$this->assertEquals($rightChangeRequest, $winner);
|
||||
}
|
||||
|
||||
public function testUnresolvedConflictExceptionThrownIfEqual(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$this->expectException(ConflictUnresolvedException::class);
|
||||
BestEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
}
|
||||
|
||||
public function testUnresolvedConflictExceptionThrownWhenLeftPossibleChangeDateTimeIsNull(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$this->expectException(ConflictUnresolvedException::class);
|
||||
BestEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
}
|
||||
|
||||
public function testUnresolvedConflictExceptionThrownWhenRightPossibleChangeDateTimeIsNull(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
|
||||
$this->expectException(ConflictUnresolvedException::class);
|
||||
BestEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncJudge\Modes;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\InformationChangeRequestDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ConflictUnresolvedException;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncJudge\Modes\FuzzyEvidence;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class FuzzyEvidenceTest extends TestCase
|
||||
{
|
||||
public function testLeftWinnerWithCertainChangeDateTime(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$winner = FuzzyEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
|
||||
$this->assertEquals($leftChangeRequest, $winner);
|
||||
}
|
||||
|
||||
public function testRightWinnerWithCertainChangeDateTime(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$winner = FuzzyEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
|
||||
$this->assertEquals($rightChangeRequest, $winner);
|
||||
}
|
||||
|
||||
public function testLeftWinnerWithPossibleChangeDateTime(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$winner = FuzzyEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
|
||||
$this->assertEquals($leftChangeRequest, $winner);
|
||||
}
|
||||
|
||||
public function testRightWinnerWithPossibleChangeDateTime(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$winner = FuzzyEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
|
||||
$this->assertEquals($rightChangeRequest, $winner);
|
||||
}
|
||||
|
||||
public function testLeftWinnerWithCertainChangeDateTimeNewerThanRightPossibleChangeDateTime(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$winner = FuzzyEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
|
||||
$this->assertEquals($leftChangeRequest, $winner);
|
||||
}
|
||||
|
||||
public function testRightWinnerWithCertainChangeDateTimeNewerThanLeftPossibleChangeDateTime(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$winner = FuzzyEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
|
||||
$this->assertEquals($rightChangeRequest, $winner);
|
||||
}
|
||||
|
||||
public function testUnresolvedConflictExceptionThrownIfLeftCertainIsEqualToRightPossible(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$this->expectException(ConflictUnresolvedException::class);
|
||||
FuzzyEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
}
|
||||
|
||||
public function testUnresolvedConflictExceptionThrownIfRightCertainIsEqualToLeftPossible(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$this->expectException(ConflictUnresolvedException::class);
|
||||
FuzzyEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
}
|
||||
|
||||
public function testUnresolvedConflictExceptionThrownIfLeftCertainIsNull(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$this->expectException(ConflictUnresolvedException::class);
|
||||
FuzzyEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
}
|
||||
|
||||
public function testUnresolvedConflictExceptionThrownIfRightCertainIsNull(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
|
||||
$this->expectException(ConflictUnresolvedException::class);
|
||||
FuzzyEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
}
|
||||
|
||||
public function testUnresolvedConflictExceptionThrownIfLeftPossibleIsNull(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$this->expectException(ConflictUnresolvedException::class);
|
||||
FuzzyEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
}
|
||||
|
||||
public function testUnresolvedConflictExceptionThrownIfRightPossibleIsNull(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setPossibleChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
|
||||
$this->expectException(ConflictUnresolvedException::class);
|
||||
FuzzyEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncJudge\Modes;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\InformationChangeRequestDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ConflictUnresolvedException;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncJudge\Modes\HardEvidence;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class HardEvidenceTest extends TestCase
|
||||
{
|
||||
public function testLeftWinner(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$winner = HardEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
|
||||
$this->assertEquals($leftChangeRequest, $winner);
|
||||
}
|
||||
|
||||
public function testRightWinner(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:01:00'));
|
||||
|
||||
$winner = HardEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
|
||||
$this->assertEquals($rightChangeRequest, $winner);
|
||||
}
|
||||
|
||||
public function testUnresolvedConflictExceptionThrownIfEqual(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$this->expectException(ConflictUnresolvedException::class);
|
||||
HardEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
}
|
||||
|
||||
public function testUnresolvedConflictExceptionThrownWhenLeftCertainChangeDateTimeIsNull(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$rightChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$this->expectException(ConflictUnresolvedException::class);
|
||||
HardEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
}
|
||||
|
||||
public function testUnresolvedConflictExceptionThrownWhenRightCertainChangeDateTimeIsNull(): void
|
||||
{
|
||||
$leftChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
$leftChangeRequest->setCertainChangeDateTime(new \DateTimeImmutable('2018-10-08 00:00:00'));
|
||||
|
||||
$rightChangeRequest = new InformationChangeRequestDAO(
|
||||
'Test',
|
||||
'Object',
|
||||
1,
|
||||
'field',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'test')
|
||||
);
|
||||
|
||||
$this->expectException(ConflictUnresolvedException::class);
|
||||
HardEvidence::adjudicate($leftChangeRequest, $rightChangeRequest);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncProcess\Direction\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Exception\RequiredValueException;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\ObjectMappingDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\FieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Helper\ValueHelper;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ValueHelperTest extends TestCase
|
||||
{
|
||||
public function testExceptionForMissingRequiredIntegrationValue(): void
|
||||
{
|
||||
$this->expectException(RequiredValueException::class);
|
||||
|
||||
$normalizedValueDAO = new NormalizedValueDAO(NormalizedValueDAO::STRING_TYPE, '');
|
||||
|
||||
$this->getValueHelper()->getValueForIntegration(
|
||||
$normalizedValueDAO,
|
||||
FieldDAO::FIELD_REQUIRED,
|
||||
ObjectMappingDAO::SYNC_TO_INTEGRATION
|
||||
);
|
||||
}
|
||||
|
||||
public function testNoExceptionForMissingNonRequiredIntegrationValue(): void
|
||||
{
|
||||
$normalizedValueDAO = new NormalizedValueDAO(NormalizedValueDAO::STRING_TYPE, '');
|
||||
|
||||
$newValue = $this->getValueHelper()->getValueForIntegration(
|
||||
$normalizedValueDAO,
|
||||
FieldDAO::FIELD_CHANGED,
|
||||
ObjectMappingDAO::SYNC_TO_MAUTIC
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'',
|
||||
$newValue->getNormalizedValue()
|
||||
);
|
||||
}
|
||||
|
||||
public function testNoExceptionForMissingOppositeSyncIntegrationValue(): void
|
||||
{
|
||||
$normalizedValueDAO = new NormalizedValueDAO(NormalizedValueDAO::STRING_TYPE, '');
|
||||
|
||||
$newValue = $this->getValueHelper()->getValueForIntegration(
|
||||
$normalizedValueDAO,
|
||||
FieldDAO::FIELD_CHANGED,
|
||||
ObjectMappingDAO::SYNC_TO_INTEGRATION
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'',
|
||||
$newValue->getNormalizedValue()
|
||||
);
|
||||
}
|
||||
|
||||
public function testExceptionForMissingRequiredMauticValue(): void
|
||||
{
|
||||
$this->expectException(RequiredValueException::class);
|
||||
|
||||
$normalizedValueDAO = new NormalizedValueDAO(NormalizedValueDAO::STRING_TYPE, '');
|
||||
|
||||
$this->getValueHelper()->getValueForMautic(
|
||||
$normalizedValueDAO,
|
||||
FieldDAO::FIELD_REQUIRED,
|
||||
ObjectMappingDAO::SYNC_TO_MAUTIC
|
||||
);
|
||||
}
|
||||
|
||||
public function testNoExceptionForMissingNonRequiredInternalValue(): void
|
||||
{
|
||||
$normalizedValueDAO = new NormalizedValueDAO(NormalizedValueDAO::STRING_TYPE, '');
|
||||
|
||||
$newValue = $this->getValueHelper()->getValueForMautic(
|
||||
$normalizedValueDAO,
|
||||
FieldDAO::FIELD_CHANGED,
|
||||
ObjectMappingDAO::SYNC_TO_INTEGRATION
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'',
|
||||
$newValue->getNormalizedValue()
|
||||
);
|
||||
}
|
||||
|
||||
public function testNoExceptionForMissingOppositeSyncInternalnValue(): void
|
||||
{
|
||||
$normalizedValueDAO = new NormalizedValueDAO(NormalizedValueDAO::STRING_TYPE, '');
|
||||
|
||||
$newValue = $this->getValueHelper()->getValueForMautic(
|
||||
$normalizedValueDAO,
|
||||
FieldDAO::FIELD_CHANGED,
|
||||
ObjectMappingDAO::SYNC_TO_MAUTIC
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'',
|
||||
$newValue->getNormalizedValue()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ValueHelper
|
||||
*/
|
||||
private function getValueHelper()
|
||||
{
|
||||
return new ValueHelper();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncProcess\Direction\Integration;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\MappingManualDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\ObjectMappingDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\InputOptionsDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\FieldDAO as OrderFieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\ObjectChangeDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\FieldDAO as ReportFieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\ObjectDAO as ReportObjectDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\ReportDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Request\ObjectDAO as RequestObjectDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Request\RequestDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Helper\MappingHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\Helper\SyncDateHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Company;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\MauticSyncDataExchange;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\SyncDataExchangeInterface;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Integration\IntegrationSyncProcess;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Integration\ObjectChangeGenerator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class IntegrationSyncProcessTest extends TestCase
|
||||
{
|
||||
private const INTEGRATION_NAME = 'Test';
|
||||
|
||||
/**
|
||||
* @var SyncDateHelper|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $syncDateHelper;
|
||||
|
||||
/**
|
||||
* @var MappingHelper|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $mappingHelper;
|
||||
|
||||
/**
|
||||
* @var ObjectChangeGenerator|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $objectChangeGenerator;
|
||||
|
||||
/**
|
||||
* @var SyncDataExchangeInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $syncDataExchange;
|
||||
|
||||
/**
|
||||
* @var InputOptionsDAO
|
||||
*/
|
||||
private $inputOptionsDAO;
|
||||
|
||||
/**
|
||||
* @var IntegrationSyncProcess
|
||||
*/
|
||||
private $integrationSyncProcess;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->syncDateHelper = $this->createMock(SyncDateHelper::class);
|
||||
$this->mappingHelper = $this->createMock(MappingHelper::class);
|
||||
$this->objectChangeGenerator = $this->createMock(ObjectChangeGenerator::class);
|
||||
$this->syncDataExchange = $this->createMock(SyncDataExchangeInterface::class);
|
||||
$this->inputOptionsDAO = new InputOptionsDAO(['integration' => self::INTEGRATION_NAME]);
|
||||
$this->integrationSyncProcess = new IntegrationSyncProcess($this->syncDateHelper, $this->mappingHelper, $this->objectChangeGenerator);
|
||||
}
|
||||
|
||||
public function testThatIntegrationGetSyncReportIsCalledBasedOnRequest(): void
|
||||
{
|
||||
$objectName = 'Contact';
|
||||
$mappingManual = new MappingManualDAO(self::INTEGRATION_NAME);
|
||||
$objectMapping = new ObjectMappingDAO(Contact::NAME, $objectName);
|
||||
$objectMapping->addFieldMapping('email', 'email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$objectMapping->addFieldMapping('firstname', 'first_name');
|
||||
$mappingManual->addObjectMapping($objectMapping);
|
||||
|
||||
$fromSyncDateTime = new \DateTimeImmutable();
|
||||
$this->syncDateHelper->expects($this->once())
|
||||
->method('getSyncFromDateTime')
|
||||
->with(self::INTEGRATION_NAME, $objectName)
|
||||
->willReturn($fromSyncDateTime);
|
||||
|
||||
$toSyncDateTime = new \DateTimeImmutable();
|
||||
$this->syncDateHelper->expects($this->once())
|
||||
->method('getSyncToDateTime')
|
||||
->willReturn($toSyncDateTime);
|
||||
|
||||
// SyncDateExchangeInterface::getSyncReport should sync because an object was added to the report
|
||||
$this->syncDataExchange->expects($this->once())
|
||||
->method('getSyncReport')
|
||||
->willReturnCallback(
|
||||
function (RequestDAO $requestDAO) use ($objectName) {
|
||||
$requestObjects = $requestDAO->getObjects();
|
||||
$this->assertCount(1, $requestObjects);
|
||||
|
||||
/** @var RequestObjectDAO $requestObject */
|
||||
$requestObject = $requestObjects[0];
|
||||
$this->assertEquals(['email'], $requestObject->getRequiredFields());
|
||||
$this->assertEquals(['email', 'first_name'], $requestObject->getFields());
|
||||
$this->assertEquals($objectName, $requestObject->getObject());
|
||||
|
||||
return new ReportDAO(self::INTEGRATION_NAME);
|
||||
}
|
||||
);
|
||||
|
||||
$this->getSyncProcess($mappingManual)->getSyncReport(1);
|
||||
}
|
||||
|
||||
public function testThatIntegrationGetSyncReportIsNotCalledBasedOnRequest(): void
|
||||
{
|
||||
$objectName = 'Contact';
|
||||
$mappingManual = new MappingManualDAO(self::INTEGRATION_NAME);
|
||||
|
||||
$this->syncDateHelper->expects($this->never())
|
||||
->method('getSyncFromDateTime')
|
||||
->with(self::INTEGRATION_NAME, $objectName);
|
||||
|
||||
// SyncDateExchangeInterface::getSyncReport should sync because an object was added to the report
|
||||
$this->syncDataExchange->expects($this->never())
|
||||
->method('getSyncReport');
|
||||
|
||||
$report = $this->getSyncProcess($mappingManual)->getSyncReport(1);
|
||||
|
||||
$this->assertEquals(self::INTEGRATION_NAME, $report->getIntegration());
|
||||
}
|
||||
|
||||
public function testOrderIsBuiltBasedOnMapping(): void
|
||||
{
|
||||
$objectName = 'Contact';
|
||||
$mappingManual = new MappingManualDAO(self::INTEGRATION_NAME);
|
||||
$objectMapping = new ObjectMappingDAO(Contact::NAME, $objectName);
|
||||
$objectMapping->addFieldMapping('email', 'email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$objectMapping->addFieldMapping('firstname', 'first_name');
|
||||
$mappingManual->addObjectMapping($objectMapping);
|
||||
|
||||
$toSyncDateTime = new \DateTimeImmutable();
|
||||
$this->syncDateHelper->expects($this->once())
|
||||
->method('getSyncDateTime')
|
||||
->willReturn($toSyncDateTime);
|
||||
|
||||
$syncReport = new ReportDAO(MauticSyncDataExchange::NAME);
|
||||
$objectDAO = new ReportObjectDAO(Contact::NAME, 1);
|
||||
$objectDAO->addField(new ReportFieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'test@test.com')));
|
||||
$objectDAO->addField(new ReportFieldDAO('firstname', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob')));
|
||||
$syncReport->addObject($objectDAO);
|
||||
|
||||
// It should search for an integration object mapped to an internal object
|
||||
$this->mappingHelper->expects($this->once())
|
||||
->method('findIntegrationObject')
|
||||
->with(self::INTEGRATION_NAME, $objectName, $objectDAO)
|
||||
->willReturn(
|
||||
new ReportObjectDAO($objectName, 2)
|
||||
);
|
||||
|
||||
$objectChangeDAO = new ObjectChangeDAO(self::INTEGRATION_NAME, $objectName, 2, Contact::NAME, 1);
|
||||
$objectChangeDAO->addField(new OrderFieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'test@test.com')));
|
||||
$objectChangeDAO->addField(new OrderFieldDAO('first_name', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob')));
|
||||
$this->objectChangeGenerator->expects($this->once())
|
||||
->method('getSyncObjectChange')
|
||||
->willReturn($objectChangeDAO);
|
||||
|
||||
$syncOrder = $this->getSyncProcess($mappingManual)->getSyncOrder($syncReport);
|
||||
|
||||
// The change should have been added to the order as an identified object
|
||||
$this->assertEquals([$objectName => [2 => $objectChangeDAO]], $syncOrder->getIdentifiedObjects());
|
||||
}
|
||||
|
||||
private function getSyncProcess(MappingManualDAO $mappingManualDAO): IntegrationSyncProcess
|
||||
{
|
||||
$this->integrationSyncProcess->setupSync($this->inputOptionsDAO, $mappingManualDAO, $this->syncDataExchange);
|
||||
|
||||
return $this->integrationSyncProcess;
|
||||
}
|
||||
|
||||
public function testThatItDoesntSyncOtherEntityTypesWhenIDsForSomeEntityAreSpecified(): void
|
||||
{
|
||||
$mappingManual = new MappingManualDAO(self::INTEGRATION_NAME);
|
||||
$this->inputOptionsDAO = new InputOptionsDAO([
|
||||
'integration' => self::INTEGRATION_NAME,
|
||||
'mautic-object-id' => ['contact:1'],
|
||||
]);
|
||||
|
||||
$contactMapping = new ObjectMappingDAO(Contact::NAME, 'Contact');
|
||||
$contactMapping->addFieldMapping('email', 'email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$mappingManual->addObjectMapping($contactMapping);
|
||||
|
||||
$leadMapping = new ObjectMappingDAO(Contact::NAME, 'Lead');
|
||||
$leadMapping->addFieldMapping('email', 'email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$mappingManual->addObjectMapping($leadMapping);
|
||||
|
||||
$companyMapping = new ObjectMappingDAO(Company::NAME, 'Account');
|
||||
$companyMapping->addFieldMapping('email', 'email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$mappingManual->addObjectMapping($companyMapping);
|
||||
|
||||
$fromSyncDateTime = new \DateTimeImmutable();
|
||||
$matcher = $this->exactly(2);
|
||||
$this->syncDateHelper->expects($matcher)
|
||||
->method('getSyncFromDateTime')->willReturnCallback(function (...$parameters) use ($matcher, $fromSyncDateTime) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(self::INTEGRATION_NAME, $parameters[0]);
|
||||
$this->assertSame('Contact', $parameters[1]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(self::INTEGRATION_NAME, $parameters[0]);
|
||||
$this->assertSame('Lead', $parameters[1]);
|
||||
}
|
||||
|
||||
return $fromSyncDateTime;
|
||||
});
|
||||
|
||||
$toSyncDateTime = new \DateTimeImmutable();
|
||||
$this->syncDateHelper->expects($this->exactly(2))
|
||||
->method('getSyncToDateTime')
|
||||
->willReturn($toSyncDateTime);
|
||||
|
||||
// SyncDateExchangeInterface::getSyncReport should sync because an object was added to the report
|
||||
$this->syncDataExchange->expects($this->once())
|
||||
->method('getSyncReport')
|
||||
->willReturnCallback(
|
||||
function (RequestDAO $requestDAO): ReportDAO {
|
||||
$requestObjects = $requestDAO->getObjects();
|
||||
$this->assertCount(2, $requestObjects);
|
||||
|
||||
/** @var RequestObjectDAO $requestObject */
|
||||
$requestObject = $requestObjects[0];
|
||||
$this->assertEquals(['email'], $requestObject->getRequiredFields());
|
||||
$this->assertEquals(['email'], $requestObject->getFields());
|
||||
$this->assertEquals('Contact', $requestObject->getObject());
|
||||
|
||||
return new ReportDAO(self::INTEGRATION_NAME);
|
||||
}
|
||||
);
|
||||
|
||||
$syncReport = $this->getSyncProcess($mappingManual)->getSyncReport(1);
|
||||
$this->assertEquals(self::INTEGRATION_NAME, $syncReport->getIntegration());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncProcess\Direction\Integration;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\MappingManualDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\ObjectMappingDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\FieldDAO as ReportFieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\ObjectDAO as ReportObjectDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\ReportDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\MauticSyncDataExchange;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Helper\ValueHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Integration\ObjectChangeGenerator;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ObjectChangeGeneratorTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var ValueHelper|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private \PHPUnit\Framework\MockObject\MockObject $valueHelper;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->valueHelper = $this->createMock(ValueHelper::class);
|
||||
}
|
||||
|
||||
public function testFieldIsAddedToObjectChange(): void
|
||||
{
|
||||
$this->valueHelper->method('getValueForIntegration')
|
||||
->willReturnCallback(
|
||||
fn (NormalizedValueDAO $normalizedValueDAO, string $fieldState, string $syncDirection) => $normalizedValueDAO
|
||||
);
|
||||
|
||||
$integration = 'Test';
|
||||
$objectName = 'Contact';
|
||||
|
||||
$mappingManual = $this->getMappingManual($integration, $objectName);
|
||||
$syncReport = $this->getInternalSyncReport();
|
||||
|
||||
$integrationReportObject = new ReportObjectDAO($objectName, 2);
|
||||
$integrationReportObject->addField(new ReportFieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'test@test.com')));
|
||||
$integrationReportObject->addField(new ReportFieldDAO('first_name', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob')));
|
||||
|
||||
$objectChangeGenerator = $this->getObjectChangeGenerator();
|
||||
$objectChangeDAO = $objectChangeGenerator->getSyncObjectChange(
|
||||
$syncReport,
|
||||
$mappingManual,
|
||||
$mappingManual->getObjectMapping(Contact::NAME, $objectName),
|
||||
$syncReport->getObject(Contact::NAME, 1),
|
||||
$integrationReportObject
|
||||
);
|
||||
|
||||
$this->assertEquals($integration, $objectChangeDAO->getIntegration());
|
||||
|
||||
// object and object ID should be the integrations (from the integration's POV)
|
||||
$this->assertEquals($objectName, $objectChangeDAO->getObject());
|
||||
$this->assertEquals(2, $objectChangeDAO->getObjectId());
|
||||
|
||||
// mapped object and ID should be Mautic's
|
||||
$this->assertEquals(Contact::NAME, $objectChangeDAO->getMappedObject());
|
||||
$this->assertEquals(1, $objectChangeDAO->getMappedObjectId());
|
||||
|
||||
// Email should be a required field
|
||||
$requiredFields = $objectChangeDAO->getRequiredFields();
|
||||
$this->assertTrue(isset($requiredFields['email']));
|
||||
|
||||
// Both fields should be included
|
||||
$fields = $objectChangeDAO->getFields();
|
||||
$this->assertTrue(isset($fields['email']) && isset($fields['first_name']));
|
||||
|
||||
// First name is presumed to be changed
|
||||
$changedFields = $objectChangeDAO->getChangedFields();
|
||||
$this->assertTrue(isset($changedFields['first_name']));
|
||||
}
|
||||
|
||||
public function testFieldIsNotAddedToObjectChangeIfNotFound(): void
|
||||
{
|
||||
$this->valueHelper->method('getValueForIntegration')
|
||||
->willReturnCallback(
|
||||
fn (NormalizedValueDAO $normalizedValueDAO, string $fieldState, string $syncDirection) => $normalizedValueDAO
|
||||
);
|
||||
|
||||
$integration = 'Test';
|
||||
$objectName = 'Contact';
|
||||
|
||||
$mappingManual = $this->getMappingManual($integration, $objectName);
|
||||
$syncReport = $this->getInternalSyncReport(false);
|
||||
|
||||
$integrationReportObject = new ReportObjectDAO($objectName, 2);
|
||||
$integrationReportObject->addField(new ReportFieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'test@test.com')));
|
||||
$integrationReportObject->addField(new ReportFieldDAO('first_name', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob')));
|
||||
|
||||
$objectChangeGenerator = $this->getObjectChangeGenerator();
|
||||
$objectChangeDAO = $objectChangeGenerator->getSyncObjectChange(
|
||||
$syncReport,
|
||||
$mappingManual,
|
||||
$mappingManual->getObjectMapping(Contact::NAME, $objectName),
|
||||
$syncReport->getObject(Contact::NAME, 1),
|
||||
$integrationReportObject
|
||||
);
|
||||
|
||||
$this->assertEquals($integration, $objectChangeDAO->getIntegration());
|
||||
|
||||
// object and object ID should be the integrations (from the integration's POV)
|
||||
$this->assertEquals($objectName, $objectChangeDAO->getObject());
|
||||
$this->assertEquals(2, $objectChangeDAO->getObjectId());
|
||||
|
||||
// mapped object and ID should be Mautic's
|
||||
$this->assertEquals(Contact::NAME, $objectChangeDAO->getMappedObject());
|
||||
$this->assertEquals(1, $objectChangeDAO->getMappedObjectId());
|
||||
|
||||
// Email should be a required field
|
||||
$requiredFields = $objectChangeDAO->getRequiredFields();
|
||||
$this->assertTrue(isset($requiredFields['email']));
|
||||
|
||||
// First name should not be included because it wasn't found in the internal object
|
||||
$fields = $objectChangeDAO->getFields();
|
||||
$this->assertFalse(isset($fields['first_name']));
|
||||
}
|
||||
|
||||
public function testFieldsWithDirectionToIntegrationAreSkipped(): void
|
||||
{
|
||||
$objectChangeGenerator = new ObjectChangeGenerator(
|
||||
new class extends ValueHelper {
|
||||
}
|
||||
);
|
||||
|
||||
$integrationName = 'Integration A';
|
||||
$reportDAO = new ReportDAO($integrationName);
|
||||
$mappingManualDAO = new MappingManualDAO($integrationName);
|
||||
$objectMappingDAO = new ObjectMappingDAO(Contact::NAME, 'Lead');
|
||||
$internalObject = new ReportObjectDAO(Contact::NAME, 123);
|
||||
$integrationObject = new ReportObjectDAO('Lead', 'integration-id-1');
|
||||
|
||||
$objectMappingDAO->addFieldMapping('email', 'Email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$objectMappingDAO->addFieldMapping('firstname', 'FirstName', ObjectMappingDAO::SYNC_TO_INTEGRATION);
|
||||
$objectMappingDAO->addFieldMapping('points', 'Score', ObjectMappingDAO::SYNC_TO_MAUTIC);
|
||||
|
||||
$internalObject->addField(new ReportFieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'john@doe.email')));
|
||||
$internalObject->addField(new ReportFieldDAO('firstname', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'John')));
|
||||
$internalObject->addField(new ReportFieldDAO('points', new NormalizedValueDAO(NormalizedValueDAO::INT_TYPE, 40)));
|
||||
|
||||
$reportDAO->addObject($internalObject);
|
||||
|
||||
$objectChange = $objectChangeGenerator->getSyncObjectChange($reportDAO, $mappingManualDAO, $objectMappingDAO, $internalObject, $integrationObject);
|
||||
|
||||
// The points/Score field should not be recorded as a change because it has direction to Mautic.
|
||||
Assert::assertCount(2, $objectChange->getFields());
|
||||
Assert::assertSame('john@doe.email', $objectChange->getField('Email')->getValue()->getNormalizedValue());
|
||||
Assert::assertSame('John', $objectChange->getField('FirstName')->getValue()->getNormalizedValue());
|
||||
Assert::assertSame(Contact::NAME, $objectChange->getMappedObject());
|
||||
Assert::assertSame(123, $objectChange->getMappedObjectId());
|
||||
Assert::assertSame('integration-id-1', $objectChange->getObjectId());
|
||||
Assert::assertSame('Lead', $objectChange->getObject());
|
||||
Assert::assertSame($integrationName, $objectChange->getIntegration());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MappingManualDAO
|
||||
*/
|
||||
private function getMappingManual(string $integration, string $objectName)
|
||||
{
|
||||
$mappingManual = new MappingManualDAO($integration);
|
||||
$objectMapping = new ObjectMappingDAO(Contact::NAME, $objectName);
|
||||
$objectMapping->addFieldMapping('email', 'email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$objectMapping->addFieldMapping('firstname', 'first_name');
|
||||
$mappingManual->addObjectMapping($objectMapping);
|
||||
|
||||
return $mappingManual;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $includeFirstNameField
|
||||
*
|
||||
* @return ReportDAO
|
||||
*/
|
||||
private function getInternalSyncReport($includeFirstNameField = true)
|
||||
{
|
||||
$syncReport = new ReportDAO(MauticSyncDataExchange::NAME);
|
||||
$internalReportObject = new ReportObjectDAO(Contact::NAME, 1);
|
||||
$internalReportObject->addField(
|
||||
new ReportFieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'test@test.com'), ReportFieldDAO::FIELD_REQUIRED)
|
||||
);
|
||||
|
||||
if ($includeFirstNameField) {
|
||||
$internalReportObject->addField(new ReportFieldDAO('firstname', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob')));
|
||||
}
|
||||
|
||||
$syncReport->addObject($internalReportObject);
|
||||
|
||||
return $syncReport;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ObjectChangeGenerator
|
||||
*/
|
||||
private function getObjectChangeGenerator()
|
||||
{
|
||||
return new ObjectChangeGenerator($this->valueHelper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncProcess\Direction\Internal;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\MappingManualDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\ObjectMappingDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\InputOptionsDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\FieldDAO as OrderFieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\ObjectChangeDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\FieldDAO as ReportFieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\ObjectDAO as ReportObjectDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\ReportDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Request\ObjectDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Request\ObjectDAO as RequestObjectDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Request\RequestDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectDeletedException;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectSyncSkippedException;
|
||||
use Mautic\IntegrationsBundle\Sync\Helper\SyncDateHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Company;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\MauticSyncDataExchange;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Internal\MauticSyncProcess;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Internal\ObjectChangeGenerator;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class MauticSyncProcessTest extends TestCase
|
||||
{
|
||||
private const INTEGRATION_NAME = 'Test';
|
||||
|
||||
/**
|
||||
* @var SyncDateHelper|MockObject
|
||||
*/
|
||||
private MockObject $syncDateHelper;
|
||||
|
||||
/**
|
||||
* @var ObjectChangeGenerator|MockObject
|
||||
*/
|
||||
private MockObject $objectChangeGenerator;
|
||||
|
||||
/**
|
||||
* @var MauticSyncDataExchange|MockObject
|
||||
*/
|
||||
private MockObject $syncDataExchange;
|
||||
|
||||
/**
|
||||
* @var InputOptionsDAO
|
||||
*/
|
||||
private $inputOptionsDAO;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->syncDateHelper = $this->createMock(SyncDateHelper::class);
|
||||
$this->objectChangeGenerator = $this->createMock(ObjectChangeGenerator::class);
|
||||
$this->syncDataExchange = $this->createMock(MauticSyncDataExchange::class);
|
||||
$this->inputOptionsDAO = new InputOptionsDAO(['integration' => self::INTEGRATION_NAME]);
|
||||
}
|
||||
|
||||
public function testThatMauticGetSyncReportIsCalledBasedOnRequest(): void
|
||||
{
|
||||
$objectName = 'Contact';
|
||||
$mappingManual = new MappingManualDAO(self::INTEGRATION_NAME);
|
||||
$objectMapping = new ObjectMappingDAO(Contact::NAME, $objectName);
|
||||
$objectMapping->addFieldMapping('email', 'email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$objectMapping->addFieldMapping('firstname', 'first_name');
|
||||
$mappingManual->addObjectMapping($objectMapping);
|
||||
|
||||
$fromSyncDateTime = new \DateTimeImmutable();
|
||||
$this->syncDateHelper->expects($this->once())
|
||||
->method('getSyncFromDateTime')
|
||||
->with(MauticSyncDataExchange::NAME, Contact::NAME)
|
||||
->willReturn($fromSyncDateTime);
|
||||
|
||||
$toSyncDateTime = new \DateTimeImmutable();
|
||||
$this->syncDateHelper->expects($this->once())
|
||||
->method('getSyncToDateTime')
|
||||
->willReturn($toSyncDateTime);
|
||||
|
||||
// SyncDateExchangeInterface::getSyncReport should sync because an object was added to the report
|
||||
$this->syncDataExchange->expects($this->once())
|
||||
->method('getSyncReport')
|
||||
->willReturnCallback(
|
||||
function (RequestDAO $requestDAO) {
|
||||
$requestObjects = $requestDAO->getObjects();
|
||||
$this->assertCount(1, $requestObjects);
|
||||
|
||||
/** @var RequestObjectDAO $requestObject */
|
||||
$requestObject = $requestObjects[0];
|
||||
$this->assertEquals(['email'], $requestObject->getRequiredFields());
|
||||
$this->assertEquals(['email', 'firstname'], $requestObject->getFields());
|
||||
$this->assertEquals(Contact::NAME, $requestObject->getObject());
|
||||
|
||||
return new ReportDAO(self::INTEGRATION_NAME);
|
||||
}
|
||||
);
|
||||
|
||||
$this->createMauticSyncProcess($mappingManual)->getSyncReport(1);
|
||||
}
|
||||
|
||||
public function testThatMauticGetSyncReportIsNotCalledBasedOnRequest(): void
|
||||
{
|
||||
$objectName = 'Contact';
|
||||
$mappingManual = new MappingManualDAO(self::INTEGRATION_NAME);
|
||||
|
||||
$this->syncDateHelper->expects($this->never())
|
||||
->method('getSyncFromDateTime')
|
||||
->with(self::INTEGRATION_NAME, $objectName);
|
||||
|
||||
// SyncDateExchangeInterface::getSyncReport should sync because an object was added to the report
|
||||
$this->syncDataExchange->expects($this->never())
|
||||
->method('getSyncReport');
|
||||
|
||||
$report = $this->createMauticSyncProcess($mappingManual)->getSyncReport(1);
|
||||
|
||||
$this->assertEquals(MauticSyncDataExchange::NAME, $report->getIntegration());
|
||||
}
|
||||
|
||||
public function testGetSyncOrder(): void
|
||||
{
|
||||
$objectName = 'Contact';
|
||||
$mappingManual = new MappingManualDAO(self::INTEGRATION_NAME);
|
||||
$objectMapping = new ObjectMappingDAO(Contact::NAME, $objectName);
|
||||
$objectMapping->addFieldMapping('email', 'email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$objectMapping->addFieldMapping('firstname', 'first_name');
|
||||
$mappingManual->addObjectMapping($objectMapping);
|
||||
|
||||
$toSyncDateTime = new \DateTimeImmutable();
|
||||
$this->syncDateHelper->expects($this->once())
|
||||
->method('getSyncDateTime')
|
||||
->willReturn($toSyncDateTime);
|
||||
|
||||
$syncReport = new ReportDAO(self::INTEGRATION_NAME);
|
||||
$objectDAO = new ReportObjectDAO($objectName, 2);
|
||||
$objectDAO->addField(new ReportFieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'test@test.com')));
|
||||
$objectDAO->addField(new ReportFieldDAO('first_name', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob')));
|
||||
$syncReport->addObject($objectDAO);
|
||||
|
||||
// Search for an internal object
|
||||
$this->syncDataExchange->expects($this->once())
|
||||
->method('getConflictedInternalObject')
|
||||
->with($mappingManual, Contact::NAME, $objectDAO)
|
||||
->willReturn(
|
||||
new ReportObjectDAO(Contact::NAME, 1)
|
||||
);
|
||||
|
||||
$objectChangeDAO = new ObjectChangeDAO(MauticSyncDataExchange::NAME, Contact::NAME, 1, $objectName, 2);
|
||||
$objectChangeDAO->addField(new OrderFieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'test@test.com')));
|
||||
$objectChangeDAO->addField(new OrderFieldDAO('firstname', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob')));
|
||||
$this->objectChangeGenerator->expects($this->once())
|
||||
->method('getSyncObjectChange')
|
||||
->willReturn($objectChangeDAO);
|
||||
|
||||
$syncOrder = $this->createMauticSyncProcess($mappingManual)->getSyncOrder($syncReport);
|
||||
|
||||
// The change should have been added to the order as an identified object
|
||||
$this->assertEquals([Contact::NAME => [1 => $objectChangeDAO]], $syncOrder->getIdentifiedObjects());
|
||||
}
|
||||
|
||||
public function testGetSyncOrderObjectDeleted(): void
|
||||
{
|
||||
$objectName = 'Contact';
|
||||
$mappingManual = new MappingManualDAO(self::INTEGRATION_NAME);
|
||||
$objectMapping = new ObjectMappingDAO(Contact::NAME, $objectName);
|
||||
$objectMapping->addFieldMapping('email', 'email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$objectMapping->addFieldMapping('firstname', 'first_name');
|
||||
$mappingManual->addObjectMapping($objectMapping);
|
||||
|
||||
$toSyncDateTime = new \DateTimeImmutable();
|
||||
$this->syncDateHelper->expects($this->once())
|
||||
->method('getSyncDateTime')
|
||||
->willReturn($toSyncDateTime);
|
||||
|
||||
$syncReport = new ReportDAO(self::INTEGRATION_NAME);
|
||||
$reportObjectDAO = new ReportObjectDAO($objectName, 2);
|
||||
$reportObjectDAO->addField(new ReportFieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'test@test.com')));
|
||||
$reportObjectDAO->addField(new ReportFieldDAO('first_name', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob')));
|
||||
$syncReport->addObject($reportObjectDAO);
|
||||
|
||||
// Search for an internal object
|
||||
$this->syncDataExchange->expects($this->once())
|
||||
->method('getConflictedInternalObject')
|
||||
->with($mappingManual, Contact::NAME, $reportObjectDAO)
|
||||
->willThrowException(new ObjectDeletedException());
|
||||
|
||||
$syncOrder = $this->createMauticSyncProcess($mappingManual)->getSyncOrder($syncReport);
|
||||
self::assertEquals([], $syncOrder->getIdentifiedObjects());
|
||||
}
|
||||
|
||||
public function testGetSyncOrderObjectSkipped(): void
|
||||
{
|
||||
$objectName = 'Contact';
|
||||
$mappingManual = new MappingManualDAO(self::INTEGRATION_NAME);
|
||||
$objectMapping = new ObjectMappingDAO(Contact::NAME, $objectName);
|
||||
$objectMapping->addFieldMapping('email', 'email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$objectMapping->addFieldMapping('firstname', 'first_name');
|
||||
$mappingManual->addObjectMapping($objectMapping);
|
||||
|
||||
$toSyncDateTime = new \DateTimeImmutable();
|
||||
$this->syncDateHelper->expects($this->once())
|
||||
->method('getSyncDateTime')
|
||||
->willReturn($toSyncDateTime);
|
||||
|
||||
$syncReport = new ReportDAO(self::INTEGRATION_NAME);
|
||||
$reportObjectDAO = new ReportObjectDAO($objectName, 2);
|
||||
$reportObjectDAO->addField(new ReportFieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'test@test.com')));
|
||||
$reportObjectDAO->addField(new ReportFieldDAO('first_name', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob')));
|
||||
$syncReport->addObject($reportObjectDAO);
|
||||
|
||||
// Search for an internal object
|
||||
$this->syncDataExchange->expects($this->once())
|
||||
->method('getConflictedInternalObject')
|
||||
->with($mappingManual, Contact::NAME, $reportObjectDAO)
|
||||
->willReturn(
|
||||
new ReportObjectDAO(Contact::NAME, 1)
|
||||
);
|
||||
|
||||
$objectChangeDAO = new ObjectChangeDAO(MauticSyncDataExchange::NAME, Contact::NAME, 1, $objectName, 2);
|
||||
$objectChangeDAO->addField(new OrderFieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'test@test.com')));
|
||||
$objectChangeDAO->addField(new OrderFieldDAO('firstname', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob')));
|
||||
$this->objectChangeGenerator->expects($this->once())
|
||||
->method('getSyncObjectChange')
|
||||
->willThrowException(new ObjectSyncSkippedException());
|
||||
|
||||
$syncOrder = $this->createMauticSyncProcess($mappingManual)->getSyncOrder($syncReport);
|
||||
|
||||
self::assertEquals([], $syncOrder->getIdentifiedObjects());
|
||||
}
|
||||
|
||||
public function testThatItDoesntSyncOtherEntityTypesWhenIDsForSomeEntityAreSpecified(): void
|
||||
{
|
||||
$mappingManual = new MappingManualDAO(self::INTEGRATION_NAME);
|
||||
$this->inputOptionsDAO = new InputOptionsDAO([
|
||||
'integration' => self::INTEGRATION_NAME,
|
||||
'mautic-object-id' => ['contact:1'],
|
||||
]);
|
||||
|
||||
$contactMapping = new ObjectMappingDAO(Contact::NAME, 'Contact');
|
||||
$contactMapping->addFieldMapping('email', 'email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$mappingManual->addObjectMapping($contactMapping);
|
||||
|
||||
$leadMapping = new ObjectMappingDAO(Contact::NAME, 'Lead');
|
||||
$leadMapping->addFieldMapping('email', 'email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$mappingManual->addObjectMapping($leadMapping);
|
||||
|
||||
$companyMapping = new ObjectMappingDAO(Company::NAME, 'Account');
|
||||
$companyMapping->addFieldMapping('email', 'email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$mappingManual->addObjectMapping($companyMapping);
|
||||
|
||||
$fromSyncDateTime = new \DateTimeImmutable();
|
||||
$this->syncDateHelper->expects($this->once())
|
||||
->method('getSyncFromDateTime')
|
||||
->with(MauticSyncDataExchange::NAME, Contact::NAME)
|
||||
->willReturn($fromSyncDateTime);
|
||||
|
||||
$toSyncDateTime = new \DateTimeImmutable();
|
||||
$this->syncDateHelper->expects($this->once())
|
||||
->method('getSyncToDateTime')
|
||||
->willReturn($toSyncDateTime);
|
||||
|
||||
$this->syncDataExchange->expects($this->once())
|
||||
->method('getSyncReport')
|
||||
->willReturnCallback(
|
||||
function (RequestDAO $requestDAO): ReportDAO {
|
||||
$requestObjects = $requestDAO->getObjects();
|
||||
$this->assertCount(1, $requestObjects);
|
||||
|
||||
/** @var ObjectDAO $requestObject */
|
||||
$requestObject = $requestObjects[0];
|
||||
$this->assertEquals(['email'], $requestObject->getRequiredFields());
|
||||
$this->assertEquals(Contact::NAME, $requestObject->getObject());
|
||||
|
||||
return new ReportDAO(self::INTEGRATION_NAME);
|
||||
}
|
||||
);
|
||||
|
||||
$syncReport = $this->createMauticSyncProcess($mappingManual)->getSyncReport(1);
|
||||
$this->assertEquals(self::INTEGRATION_NAME, $syncReport->getIntegration());
|
||||
}
|
||||
|
||||
private function createMauticSyncProcess(MappingManualDAO $mappingManualDAO): MauticSyncProcess
|
||||
{
|
||||
$mauticSyncProcess = new MauticSyncProcess(
|
||||
$this->syncDateHelper,
|
||||
$this->objectChangeGenerator,
|
||||
);
|
||||
|
||||
$mauticSyncProcess->setupSync(
|
||||
$this->inputOptionsDAO,
|
||||
$mappingManualDAO,
|
||||
$this->syncDataExchange
|
||||
);
|
||||
|
||||
return $mauticSyncProcess;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,479 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncProcess\Direction\Internal;
|
||||
|
||||
use Mautic\IntegrationsBundle\Exception\RequiredValueException;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\MappingManualDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\ObjectMappingDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\InformationChangeRequestDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\FieldDAO as ReportFieldDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\ObjectDAO as ReportObjectDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\ReportDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectSyncSkippedException;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\BulkNotification;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Helper\FieldHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncJudge\SyncJudgeInterface;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Helper\ValueHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Internal\ObjectChangeGenerator;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ObjectChangeGeneratorTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var SyncJudgeInterface&MockObject
|
||||
*/
|
||||
private MockObject $syncJudge;
|
||||
|
||||
/**
|
||||
* @var ValueHelper&MockObject
|
||||
*/
|
||||
private MockObject $valueHelper;
|
||||
|
||||
/**
|
||||
* @var FieldHelper&MockObject
|
||||
*/
|
||||
private MockObject $fieldHelper;
|
||||
|
||||
/**
|
||||
* @var MockObject&BulkNotification
|
||||
*/
|
||||
private MockObject $bulkNotification;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->syncJudge = $this->createMock(SyncJudgeInterface::class);
|
||||
$this->valueHelper = $this->createMock(ValueHelper::class);
|
||||
$this->fieldHelper = $this->createMock(FieldHelper::class);
|
||||
$this->bulkNotification = $this->createMock(BulkNotification::class);
|
||||
}
|
||||
|
||||
public function testFieldsAreAddedToObjectChangeAndIntegrationFirstNameWins(): void
|
||||
{
|
||||
$this->valueHelper->method('getValueForMautic')
|
||||
->willReturnCallback(
|
||||
fn (NormalizedValueDAO $normalizedValueDAO, string $fieldState, string $syncDirection) => $normalizedValueDAO
|
||||
);
|
||||
|
||||
$integration = 'Test';
|
||||
$objectName = 'Contact';
|
||||
|
||||
$mappingManual = $this->getMappingManual($integration, $objectName);
|
||||
$syncReport = $this->getIntegrationSyncReport($integration, $objectName);
|
||||
|
||||
$internalReportObject = new ReportObjectDAO(Contact::NAME, 1);
|
||||
$internalReportObject->addField(new ReportFieldDAO('email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'test@test.com')));
|
||||
$internalReportObject->addField(new ReportFieldDAO('firstname', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob')));
|
||||
|
||||
$this->syncJudge->expects($this->exactly(2))
|
||||
->method('adjudicate')
|
||||
->willReturnCallback(
|
||||
fn ($mode, InformationChangeRequestDAO $internalInformationChangeRequest, InformationChangeRequestDAO $integrationInformationChangeRequest) => $integrationInformationChangeRequest
|
||||
);
|
||||
|
||||
$objectChangeDAO = $this->createObjectGenerator()->getSyncObjectChange(
|
||||
$syncReport,
|
||||
$mappingManual,
|
||||
$mappingManual->getObjectMapping(Contact::NAME, $objectName),
|
||||
$internalReportObject,
|
||||
$syncReport->getObject($objectName, 2)
|
||||
);
|
||||
|
||||
$this->assertEquals($integration, $objectChangeDAO->getIntegration());
|
||||
|
||||
// object and object ID should be Mautic's (from the Mautic's POV)
|
||||
$this->assertEquals(Contact::NAME, $objectChangeDAO->getObject());
|
||||
$this->assertEquals(1, $objectChangeDAO->getObjectId());
|
||||
|
||||
// mapped object and ID should be the integrations
|
||||
$this->assertEquals($objectName, $objectChangeDAO->getMappedObject());
|
||||
$this->assertEquals(2, $objectChangeDAO->getMappedObjectId());
|
||||
|
||||
// Email should be a required field
|
||||
$requiredFields = $objectChangeDAO->getRequiredFields();
|
||||
$this->assertTrue(isset($requiredFields['email']));
|
||||
|
||||
// Both fields should be included
|
||||
$fields = $objectChangeDAO->getFields();
|
||||
$this->assertTrue(isset($fields['email']) && isset($fields['firstname']));
|
||||
|
||||
// First name is presumed to be changed
|
||||
$changedFields = $objectChangeDAO->getChangedFields();
|
||||
$this->assertTrue(isset($changedFields['firstname']));
|
||||
|
||||
// First name should have changed to Robert because the sync judge returned the integration's information change request
|
||||
$this->assertEquals('Robert', $changedFields['firstname']->getValue()->getNormalizedValue());
|
||||
}
|
||||
|
||||
public function testFieldsAreAddedToObjectChangeAndInternalFirstNameWins(): void
|
||||
{
|
||||
$this->valueHelper->method('getValueForMautic')
|
||||
->willReturnCallback(
|
||||
fn (NormalizedValueDAO $normalizedValueDAO, string $fieldState, string $syncDirection) => $normalizedValueDAO
|
||||
);
|
||||
|
||||
$integration = 'Test';
|
||||
$objectName = 'Contact';
|
||||
|
||||
$mappingManual = $this->getMappingManual($integration, $objectName);
|
||||
$syncReport = $this->getIntegrationSyncReport($integration, $objectName);
|
||||
|
||||
$internalReportObject = new ReportObjectDAO(Contact::NAME, 1);
|
||||
$internalReportObject->addField(
|
||||
new ReportFieldDAO(
|
||||
'email',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'test@test.com')
|
||||
)
|
||||
);
|
||||
$internalReportObject->addField(
|
||||
new ReportFieldDAO(
|
||||
'firstname',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob')
|
||||
)
|
||||
);
|
||||
|
||||
$this->syncJudge->expects($this->exactly(2))
|
||||
->method('adjudicate')
|
||||
->willReturnCallback(
|
||||
fn ($mode, InformationChangeRequestDAO $internalInformationChangeRequest, InformationChangeRequestDAO $integrationInformationChangeRequest) => $internalInformationChangeRequest
|
||||
);
|
||||
|
||||
$objectChangeDAO = $this->createObjectGenerator()->getSyncObjectChange(
|
||||
$syncReport,
|
||||
$mappingManual,
|
||||
$mappingManual->getObjectMapping(Contact::NAME, $objectName),
|
||||
$internalReportObject,
|
||||
$syncReport->getObject($objectName, 2)
|
||||
);
|
||||
|
||||
$this->assertEquals($integration, $objectChangeDAO->getIntegration());
|
||||
|
||||
// object and object ID should be Mautic's (from the Mautic's POV)
|
||||
$this->assertEquals(Contact::NAME, $objectChangeDAO->getObject());
|
||||
$this->assertEquals(1, $objectChangeDAO->getObjectId());
|
||||
|
||||
// mapped object and ID should be the integrations
|
||||
$this->assertEquals($objectName, $objectChangeDAO->getMappedObject());
|
||||
$this->assertEquals(2, $objectChangeDAO->getMappedObjectId());
|
||||
|
||||
// Email should be a required field
|
||||
$requiredFields = $objectChangeDAO->getRequiredFields();
|
||||
$this->assertTrue(isset($requiredFields['email']));
|
||||
|
||||
// Both fields should be included
|
||||
$fields = $objectChangeDAO->getFields();
|
||||
$this->assertTrue(isset($fields['email']) && isset($fields['firstname']));
|
||||
|
||||
// First name is presumed to be changed
|
||||
$changedFields = $objectChangeDAO->getChangedFields();
|
||||
$this->assertTrue(isset($changedFields['firstname']));
|
||||
|
||||
// First name should have changed to Robert because the sync judge returned the integration's information change request
|
||||
$this->assertEquals('Bob', $changedFields['firstname']->getValue()->getNormalizedValue());
|
||||
}
|
||||
|
||||
public function testRequiredValueRejected(): void
|
||||
{
|
||||
$exceptionMessage = 'exceptionMessage';
|
||||
|
||||
$this->valueHelper->method('getValueForMautic')
|
||||
->willThrowException(new RequiredValueException($exceptionMessage));
|
||||
|
||||
$integrationName = 'Test';
|
||||
$objectName = 'Contact';
|
||||
|
||||
$mappingManual = $this->getMappingManual($integrationName, $objectName);
|
||||
$syncReport = $this->getIntegrationSyncReport($integrationName, $objectName);
|
||||
|
||||
$internalReportObject = new ReportObjectDAO(Contact::NAME, 1);
|
||||
$internalReportObject->addField(
|
||||
new ReportFieldDAO(
|
||||
'email',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, '')
|
||||
)
|
||||
);
|
||||
$internalReportObject->addField(
|
||||
new ReportFieldDAO(
|
||||
'firstname',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob')
|
||||
)
|
||||
);
|
||||
|
||||
$this->syncJudge->expects($this->exactly(2))
|
||||
->method('adjudicate')
|
||||
->willReturnCallback(
|
||||
function ($mode, InformationChangeRequestDAO $internalInformationChangeRequest, InformationChangeRequestDAO $integrationInformationChangeRequest) {
|
||||
return $internalInformationChangeRequest;
|
||||
}
|
||||
);
|
||||
$matcher = $this->exactly(2);
|
||||
|
||||
$this->bulkNotification->expects($matcher)
|
||||
->method('addNotification')->willReturnCallback(function (...$parameters) use ($matcher, $exceptionMessage, $integrationName, $objectName) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Internal\ObjectChangeGenerator-Test-lead-email', $parameters[0]);
|
||||
$this->assertSame($exceptionMessage, $parameters[1]);
|
||||
$this->assertSame($integrationName, $parameters[2]);
|
||||
$this->assertSame($objectName, $parameters[3]);
|
||||
$this->assertSame(Contact::NAME, $parameters[4]);
|
||||
$this->assertSame(0, $parameters[5]);
|
||||
$this->assertSame("Field 'email' for object ID '2' mapped to internal 'email' with value 'test@test.com'", $parameters[6]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Internal\ObjectChangeGenerator-Test-lead-first_name', $parameters[0]);
|
||||
$this->assertSame($exceptionMessage, $parameters[1]);
|
||||
$this->assertSame($integrationName, $parameters[2]);
|
||||
$this->assertSame($objectName, $parameters[3]);
|
||||
$this->assertSame(Contact::NAME, $parameters[4]);
|
||||
$this->assertSame(0, $parameters[5]);
|
||||
$this->assertSame("Field 'first_name' for object ID '2' mapped to internal 'first_name' with value 'Robert'", $parameters[6]);
|
||||
}
|
||||
});
|
||||
|
||||
$this->createObjectGenerator()->getSyncObjectChange(
|
||||
$syncReport,
|
||||
$mappingManual,
|
||||
$mappingManual->getObjectMapping(Contact::NAME, $objectName),
|
||||
$internalReportObject,
|
||||
$syncReport->getObject($objectName, 2)
|
||||
);
|
||||
}
|
||||
|
||||
public function testRequiredValueRejectedForExistingObject(): void
|
||||
{
|
||||
$exceptionMessage = 'exceptionMessage';
|
||||
|
||||
$this->valueHelper->method('getValueForMautic')
|
||||
->willThrowException(new RequiredValueException($exceptionMessage));
|
||||
|
||||
$integrationName = 'Test';
|
||||
$objectName = 'Contact';
|
||||
|
||||
$mappingManual = $this->getMappingManual($integrationName, $objectName);
|
||||
$syncReport = $this->getIntegrationSyncReport($integrationName, $objectName);
|
||||
|
||||
$internalReportObject = new ReportObjectDAO(Contact::NAME, 1);
|
||||
$internalReportObject->addField(
|
||||
new ReportFieldDAO(
|
||||
'email',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, '')
|
||||
)
|
||||
);
|
||||
$internalReportObject->addField(
|
||||
new ReportFieldDAO(
|
||||
'firstname',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Bob')
|
||||
)
|
||||
);
|
||||
|
||||
$this->syncJudge->expects($this->exactly(2))
|
||||
->method('adjudicate')
|
||||
->willReturnCallback(
|
||||
function ($mode, InformationChangeRequestDAO $internalInformationChangeRequest, InformationChangeRequestDAO $integrationInformationChangeRequest) {
|
||||
return $internalInformationChangeRequest;
|
||||
}
|
||||
);
|
||||
$matcher = $this->exactly(2);
|
||||
|
||||
$this->bulkNotification->expects($matcher)
|
||||
->method('addNotification')->willReturnCallback(function (...$parameters) use ($matcher, $exceptionMessage, $integrationName, $objectName) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Internal\ObjectChangeGenerator-Test-lead-email', $parameters[0]);
|
||||
$this->assertSame($exceptionMessage, $parameters[1]);
|
||||
$this->assertSame($integrationName, $parameters[2]);
|
||||
$this->assertSame($objectName, $parameters[3]);
|
||||
$this->assertSame(Contact::NAME, $parameters[4]);
|
||||
$this->assertSame(0, $parameters[5]);
|
||||
$this->assertSame("Field 'email' for object ID '2' mapped to internal 'email' with value 'test@test.com'", $parameters[6]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame('Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Internal\ObjectChangeGenerator-Test-lead-first_name', $parameters[0]);
|
||||
$this->assertSame($exceptionMessage, $parameters[1]);
|
||||
$this->assertSame($integrationName, $parameters[2]);
|
||||
$this->assertSame($objectName, $parameters[3]);
|
||||
$this->assertSame(Contact::NAME, $parameters[4]);
|
||||
$this->assertSame(0, $parameters[5]);
|
||||
$this->assertSame("Field 'first_name' for object ID '2' mapped to internal 'first_name' with value 'Robert'", $parameters[6]);
|
||||
}
|
||||
});
|
||||
|
||||
$this->createObjectGenerator()->getSyncObjectChange(
|
||||
$syncReport,
|
||||
$mappingManual,
|
||||
$mappingManual->getObjectMapping(Contact::NAME, $objectName),
|
||||
$internalReportObject,
|
||||
$syncReport->getObject($objectName, 2)
|
||||
);
|
||||
}
|
||||
|
||||
public function testRequiredValueRejectedForNewObject(): void
|
||||
{
|
||||
$exceptionMessage = 'exceptionMessage';
|
||||
|
||||
$this->valueHelper->method('getValueForMautic')
|
||||
->willThrowException(new RequiredValueException($exceptionMessage));
|
||||
|
||||
$integrationName = 'Test';
|
||||
$objectName = 'Contact';
|
||||
|
||||
$mappingManual = $this->getMappingManual($integrationName, $objectName);
|
||||
$syncReport = $this->getIntegrationSyncReport($integrationName, $objectName);
|
||||
|
||||
$internalReportObject = new ReportObjectDAO(Contact::NAME, null);
|
||||
$internalReportObject->addField(
|
||||
new ReportFieldDAO(
|
||||
'email',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, '')
|
||||
)
|
||||
);
|
||||
|
||||
$this->syncJudge->expects($this->exactly(1))
|
||||
->method('adjudicate')
|
||||
->willReturnCallback(
|
||||
function ($mode, InformationChangeRequestDAO $internalInformationChangeRequest, InformationChangeRequestDAO $integrationInformationChangeRequest) {
|
||||
return $internalInformationChangeRequest;
|
||||
}
|
||||
);
|
||||
|
||||
$this->bulkNotification->expects($this->exactly(1))
|
||||
->method('addNotification')
|
||||
->with(
|
||||
'Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Internal\ObjectChangeGenerator-Test-lead-email',
|
||||
$exceptionMessage.' New object sync skipped.',
|
||||
$integrationName,
|
||||
$objectName,
|
||||
Contact::NAME,
|
||||
0,
|
||||
"Field 'email' for object ID '2' mapped to internal 'email' with value 'test@test.com'"
|
||||
);
|
||||
|
||||
$this->expectException(ObjectSyncSkippedException::class);
|
||||
|
||||
$this->createObjectGenerator()->getSyncObjectChange(
|
||||
$syncReport,
|
||||
$mappingManual,
|
||||
$mappingManual->getObjectMapping(Contact::NAME, $objectName),
|
||||
$internalReportObject,
|
||||
$syncReport->getObject($objectName, 2)
|
||||
);
|
||||
}
|
||||
|
||||
public function testFieldsWithDirectionToIntegrationAreSkipped(): void
|
||||
{
|
||||
$objectChangeGenerator = new ObjectChangeGenerator(
|
||||
new class implements SyncJudgeInterface {
|
||||
public function adjudicate(
|
||||
$mode,
|
||||
InformationChangeRequestDAO $leftChangeRequest,
|
||||
InformationChangeRequestDAO $rightChangeRequest,
|
||||
) {
|
||||
return $leftChangeRequest;
|
||||
}
|
||||
},
|
||||
new class extends ValueHelper {
|
||||
},
|
||||
new class extends FieldHelper {
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function getRequiredFields(string $object): array
|
||||
{
|
||||
Assert::assertSame(Contact::NAME, $object);
|
||||
|
||||
return ['email' => []];
|
||||
}
|
||||
},
|
||||
new class extends BulkNotification {
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
$integrationName = 'Integration A';
|
||||
$reportDAO = new ReportDAO($integrationName);
|
||||
$mappingManualDAO = new MappingManualDAO($integrationName);
|
||||
$objectMappingDAO = new ObjectMappingDAO(Contact::NAME, 'Lead');
|
||||
$internalObject = new ReportObjectDAO(Contact::NAME, 123);
|
||||
$integrationObject = new ReportObjectDAO('Lead', 'integration-id-1');
|
||||
|
||||
$objectMappingDAO->addFieldMapping('email', 'Email', ObjectMappingDAO::SYNC_BIDIRECTIONALLY, true);
|
||||
$objectMappingDAO->addFieldMapping('firstname', 'FirstName', ObjectMappingDAO::SYNC_TO_MAUTIC);
|
||||
$objectMappingDAO->addFieldMapping('points', 'Score', ObjectMappingDAO::SYNC_TO_INTEGRATION);
|
||||
|
||||
$integrationObject->addField(new ReportFieldDAO('Email', new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'john@doe.email')));
|
||||
$integrationObject->addField(new ReportFieldDAO('FirstName', new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'John')));
|
||||
$integrationObject->addField(new ReportFieldDAO('Score', new NormalizedValueDAO(NormalizedValueDAO::INT_TYPE, 40)));
|
||||
|
||||
$reportDAO->addObject($integrationObject);
|
||||
|
||||
$objectChange = $objectChangeGenerator->getSyncObjectChange($reportDAO, $mappingManualDAO, $objectMappingDAO, $internalObject, $integrationObject);
|
||||
|
||||
// The points/Score field should not be recorded as a change because it has direction to integration.
|
||||
Assert::assertCount(2, $objectChange->getFields());
|
||||
Assert::assertSame('john@doe.email', $objectChange->getField('email')->getValue()->getNormalizedValue());
|
||||
Assert::assertSame('John', $objectChange->getField('firstname')->getValue()->getNormalizedValue());
|
||||
Assert::assertSame('Lead', $objectChange->getMappedObject());
|
||||
Assert::assertSame('integration-id-1', $objectChange->getMappedObjectId());
|
||||
Assert::assertSame(Contact::NAME, $objectChange->getObject());
|
||||
Assert::assertSame(123, $objectChange->getObjectId());
|
||||
Assert::assertSame($integrationName, $objectChange->getIntegration());
|
||||
}
|
||||
|
||||
private function getMappingManual(string $integration, string $objectName): MappingManualDAO
|
||||
{
|
||||
$mappingManual = new MappingManualDAO($integration);
|
||||
$objectMapping = new ObjectMappingDAO(Contact::NAME, $objectName);
|
||||
$objectMapping->addFieldMapping(
|
||||
'email',
|
||||
'email',
|
||||
ObjectMappingDAO::SYNC_BIDIRECTIONALLY,
|
||||
true);
|
||||
$objectMapping->addFieldMapping(
|
||||
'firstname',
|
||||
'first_name'
|
||||
);
|
||||
$mappingManual->addObjectMapping($objectMapping);
|
||||
|
||||
return $mappingManual;
|
||||
}
|
||||
|
||||
private function getIntegrationSyncReport(string $integration, string $objectName): ReportDAO
|
||||
{
|
||||
$syncReport = new ReportDAO($integration);
|
||||
$reportObject = new ReportObjectDAO($objectName, 2);
|
||||
$reportObject->addField(
|
||||
new ReportFieldDAO(
|
||||
'email',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::EMAIL_TYPE, 'test@test.com'),
|
||||
ReportFieldDAO::FIELD_REQUIRED
|
||||
)
|
||||
);
|
||||
$reportObject->addField(
|
||||
new ReportFieldDAO(
|
||||
'first_name',
|
||||
new NormalizedValueDAO(NormalizedValueDAO::TEXT_TYPE, 'Robert')
|
||||
)
|
||||
);
|
||||
|
||||
$syncReport->addObject($reportObject);
|
||||
|
||||
return $syncReport;
|
||||
}
|
||||
|
||||
private function createObjectGenerator(): ObjectChangeGenerator
|
||||
{
|
||||
return new ObjectChangeGenerator(
|
||||
$this->syncJudge,
|
||||
$this->valueHelper,
|
||||
$this->fieldHelper,
|
||||
$this->bulkNotification
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\SyncProcess;
|
||||
|
||||
use Mautic\IntegrationsBundle\Entity\ObjectMapping;
|
||||
use Mautic\IntegrationsBundle\Event\CompletedSyncIterationEvent;
|
||||
use Mautic\IntegrationsBundle\IntegrationEvents;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\MappingManualDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\RemappedObjectDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\UpdatedObjectMappingDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\InputOptionsDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\ObjectChangeDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\ObjectMappingsDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Order\OrderDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\ReportDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Helper\MappingHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\Helper\RelationsHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\Helper\SyncDateHelper;
|
||||
use Mautic\IntegrationsBundle\Sync\Notification\Notifier;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\MauticSyncDataExchange;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\SyncDataExchangeInterface;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Integration\IntegrationSyncProcess;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncProcess\Direction\Internal\MauticSyncProcess;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncProcess\SyncProcess;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncService\SyncServiceInterface;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class SyncProcessTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var MockObject|MappingManualDAO
|
||||
*/
|
||||
private MockObject $mappingManualDAO;
|
||||
|
||||
/**
|
||||
* @var MockObject|MauticSyncDataExchange
|
||||
*/
|
||||
private MockObject $internalSyncDataExchange;
|
||||
|
||||
/**
|
||||
* @var MockObject|SyncDataExchangeInterface
|
||||
*/
|
||||
private MockObject $integrationSyncDataExchange;
|
||||
|
||||
/**
|
||||
* @var MockObject|SyncDateHelper
|
||||
*/
|
||||
private MockObject $syncDateHelper;
|
||||
|
||||
/**
|
||||
* @var MockObject|MappingHelper
|
||||
*/
|
||||
private MockObject $mappingHelper;
|
||||
|
||||
/**
|
||||
* @var MockObject|RelationsHelper
|
||||
*/
|
||||
private MockObject $relationsHelper;
|
||||
|
||||
/**
|
||||
* @var MockObject|IntegrationSyncProcess
|
||||
*/
|
||||
private MockObject $integrationSyncProcess;
|
||||
|
||||
/**
|
||||
* @var MockObject|MauticSyncProcess
|
||||
*/
|
||||
private MockObject $mauticSyncProcess;
|
||||
|
||||
/**
|
||||
* @var MockObject|EventDispatcherInterface
|
||||
*/
|
||||
private MockObject $eventDispatcher;
|
||||
|
||||
/**
|
||||
* @var MockObject|Notifier
|
||||
*/
|
||||
private MockObject $notifier;
|
||||
|
||||
/**
|
||||
* @var MockObject|InputOptionsDAO
|
||||
*/
|
||||
private MockObject $inputOptionsDAO;
|
||||
|
||||
/**
|
||||
* @var MockObject|SyncServiceInterface
|
||||
*/
|
||||
private MockObject $syncService;
|
||||
|
||||
private SyncProcess $syncProcess;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->syncDateHelper = $this->createMock(SyncDateHelper::class);
|
||||
$this->mappingHelper = $this->createMock(MappingHelper::class);
|
||||
$this->relationsHelper = $this->createMock(RelationsHelper::class);
|
||||
$this->integrationSyncProcess = $this->createMock(IntegrationSyncProcess::class);
|
||||
$this->mauticSyncProcess = $this->createMock(MauticSyncProcess::class);
|
||||
$this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||
$this->notifier = $this->createMock(Notifier::class);
|
||||
$this->mappingManualDAO = $this->createMock(MappingManualDAO::class);
|
||||
$this->integrationSyncDataExchange = $this->createMock(SyncDataExchangeInterface::class);
|
||||
$this->internalSyncDataExchange = $this->createMock(MauticSyncDataExchange::class);
|
||||
$this->inputOptionsDAO = $this->createMock(InputOptionsDAO::class);
|
||||
$this->syncService = $this->createMock(SyncServiceInterface::class);
|
||||
|
||||
$this->syncProcess = new SyncProcess(
|
||||
$this->syncDateHelper,
|
||||
$this->mappingHelper,
|
||||
$this->relationsHelper,
|
||||
$this->integrationSyncProcess,
|
||||
$this->mauticSyncProcess,
|
||||
$this->eventDispatcher,
|
||||
$this->notifier,
|
||||
$this->mappingManualDAO,
|
||||
$this->internalSyncDataExchange,
|
||||
$this->integrationSyncDataExchange,
|
||||
$this->inputOptionsDAO,
|
||||
$this->syncService
|
||||
);
|
||||
}
|
||||
|
||||
public function testBatchSyncEventsAreDispatched(): void
|
||||
{
|
||||
$this->inputOptionsDAO->expects($this->once())
|
||||
->method('pullIsEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->inputOptionsDAO->expects($this->once())
|
||||
->method('pushIsEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->syncDateHelper->expects($this->once())
|
||||
->method('setInternalSyncStartDateTime');
|
||||
|
||||
// Integration to Mautic
|
||||
|
||||
// fetch the report from the integration
|
||||
$integrationSyncReport = $this->createMock(ReportDAO::class);
|
||||
$integrationSyncReport->expects($this->exactly(2))
|
||||
->method('shouldSync')
|
||||
->willReturnOnConsecutiveCalls(true, false);
|
||||
$matcher = $this->exactly(2);
|
||||
$this->integrationSyncProcess->expects($matcher)
|
||||
->method('getSyncReport')->willReturnCallback(function (...$parameters) use ($matcher, $integrationSyncReport) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(1, $parameters[0]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(2, $parameters[0]);
|
||||
}
|
||||
|
||||
return $integrationSyncReport;
|
||||
});
|
||||
|
||||
// generate the order based on the report
|
||||
$integrationSyncOrder = $this->createMock(OrderDAO::class);
|
||||
$integrationSyncOrder->expects($this->once())
|
||||
->method('shouldSync')
|
||||
->willReturn(true);
|
||||
$this->mauticSyncProcess->expects($this->once())
|
||||
->method('getSyncOrder')
|
||||
->with($integrationSyncReport)
|
||||
->willReturn($integrationSyncOrder);
|
||||
$integrationSyncOrder->expects($this->once())
|
||||
->method('getDeletedObjects')
|
||||
->willReturn([new ObjectChangeDAO('foobar', 'foo', 'foo1', 'contact', 1)]);
|
||||
$integrationSyncOrder->expects($this->once())
|
||||
->method('getRemappedObjects')
|
||||
->willReturn([new RemappedObjectDAO('foobar', 'foo', 'foo1', 'bar', 'bar1')]);
|
||||
|
||||
// execute the order
|
||||
$objectMappings = $this->createMock(ObjectMappingsDAO::class);
|
||||
$objectMappings->expects($this->once())
|
||||
->method('getNewMappings')
|
||||
->willReturn([(new ObjectMapping())->setIntegrationObjectName('foo')]);
|
||||
$objectMappings->expects($this->once())
|
||||
->method('getUpdatedMappings')
|
||||
->willReturn([(new ObjectMapping())->setIntegrationObjectName('bar')]);
|
||||
$this->internalSyncDataExchange->expects($this->once())
|
||||
->method('executeSyncOrder')
|
||||
->willReturn($objectMappings);
|
||||
$matcher = $this->any();
|
||||
|
||||
$this->eventDispatcher->expects($matcher)
|
||||
->method('dispatch')->willReturnCallback(function (...$parameters) use ($matcher) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (CompletedSyncIterationEvent $event) {
|
||||
$orderResult = $event->getOrderResults();
|
||||
Assert::assertCount(1, $orderResult->getUpdatedObjectMappings('bar'));
|
||||
Assert::assertCount(1, $orderResult->getNewObjectMappings('foo'));
|
||||
Assert::assertCount(1, $orderResult->getDeletedObjects('foo'));
|
||||
Assert::assertCount(1, $orderResult->getRemappedObjects('bar'));
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_BATCH_SYNC_COMPLETED_INTEGRATION_TO_MAUTIC, $parameters[1]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$callback = function (CompletedSyncIterationEvent $event) {
|
||||
$orderResult = $event->getOrderResults();
|
||||
Assert::assertCount(1, $orderResult->getNewObjectMappings('bar'));
|
||||
Assert::assertCount(1, $orderResult->getUpdatedObjectMappings('foo'));
|
||||
};
|
||||
$callback($parameters[0]);
|
||||
$this->assertSame(IntegrationEvents::INTEGRATION_BATCH_SYNC_COMPLETED_MAUTIC_TO_INTEGRATION, $parameters[1]);
|
||||
}
|
||||
|
||||
return $parameters[0];
|
||||
});
|
||||
|
||||
// Mautic to integration
|
||||
|
||||
// fetch the report from Mautic
|
||||
$internalSyncReport = $this->createMock(ReportDAO::class);
|
||||
$internalSyncReport->expects($this->exactly(2))
|
||||
->method('shouldSync')
|
||||
->willReturnOnConsecutiveCalls(true, false);
|
||||
$matcher = $this->exactly(2);
|
||||
$this->mauticSyncProcess->expects($matcher)
|
||||
->method('getSyncReport')->willReturnCallback(function (...$parameters) use ($matcher, $internalSyncReport) {
|
||||
if (1 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(1, $parameters[0]);
|
||||
}
|
||||
if (2 === $matcher->numberOfInvocations()) {
|
||||
$this->assertSame(2, $parameters[0]);
|
||||
}
|
||||
|
||||
return $internalSyncReport;
|
||||
});
|
||||
|
||||
// generate the order based on the report
|
||||
$internalSyncOrder = $this->createMock(OrderDAO::class);
|
||||
$internalSyncOrder->expects($this->once())
|
||||
->method('shouldSync')
|
||||
->willReturnOnConsecutiveCalls(true);
|
||||
$internalSyncOrder->expects($this->exactly(2))
|
||||
->method('getObjectMappings')
|
||||
->willReturn([(new ObjectMapping())->setIntegrationObjectName('bar')]);
|
||||
$updatedObjectMapping = new UpdatedObjectMappingDAO('foobar', 'foo', 'foo1', new \DateTime());
|
||||
$updatedObjectMapping->setObjectMapping((new ObjectMapping())->setIntegrationObjectName('foo'));
|
||||
|
||||
// Test that getOrderResultsForInternalSync ignores an object with a missing ObjectMapping
|
||||
$updatedObjectMapping2 = new UpdatedObjectMappingDAO('foobar', 'foo', 'foo2', new \DateTime());
|
||||
|
||||
$internalSyncOrder->expects($this->exactly(2))
|
||||
->method('getUpdatedObjectMappings')
|
||||
->willReturn([$updatedObjectMapping, $updatedObjectMapping2]);
|
||||
$internalSyncOrder->expects($this->exactly(2))
|
||||
->method('getDeletedObjects')
|
||||
->willReturn([]); // currently not supported for Mautic to integration
|
||||
$internalSyncOrder->expects($this->exactly(2))
|
||||
->method('getRemappedObjects')
|
||||
->willReturn([]); // currently not supported for Mautic to integration
|
||||
$internalSyncOrder->expects($this->once())
|
||||
->method('getNotifications')
|
||||
->willReturn([]);
|
||||
$internalSyncOrder->expects($this->once())
|
||||
->method('getSuccessfullySyncedObjects')
|
||||
->willReturn([]);
|
||||
|
||||
$this->integrationSyncProcess->expects($this->once())
|
||||
->method('getSyncOrder')
|
||||
->with($internalSyncReport)
|
||||
->willReturn($internalSyncOrder);
|
||||
|
||||
// execute the order
|
||||
$this->internalSyncDataExchange->expects($this->once())
|
||||
->method('executeSyncOrder')
|
||||
->willReturn($objectMappings);
|
||||
|
||||
$this->syncProcess->execute();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Tests\Unit\Sync\ValueNormalizer;
|
||||
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\ValueNormalizer\ValueNormalizer;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ValueNormalizerTest extends TestCase
|
||||
{
|
||||
public function testNullDateTimeValue(): void
|
||||
{
|
||||
$valueNormalizer = new ValueNormalizer();
|
||||
$normalizedValueDAO = $valueNormalizer->normalizeForMautic(NormalizedValueDAO::DATETIME_TYPE, null);
|
||||
|
||||
$this->assertNull($normalizedValueDAO->getNormalizedValue());
|
||||
$this->assertNull($normalizedValueDAO->getOriginalValue());
|
||||
}
|
||||
|
||||
public function testNotNullDateTimeValue(): void
|
||||
{
|
||||
$valueNormalizer = new ValueNormalizer();
|
||||
$normalizedValueDAO = $valueNormalizer->normalizeForMautic(NormalizedValueDAO::DATETIME_TYPE, '2019-10-08');
|
||||
|
||||
$this->assertInstanceOf(\DateTimeInterface::class, $normalizedValueDAO->getNormalizedValue());
|
||||
$this->assertSame('2019-10-08', $normalizedValueDAO->getNormalizedValue()->format('Y-m-d'));
|
||||
$this->assertSame('2019-10-08', $normalizedValueDAO->getOriginalValue());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user