<commit_before>package uk.ac.wellcome.platform.matcher.locking

import java.time.{Duration, Instant}
import java.util
import java.util.concurrent.{CountDownLatch, TimeUnit}

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB
import com.amazonaws.services.dynamodbv2.model._
import com.gu.scanamo._
import org.mockito.Matchers.any
import org.mockito.Mockito.when
import org.scalatest.concurrent.ScalaFutures
import org.scalatest.{FunSpec, Matchers}
import uk.ac.wellcome.platform.matcher.fixtures.MatcherFixtures
import uk.ac.wellcome.platform.matcher.lockable._

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.Random

class DynamoRowLockDaoTest
    extends FunSpec
    with Matchers
    with ScalaFutures
    with MatcherFixtures {

  import com.gu.scanamo.syntax._

  case class ThingToStore(id: String, value: String)

  private val contextId = "contextId"

  it("locks a thing") {
    withSpecifiedLocalDynamoDbTable(createLockTable) { lockTable =>
      withDynamoRowLockDao(lockTable) { dynamoRowLockDao =>
        val id = Random.nextString(32)
        whenReady(dynamoRowLockDao.lockRow(Identifier(id), contextId)) {
          lock =>
            lock.id shouldBe id

            val actualStored =
              Scanamo.get[RowLock](dynamoDbClient)(lockTable.name)('id -> id)
            val storedRowLock = actualStored.get.right.get
            storedRowLock.id shouldBe id
        }
      }
    }
  }

  it("cannot lock a locked thing") {
    withSpecifiedLocalDynamoDbTable(createLockTable) { lockTable =>
      withDynamoRowLockDao(lockTable) { dynamoRowLockDao =>
        val id = Random.nextString(32)
        Scanamo.put[RowLock](dynamoDbClient)(lockTable.name)(
          RowLock(id, contextId, Instant.now, Instant.now.plusSeconds(100)))

        whenReady(dynamoRowLockDao.lockRow(Identifier(id), contextId).failed) {
          secondLockFailure =>
            secondLockFailure shouldBe a[FailedLockException]
        }
      }
    }
  }

  it("can lock a locked thing that has expired") {
    withSpecifiedLocalDynamoDbTable(createLockTable) { lockTable =>
      withDynamoRowLockDao(lockTable) { dynamoRowLockDao =>
        val id = Random.nextString(32)
        whenReady(dynamoRowLockDao.lockRow(Identifier(id), contextId)) {
          firstLock =>
            firstLock.id shouldBe id
        }<commit_msg>improved test error when checking locks<commit_after>package uk.ac.wellcome.platform.matcher.locking

import java.time.{Duration, Instant}
import java.util
import java.util.concurrent.{CountDownLatch, TimeUnit}

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB
import com.amazonaws.services.dynamodbv2.model._
import com.gu.scanamo._
import org.mockito.Matchers.any
import org.mockito.Mockito.when
import org.scalatest.concurrent.ScalaFutures
import org.scalatest.{FunSpec, Matchers}
import uk.ac.wellcome.platform.matcher.fixtures.MatcherFixtures
import uk.ac.wellcome.platform.matcher.lockable._

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.Random

class DynamoRowLockDaoTest
    extends FunSpec
    with Matchers
    with ScalaFutures
    with MatcherFixtures {

  import com.gu.scanamo.syntax._

  case class ThingToStore(id: String, value: String)

  private val contextId = "contextId"

  it("locks a thing") {
    withSpecifiedLocalDynamoDbTable(createLockTable) { lockTable =>
      withDynamoRowLockDao(lockTable) { dynamoRowLockDao =>
        val id = Random.nextString(32)
        whenReady(dynamoRowLockDao.lockRow(Identifier(id), contextId)) {
          lock =>
            lock.id shouldBe id

            val actualStored =
              Scanamo.get[RowLock](dynamoDbClient)(lockTable.name)('id -> id)
            actualStored.get match {
              case Right(storedRowLock) => storedRowLock.id shouldBe id
              case Left(failed) => fail(s"failed to get rowLocks $failed")
            }
        }
      }
    }
  }

  it("cannot lock a locked thing") {
    withSpecifiedLocalDynamoDbTable(createLockTable) { lockTable =>
      withDynamoRowLockDao(lockTable) { dynamoRowLockDao =>
        val id = Random.nextString(32)
        Scanamo.put[RowLock](dynamoDbClient)(lockTable.name)(
          RowLock(id, contextId, Instant.now, Instant.now.plusSeconds(100)))

        whenReady(dynamoRowLockDao.lockRow(Identifier(id), contextId).failed) {
          secondLockFailure =>
            secondLockFailure shouldBe a[FailedLockException]
        }
      }
    }
  }

  it("can lock a locked thing that has expired") {
    withSpecifiedLocalDynamoDbTable(createLockTable) { lockTable =>
      withDynamoRowLockDao(lockTable) { dynamoRowLockDao =>
        val id = Random.nextString(32)
        whenReady(dynamoRowLockDao.lockRow(Identifier(id), contextId)) {
          firstLock =>
            firstLock.id shouldBe id
        }
{'fraction_non_alphanumeric': 0.09275834011391375, 'fraction_numerical': 0.004475183075671277, 'mean_word_length': 3.3551815766164745, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2503642', 'n_tokens_mistral': 1552, 'n_tokens_neox': 1522, 'n_words': 267}