|
22 | 22 | */
|
23 | 23 | package org.opengrok.web.api.v1.controller;
|
24 | 24 |
|
| 25 | +import static org.junit.Assert.assertEquals; |
| 26 | +import static org.mockito.Mockito.reset; |
| 27 | +import static org.mockito.Mockito.verify; |
| 28 | + |
| 29 | +import java.io.IOException; |
| 30 | +import java.nio.file.Paths; |
| 31 | +import java.util.ArrayList; |
| 32 | +import java.util.List; |
| 33 | +import java.util.Map; |
| 34 | +import java.util.TreeMap; |
| 35 | +import java.util.concurrent.CountDownLatch; |
| 36 | +import javax.servlet.http.HttpServletRequest; |
| 37 | +import javax.ws.rs.client.Entity; |
| 38 | +import javax.ws.rs.core.Application; |
| 39 | +import javax.ws.rs.core.Response; |
| 40 | +import org.apache.commons.io.FileUtils; |
25 | 41 | import org.glassfish.jersey.internal.inject.AbstractBinder;
|
26 | 42 | import org.glassfish.jersey.server.ResourceConfig;
|
27 | 43 | import org.glassfish.jersey.test.JerseyTest;
|
28 | 44 | import org.junit.Assert;
|
| 45 | +import org.junit.Rule; |
29 | 46 | import org.junit.Test;
|
30 | 47 | import org.mockito.Mock;
|
31 | 48 | import org.mockito.MockitoAnnotations;
|
| 49 | +import org.opengrok.indexer.condition.ConditionalRun; |
| 50 | +import org.opengrok.indexer.condition.ConditionalRunRule; |
| 51 | +import org.opengrok.indexer.condition.RepositoryInstalled; |
32 | 52 | import org.opengrok.indexer.configuration.Configuration;
|
| 53 | +import org.opengrok.indexer.configuration.Project; |
33 | 54 | import org.opengrok.indexer.configuration.RuntimeEnvironment;
|
| 55 | +import org.opengrok.indexer.history.HistoryGuru; |
| 56 | +import org.opengrok.indexer.history.RepositoryInfo; |
| 57 | +import org.opengrok.indexer.util.TestRepository; |
34 | 58 | import org.opengrok.indexer.web.DummyHttpServletRequest;
|
35 | 59 | import org.opengrok.indexer.web.PageConfig;
|
36 | 60 | import org.opengrok.web.api.v1.suggester.provider.service.SuggesterService;
|
37 | 61 |
|
38 |
| -import javax.servlet.http.HttpServletRequest; |
39 |
| -import javax.ws.rs.client.Entity; |
40 |
| -import javax.ws.rs.core.Application; |
41 |
| -import javax.ws.rs.core.Response; |
42 |
| - |
43 |
| -import java.util.concurrent.CountDownLatch; |
44 |
| -import java.util.concurrent.ExecutorService; |
45 |
| -import java.util.concurrent.Executors; |
46 |
| -import java.util.concurrent.TimeUnit; |
47 |
| - |
48 |
| -import static org.junit.Assert.assertEquals; |
49 |
| -import static org.mockito.Mockito.reset; |
50 |
| -import static org.mockito.Mockito.verify; |
51 |
| - |
52 | 62 | public class ConfigurationControllerTest extends JerseyTest {
|
53 | 63 |
|
54 | 64 | private RuntimeEnvironment env = RuntimeEnvironment.getInstance();
|
@@ -291,4 +301,83 @@ public void run() {
|
291 | 301 | // Revert the value back to the default.
|
292 | 302 | env.setHitsPerPage(origValue);
|
293 | 303 | }
|
| 304 | + |
| 305 | + @Rule |
| 306 | + public ConditionalRunRule rule = new ConditionalRunRule(); |
| 307 | + |
| 308 | + @Test |
| 309 | + @ConditionalRun(RepositoryInstalled.GitInstalled.class) |
| 310 | + public void testConcurrentConfigurationReloads() throws InterruptedException, IOException { |
| 311 | + final String origSourceRootPath = env.getSourceRootPath(); |
| 312 | + final String origDataRootPath = env.getDataRootPath(); |
| 313 | + final Map<String, Project> origProjects = env.getProjects(); |
| 314 | + final List<RepositoryInfo> origRepositories = env.getRepositories(); |
| 315 | + |
| 316 | + final int nThreads = Math.max(40, Runtime.getRuntime().availableProcessors() * 2); |
| 317 | + final int nProjects = 20; |
| 318 | + |
| 319 | + // prepare test repository |
| 320 | + TestRepository repository = new TestRepository(); |
| 321 | + repository.create(HistoryGuru.class.getResourceAsStream("repositories.zip")); |
| 322 | + |
| 323 | + env.setSourceRoot(repository.getSourceRoot()); |
| 324 | + env.setDataRoot(repository.getDataRoot()); |
| 325 | + |
| 326 | + final CountDownLatch latch = new CountDownLatch(nThreads); |
| 327 | + |
| 328 | + List<RepositoryInfo> repositoryInfos = new ArrayList<>(); |
| 329 | + Map<String, Project> projects = new TreeMap<>(); |
| 330 | + |
| 331 | + /* |
| 332 | + * Prepare nProjects git repositories, named project-{i} in the test repositories directory. |
| 333 | + */ |
| 334 | + for (int i = 0; i < nProjects; i++) { |
| 335 | + Project project = new Project(); |
| 336 | + project.setName("project-" + i); |
| 337 | + project.setPath("/project-" + i); |
| 338 | + RepositoryInfo repo = new RepositoryInfo(); |
| 339 | + repo.setDirectoryNameRelative("/project-" + i); |
| 340 | + |
| 341 | + projects.put("project-" + i, project); |
| 342 | + repositoryInfos.add(repo); |
| 343 | + |
| 344 | + // create the repository |
| 345 | + FileUtils.copyDirectory( |
| 346 | + Paths.get(repository.getSourceRoot(), "git").toFile(), |
| 347 | + Paths.get(repository.getSourceRoot(), "project-" + i).toFile() |
| 348 | + ); |
| 349 | + } |
| 350 | + |
| 351 | + env.setRepositories(repositoryInfos); |
| 352 | + env.setProjects(projects); |
| 353 | + |
| 354 | + /* |
| 355 | + * Now run setting a value in parallel, which triggers configuration reload. |
| 356 | + */ |
| 357 | + for (int i = 0; i < nThreads; i++) { |
| 358 | + new Thread(() -> { |
| 359 | + Response put = target("configuration") |
| 360 | + .path("projectsEnabled") |
| 361 | + .request() |
| 362 | + .put(Entity.text("true")); |
| 363 | + Assert.assertEquals(204, put.getStatus()); |
| 364 | + latch.countDown(); |
| 365 | + }).start(); |
| 366 | + } |
| 367 | + |
| 368 | + latch.await(); |
| 369 | + |
| 370 | + Assert.assertEquals(nProjects, env.getProjects().size()); |
| 371 | + Assert.assertEquals(nProjects, env.getProjectRepositoriesMap().size()); |
| 372 | + env.getProjectRepositoriesMap().forEach((project, repositories) -> { |
| 373 | + Assert.assertEquals(1, repositories.size()); |
| 374 | + }); |
| 375 | + |
| 376 | + repository.destroy(); |
| 377 | + |
| 378 | + env.setProjects(origProjects); |
| 379 | + env.setRepositories(origRepositories); |
| 380 | + env.setSourceRoot(origSourceRootPath); |
| 381 | + env.setDataRoot(origDataRootPath); |
| 382 | + } |
294 | 383 | }
|
0 commit comments