Artie Peshimam
Artie Peshimam

Reputation: 61

ScalaMock: Can't log call to mock object, have expectations been verified already

Im running into an issue with scala mock. Where the error message indicates that it cannot log a call to a mock object.

I've set up the following spec. I've a few mocks setup but nothing to extraordinary:

    "get accounts" in {
      import CodatAccount._
      val mockCompanyId = UUID.randomUUID().toString
      val mockLedger = Ledger.defaultInstance.copy(connection =
        Ledger.Connection.CodatConnection(common.CodatConnection(codatCompanyUuid = mockCompanyId)),
        ledgerUuid = UUID.randomUUID().toString
      )
      def getMockAccount = CodatAccount(
        id = Some(UUID.randomUUID().toString),
        `type` = CodatAccountType.Asset,
        status = CodatStatus.Active,
        isBankAccount = false)

      val mockAccounts =
        CodatAccountsPage(Seq(getMockAccount, getMockAccount, getMockAccount, getMockAccount, getMockAccount))
      val expectedAccountsJson = mockAccounts.results.asJson
      val mockGleanAccounts = mockAccounts.results.map(_.asProto(mockLedger))

      (mockAccountCacheDAO.refreshCache(_: Seq[Account], _: UUID, _: UUID)(_: ExecutionContext))
        .expects(mockGleanAccounts.toSeq, UUID.fromString(mockLedger.ledgerUuid), *, *)
        .returns(Future.successful())

      (mockSyncDataLakeDAO.getSyncDataByLedgerIdAndDataType(_: UUID, _: DataTypeEntity)(_: ExecutionContext))
        .expects(UUID.fromString(mockLedger.ledgerUuid), DataTypeEntity.ACCOUNT, *)
        .returns(Future.successful(None))

      (mockSyncDataLakeDAO.upsertSyncDataLake(_: SyncData)(_: ExecutionContext))
        .expects(where { (syncData: SyncData, _) =>
          syncData.ledgerId == UUID.fromString(mockLedger.ledgerUuid) && syncData.json == expectedAccountsJson
        })
        .returns(Future.successful())

      (mockHttpClient
        .get[CodatAccountsPage](_: Uri, _: Map[String, String])(_: Decoder[CodatAccountsPage]))
        .expects(
          uri"/companies/${mockCompanyId}/data/accounts".addParam("query", "status=Active").addParam("page", "1"),
          Map[String, String](),
          *)
        .returns(Right(mockAccounts).future)

      (mockHttpClient
        .get[CodatAccountsPage](_: Uri, _: Map[String, String])(_: Decoder[CodatAccountsPage]))
        .expects(
          uri"/companies/${mockCompanyId}/data/accounts".addParam("query", "status=Active").addParam("page", "2"),
          Map[String, String](),
          *)
        .returns(Right(CodatAccountsPage(Nil)).future)

      codatLedgerService.getAccounts(mockLedger, None).map {
        case Nil => fail("failed get accounts")
        case accounts =>
          accounts shouldBe mockAccounts.results.map(_.asProto(mockLedger))
      }
    }

And have the following application code under test:

 override def getAccounts(ledger: states.Ledger, modifiedAfter: Option[Instant]): Future[Iterable[common.Account]] = {
    val ledgerId = UUID.fromString(ledger.ledgerUuid)
    val codatAccounts = ListBuffer.empty[CodatAccount]
    ledger.extractAndMap(entity = "accounts") { (companyId, entity) =>
      log.info(s"Codat getAccounts for companyId= [$companyId]")
      val path = uri"/companies/${companyId}/data/accounts".addCommonParams(modifiedAfter)

      def request(pageNumber: Int) = {
        httpClient.get[CodatAccountsPage](path = path.addParam("page", pageNumber.toString)).collect {
          case Right(responsePage) =>
            codatAccounts.addAll(responsePage.results)
            Right(responsePage.results.map(_.asProto(ledger)))
        }
      }

      val resultF = UnfoldIO
        .getWhileNotEmpty(request = request, pageNumber = 1)
        .collectAndRecover(entity = entity, companyId = companyId)

      resultF.map { accounts =>
        updateAccountsCache(ledgerId = ledgerId, accounts = accounts.toSeq, codatAccounts = codatAccounts.toSeq)
      }

      resultF.recoverWith { case _: Timeout =>
        accountCacheDAO.getAccounts(ledgerId = ledgerId)
      }
    }
  }

  private def updateAccountsCache(
      ledgerId: UUID,
      accounts: Seq[Account],
      codatAccounts: Seq[CodatAccount]): Future[Unit] = {
    val syncData = SyncData(ledgerId = ledgerId, dataType = DataTypeEntity.ACCOUNT, codatAccounts.asJson)

    val resultF = for {
      existingSyncDataO <- syncDataLakeDAO.getSyncDataByLedgerIdAndDataType(
        ledgerId = ledgerId,
        dataType = DataTypeEntity.ACCOUNT)
      updateCache = existingSyncDataO.forall(existingSyncData => !existingSyncData.compareHashes(compareTo = syncData))
      if updateCache
      _ <- syncDataLakeDAO.upsertSyncDataLake(syncData = syncData)
      result <- accountCacheDAO.refreshCache(accounts = accounts, ledgerId = ledgerId, syncDataId = syncData.syncDataId)
    } yield result

    resultF.onComplete {
      case Failure(ex) => log.error(f"Failed to update the account cache due to ${ex.getMessage}", ex)
      case Success(_)  => log.debug("Successfully updated the account cache")
    }
    resultF
  }

The issue is that Im getting the following exception when I try to run my test:

2022-06-29 00:35:15,870 ERROR com.gleanhq.ledger.external.CodatLedgerServiceImpl - Failed to update the account cache due to Can't log call to mock object, have expectations been verified already?

Im unclear as to why this is failing. As far as I can tell, ScalaMock is complaining that it can't record invocations. But Im not clear why this issue is presenting.

Upvotes: 1

Views: 607

Answers (0)

Related Questions