@Test
  public void shouldThrowException_WhenOperatingWithNoKey() {
    when(coRepository.lock(noKey)).thenReturn(true);
    when(originalRepository.read(noKey)).thenReturn(Item.withNoValue(noKey));
    sut = new CoRepositoryClient(coRepository, originalRepository);

    try {
      when(coRepository.selectAsInt(noKey)).thenReturn(Item.withNoValue(noKey));
      sut.selectAsInt(noKey);
      fail();
    } catch (NonExistentKeyException e) {
    }

    try {
      sut.update(new Item(noKey, "anyValue"));
      fail();
    } catch (NonExistentKeyException e) {
    }

    try {
      sut.increase(noKey);
      fail();
    } catch (NonExistentKeyException e) {
    }

    try {
      sut.decrease(noKey);
      fail();
    } catch (NonExistentKeyException e) {
    }
  }
  @Test
  public void canDecreaseValue() {
    when(originalRepository.read(key)).thenReturn(integerItem);
    sut = new CoRepositoryClient(coRepository, originalRepository, keyUpdateTime, 1);

    sut.decrease(key);

    verify(coRepository).decrease(key);
    verify(keyUpdateTime, times(2)).notifyUpdated(Mockito.eq(key), Mockito.anyLong());
  }
  @Test
  public void canSelectStringValue() {
    when(originalRepository.read(key)).thenReturn(stringItem);
    when(coRepository.selectAsObject(key)).thenReturn(stringItem);
    sut = new CoRepositoryClient(coRepository, originalRepository);

    Item result = sut.selectAsObject(key);

    assertThat(result, is(stringItem));
  }
  @Test
  public void canSelectIntegerValue() {
    when(originalRepository.read(key)).thenReturn(integerItem);
    when(coRepository.selectAsInt(key)).thenReturn(integerItem);
    sut = new CoRepositoryClient(coRepository, originalRepository);

    Item result = sut.selectAsInt(key);

    assertThat(result, is(integerItem));
  }
  void ensurePulled(String key) {
    if (keyUpdateTime.exists(key)) {
      return;
    }

    if (coRepository.exists(key)) {
      return;
    }

    if (coRepository.lock(key) == false) {
      waitUntilInitialValueIsPulled(key);
      return;
    }

    Item item = originalRepository.read(key);
    if (item.isNotFound()) {
      wakeUpAllThreadsWatingForCompletingPull(key);
      throw new NonExistentKeyException(key);
    }

    keyUpdateTime.notifyUpdated(key, System.currentTimeMillis());
    coRepository.insert(item);
    wakeUpAllThreadsWatingForCompletingPull(key);
  }