private Thread createThread(Runnable runnable, String name) throws InterruptedException {
   Thread thread = new Thread(runnable, name);
   thread.setUncaughtExceptionHandler(
       new Thread.UncaughtExceptionHandler() {
         public void uncaughtException(Thread t, Throwable e) {
           e.printStackTrace();
           throw new RuntimeException(e.getMessage(), e);
         }
       });
   return thread;
 }
 private void run(
     Runnable runnable, int numberOfRequests, final ConcurrentHashMap<String, Boolean> results)
     throws InterruptedException {
   Boolean finalResult = true;
   LOGGER.info("Tests start now!");
   final ArrayList<Thread> threads = new ArrayList<>();
   for (int i = 0; i < numberOfRequests; i++) {
     Thread t = new Thread(runnable, "pipeline" + i);
     threads.add(t);
   }
   for (Thread t : threads) {
     Thread.sleep(1000 * (new Random().nextInt(3) + 1));
     t.setUncaughtExceptionHandler(
         new Thread.UncaughtExceptionHandler() {
           public void uncaughtException(Thread t, Throwable e) {
             LOGGER.error("Exception " + e + " from thread " + t);
             results.put(t.getName(), false);
           }
         });
     t.start();
   }
   for (Thread t : threads) {
     int i = threads.indexOf(t);
     if (i == (numberOfRequests - 1)) {
       //                takeHeapDump(dumpDir, i);
     }
     t.join();
   }
   for (String threadId : results.keySet()) {
     finalResult = results.get(threadId) && finalResult;
   }
   assertThat(finalResult, is(true));
 }
  @Test
  public void shouldNotDeadlockWhenAllPossibleWaysOfUpdatingTheConfigAreBeingUsedAtTheSameTime()
      throws Exception {
    final ArrayList<Thread> configSaveThreads = new ArrayList<>();
    final int pipelineCreatedThroughApiCount = 100;
    final int pipelineCreatedThroughUICount = 100;

    for (int i = 0; i < pipelineCreatedThroughUICount; i++) {
      Thread thread = configSaveThread(i);
      configSaveThreads.add(thread);
    }

    for (int i = 0; i < pipelineCreatedThroughApiCount; i++) {
      Thread thread = pipelineSaveThread(i);
      configSaveThreads.add(thread);
    }

    for (Thread configSaveThread : configSaveThreads) {
      Thread timerThread = null;
      try {
        timerThread =
            createThread(
                new Runnable() {
                  @Override
                  public void run() {
                    try {
                      File configFile = new File(goConfigDao.fileLocation());
                      String currentConfig = FileUtil.readContentFromFile(configFile);
                      String updatedConfig =
                          currentConfig.replaceFirst(
                              "artifactsdir=\".*\"",
                              "artifactsdir=\"" + UUID.randomUUID().toString() + "\"");
                      FileUtil.writeContentToFile(updatedConfig, configFile);
                    } catch (IOException e) {
                      fail("Failed with error: " + e.getMessage());
                    }
                    cachedFileGoConfig.forceReload();
                  }
                },
                "timer-thread");
      } catch (InterruptedException e) {
        fail(e.getMessage());
      }

      try {
        configSaveThread.start();
        timerThread.start();
        configSaveThread.join();
        timerThread.join();
      } catch (InterruptedException e) {
        fail(e.getMessage());
      }
    }
    assertThat(
        goConfigService.getAllPipelineConfigs().size(),
        is(pipelineCreatedThroughApiCount + pipelineCreatedThroughUICount));
  }
  @Test
  public void shouldNotReloadScheduledJobPlansWhenAgentWorkAssignmentIsInProgress()
      throws Exception {
    fixture.createPipelineWithFirstStageScheduled();
    Pipeline pipeline = pipelineDao.mostRecentPipeline(fixture.pipelineName);
    JobInstance job = pipeline.getFirstStage().getJobInstances().first();

    final JobInstanceService mockJobInstanceService = mock(JobInstanceService.class);

    final Pipeline pipeline1 = pipeline;
    final Semaphore sem = new Semaphore(1);
    sem.acquire();
    when(mockJobInstanceService.orderedScheduledBuilds())
        .thenReturn(jobInstanceService.orderedScheduledBuilds());
    when(mockJobInstanceService.buildByIdWithTransitions(job.getId()))
        .thenReturn(jobInstanceService.buildByIdWithTransitions(job.getId()));

    ScheduledPipelineLoader scheduledPipelineLoader =
        new ScheduledPipelineLoader(null, null, null, null, null, null, null, null) {
          @Override
          public Pipeline pipelineWithPasswordAwareBuildCauseByBuildId(long buildId) {
            sem.release();
            sleepQuietly(1000);
            verify(mockJobInstanceService, times(1)).orderedScheduledBuilds();
            return pipeline1;
          }
        };

    final BuildAssignmentService buildAssignmentServiceUnderTest =
        new BuildAssignmentService(
            goConfigService,
            mockJobInstanceService,
            scheduleService,
            agentService,
            environmentConfigService,
            timeProvider,
            transactionTemplate,
            scheduledPipelineLoader,
            pipelineService,
            builderFactory,
            agentRemoteHandler);

    final Throwable[] fromThread = new Throwable[1];
    buildAssignmentServiceUnderTest.onTimer();

    Thread assigner =
        new Thread(
            new Runnable() {
              public void run() {
                try {
                  final AgentConfig agentConfig =
                      AgentMother.localAgentWithResources("some-other-resource");

                  buildAssignmentServiceUnderTest.assignWorkToAgent(agent(agentConfig));
                } catch (Throwable e) {
                  e.printStackTrace();
                  fromThread[0] = e;
                } finally {

                }
              }
            },
            "assignmentThread");
    assigner.start();

    sem.acquire();
    buildAssignmentServiceUnderTest.onTimer();

    assigner.join();
    assertThat(fromThread[0], is(nullValue()));
  }