@Test
  public void checkpointRestoreWithPendingWindowSliding() {
    final ScheduledExecutorService timerService = Executors.newSingleThreadScheduledExecutor();
    try {
      final int factor = 4;
      final int windowSlide = 50;
      final int windowSize = factor * windowSlide;

      final CollectingOutput<Integer> out = new CollectingOutput<>(windowSlide);
      final Object lock = new Object();
      final StreamTask<?, ?> mockTask = createMockTaskWithTimer(timerService, lock);

      // sliding window (200 msecs) every 50 msecs
      AccumulatingProcessingTimeWindowOperator<Integer, Integer, Integer> op =
          new AccumulatingProcessingTimeWindowOperator<>(
              validatingIdentityFunction,
              identitySelector,
              IntSerializer.INSTANCE,
              IntSerializer.INSTANCE,
              windowSize,
              windowSlide);

      op.setup(mockTask, new StreamConfig(new Configuration()), out);
      op.open();

      // inject some elements
      final int numElements = 1000;
      final int numElementsFirst = 700;

      for (int i = 0; i < numElementsFirst; i++) {
        synchronized (lock) {
          op.processElement(new StreamRecord<Integer>(i));
        }
        Thread.sleep(1);
      }

      // draw a snapshot
      StreamTaskState state;
      List<Integer> resultAtSnapshot;
      synchronized (lock) {
        int beforeSnapShot = out.getElements().size();
        state = op.snapshotOperatorState(1L, System.currentTimeMillis());
        resultAtSnapshot = new ArrayList<>(out.getElements());
        int afterSnapShot = out.getElements().size();
        assertEquals(
            "operator performed computation during snapshot", beforeSnapShot, afterSnapShot);
      }

      assertTrue(resultAtSnapshot.size() <= factor * numElementsFirst);

      // inject the remaining elements - these should not influence the snapshot
      for (int i = numElementsFirst; i < numElements; i++) {
        synchronized (lock) {
          op.processElement(new StreamRecord<Integer>(i));
        }
        Thread.sleep(1);
      }

      op.dispose();

      // re-create the operator and restore the state
      final CollectingOutput<Integer> out2 = new CollectingOutput<>(windowSlide);
      op =
          new AccumulatingProcessingTimeWindowOperator<>(
              validatingIdentityFunction,
              identitySelector,
              IntSerializer.INSTANCE,
              IntSerializer.INSTANCE,
              windowSize,
              windowSlide);

      op.setup(mockTask, new StreamConfig(new Configuration()), out2);
      op.restoreState(state, 1);
      op.open();

      // inject again the remaining elements
      for (int i = numElementsFirst; i < numElements; i++) {
        synchronized (lock) {
          op.processElement(new StreamRecord<Integer>(i));
        }
        Thread.sleep(1);
      }

      // for a deterministic result, we need to wait until all pending triggers
      // have fired and emitted their results
      long deadline = System.currentTimeMillis() + 120000;
      do {
        Thread.sleep(20);
      } while (resultAtSnapshot.size() + out2.getElements().size() < factor * numElements
          && System.currentTimeMillis() < deadline);

      synchronized (lock) {
        op.close();
      }
      op.dispose();

      // get and verify the result
      List<Integer> finalResult = new ArrayList<>(resultAtSnapshot);
      finalResult.addAll(out2.getElements());
      assertEquals(factor * numElements, finalResult.size());

      Collections.sort(finalResult);
      for (int i = 0; i < factor * numElements; i++) {
        assertEquals(i / factor, finalResult.get(i).intValue());
      }
    } catch (Exception e) {
      e.printStackTrace();
      fail(e.getMessage());
    } finally {
      timerService.shutdown();
    }
  }
  @Test
  public void checkpointRestoreWithPendingWindowTumbling() {
    final ScheduledExecutorService timerService = Executors.newSingleThreadScheduledExecutor();
    try {
      final int windowSize = 200;
      final CollectingOutput<Integer> out = new CollectingOutput<>(windowSize);
      final Object lock = new Object();
      final StreamTask<?, ?> mockTask = createMockTaskWithTimer(timerService, lock);

      // tumbling window that triggers every 50 milliseconds
      AccumulatingProcessingTimeWindowOperator<Integer, Integer, Integer> op =
          new AccumulatingProcessingTimeWindowOperator<>(
              validatingIdentityFunction,
              identitySelector,
              IntSerializer.INSTANCE,
              IntSerializer.INSTANCE,
              windowSize,
              windowSize);

      op.setup(mockTask, new StreamConfig(new Configuration()), out);
      op.open();

      // inject some elements
      final int numElementsFirst = 700;
      final int numElements = 1000;
      for (int i = 0; i < numElementsFirst; i++) {
        synchronized (lock) {
          op.processElement(new StreamRecord<Integer>(i));
        }
        Thread.sleep(1);
      }

      // draw a snapshot and dispose the window
      StreamTaskState state;
      List<Integer> resultAtSnapshot;
      synchronized (lock) {
        int beforeSnapShot = out.getElements().size();
        state = op.snapshotOperatorState(1L, System.currentTimeMillis());
        resultAtSnapshot = new ArrayList<>(out.getElements());
        int afterSnapShot = out.getElements().size();
        assertEquals(
            "operator performed computation during snapshot", beforeSnapShot, afterSnapShot);
        assertTrue(afterSnapShot <= numElementsFirst);
      }

      // inject some random elements, which should not show up in the state
      for (int i = 0; i < 300; i++) {
        synchronized (lock) {
          op.processElement(new StreamRecord<Integer>(i + numElementsFirst));
        }
        Thread.sleep(1);
      }

      op.dispose();

      // re-create the operator and restore the state
      final CollectingOutput<Integer> out2 = new CollectingOutput<>(windowSize);
      op =
          new AccumulatingProcessingTimeWindowOperator<>(
              validatingIdentityFunction,
              identitySelector,
              IntSerializer.INSTANCE,
              IntSerializer.INSTANCE,
              windowSize,
              windowSize);

      op.setup(mockTask, new StreamConfig(new Configuration()), out2);
      op.restoreState(state, 1);
      op.open();

      // inject some more elements
      for (int i = numElementsFirst; i < numElements; i++) {
        synchronized (lock) {
          op.processElement(new StreamRecord<Integer>(i));
        }
        Thread.sleep(1);
      }

      synchronized (lock) {
        op.close();
      }
      op.dispose();

      // get and verify the result
      List<Integer> finalResult = new ArrayList<>(resultAtSnapshot);
      finalResult.addAll(out2.getElements());
      assertEquals(numElements, finalResult.size());

      Collections.sort(finalResult);
      for (int i = 0; i < numElements; i++) {
        assertEquals(i, finalResult.get(i).intValue());
      }
    } catch (Exception e) {
      e.printStackTrace();
      fail(e.getMessage());
    } finally {
      timerService.shutdown();
    }
  }