mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-17 18:51:10 +01:00
Implement reindex mechanism for search (#2104)
Adds a new button to repository settings to allow users to manually delete and re-create search indices. The actual re-indexing is happening in plugins that subscribe to the newly created event. Co-authored-by: Eduard Heimbuch <eduard.heimbuch@cloudogu.com>
This commit is contained in:
committed by
GitHub
parent
e590a3ee68
commit
56ace2811b
2
gradle/changelog/reindex.yaml
Normal file
2
gradle/changelog/reindex.yaml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
- type: added
|
||||||
|
description: Reindex mechanism for search ([#2104](https://github.com/scm-manager/scm-manager/pull/2104))
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.search;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import sonia.scm.event.Event;
|
||||||
|
import sonia.scm.repository.Repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.39.0
|
||||||
|
*/
|
||||||
|
@Event
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public class ReindexRepositoryEvent {
|
||||||
|
private Repository repository;
|
||||||
|
}
|
||||||
@@ -373,3 +373,24 @@ export const useRenameRepository = (repository: Repository) => {
|
|||||||
isRenamed: !!data
|
isRenamed: !!data
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useReindexRepository = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const { mutate, isLoading, error, data } = useMutation<unknown, Error, Repository>(
|
||||||
|
(repository) => {
|
||||||
|
const link = requiredLink(repository, "reindex");
|
||||||
|
return apiClient.post(link);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onSuccess: async (_, repository) => {
|
||||||
|
await queryClient.invalidateQueries(repoQueryKey(repository));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
reindex: (repository: Repository) => mutate(repository),
|
||||||
|
isLoading,
|
||||||
|
error,
|
||||||
|
isRunning: !!data,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@@ -492,6 +492,12 @@
|
|||||||
"descriptionNotRunning": "Starten der Integritätsprüfung dieses Repositories. Dieser Vorgang kann einige Zeit in Anspruch nehmen.",
|
"descriptionNotRunning": "Starten der Integritätsprüfung dieses Repositories. Dieser Vorgang kann einige Zeit in Anspruch nehmen.",
|
||||||
"descriptionRunning": "Die Integritätsprüfung für dieses Repository läuft bereits und kann nicht parallel erneut gestartet werden."
|
"descriptionRunning": "Die Integritätsprüfung für dieses Repository läuft bereits und kann nicht parallel erneut gestartet werden."
|
||||||
},
|
},
|
||||||
|
"reindex": {
|
||||||
|
"button": "Reindizieren",
|
||||||
|
"subtitle": "Suchindizes neu erstellen",
|
||||||
|
"description": "Löscht alle existierenden Suchindizes für dieses Repository and erstellt sie komplett neu. Dieser Vorgang kann einige Zeit in Anspruch nehmen.",
|
||||||
|
"started": "Die Reindizierung wurde erfolgreich gestartet. Dies ist eine asynchrone Operation und kann einige Zeit in Anspruch nehmen."
|
||||||
|
},
|
||||||
"diff": {
|
"diff": {
|
||||||
"jumpToSource": "Zur Quelldatei springen",
|
"jumpToSource": "Zur Quelldatei springen",
|
||||||
"jumpToTarget": "Zur vorherigen Version der Datei springen",
|
"jumpToTarget": "Zur vorherigen Version der Datei springen",
|
||||||
|
|||||||
@@ -481,6 +481,12 @@
|
|||||||
"descriptionNotRunning": "Run the health checks for this repository. This may take a while.",
|
"descriptionNotRunning": "Run the health checks for this repository. This may take a while.",
|
||||||
"descriptionRunning": "Health checks for this repository are currently running and cannot be started again in parallel."
|
"descriptionRunning": "Health checks for this repository are currently running and cannot be started again in parallel."
|
||||||
},
|
},
|
||||||
|
"reindex": {
|
||||||
|
"button": "Reindex",
|
||||||
|
"subtitle": "Recreate Search Indices",
|
||||||
|
"description": "Deletes all existing search indices for this repository and recreates them from scratch. This may take a while.",
|
||||||
|
"started": "Reindexing has been started successfully. This is an asynchronous operation and may take a while."
|
||||||
|
},
|
||||||
"archive": {
|
"archive": {
|
||||||
"tooltip": "Read only. The archive cannot be changed."
|
"tooltip": "Read only. The archive cannot be changed."
|
||||||
},
|
},
|
||||||
|
|||||||
64
scm-ui/ui-webapp/src/repos/components/Reindex.tsx
Normal file
64
scm-ui/ui-webapp/src/repos/components/Reindex.tsx
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Repository } from "@scm-manager/ui-types";
|
||||||
|
import React, { FC } from "react";
|
||||||
|
import { useReindexRepository } from "@scm-manager/ui-api";
|
||||||
|
import { Button, ErrorNotification, Level, Notification, Subtitle } from "@scm-manager/ui-components";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
repository: Repository;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Reindex: FC<Props> = ({ repository }) => {
|
||||||
|
const [t] = useTranslation("repos");
|
||||||
|
const { reindex, error, isLoading, isRunning } = useReindexRepository();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<hr />
|
||||||
|
<ErrorNotification error={error} />
|
||||||
|
{isRunning ? <Notification type="success">{t("reindex.started")}</Notification> : null}
|
||||||
|
<Subtitle>{t("reindex.subtitle")}</Subtitle>
|
||||||
|
<p>{t("reindex.description")}</p>
|
||||||
|
<Level
|
||||||
|
right={
|
||||||
|
<Button
|
||||||
|
color="warning"
|
||||||
|
icon="sync-alt"
|
||||||
|
className="mt-4"
|
||||||
|
action={() => reindex(repository)}
|
||||||
|
disabled={isLoading}
|
||||||
|
loading={isLoading}
|
||||||
|
>
|
||||||
|
{t("reindex.button")}
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Reindex;
|
||||||
@@ -34,6 +34,7 @@ import { useUpdateRepository } from "@scm-manager/ui-api";
|
|||||||
import HealthCheckWarning from "./HealthCheckWarning";
|
import HealthCheckWarning from "./HealthCheckWarning";
|
||||||
import RunHealthCheck from "./RunHealthCheck";
|
import RunHealthCheck from "./RunHealthCheck";
|
||||||
import UpdateNotification from "../../components/UpdateNotification";
|
import UpdateNotification from "../../components/UpdateNotification";
|
||||||
|
import Reindex from "../components/Reindex";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
repository: Repository;
|
repository: Repository;
|
||||||
@@ -71,6 +72,7 @@ const EditRepo: FC<Props> = ({ repository }) => {
|
|||||||
{(repository._links.runHealthCheck || repository.healthCheckRunning) && (
|
{(repository._links.runHealthCheck || repository.healthCheckRunning) && (
|
||||||
<RunHealthCheck repository={repository} />
|
<RunHealthCheck repository={repository} />
|
||||||
)}
|
)}
|
||||||
|
{repository._links.reindex ? <Reindex repository={repository} /> : null}
|
||||||
<RepositoryDangerZone repository={repository} />
|
<RepositoryDangerZone repository={repository} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -30,10 +30,13 @@ import io.swagger.v3.oas.annotations.media.ExampleObject;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import sonia.scm.event.ScmEventBus;
|
||||||
import sonia.scm.repository.HealthCheckService;
|
import sonia.scm.repository.HealthCheckService;
|
||||||
import sonia.scm.repository.NamespaceAndName;
|
import sonia.scm.repository.NamespaceAndName;
|
||||||
import sonia.scm.repository.Repository;
|
import sonia.scm.repository.Repository;
|
||||||
import sonia.scm.repository.RepositoryManager;
|
import sonia.scm.repository.RepositoryManager;
|
||||||
|
import sonia.scm.repository.RepositoryPermissions;
|
||||||
|
import sonia.scm.search.ReindexRepositoryEvent;
|
||||||
import sonia.scm.web.VndMediaType;
|
import sonia.scm.web.VndMediaType;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -294,6 +297,26 @@ public class RepositoryResource {
|
|||||||
healthCheckService.fullCheck(repository);
|
healthCheckService.fullCheck(repository);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("reindex")
|
||||||
|
@Operation(summary = "Manually reindex repository", description = "Asynchronously update search indices for repository", tags = "Repository")
|
||||||
|
@ApiResponse(responseCode = "204", description = "event submitted")
|
||||||
|
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||||
|
@ApiResponse(responseCode = "403", description = "not authorized, the current user does not have owner permissions for this repository")
|
||||||
|
@ApiResponse(
|
||||||
|
responseCode = "404",
|
||||||
|
description = "not found, no repository with the specified namespace and name available",
|
||||||
|
content = @Content(
|
||||||
|
mediaType = VndMediaType.ERROR_TYPE,
|
||||||
|
schema = @Schema(implementation = ErrorDto.class)
|
||||||
|
))
|
||||||
|
@ApiResponse(responseCode = "500", description = "internal server error")
|
||||||
|
public void reindex(@PathParam("namespace") String namespace, @PathParam("name") String name) {
|
||||||
|
Repository repository = loadBy(namespace, name).get();
|
||||||
|
RepositoryPermissions.custom("*", repository).check();
|
||||||
|
ScmEventBus.getInstance().post(new ReindexRepositoryEvent(repository));
|
||||||
|
}
|
||||||
|
|
||||||
private Repository processUpdate(RepositoryDto repositoryDto, Repository existing) {
|
private Repository processUpdate(RepositoryDto repositoryDto, Repository existing) {
|
||||||
Repository changedRepository = dtoToRepositoryMapper.map(repositoryDto, existing.getId());
|
Repository changedRepository = dtoToRepositoryMapper.map(repositoryDto, existing.getId());
|
||||||
changedRepository.setPermissions(existing.getPermissions());
|
changedRepository.setPermissions(existing.getPermissions());
|
||||||
|
|||||||
@@ -111,6 +111,9 @@ public abstract class RepositoryToRepositoryDtoMapper extends BaseMapper<Reposit
|
|||||||
@ObjectFactory
|
@ObjectFactory
|
||||||
RepositoryDto createDto(Repository repository) {
|
RepositoryDto createDto(Repository repository) {
|
||||||
Links.Builder linksBuilder = linkingTo().self(resourceLinks.repository().self(repository.getNamespace(), repository.getName()));
|
Links.Builder linksBuilder = linkingTo().self(resourceLinks.repository().self(repository.getNamespace(), repository.getName()));
|
||||||
|
if (RepositoryPermissions.custom("*", repository).isPermitted()) {
|
||||||
|
linksBuilder.single(link("reindex", resourceLinks.repository().reindex(repository.getNamespace(), repository.getName())));
|
||||||
|
}
|
||||||
if (RepositoryPermissions.delete(repository).isPermitted()) {
|
if (RepositoryPermissions.delete(repository).isPermitted()) {
|
||||||
linksBuilder.single(link("delete", resourceLinks.repository().delete(repository.getNamespace(), repository.getName())));
|
linksBuilder.single(link("delete", resourceLinks.repository().delete(repository.getNamespace(), repository.getName())));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -439,6 +439,10 @@ class ResourceLinks {
|
|||||||
String runHealthCheck(String namespace, String name) {
|
String runHealthCheck(String namespace, String name) {
|
||||||
return repositoryLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("runHealthCheck").parameters().href();
|
return repositoryLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("runHealthCheck").parameters().href();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String reindex(String namespace, String name) {
|
||||||
|
return repositoryLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("reindex").parameters().href();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RepositoryCollectionLinks repositoryCollection() {
|
RepositoryCollectionLinks repositoryCollection() {
|
||||||
|
|||||||
@@ -24,11 +24,13 @@
|
|||||||
|
|
||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import com.github.legman.Subscribe;
|
||||||
import com.github.sdorra.shiro.ShiroRule;
|
import com.github.sdorra.shiro.ShiroRule;
|
||||||
import com.github.sdorra.shiro.SubjectAware;
|
import com.github.sdorra.shiro.SubjectAware;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.io.Resources;
|
import com.google.common.io.Resources;
|
||||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||||
|
import org.apache.shiro.authz.AuthorizationException;
|
||||||
import org.apache.shiro.subject.SimplePrincipalCollection;
|
import org.apache.shiro.subject.SimplePrincipalCollection;
|
||||||
import org.apache.shiro.subject.Subject;
|
import org.apache.shiro.subject.Subject;
|
||||||
import org.jboss.resteasy.mock.MockHttpRequest;
|
import org.jboss.resteasy.mock.MockHttpRequest;
|
||||||
@@ -45,6 +47,7 @@ import org.mockito.junit.MockitoJUnitRunner;
|
|||||||
import sonia.scm.NotFoundException;
|
import sonia.scm.NotFoundException;
|
||||||
import sonia.scm.PageResult;
|
import sonia.scm.PageResult;
|
||||||
import sonia.scm.config.ScmConfiguration;
|
import sonia.scm.config.ScmConfiguration;
|
||||||
|
import sonia.scm.event.ScmEventBus;
|
||||||
import sonia.scm.importexport.ExportFileExtensionResolver;
|
import sonia.scm.importexport.ExportFileExtensionResolver;
|
||||||
import sonia.scm.importexport.ExportNotificationHandler;
|
import sonia.scm.importexport.ExportNotificationHandler;
|
||||||
import sonia.scm.importexport.ExportService;
|
import sonia.scm.importexport.ExportService;
|
||||||
@@ -68,6 +71,7 @@ import sonia.scm.repository.api.BundleCommandBuilder;
|
|||||||
import sonia.scm.repository.api.Command;
|
import sonia.scm.repository.api.Command;
|
||||||
import sonia.scm.repository.api.RepositoryService;
|
import sonia.scm.repository.api.RepositoryService;
|
||||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||||
|
import sonia.scm.search.ReindexRepositoryEvent;
|
||||||
import sonia.scm.search.SearchEngine;
|
import sonia.scm.search.SearchEngine;
|
||||||
import sonia.scm.user.User;
|
import sonia.scm.user.User;
|
||||||
import sonia.scm.web.RestDispatcher;
|
import sonia.scm.web.RestDispatcher;
|
||||||
@@ -97,6 +101,8 @@ import static javax.servlet.http.HttpServletResponse.SC_OK;
|
|||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyMap;
|
import static org.mockito.ArgumentMatchers.anyMap;
|
||||||
@@ -749,6 +755,60 @@ public class RepositoryRootResourceTest extends RepositoryTestBase {
|
|||||||
verify(exportService).getExportInformation(repository);
|
verify(exportService).getExportInformation(repository);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldDispatchReindexEvent() throws URISyntaxException {
|
||||||
|
ReindexTestListener listener = new ReindexTestListener();
|
||||||
|
|
||||||
|
ScmEventBus.getInstance().register(listener);
|
||||||
|
|
||||||
|
Repository repository = createRepository("space", "repo");
|
||||||
|
|
||||||
|
MockHttpRequest request = MockHttpRequest
|
||||||
|
.post("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/reindex");
|
||||||
|
MockHttpResponse response = new MockHttpResponse();
|
||||||
|
|
||||||
|
dispatcher.invoke(request, response);
|
||||||
|
assertNotNull(listener.event);
|
||||||
|
assertEquals(repository, listener.repository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldThrowErrorWhenMissingPermissions() throws URISyntaxException {
|
||||||
|
Subject subject = mock(Subject.class);
|
||||||
|
doThrow(new AuthorizationException()).when(subject).checkPermission("repository:*:space-repo");
|
||||||
|
shiro.setSubject(subject);
|
||||||
|
|
||||||
|
ReindexTestListener listener = new ReindexTestListener();
|
||||||
|
|
||||||
|
ScmEventBus.getInstance().register(listener);
|
||||||
|
|
||||||
|
createRepository("space", "repo");
|
||||||
|
|
||||||
|
MockHttpRequest request = MockHttpRequest
|
||||||
|
.post("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/reindex");
|
||||||
|
MockHttpResponse response = new MockHttpResponse();
|
||||||
|
|
||||||
|
dispatcher.invoke(request, response);
|
||||||
|
|
||||||
|
assertEquals(403, response.getStatus());
|
||||||
|
assertNull(listener.event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ReindexTestListener {
|
||||||
|
|
||||||
|
private ReindexRepositoryEvent event;
|
||||||
|
|
||||||
|
private Repository repository;
|
||||||
|
|
||||||
|
@Subscribe(async = false)
|
||||||
|
public void onEvent(ReindexRepositoryEvent event) {
|
||||||
|
this.repository = event.getRepository();
|
||||||
|
this.event = event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void mockRepositoryHandler(Set<Command> cmds) {
|
private void mockRepositoryHandler(Set<Command> cmds) {
|
||||||
RepositoryHandler repositoryHandler = mock(RepositoryHandler.class);
|
RepositoryHandler repositoryHandler = mock(RepositoryHandler.class);
|
||||||
RepositoryType repositoryType = mock(RepositoryType.class);
|
RepositoryType repositoryType = mock(RepositoryType.class);
|
||||||
|
|||||||
@@ -408,6 +408,23 @@ public class RepositoryToRepositoryDtoMapperTest {
|
|||||||
.isEqualTo("http://example.com/base/v2/search/searchableTypes/testspace/test");
|
.isEqualTo("http://example.com/base/v2/search/searchableTypes/testspace/test");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateReindexLink() {
|
||||||
|
Repository testRepository = createTestRepository();
|
||||||
|
RepositoryDto dto = mapper.map(testRepository);
|
||||||
|
assertThat(dto.getLinks().getLinkBy("reindex"))
|
||||||
|
.get()
|
||||||
|
.hasFieldOrPropertyWithValue("href", "http://example.com/base/v2/repositories/testspace/test/reindex");
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubjectAware(username = "unpriv")
|
||||||
|
@Test
|
||||||
|
public void shouldNotCreateReindexLinkWithoutPermission() {
|
||||||
|
Repository testRepository = createTestRepository();
|
||||||
|
RepositoryDto dto = mapper.map(testRepository);
|
||||||
|
assertThat(dto.getLinks().getLinkBy("reindex")).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
private ScmProtocol mockProtocol(String type, String protocol) {
|
private ScmProtocol mockProtocol(String type, String protocol) {
|
||||||
return new MockScmProtocol(type, protocol);
|
return new MockScmProtocol(type, protocol);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user