chrisbryan17's picture
Upload folder using huggingface_hub
d2897cd verified
<?php
namespace Mautic\LeadBundle\Tests\Deduplicate;
use Doctrine\Common\Collections\ArrayCollection;
use Mautic\CoreBundle\Entity\IpAddress;
use Mautic\LeadBundle\Deduplicate\ContactMerger;
use Mautic\LeadBundle\Deduplicate\Exception\SameContactException;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\LeadBundle\Entity\LeadRepository;
use Mautic\LeadBundle\Entity\MergeRecordRepository;
use Mautic\LeadBundle\Entity\Tag;
use Mautic\LeadBundle\Model\LeadModel;
use Mautic\UserBundle\Entity\User;
use Monolog\Logger;
use Symfony\Component\EventDispatcher\EventDispatcher;
class ContactMergerTest extends \PHPUnit\Framework\TestCase
{
/**
* @var \PHPUnit\Framework\MockObject\MockObject|LeadModel
*/
private \PHPUnit\Framework\MockObject\MockObject $leadModel;
/**
* @var \PHPUnit\Framework\MockObject\MockObject|MergeRecordRepository
*/
private \PHPUnit\Framework\MockObject\MockObject $leadRepo;
/**
* @var \PHPUnit\Framework\MockObject\MockObject|MergeRecordRepository
*/
private \PHPUnit\Framework\MockObject\MockObject $mergeRecordRepo;
/**
* @var \PHPUnit\Framework\MockObject\MockObject|EventDispatcher
*/
private \PHPUnit\Framework\MockObject\MockObject $dispatcher;
/**
* @var \PHPUnit\Framework\MockObject\MockObject|Logger
*/
private \PHPUnit\Framework\MockObject\MockObject $logger;
protected function setUp(): void
{
$this->leadModel = $this->createMock(LeadModel::class);
$this->leadRepo = $this->createMock(LeadRepository::class);
$this->mergeRecordRepo = $this->createMock(MergeRecordRepository::class);
$this->dispatcher = $this->createMock(EventDispatcher::class);
$this->logger = $this->createMock(Logger::class);
$this->leadModel->method('getRepository')->willReturn($this->leadRepo);
}
public function testMergeTimestamps(): void
{
$oldestDateTime = new \DateTime('-60 minutes');
$latestDateTime = new \DateTime('-30 minutes');
$winner = new Lead();
$winner->setLastActive($oldestDateTime);
$winner->setDateIdentified($latestDateTime);
$loser = new Lead();
$loser->setLastActive($latestDateTime);
$loser->setDateIdentified($oldestDateTime);
$this->getMerger()->mergeTimestamps($winner, $loser);
$this->assertEquals($latestDateTime, $winner->getLastActive());
$this->assertEquals($oldestDateTime, $winner->getDateIdentified());
// Test with null date identified loser
$winner->setDateIdentified($latestDateTime);
$loser->setDateIdentified(null);
$this->getMerger()->mergeTimestamps($winner, $loser);
$this->assertEquals($latestDateTime, $winner->getDateIdentified());
// Test with null date identified winner
$winner->setDateIdentified(null);
$loser->setDateIdentified($latestDateTime);
$this->getMerger()->mergeTimestamps($winner, $loser);
$this->assertEquals($latestDateTime, $winner->getDateIdentified());
}
public function testMergeIpAddresses(): void
{
$winner = new Lead();
$winner->addIpAddress((new IpAddress('1.2.3.4'))->setIpDetails(['extra' => 'from winner']));
$winner->addIpAddress((new IpAddress('4.3.2.1'))->setIpDetails(['extra' => 'from winner']));
$winner->addIpAddress((new IpAddress('5.6.7.8'))->setIpDetails(['extra' => 'from winner']));
$loser = new Lead();
$loser->addIpAddress((new IpAddress('5.6.7.8'))->setIpDetails(['extra' => 'from loser']));
$loser->addIpAddress((new IpAddress('8.7.6.5'))->setIpDetails(['extra' => 'from loser']));
$this->getMerger()->mergeIpAddressHistory($winner, $loser);
$ipAddresses = $winner->getIpAddresses();
$this->assertCount(4, $ipAddresses);
$ipAddressArray = $ipAddresses->toArray();
$expectedIpAddressArray = [
'1.2.3.4' => ['extra' => 'from winner'],
'4.3.2.1' => ['extra' => 'from winner'],
'5.6.7.8' => ['extra' => 'from winner'],
'8.7.6.5' => ['extra' => 'from loser'],
];
foreach ($expectedIpAddressArray as $ipAddress => $ipId) {
$this->assertSame($ipAddress, $ipAddressArray[$ipAddress]->getIpAddress());
$this->assertSame($ipId, $ipAddressArray[$ipAddress]->getIpDetails());
}
}
public function testMergeFieldDataWithLoserAsNewlyUpdated(): void
{
$winner = $this->getMockBuilder(Lead::class)
->getMock();
$winner->expects($this->once())
->method('getProfileFields')
->willReturn(
[
'id' => 1,
'points' => 10,
'email' => '[email protected]',
]
);
$loser = $this->getMockBuilder(Lead::class)
->getMock();
$loser->expects($this->once())
->method('getProfileFields')
->willReturn(
[
'id' => 2,
'points' => 20,
'email' => '[email protected]',
]
);
$merger = $this->getMerger();
$winnerDateModified = new \DateTime('-30 minutes');
$loserDateModified = new \DateTime();
$winner->expects($this->exactly(1))
->method('getDateModified')
->willReturn($winnerDateModified);
$loser->expects($this->exactly(1))
->method('getDateModified')
->willReturn($loserDateModified);
$winner->expects($this->once())
->method('getFieldValue')
->with('email')
->willReturn('[email protected]');
$winner->expects($this->once())
->method('getField')
->with('email')
->willReturn([
'value' => '[email protected]',
'id' => 22,
'label' => 'Email',
'alias' => 'email',
'type' => 'email',
'group' => 'core',
'object' => 'lead',
'is_fixed' => true,
'default_value' => null,
]);
$winner->expects($this->exactly(3))
->method('getId')
->willReturn(1);
$loser->expects($this->exactly(2))
->method('getId')
->willReturn(2);
// Loser values are newest so should be kept
// id and points should not be set addUpdatedField should only be called once for email
$winner->expects($this->once())
->method('addUpdatedField')
->with('email', '[email protected]');
$merger->mergeFieldData($winner, $loser);
}
public function testMergeFieldDataWithWinnerAsNewlyUpdated(): void
{
$winner = $this->getMockBuilder(Lead::class)
->getMock();
$winner->expects($this->once())
->method('getProfileFields')
->willReturn(
[
'id' => 1,
'points' => 10,
'email' => '[email protected]',
]
);
$loser = $this->getMockBuilder(Lead::class)
->getMock();
$loser->expects($this->once())
->method('getProfileFields')
->willReturn(
[
'id' => 2,
'points' => 20,
'email' => '[email protected]',
]
);
$merger = $this->getMerger();
$winnerDateModified = new \DateTime();
$loserDateModified = new \DateTime('-30 minutes');
$winner->expects($this->exactly(1))
->method('getDateModified')
->willReturn($winnerDateModified);
$winner->expects($this->once())
->method('getField')
->with('email')
->willReturn([
'value' => '[email protected]',
'id' => 22,
'label' => 'Email',
'alias' => 'email',
'type' => 'email',
'group' => 'core',
'object' => 'lead',
'is_fixed' => true,
'default_value' => null,
]);
$winner->expects($this->once())
->method('getFieldValue')
->with('email')
->willReturn('[email protected]');
$loser->expects($this->exactly(1))
->method('getDateModified')
->willReturn($loserDateModified);
$winner->expects($this->exactly(4))
->method('getId')
->willReturn(1);
$loser->expects($this->once())
->method('getId');
// Winner values are newest so should be kept
// addUpdatedField should never be called as they aren't different values
$winner->expects($this->never())
->method('addUpdatedField');
$merger->mergeFieldData($winner, $loser);
}
public function testMergeFieldDataWithLoserAsNewlyCreated(): void
{
$winner = $this->getMockBuilder(Lead::class)
->getMock();
$winner->expects($this->once())
->method('getProfileFields')
->willReturn(
[
'id' => 1,
'points' => 10,
'email' => '[email protected]',
]
);
$loser = $this->getMockBuilder(Lead::class)
->getMock();
$loser->expects($this->once())
->method('getProfileFields')
->willReturn(
[
'id' => 2,
'points' => 20,
'email' => '[email protected]',
]
);
$merger = $this->getMerger();
$winnerDateModified = new \DateTime('-30 minutes');
$loserDateModified = new \DateTime();
$winner->expects($this->exactly(1))
->method('getDateModified')
->willReturn($winnerDateModified);
$winner->expects($this->once())
->method('getField')
->with('email')
->willReturn([
'value' => '[email protected]',
'id' => 22,
'label' => 'Email',
'alias' => 'email',
'type' => 'email',
'group' => 'core',
'object' => 'lead',
'is_fixed' => true,
'default_value' => null,
]);
$winner->expects($this->once())
->method('getFieldValue')
->with('email')
->willReturn('[email protected]');
$loser->expects($this->exactly(1))
->method('getDateModified')
->willReturn(null);
$loser->expects($this->once())
->method('getDateAdded')
->willReturn($loserDateModified);
$winner->expects($this->exactly(3))
->method('getId')
->willReturn(1);
$loser->expects($this->exactly(2))
->method('getId')
->willReturn(2);
// Loser values are newest so should be kept
// id and points should not be set addUpdatedField should only be called once for email
$winner->expects($this->once())
->method('addUpdatedField')
->with('email', '[email protected]');
$merger->mergeFieldData($winner, $loser);
}
public function testMergeFieldDataWithWinnerAsNewlyCreated(): void
{
$winner = $this->getMockBuilder(Lead::class)
->getMock();
$winner->expects($this->once())
->method('getProfileFields')
->willReturn(
[
'id' => 1,
'points' => 10,
'email' => '[email protected]',
]
);
$loser = $this->getMockBuilder(Lead::class)
->getMock();
$loser->expects($this->once())
->method('getProfileFields')
->willReturn(
[
'id' => 2,
'points' => 20,
'email' => '[email protected]',
]
);
$merger = $this->getMerger();
$winnerDateModified = new \DateTime();
$loserDateModified = new \DateTime('-30 minutes');
$winner->expects($this->once())
->method('getDateModified')
->willReturn(null);
$winner->expects($this->once())
->method('getDateAdded')
->willReturn($winnerDateModified);
$winner->expects($this->once())
->method('getField')
->with('email')
->willReturn([
'value' => '[email protected]',
'id' => 22,
'label' => 'Email',
'alias' => 'email',
'type' => 'email',
'group' => 'core',
'object' => 'lead',
'is_fixed' => true,
'default_value' => null,
]);
$winner->expects($this->once())
->method('getFieldValue')
->with('email')
->willReturn('[email protected]');
$loser->expects($this->exactly(1))
->method('getDateModified')
->willReturn($loserDateModified);
$winner->expects($this->exactly(4))
->method('getId')
->willReturn(1);
$loser->expects($this->once())
->method('getId');
// Winner values are newest so should be kept
// addUpdatedField should never be called as they aren't different values
$winner->expects($this->never())
->method('addUpdatedField');
$merger->mergeFieldData($winner, $loser);
}
/**
* Scenario: A contact clicks on a tracked email link that goes to a tracked page.
* The browser must contain no Mautic cookies. A new contact is created with only default values.
* If default values from the new contact overwrite the values of the original contact then data are lost.
*/
public function testMergeFieldDataWithDefaultValues(): void
{
$winner = $this->createMock(Lead::class);
$loser = $this->createMock(Lead::class);
$merger = $this->getMerger();
$winnerDateModified = new \DateTime('-30 minutes');
$loserDateModified = new \DateTime();
$winner->expects($this->once())
->method('getProfileFields')
->willReturn([
'id' => 1,
'email' => '[email protected]',
'consent' => 'Yes',
'boolean' => 1,
]);
$loser->expects($this->once())
->method('getProfileFields')
->willReturn([
'id' => 2,
'email' => null,
'consent' => 'No',
'boolean' => 0,
]);
$winner->method('getDateModified')->willReturn($winnerDateModified);
$winner->method('getId')->willReturn(1);
$loser->method('getDateModified')->willReturn($loserDateModified);
$loser->method('getId')->willReturn(2);
$loser->method('isAnonymous')->willReturn(true);
$winner->expects($this->exactly(3))
->method('getFieldValue')
->withConsecutive(['email'], ['consent'], ['boolean'])
->will($this->onConsecutiveCalls('[email protected]', 'Yes', 1));
$winner->expects($this->exactly(3))
->method('getField')
->withConsecutive(['email'], ['consent'], ['boolean'])
->will($this->onConsecutiveCalls([
'id' => 22,
'label' => 'Email',
'alias' => 'email',
'type' => 'email',
'group' => 'core',
'object' => 'lead',
'is_fixed' => true,
'default_value' => null,
], [
'id' => 44,
'label' => 'Email Consent',
'alias' => 'consent',
'type' => 'select',
'group' => 'core',
'object' => 'lead',
'is_fixed' => true,
'default_value' => 'No',
], [
'id' => 45,
'label' => 'Boolean Field',
'alias' => 'boolean',
'type' => 'boolean',
'group' => 'core',
'object' => 'lead',
'is_fixed' => true,
'default_value' => 0,
]));
$winner->expects($this->exactly(3))
->method('addUpdatedField')
->withConsecutive(
['email', '[email protected]'],
['consent', 'Yes'],
['boolean', 1]
);
$merger->mergeFieldData($winner, $loser);
}
public function testMergeOwners(): void
{
$winner = new Lead();
$loser = new Lead();
$winnerOwner = new User();
$winnerOwner->setUsername('bob');
$winner->setOwner($winnerOwner);
$loserOwner = new User();
$loserOwner->setUsername('susan');
$loser->setOwner($loserOwner);
// Should not have been merged due to winner already having one
$this->getMerger()->mergeOwners($winner, $loser);
$this->assertEquals($winnerOwner->getUserIdentifier(), $winner->getOwner()->getUserIdentifier());
$winner->setOwner(null);
$this->getMerger()->mergeOwners($winner, $loser);
// Should be set to loser owner since winner owner was null
$this->assertEquals($loserOwner->getUserIdentifier(), $winner->getOwner()->getUserIdentifier());
}
public function testMergePoints(): void
{
$winner = new Lead();
$loser = new Lead();
$winner->setPoints(100);
$loser->setPoints(50);
$this->getMerger()->mergePoints($winner, $loser);
$this->assertEquals(150, $winner->getPoints());
}
public function testMergeTags(): void
{
$winner = new Lead();
$loser = new Lead();
$loser->addTag(new Tag('loser'));
$loser->addTag(new Tag('loser2'));
$this->leadModel->expects($this->once())
->method('modifyTags')
->with($winner, ['loser', 'loser2'], null, false);
$this->getMerger()->mergeTags($winner, $loser);
}
public function testFullMergeThrowsSameContactException(): void
{
$winner = $this->getMockBuilder(Lead::class)
->getMock();
$winner->expects($this->once())
->method('getId')
->willReturn(1);
$loser = $this->getMockBuilder(Lead::class)
->getMock();
$loser->expects($this->once())
->method('getId')
->willReturn(1);
$this->expectException(SameContactException::class);
$this->getMerger()->merge($winner, $loser);
}
public function testFullMerge(): void
{
$winner = $this->getMockBuilder(Lead::class)
->getMock();
$winner->expects($this->any())
->method('getId')
->willReturn(1);
$winner->expects($this->once())
->method('getProfileFields')
->willReturn(
[
'id' => 1,
'points' => 10,
'email' => '[email protected]',
]
);
$winner->expects($this->exactly(1))
->method('getDateModified')
->willReturn(new \DateTime('-30 minutes'));
$loser = $this->getMockBuilder(Lead::class)
->getMock();
$loser->expects($this->any())
->method('getId')
->willReturn(2);
$loser->expects($this->once())
->method('getProfileFields')
->willReturn(
[
'id' => 2,
'points' => 20,
'email' => '[email protected]',
]
);
$loser->expects($this->exactly(1))
->method('getDateModified')
->willReturn(new \DateTime());
// updateMergeRecords
$this->mergeRecordRepo->expects($this->once())
->method('moveMergeRecord')
->with(2, 1);
// mergeIpAddresses
$ip = new IpAddress('1.2.3..4');
$loser->expects($this->once())
->method('getIpAddresses')
->willReturn(new ArrayCollection([$ip]));
$winner->expects($this->once())
->method('addIpAddress')
->with($ip);
// mergeFieldData
$winner->expects($this->once())
->method('getFieldValue')
->with('email')
->willReturn('[email protected]');
$winner->expects($this->once())
->method('getField')
->with('email')
->willReturn([
'value' => '[email protected]',
'id' => 22,
'label' => 'Email',
'alias' => 'email',
'type' => 'email',
'group' => 'core',
'object' => 'lead',
'is_fixed' => true,
'default_value' => null,
]);
$winner->expects($this->once())
->method('addUpdatedField')
->with('email', '[email protected]');
// mergeOwners
$winner->expects($this->never())
->method('setOwner');
// mergePoints
$loser->expects($this->once())
->method('getPoints')
->willReturn(100);
$winner->expects($this->once())
->method('adjustPoints')
->with(100);
// mergeTags
$loser->expects($this->once())
->method('getTags')
->willReturn(new ArrayCollection());
$this->leadModel->expects($this->once())
->method('modifyTags')
->with($winner, [], null, false);
$this->getMerger()->merge($winner, $loser);
}
public function testMergeFieldWithEmptyFieldData(): void
{
$loser = $this->createMock(Lead::class);
$winner = $this->createMock(Lead::class);
$loser->expects($this->exactly(1))
->method('getDateModified')
->willReturn(new \DateTime('-10 minutes'));
$winner->expects($this->exactly(1))
->method('getDateModified')
->willReturn(new \DateTime());
$winner->expects($this->exactly(4))
->method('getId')
->willReturn(1);
$loser->expects($this->once())
->method('getId')
->willReturn(2);
$winner->expects($this->once())
->method('getProfileFields')
->willReturn([
'email' => '[email protected]',
]);
$winner->expects($this->once())
->method('getField')
->with('email')
->willReturn(false);
$this->logger->expects($this->once())
->method('info')
->with('CONTACT: email is not mergeable for 1 - ');
$this->getMerger()->mergeFieldData($winner, $loser);
}
/**
* @return ContactMerger
*/
private function getMerger()
{
return new ContactMerger(
$this->leadModel,
$this->mergeRecordRepo,
$this->dispatcher,
$this->logger
);
}
}