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

476 Views Asked by At

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.

0

There are 0 best solutions below