From d13572d8bc390b4a6bdf02b1e0a6fa946b3f3d02 Mon Sep 17 00:00:00 2001
From: git <git@787980.no-reply.drupal.org>
Date: Fri, 3 Feb 2017 16:43:33 -0500
Subject: [PATCH] =?UTF-8?q?End=20of=20week=20commit=20Adds=20DeleteHandler?=
 =?UTF-8?q?Test=20(not=20quite=20working=20yet)=20Removes=20injected=20Url?=
 =?UTF-8?q?=20object=20in=20RestClient.=20There=20is=20no=20@url=20service?=
 =?UTF-8?q?=20in=20core.services.yml=20and=20we=E2=80=99re=20not=20suppose?=
 =?UTF-8?q?d=20to=20use=20UrlGenerator.=20Since=20Url=20is=20only=20used?=
 =?UTF-8?q?=20once=20in=20RestClient::getAuthCallbackUrl(),=20Url=20is=20u?=
 =?UTF-8?q?sed=20directly=20and=20that=20method=20can=20be=20easily=20mock?=
 =?UTF-8?q?ed=20under=20test.=20Cleans=20up=20salesforce=5Fpull=5Fcron()?=
 =?UTF-8?q?=20Cleans=20up=20DeleteHandler=E2=80=99s=20use=20statements=20A?=
 =?UTF-8?q?dds=20Request=20object=20to=20DeleteHandler=E2=80=99s=20constru?=
 =?UTF-8?q?ctor=20to=20handle=20REQUEST=5FTIME=20server=20global=20Adds=20?=
 =?UTF-8?q?boolean=20returns=20to=20DeleteHandler=20methods=20for=20unit?=
 =?UTF-8?q?=20testing=20purposes=20Fixes=20camel=20casing=20in=20MappedObj?=
 =?UTF-8?q?ectStorage::loadBySfid()=20call=20in=20DeleteHandler=20Converts?=
 =?UTF-8?q?=20try/catch=20pairs=20in=20DeleteHandler=20to=20non-exception?=
 =?UTF-8?q?=20based=20conditional=20logic=20to=20make=20logic=20testable?=
 =?UTF-8?q?=20Cleans=20up=20PullBase=E2=80=99s=20use=20statements=20Adds?=
 =?UTF-8?q?=20event=20dispatcher=20service=20to=20PullBase=E2=80=99s=20con?=
 =?UTF-8?q?structor=20Removes=20some=20property=20reference=20discrepancie?=
 =?UTF-8?q?s=20in=20PullBase=20Removes=20unnecessary=20code=20from=20PullB?=
 =?UTF-8?q?aseTest=20Removes=20unnecessary=20code=20from=20QueueHandlerTes?=
 =?UTF-8?q?t=20Adds=20back=20in=20missing=20properties=20in=20a=20loadByPr?=
 =?UTF-8?q?operties=20call=20in=20salesforce=5Fpush.module=20Adds=20logger?=
 =?UTF-8?q?.factory=20service=20to=20PushQueue=E2=80=99s=20service=20defin?=
 =?UTF-8?q?ition=20in=20salesforce=5Fpush.services.yml=20Changes=20logger?=
 =?UTF-8?q?=20service=20injection=20in=20PushQueue=E2=80=99s=20constructor?=
 =?UTF-8?q?=20to=20logger.factory=20service=20(there=20is=20no=20logger=20?=
 =?UTF-8?q?service=20defined=20in=20core.services.yml)=20Fixes=20all=20log?=
 =?UTF-8?q?ger=20service=20references=20in=20PushQueue=20Cleans=20up=20Sal?=
 =?UTF-8?q?esforcePushQueueProcessor/Rest=E2=80=99s=20use=20statements=20R?=
 =?UTF-8?q?emoves=20EntityManager=20service=20injection=20in=20SalesforceP?=
 =?UTF-8?q?ushQueueProcessor/Rest=E2=80=99s=20constructor=20in=20favor=20o?=
 =?UTF-8?q?f=20already=20existing=20EntityTypeManager=20service?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Still to do:
DeletehandlerTest needs to pass - A deep property call is not working, causing the test to
error out.
Fix DeleteHandler’s call to property so it’s easier to mock under test
Address Warning: array_flip(): Can only flip STRING and INTEGER values! error in or around
SalesForcePullEvent
Fix PullBase’s multiple creation of same new Drupal entity (was fixed, now showing up again).
---
 .../salesforce_pull/salesforce_pull.module    |   8 +-
 modules/salesforce_pull/src/DeleteHandler.php | 130 +++++++-------
 .../src/Plugin/QueueWorker/PullBase.php       |  13 +-
 .../tests/src/Unit/DeleteHandlerTest.php      | 165 ++++++++++++++++++
 .../tests/src/Unit/PullBaseTest.php           |   4 -
 .../tests/src/Unit/QueueHandlerTest.php       |   1 -
 .../salesforce_push/salesforce_push.module    |   6 +-
 .../salesforce_push.services.yml              |   2 +-
 .../SalesforcePushQueueProcessor/Rest.php     |  30 ++--
 modules/salesforce_push/src/PushQueue.php     |  22 +--
 salesforce.services.yml                       |   2 +-
 src/Rest/RestClient.php                       |   5 +-
 12 files changed, 282 insertions(+), 106 deletions(-)
 create mode 100644 modules/salesforce_pull/tests/src/Unit/DeleteHandlerTest.php

diff --git a/modules/salesforce_pull/salesforce_pull.module b/modules/salesforce_pull/salesforce_pull.module
index d3fc8e8e..634d3e6a 100644
--- a/modules/salesforce_pull/salesforce_pull.module
+++ b/modules/salesforce_pull/salesforce_pull.module
@@ -22,15 +22,17 @@ function salesforce_pull_cron() {
         ->getStorage('salesforce_mapping')
         ->loadMultiple(),
       \Drupal::queue('cron_salesforce_pull'),
+      \Drupal::state(),
+      \Drupal::logger('Salesforce Pull'),
       \Drupal::service('event_dispatcher'),
-      \Drupal::request(),
-      \Drupal::logger('Salesforce Pull')
+      \Drupal::request()
     )->getUpdatedRecords();
     DeleteHandler::create(
       $sfapi,
       \Drupal::service('entity_type.manager'),
       \Drupal::state(),
-      \Drupal::logger('Salesforce Pull')
+      \Drupal::logger('Salesforce Pull'),
+      \Drupal::request()
     )->processDeletedRecords();
   }
 }
diff --git a/modules/salesforce_pull/src/DeleteHandler.php b/modules/salesforce_pull/src/DeleteHandler.php
index b6f995aa..c31ffdb0 100644
--- a/modules/salesforce_pull/src/DeleteHandler.php
+++ b/modules/salesforce_pull/src/DeleteHandler.php
@@ -2,18 +2,20 @@
 
 namespace Drupal\salesforce_pull;
 
-use Drupal\salesforce\Exception;
-use Drupal\salesforce\Rest\RestClient;
-use Drupal\salesforce\SFID;
-use Drupal\salesforce\SelectQuery;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\State\StateInterface;
+use Drupal\Core\Utility\Error;
 use Drupal\salesforce_mapping\Entity\SalesforceMapping;
 use Drupal\salesforce_mapping\MappedObjectStorage;
 use Drupal\salesforce_mapping\MappingConstants;
 use Drupal\salesforce_mapping\SalesforceMappingStorage;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\State\StateInterface;
-use Psr\Log\LogLevel;
+use Drupal\salesforce\Exception;
+use Drupal\salesforce\Rest\RestClient;
+use Drupal\salesforce\SelectQuery;
+use Drupal\salesforce\SFID;
 use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Handles pull cron deletion of Drupal entities based onSF mapping settings.
@@ -29,14 +31,16 @@ class DeleteHandler {
   protected $etm;
   protected $state;
   protected $logger;
+  protected $request;
 
-  private function __construct(RestClient $sfapi, EntityTypeManagerInterface $entity_type_manager, StateInterface $state, LoggerInterface $logger) {
+  private function __construct(RestClient $sfapi, EntityTypeManagerInterface $entity_type_manager, StateInterface $state, LoggerInterface $logger, Request $request) {
     $this->sfapi = $sfapi;
     $this->etm = $entity_type_manager;
     $this->mapping_storage = $this->etm->getStorage('salesforce_mapping');
     $this->mapped_object_storage = $this->etm->getStorage('salesforce_mapped_object');
     $this->state = $state;
     $this->logger = $logger;
+    $this->request = $request;
   }
 
   /**
@@ -51,8 +55,8 @@ class DeleteHandler {
    * @param Psr\Log\LoggerInterface $logger
    *  Logging service
    */
-  public static function create(RestClient $sfapi, EntityTypeManagerInterface $entity_type_manager, StateInterface $state, LoggerInterface $logger) {
-    return new DeleteHandler($sfapi, $entity_type_manager, $state, $logger);
+  public static function create(RestClient $sfapi, EntityTypeManagerInterface $entity_type_manager, StateInterface $state, LoggerInterface $logger, Request $request) {
+    return new DeleteHandler($sfapi, $entity_type_manager, $state, $logger, $request);
   }
 
   /**
@@ -61,7 +65,7 @@ class DeleteHandler {
   public function processDeletedRecords() {
     // @TODO Add back in SOAP, and use autoloading techniques
     foreach (array_reverse($this->mapping_storage->getMappedSobjectTypes()) as $type) {
-      $last_delete_sync = $this->state->get('salesforce_pull_delete_last_' . $type, REQUEST_TIME);
+      $last_delete_sync = $this->state->get('salesforce_pull_last_delete_' . $type, $this->request->server->get('REQUEST_TIME'));
       $now = time();
       // getDeleted() restraint: startDate must be at least one minute
       // greater than endDate.
@@ -70,8 +74,9 @@ class DeleteHandler {
       $now_sf = gmdate('Y-m-d\TH:i:s\Z', $now);
       $deleted = $this->sfapi->getDeleted($type, $last_delete_sync_sf, $now_sf);
       $this->handleDeletedRecords($deleted, $type);
-      $this->state->set('salesforce_pull_delete_last_' . $type, REQUEST_TIME);
+      $this->state->set('salesforce_pull_last_delete_' . $type, $this->request->server->get('REQUEST_TIME'));
     }
+    return true;
   }
 
   protected function handleDeletedRecords(array $deleted, $type) {
@@ -92,69 +97,74 @@ class DeleteHandler {
   }
 
   protected function handleDeletedRecord($record, $type) {
-    $mapped_objects = $this->mapped_object_storage->loadBySFID(new SFID($record['id']));
+    $mapped_objects = $this->mapped_object_storage->loadBySfid(new SFID($record['id']));
     if (empty($mapped_objects)) {
       return;
     }
 
     foreach ($mapped_objects as $mapped_object) {
-        $entity = $this->etm
-          ->getStorage($mapped_object->entity_type_id->value)
-          ->load($mapped_object->entity_id->value);
-        if (!$entity) {
-          $this->logger->log(
-            LogLevel::NOTICE,
-            'No entity found for ID %id associated with Salesforce Object ID: %sfid ',
-            [
-              '%id' => $mapped_object->entity_id->value,
-              '%sfid' => $record['id'],
-            ]
-          );
-          $mapped_object->delete();
-          continue;
-        }
-      }
-
-      // The mapping entity is an Entity reference field on mapped object, so we need to get the id value this way.
-      $sf_mapping = $this->mapping_storage
-        ->load($mapped_object->salesforce_mapping->entity->id());
-      if (!$sf_mapping) {
+      $entity = $this->etm
+        ->getStorage($mapped_object->entity_type_id->value)
+        ->load($mapped_object->entity_id->value);
+      if (!$entity) {
         $this->logger->log(
           LogLevel::NOTICE,
-          'No mapping exists for mapped object %id with Salesforce Object ID: %sfid',
+          'No entity found for ID %id associated with Salesforce Object ID: %sfid ',
           [
-            '%id' => $mapped_object->id(),
+            '%id' => $mapped_object->entity_id->value,
             '%sfid' => $record['id'],
           ]
         );
-        // @TODO should we delete a mapped object whose parent mapping no longer exists? Feels like someone else's job.
-        // $mapped_object->delete();
-        continue;
+        $mapped_object->delete();
+        return;
       }
+    }
 
-      if (!$sf_mapping->checkTriggers([MappingConstants::SALESFORCE_MAPPING_SYNC_SF_DELETE])) {
-        continue;
-      }
+    // The mapping entity is an Entity reference field on mapped object, so we need to get the id value this way.
+    $foo = $mapped_object->salesforce_mapping->id;
+    $sf_mapping = $this->mapping_storage
+    //  ->load($mapped_object->salesforce_mapping->id);
+      ->load($mapped_object->salesforce_mapping->entity->id());
+    if (!$sf_mapping) {
+      $this->logger->log(
+        LogLevel::NOTICE,
+        'No mapping exists for mapped object %id with Salesforce Object ID: %sfid',
+        [
+          '%id' => $mapped_object->id(),
+          '%sfid' => $record['id'],
+        ]
+      );
+      // @TODO should we delete a mapped object whose parent mapping no longer exists? Feels like someone else's job.
+      // $mapped_object->delete();
+      return;
+    }
 
-      try {
-        $entity->delete();
-        $this->logger->log(
-          LogLevel::NOTICE,
-          'Deleted entity %label with ID: %id associated with Salesforce Object ID: %sfid',
-          [
-            '%label' => $entity->label(),
-            '%id' => $mapped_object->entity_id,
-            '%sfid' => $record->id,
-          ]
-        );
-      }
-      catch (\Exception $e) {
-        $this->watchdogException($e);
-        // If mapped entity couldn't be deleted, do not delete the mapped object either.
-        continue;
-      }
+    if (!$sf_mapping->checkTriggers([MappingConstants::SALESFORCE_MAPPING_SYNC_SF_DELETE])) {
+      return;
+    }
 
-      $mapped_object->delete();
+    try {
+      $entity->delete();
+      $this->logger->log(
+        LogLevel::NOTICE,
+        'Deleted entity %label with ID: %id associated with Salesforce Object ID: %sfid',
+        [
+          '%label' => $entity->label(),
+          '%id' => $mapped_object->entity_id,
+          '%sfid' => $record->id,
+        ]
+      );
+    }
+    catch (\Exception $e) {
+      $this->logger->log(
+        LogLevel::ERROR,
+        '%type: @message in %function (line %line of %file).',
+        Error::decodeException($e)
+      );
+      // If mapped entity couldn't be deleted, do not delete the mapped object either.
+      return;
     }
+
+    $mapped_object->delete();
   }
 }
diff --git a/modules/salesforce_pull/src/Plugin/QueueWorker/PullBase.php b/modules/salesforce_pull/src/Plugin/QueueWorker/PullBase.php
index 6c62b2ce..78b60cfc 100644
--- a/modules/salesforce_pull/src/Plugin/QueueWorker/PullBase.php
+++ b/modules/salesforce_pull/src/Plugin/QueueWorker/PullBase.php
@@ -7,20 +7,24 @@
 
 namespace Drupal\salesforce_pull\Plugin\QueueWorker;
 
+use Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Logger\LoggerChannelFactoryInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Queue\QueueWorkerBase;
 use Drupal\Core\Utility\Error;
+use Drupal\salesforce_mapping\Entity\MappedObject;
 use Drupal\salesforce_mapping\Entity\MappedObjectInterface;
 use Drupal\salesforce_mapping\Entity\SalesforceMappingInterface;
 use Drupal\salesforce_mapping\MappedObjectStorage;
 use Drupal\salesforce_mapping\MappingConstants;
 use Drupal\salesforce_mapping\PushParams;
 use Drupal\salesforce_mapping\SalesforceMappingStorage;
+use Drupal\salesforce_mapping\SalesforcePullEvent;
 use Drupal\salesforce\Exception;
 use Drupal\salesforce\Rest\RestClient;
+use Drupal\salesforce\SalesforceEvents;
 use Drupal\salesforce\SObject;
 use Psr\Log\LogLevel;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -80,19 +84,21 @@ abstract class PullBase extends QueueWorkerBase implements ContainerFactoryPlugi
   protected $logger;
 
   protected $event_dispatcher;
+
   /**
    * Creates a new PullBase object.
    *
    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $etm
    *   The entity type manager.
    */
-  public function __construct(EntityTypeManagerInterface $entity_type_manager, RestClient $client, ModuleHandlerInterface $module_handler, LoggerChannelFactoryInterface $logger_factory) {
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, RestClient $client, ModuleHandlerInterface $module_handler, LoggerChannelFactoryInterface $logger_factory, ContainerAwareEventDispatcher $event_dispatcher) {
     $this->etm = $entity_type_manager;
     $this->client = $client;
     $this->mh = $module_handler;
     $this->logger = $logger_factory->get('Salesforce Pull');
     $this->mapping_storage = $this->etm->getStorage('salesforce_mapping');
     $this->mapped_object_storage = $this->etm->getStorage('salesforce_mapped_object');
+    $this->event_dispatcher = $event_dispatcher;
     $this->done = '';
   }
 
@@ -104,7 +110,8 @@ abstract class PullBase extends QueueWorkerBase implements ContainerFactoryPlugi
       $container->get('entity_type.manager'),
       $container->get('salesforce.client'),
       $container->get('module_handler'),
-      $container->get('logger.factory')
+      $container->get('logger.factory'),
+      $container->get('event_dispatcher')
     );
   }
 
@@ -256,7 +263,7 @@ abstract class PullBase extends QueueWorkerBase implements ContainerFactoryPlugi
       // Create mapping object.
       $mapped_object = new MappedObject([
           'entity_type_id' => $entity_type,
-          'salesforce_mapping' => $mapping->id(),
+          'salesforce_mapping' => $mapping->id,
           'salesforce_id' => (string)$sf_object->id(),
         ]);
 
diff --git a/modules/salesforce_pull/tests/src/Unit/DeleteHandlerTest.php b/modules/salesforce_pull/tests/src/Unit/DeleteHandlerTest.php
new file mode 100644
index 00000000..f70e49a8
--- /dev/null
+++ b/modules/salesforce_pull/tests/src/Unit/DeleteHandlerTest.php
@@ -0,0 +1,165 @@
+<?php
+namespace Drupal\Tests\salesforce_pull\Unit;
+
+//use Drupal\Core\Config\Entity\ConfigEntityStorage;
+use Drupal\Core\Entity\EntityStorageBase;
+//use Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\Entity;
+use Drupal\Core\Queue\QueueInterface;
+use Drupal\Core\State\StateInterface;
+use Drupal\salesforce_mapping\Entity\MappedObject;
+use Drupal\salesforce_mapping\Entity\SalesforceMappingInterface;
+use Drupal\salesforce_mapping\SalesforceMappingStorage;
+use Drupal\salesforce_mapping\MappedObjectStorage;
+use Drupal\salesforce_pull\DeleteHandler;
+use Drupal\salesforce\Rest\RestClient;
+use Drupal\salesforce\SelectQueryResult;
+use Drupal\salesforce\SObject;
+use Drupal\Tests\UnitTestCase;
+use Prophecy\Argument;
+use Psr\Log\LoggerInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\ServerBag;
+
+/**
+ * Test Object instantitation
+ *
+ * @group salesforce_pull
+ */
+
+class DeleteHanderTest extends UnitTestCase {
+  static $modules = ['salesforce_pull'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $result = [
+      'totalSize' => 1,
+      'done' => true,
+      'deletedRecords' => [
+        [
+          'id' => '1234567890abcde',
+          'attributes' => ['type' => 'dummy',],
+          'name' => 'Example',
+        ],
+      ]
+    ];
+
+    $prophecy = $this->prophesize(RestClient::CLASS);
+    $prophecy->getDeleted(Argument::any(),Argument::any(),Argument::any())
+      ->willReturn($result); // revisit
+    $this->sfapi = $prophecy->reveal();
+
+    $this->mapping = $this->getMockBuilder(SalesforceMappingInterface::CLASS)
+      ->setMethods(['__construct', '__get', 'get', 'getSalesforceObjectType', 'getPullFieldsArray','checkTriggers'])
+      ->getMock();
+    $this->mapping->expects($this->any())
+      ->method('__get')
+      ->with($this->equalTo('id'))
+      ->willReturn(1);
+    $this->mapping->expects($this->any())
+      ->method('getSalesforceObjectType')
+      ->willReturn('default');
+    $this->mapping->expects($this->any())
+      ->method('getPullFieldsArray')
+      ->willReturn(['Name' => 'Name', 'Account Number' => 'Account Number']);
+    $this->mapping->expects($this->any())
+      ->method('checkTriggers')
+      ->willReturn(true);
+
+    // mock mapped object
+    $this->entityTypeId = new \stdClass();
+    $this->entityId = new \stdClass();
+    $this->entityRef = new \stdClass();
+    $this->entityTypeId->value = 'test';
+    $this->entityId->value = '1';
+    $this->entityRef->entity = $this->mapping;
+
+    $prophecy = $this->prophesize(MappedObject::CLASS);
+    $prophecy->delete()->willReturn(true);
+    $prophecy->getFieldDefinitions()->willReturn(['entity_type_id','entity_id','salesforce_mapping']);
+    $prophecy->entity_type_id = $this->entityTypeId;
+    $prophecy->entity_id = $this->entityId;
+    $prophecy->salesforce_mapping = $this->mapping;
+    $this->mappedObject = $prophecy->reveal();
+    //print_r($this->mappedObject);
+
+    // mock Drupal entity
+    $prophecy = $this->prophesize(Entity::CLASS);
+    $prophecy->delete()->willReturn(true);
+    $this->entity = $prophecy->reveal();
+
+    // mock mapping ConfigEntityStorage object
+    $prophecy = $this->prophesize(SalesforceMappingStorage::CLASS);
+    $prophecy->loadByProperties(Argument::any())->willReturn([$this->mapping]);
+    $prophecy->load(Argument::any())->willReturn([$this->mapping]);
+    $prophecy->getMappedSobjectTypes()->willReturn([
+      'default'
+    ]);
+    $this->configStorage = $prophecy->reveal();
+
+    // mock mapped object EntityStorage object
+    $prophecy = $this->prophesize(MappedObjectStorage::CLASS);
+    $prophecy->loadBySfid(Argument::any())->willReturn([$this->mappedObject]);
+    $this->entityStorage = $prophecy->reveal();
+
+    // mock Drupal entity EntityStorage object
+    $prophecy = $this->prophesize(EntityStorageBase::CLASS);
+    $prophecy->load(Argument::any())->willReturn($this->entity);
+    $this->drupalEntityStorage = $prophecy->reveal();
+
+    // mock EntityTypeManagerInterface
+    $prophecy = $this->prophesize(EntityTypeManagerInterface::CLASS);
+    $prophecy->getStorage('salesforce_mapping')->willReturn($this->configStorage);
+    $prophecy->getStorage('salesforce_mapped_object')->willReturn($this->entityStorage);
+    $prophecy->getStorage('test')->willReturn($this->drupalEntityStorage);
+    $this->etm = $prophecy->reveal();
+
+    // mock state
+    $prophecy = $this->prophesize(StateInterface::CLASS);
+    $prophecy->get('salesforce_pull_last_delete_default', Argument::any())->willReturn('1485787434');
+    $prophecy->set('salesforce_pull_last_delete_default', Argument::any())->willReturn(null);
+    $this->state = $prophecy->reveal();
+
+    // mock logger
+    $prophecy = $this->prophesize(LoggerInterface::CLASS);
+    $prophecy->log(Argument::any(), Argument::any(), Argument::any())->willReturn(null);
+    $this->logger = $prophecy->reveal();
+
+    // mock server
+    $prophecy = $this->prophesize(ServerBag::CLASS);
+    $prophecy->get(Argument::any())->willReturn('1485787434');
+    $this->server = $prophecy->reveal();
+
+    // mock request
+    $prophecy = $this->prophesize(Request::CLASS);
+    $prophecy->server = $this->server;
+    $this->request = $prophecy->reveal();
+
+    $this->dh = DeleteHandler::create(
+      $this->sfapi,
+      $this->etm,
+      $this->state,
+      $this->logger,
+      $this->request
+    );
+  }
+
+  /**
+   * Test object instantiation
+   */
+  public function testObject() {
+    $this->assertTrue($this->dh instanceof DeleteHander);
+  }
+
+  /**
+   * Test handler operation, good data
+   */
+  public function testGetUpdatedRecords() {
+    $result = $this->dh->processDeletedRecords();
+    $this->assertTrue($result);
+  }
+}
diff --git a/modules/salesforce_pull/tests/src/Unit/PullBaseTest.php b/modules/salesforce_pull/tests/src/Unit/PullBaseTest.php
index acae5689..96f55b80 100644
--- a/modules/salesforce_pull/tests/src/Unit/PullBaseTest.php
+++ b/modules/salesforce_pull/tests/src/Unit/PullBaseTest.php
@@ -7,7 +7,6 @@ use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Logger\LoggerChannelFactoryInterface;
-use Drupal\Core\StringTranslation\Translator\TranslationInterface;
 use Drupal\salesforce_mapping\Entity\MappedObjectInterface;
 use Drupal\salesforce_mapping\Entity\SalesforceMappingInterface;
 use Drupal\salesforce_mapping\Entity\SalesforceMapping;
@@ -58,9 +57,6 @@ class PullBaseTest extends UnitTestCase {
 
     // mock mapped object
     $prophecy = $this->prophesize(MappedObjectInterface::CLASS);
-    // @TODO: make MappedObjects testable and thus mockable better here
-    //$prophecy->get('entity_type_id')->willReturn($this->entityTypeId);
-    //$prophecy->get('entity_id')->willReturn($this->entityId);
     $this->mappedObject = $prophecy->reveal();
 
 
diff --git a/modules/salesforce_pull/tests/src/Unit/QueueHandlerTest.php b/modules/salesforce_pull/tests/src/Unit/QueueHandlerTest.php
index db32867a..ddb9376c 100644
--- a/modules/salesforce_pull/tests/src/Unit/QueueHandlerTest.php
+++ b/modules/salesforce_pull/tests/src/Unit/QueueHandlerTest.php
@@ -9,7 +9,6 @@ use Drupal\salesforce_pull\QueueHandler;
 use Drupal\salesforce\Rest\RestClient;
 use Drupal\salesforce\SelectQueryResult;
 use Drupal\salesforce\SObject;
-use Drupal\Tests\salesforce\salesforce_pull\TestQueueHandler;
 use Drupal\Tests\UnitTestCase;
 use Prophecy\Argument;
 use Psr\Log\LoggerInterface;
diff --git a/modules/salesforce_push/salesforce_push.module b/modules/salesforce_push/salesforce_push.module
index 10344b9b..2c18b6a1 100644
--- a/modules/salesforce_push/salesforce_push.module
+++ b/modules/salesforce_push/salesforce_push.module
@@ -58,8 +58,10 @@ function salesforce_push_entity_crud(EntityInterface $entity, $op) {
     return;
   }
 
-  $mappings =
-    $mappings = \Drupal::service('entity.manager')
+  $properties = empty($entity->getEntityTypeId())
+    ? []
+    : ["drupal_entity_type" => $entity->getEntityTypeId()];
+  $mappings = \Drupal::service('entity.manager')
       ->getStorage('salesforce_mapping')
       ->loadByProperties($properties);
   if (empty($mappings)) {
diff --git a/modules/salesforce_push/salesforce_push.services.yml b/modules/salesforce_push/salesforce_push.services.yml
index 73dec8c9..ba23d1ea 100644
--- a/modules/salesforce_push/salesforce_push.services.yml
+++ b/modules/salesforce_push/salesforce_push.services.yml
@@ -5,4 +5,4 @@ services:
 
   queue.salesforce_push:
     class: Drupal\salesforce_push\PushQueue
-    arguments: ['@database', '@state', '@plugin.manager.salesforce_push_queue_processor', '@entity.manager']
+    arguments: ['@database', '@state', '@plugin.manager.salesforce_push_queue_processor', '@entity.manager', '@logger.factory']
diff --git a/modules/salesforce_push/src/Plugin/SalesforcePushQueueProcessor/Rest.php b/modules/salesforce_push/src/Plugin/SalesforcePushQueueProcessor/Rest.php
index b913e035..cf06b0c7 100644
--- a/modules/salesforce_push/src/Plugin/SalesforcePushQueueProcessor/Rest.php
+++ b/modules/salesforce_push/src/Plugin/SalesforcePushQueueProcessor/Rest.php
@@ -2,21 +2,21 @@
 
 namespace Drupal\salesforce_push\Plugin\SalesforcePushQueueProcessor;
 
+use Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher;
+use Drupal\Core\Entity\EntityTypeManager;
 use Drupal\Core\Plugin\PluginBase;
 use Drupal\Core\Queue\SuspendQueueException;
-use Drupal\salesforce\EntityNotFoundException;
-use Drupal\salesforce\Rest\RestClient;
 use Drupal\salesforce_mapping\Entity\MappedObject;
 use Drupal\salesforce_mapping\MappedObjectStorage;
 use Drupal\salesforce_mapping\MappingConstants;
 use Drupal\salesforce_mapping\SalesforceMappingStorage;
+use Drupal\salesforce_mapping\SalesforcePushEvent;
 use Drupal\salesforce_push\PushQueue;
 use Drupal\salesforce_push\PushQueueProcessorInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\salesforce\EntityNotFoundException;
+use Drupal\salesforce\Rest\RestClient;
 use Drupal\salesforce\SalesforceEvents;
-use Drupal\salesforce_mapping\SalesforcePushEvent;
-use Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Rest queue processor plugin.
@@ -43,18 +43,15 @@ class Rest extends PluginBase implements PushQueueProcessorInterface {
    * @var MappedObjectStorage
    */
   protected $mapped_object_storage;
-
-  protected $entity_manager;
   protected $event_dispatcher;
-  protected $entityTypeManager;
+  protected $etm;
 
-  public function __construct(array $configuration, $plugin_id, array $plugin_definition, PushQueue $queue, RestClient $client, EntityManagerInterface $entity_manager, EntityTypeManagerInterface $etm, ContainerAwareEventDispatcher $event_dispatcher) {
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, PushQueue $queue, RestClient $client,  EntityTypeManager $etm, ContainerAwareEventDispatcher $event_dispatcher) {
     $this->queue = $queue;
     $this->client = $client;
-    $this->entity_manager = $entity_manager;
-    $this->entityTypeManager = $etm;
-    $this->mapping_storage = $entity_manager->getStorage('salesforce_mapping');
-    $this->mapped_object_storage = $entity_manager->getStorage('salesforce_mapped_object');
+    $this->etm = $etm;
+    $this->mapping_storage = $etm->getStorage('salesforce_mapping');
+    $this->mapped_object_storage = $etm->getStorage('salesforce_mapped_object');
     $this->event_dispatcher = $event_dispatcher;
   }
 
@@ -65,9 +62,8 @@ class Rest extends PluginBase implements PushQueueProcessorInterface {
     return new static($configuration, $plugin_id, $plugin_definition,
       $container->get('queue.salesforce_push'),
       $container->get('salesforce.client'),
-      $container->get('entity.manager'),
       $container->get('entity_type.manager'),
-      $container->get('event_dispatcher'),
+      $container->get('event_dispatcher')
     );
   }
 
@@ -118,7 +114,7 @@ class Rest extends PluginBase implements PushQueueProcessorInterface {
         $mapped_object->pushDelete();
       }
       else {
-        $entity = $this->entityTypeManager
+        $entity = $this->etm
           ->getStorage($mapping->drupal_entity_type)
           ->load($item->entity_id);
         if (!$entity) {
diff --git a/modules/salesforce_push/src/PushQueue.php b/modules/salesforce_push/src/PushQueue.php
index 761cbba6..b309de91 100644
--- a/modules/salesforce_push/src/PushQueue.php
+++ b/modules/salesforce_push/src/PushQueue.php
@@ -3,19 +3,19 @@
 namespace Drupal\salesforce_push;
 
 use Drupal\Core\Database\Connection;
+use Drupal\Core\Database\Query\Merge;
 use Drupal\Core\Database\SchemaObjectExistsException;
 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
-use Drupal\Core\Database\Query\Merge;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Logger\LoggerChannelFactoryInterface;
 use Drupal\Core\Queue\DatabaseQueue;
-use Drupal\Core\State\State;
-use Drupal\Core\Queue\SuspendQueueException;
 use Drupal\Core\Queue\RequeueException;
-use Drupal\salesforce\EntityNotFoundException;
-use Drupal\salesforce_mapping\SalesforceMappingStorage;
+use Drupal\Core\Queue\SuspendQueueException;
+use Drupal\Core\State\State;
 use Drupal\salesforce_mapping\MappedObjectStorage;
-use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\Core\Entity\EntityInterface;
-use Psr\Log\LoggerInterface;
+use Drupal\salesforce_mapping\SalesforceMappingStorage;
+use Drupal\salesforce\EntityNotFoundException;
 
 /**
  * Salesforce push queue.
@@ -61,14 +61,14 @@ class PushQueue extends DatabaseQueue {
    * @param \Drupal\Core\Database\Connection $connection
    *   The Connection object containing the key-value tables.
    */
-  public function __construct(Connection $connection, State $state, PushQueueProcessorPluginManager $queue_manager, EntityManagerInterface $entity_manager, LoggerInterface $logger) {
+  public function __construct(Connection $connection, State $state, PushQueueProcessorPluginManager $queue_manager, EntityManagerInterface $entity_manager, LoggerChannelFactoryInterface $logger_factory) {
     $this->connection = $connection;
     $this->state = $state;
     $this->queueManager = $queue_manager;
     $this->entity_manager = $entity_manager;
     $this->mapping_storage = $entity_manager->getStorage('salesforce_mapping');
     $this->mapped_object_storage = $entity_manager->getStorage('salesforce_mapped_object');
-    $this->logger = $logger;
+    $this->logger = $logger_factory->get('Salesforce Push');
 
     $this->limit = $state->get('salesforce.push_limit', static::DEFAULT_CRON_PUSH_LIMIT);
 
@@ -372,7 +372,7 @@ class PushQueue extends DatabaseQueue {
       $message = 'Queue item %item failed %fail times. Exception while pushing entity %type %id for salesforce mapping %mapping. ' . $message;
     }
 
-    $this->log->error($message,
+    $this->logger->error($message,
       [
         '%type' => $mapping->get('drupal_entity_type'),
         '%id' => $item->entity_id,
diff --git a/salesforce.services.yml b/salesforce.services.yml
index 58dad7f8..777d1397 100644
--- a/salesforce.services.yml
+++ b/salesforce.services.yml
@@ -1,4 +1,4 @@
 services:
   salesforce.client:
     class: Drupal\salesforce\Rest\RestClient
-    arguments: ['@http_client', '@config.factory', '@url', '@state', '@cache.default']
+    arguments: ['@http_client', '@config.factory', '@state', '@cache.default']
diff --git a/src/Rest/RestClient.php b/src/Rest/RestClient.php
index 6f555749..cef74a05 100644
--- a/src/Rest/RestClient.php
+++ b/src/Rest/RestClient.php
@@ -42,10 +42,9 @@ class RestClient {
    * @param \Guzzle\Http\ClientInterface $http_client
    *   The config factory.
    */
-  public function __construct(ClientInterface $http_client, ConfigFactoryInterface $config_factory, Url $url, StateInterface $state, CacheBackendInterface $cache) {
+  public function __construct(ClientInterface $http_client, ConfigFactoryInterface $config_factory, StateInterface $state, CacheBackendInterface $cache) {
     $this->configFactory = $config_factory;
     $this->httpClient = $http_client;
-    $this->url = $url;
     $this->config = $this->configFactory->get('salesforce.settings');
     $this->configEditable = $this->configFactory->getEditable('salesforce.settings');
     $this->state = $state;
@@ -426,7 +425,7 @@ class RestClient {
    * @see Drupal\salesforce\Controller\SalesforceController
    */
   public function getAuthCallbackUrl() {
-    return $this->url->fromRoute('salesforce.oauth_callback', [], [
+    return Url::fromRoute('salesforce.oauth_callback', [], [
       'absolute' => TRUE,
       'https' => TRUE,
     ]);
-- 
GitLab