HostedDockerInstance extends DockerInstance { @Override protected void commitContainer(String repository, String tag) throws IOException { final Semaphore nodeSemaphore = getSemaphore(getNode().getHost()); try { nodeSemaphore.acquire(); super.commitContainer(repository, tag); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new IOException(e.getLocalizedMessage(), e); } finally { nodeSemaphore.release(); } } @Inject  HostedDockerInstance(
      DockerConnectorProvider dockerConnectorProvider,
      @Named("che.docker.registry") String registry,
      @Named("che.docker.namespace") @Nullable String registryNamespace,
      DockerMachineFactory dockerMachineFactory,
      @Assisted Machine machine,
      @Assisted("container") String container,
      @Assisted("image") String image,
      @Assisted DockerNode node,
      @Assisted LineConsumer outputConsumer,
      DockerInstanceStopDetector dockerInstanceStopDetector,
      DockerInstanceProcessesCleaner processesCleaner,
      @Named("che.docker.registry_for_snapshots") boolean snapshotUseRegistry,
      @Named("che.docker.concurrent_commits_on_node") int concurrentCommits);   }
@Test public void shouldBeAbleToCommitSimultaneously() throws Exception { String repo1 = "repo1"; String repo2 = "repo2"; String repo3 = "repo3"; WaitingAnswer<Void> waitingAnswer1 = new WaitingAnswer<>(); WaitingAnswer<Void> waitingAnswer2 = new WaitingAnswer<>(); doAnswer(waitingAnswer1) .when(dockerConnectorMock) .commit(argThat(new CommitParamsMatcher(repo1))); doAnswer(waitingAnswer2) .when(dockerConnectorMock) .commit(argThat(new CommitParamsMatcher(repo2))); executor.execute(() -> performCommit(repo1, TAG)); executor.execute(() -> performCommit(repo2, TAG)); waitingAnswer1.waitAnswerCall(1, TimeUnit.SECONDS); waitingAnswer2.waitAnswerCall(1, TimeUnit.SECONDS); executor.execute(() -> performCommit(repo3, TAG)); Thread.sleep(200); verify(dockerInstance).commitContainer(eq(repo3), eq(TAG)); verify(dockerConnectorMock, never()).commit(argThat(new CommitParamsMatcher(repo3))); waitingAnswer1.completeAnswer(); waitingAnswer2.completeAnswer(); awaitFinalization(); verify(dockerConnectorMock).commit(argThat(new CommitParamsMatcher(repo1))); verify(dockerConnectorMock).commit(argThat(new CommitParamsMatcher(repo2))); verify(dockerConnectorMock).commit(argThat(new CommitParamsMatcher(repo3))); }
@Test public void shouldBeAbleToCommitSimultaneouslyOnDifferentNodes() throws Exception { String repo1 = "repo1"; String repo2 = "repo2"; String repo3 = "repo3"; WaitingAnswer<Void> waitingAnswer1 = new WaitingAnswer<>(); WaitingAnswer<Void> waitingAnswer2 = new WaitingAnswer<>(); doAnswer(waitingAnswer1) .when(dockerConnectorMock) .commit(argThat(new CommitParamsMatcher(repo1))); doAnswer(waitingAnswer2) .when(dockerConnectorMock) .commit(argThat(new CommitParamsMatcher(repo2))); executor.execute(() -> performCommit(repo1, TAG)); executor.execute(() -> performCommit(repo2, TAG)); waitingAnswer1.waitAnswerCall(1, TimeUnit.SECONDS); waitingAnswer2.waitAnswerCall(1, TimeUnit.SECONDS); when(dockerNode.getHost()).thenReturn("host2"); executor.execute(() -> performCommit(repo3, TAG)); verify(dockerInstance, timeout(2000)).commitContainer(eq(repo3), eq(TAG)); ArgumentCaptor<CommitParams> paramsCaptor = ArgumentCaptor.forClass(CommitParams.class); verify(dockerConnectorMock, atLeastOnce()).commit(paramsCaptor.capture()); assertEquals(paramsCaptor.getValue().getRepository(), repo3); waitingAnswer1.completeAnswer(); waitingAnswer2.completeAnswer(); awaitFinalization(); }