@Test
  public void testAllUpdatesReflectedToMapStore() throws Exception {
    int nodeCount = 3;
    final MapStoreWithCounter mapStore = new MapStoreWithCounter<Integer, String>();
    TestMapUsingMapStoreBuilder builder =
        TestMapUsingMapStoreBuilder.create()
            .withMapStore(mapStore)
            .withNodeCount(nodeCount)
            .withNodeFactory(createHazelcastInstanceFactory(nodeCount))
            .withBackupCount(0)
            .withWriteCoalescing(false)
            .withWriteDelaySeconds(3);
    IMap<Object, Object> map = builder.build();

    for (int i = 0; i < 500; i++) {
      map.put(i, randomString());
    }

    for (int i = 0; i < 500; i++) {
      map.remove(i);
    }

    assertTrueEventually(
        new AssertTask() {
          @Override
          public void run() throws Exception {
            final int storeCount = mapStore.countStore.get();
            final int deleteCount = mapStore.countDelete.get();

            assertEquals(1000, storeCount + deleteCount);
            assertTrue(mapStore.store.isEmpty());
          }
        });
  }
  @Test
  @Category(SlowTest.class)
  public void testPutTransientDoesNotStoreEntry_onPromotedReplica() {
    String mapName = randomMapName();
    final MapStoreWithCounter mapStore = new MapStoreWithCounter<Integer, String>();
    TestMapUsingMapStoreBuilder<String, Object> storeBuilder = TestMapUsingMapStoreBuilder.create();
    TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(2);
    final IMap<String, Object> map =
        storeBuilder
            .mapName(mapName)
            .withMapStore(mapStore)
            .withNodeCount(2)
            .withNodeFactory(factory)
            .withWriteDelaySeconds(5)
            .withBackupCount(1)
            .withPartitionCount(1)
            .withBackupProcessingDelay(1)
            .build();

    String key = UUID.randomUUID().toString();

    map.putTransient(key, 1, 1, TimeUnit.DAYS);

    killKeyOwner(key, storeBuilder);

    sleepSeconds(10);

    assertEquals(
        "There should not be any store operation on promoted replica",
        0,
        mapStore.countStore.get());
  }
  @Test(expected = ReachedMaxSizeException.class)
  public void testCounter_whenMaxCapacityExceeded() throws Exception {
    final int maxCapacityPerNode = 100;
    final int nodeCount = 1;
    final MapStoreWithCounter mapStore = new MapStoreWithCounter<Integer, String>();
    final TestMapUsingMapStoreBuilder builder =
        TestMapUsingMapStoreBuilder.create()
            .withMapStore(mapStore)
            .withNodeCount(nodeCount)
            .withNodeFactory(createHazelcastInstanceFactory(1))
            .withBackupCount(0)
            .withWriteCoalescing(false)
            .withWriteBehindQueueCapacity(maxCapacityPerNode)
            .withWriteDelaySeconds(100);
    final IMap<Object, Object> map = builder.build();

    // exceed max write-behind queue capacity per node.
    populateMap(map, 2 * maxCapacityPerNode);
  }
  @Test
  public void testCounter_against_one_node_zero_backup() throws Exception {
    final int maxCapacityPerNode = 100;
    final MapStoreWithCounter mapStore = new MapStoreWithCounter<Integer, String>();
    final TestMapUsingMapStoreBuilder builder =
        TestMapUsingMapStoreBuilder.create()
            .withMapStore(mapStore)
            .withNodeCount(1)
            .withNodeFactory(createHazelcastInstanceFactory(1))
            .withBackupCount(0)
            .withWriteDelaySeconds(100)
            .withWriteCoalescing(false)
            .withWriteBehindQueueCapacity(maxCapacityPerNode);

    final IMap<Object, Object> map = builder.build();
    populateMap(map, maxCapacityPerNode);

    assertEquals(maxCapacityPerNode, map.size());
  }
  @Test
  public void testCounter_against_many_nodes() throws Exception {
    final int maxCapacityPerNode = 100;
    final int nodeCount = 2;
    final MapStoreWithCounter mapStore = new MapStoreWithCounter<Integer, String>();
    final TestMapUsingMapStoreBuilder builder =
        TestMapUsingMapStoreBuilder.create()
            .withMapStore(mapStore)
            .withNodeCount(nodeCount)
            .withNodeFactory(createHazelcastInstanceFactory(nodeCount))
            .withBackupCount(0)
            .withWriteCoalescing(false)
            .withWriteBehindQueueCapacity(maxCapacityPerNode)
            .withWriteDelaySeconds(100);
    final IMap<Object, Object> map = builder.build();
    // put slightly more number of entries which is higher than max write-behind queue capacity per
    // node.
    populateMap(map, maxCapacityPerNode + 3);

    assertTrue(map.size() > maxCapacityPerNode);
  }
  @Test
  public void testPutTransientDoesNotStoreEntry_onBackupPartition() {
    String mapName = randomMapName();
    final MapStoreWithCounter mapStore = new MapStoreWithCounter<Integer, String>();
    TestMapUsingMapStoreBuilder<Object, Object> storeBuilder = TestMapUsingMapStoreBuilder.create();
    final IMap<Object, Object> map =
        storeBuilder
            .mapName(mapName)
            .withMapStore(mapStore)
            .withNodeCount(2)
            .withNodeFactory(createHazelcastInstanceFactory(2))
            .withWriteDelaySeconds(1)
            .withBackupCount(1)
            .withPartitionCount(1)
            .withBackupProcessingDelay(1)
            .build();

    map.putTransient(1, 1, 1, TimeUnit.DAYS);

    sleepSeconds(5);

    assertEquals("There should not be any store operation", 0, mapStore.countStore.get());
  }
  /**
   * {@link com.hazelcast.map.impl.mapstore.writebehind.StoreWorker} delays processing of
   * write-behind queues (wbq) by adding delay with {@link
   * com.hazelcast.instance.GroupProperty#MAP_REPLICA_SCHEDULED_TASK_DELAY_SECONDS} property. This
   * is used to provide some extra robustness against node disaster scenarios by trying to prevent
   * lost of entries in wbq-s. Normally backup nodes don't store entries only remove them from
   * wbq-s. Here, we are testing removal of entries occurred or not.
   */
  @Test
  public void testBackupRemovesEntries_afterProcessingDelay() throws Exception {
    final int numberOfItems = 10;
    final String mapName = randomMapName();
    final MapStoreWithCounter mapStore = new MapStoreWithCounter<Integer, String>();
    TestMapUsingMapStoreBuilder<Object, Object> storeBuilder = TestMapUsingMapStoreBuilder.create();
    final IMap<Object, Object> map =
        storeBuilder
            .mapName(mapName)
            .withMapStore(mapStore)
            .withNodeCount(2)
            .withNodeFactory(createHazelcastInstanceFactory(2))
            .withWriteDelaySeconds(1)
            .withBackupCount(1)
            .withPartitionCount(1)
            .withBackupProcessingDelay(1)
            .build();

    populateMap(map, numberOfItems);

    assertWriteBehindQueuesEmptyOnOwnerAndOnBackups(
        mapName, numberOfItems, mapStore, storeBuilder.getNodes());
  }
 private void killKeyOwner(String key, TestMapUsingMapStoreBuilder<String, Object> storeBuilder) {
   HazelcastInstance[] nodes = storeBuilder.getNodes();
   HazelcastInstance ownerNode = getOwnerNode(key, nodes);
   ownerNode.shutdown();
 }