mirror of https://github.com/halo-dev/halo
Add update and delete handlers for Extensions (#2172)
parent
b9e5ed2f4c
commit
d556787b3a
|
@ -2,8 +2,12 @@ package run.halo.app.extension;
|
|||
|
||||
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.reactive.function.server.HandlerFunction;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
|
@ -28,11 +32,15 @@ public class ExtensionRouterFunctionFactory {
|
|||
var getHandler = new ExtensionGetHandler(scheme, client);
|
||||
var listHandler = new ExtensionListHandler(scheme, client);
|
||||
var createHandler = new ExtensionCreateHandler(scheme, client);
|
||||
var updateHandler = new ExtensionUpdateHandler(scheme, client);
|
||||
var deleteHandler = new ExtensionDeleteHandler(scheme, client);
|
||||
// TODO More handlers here
|
||||
return route()
|
||||
.GET(getHandler.pathPattern(), getHandler)
|
||||
.GET(listHandler.pathPattern(), listHandler)
|
||||
.POST(createHandler.pathPattern(), createHandler)
|
||||
.PUT(updateHandler.pathPattern(), updateHandler)
|
||||
.DELETE(deleteHandler.pathPattern(), deleteHandler)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -65,6 +73,14 @@ public class ExtensionRouterFunctionFactory {
|
|||
|
||||
}
|
||||
|
||||
interface UpdateHandler extends HandlerFunction<ServerResponse>, PathPatternGenerator {
|
||||
|
||||
}
|
||||
|
||||
interface DeleteHandler extends HandlerFunction<ServerResponse>, PathPatternGenerator {
|
||||
|
||||
}
|
||||
|
||||
static class ExtensionCreateHandler implements CreateHandler {
|
||||
|
||||
private final Scheme scheme;
|
||||
|
@ -82,16 +98,17 @@ public class ExtensionRouterFunctionFactory {
|
|||
return request.bodyToMono(Unstructured.class)
|
||||
.switchIfEmpty(Mono.error(() -> new ExtensionConvertException(
|
||||
"Cannot read body to " + scheme.groupVersionKind())))
|
||||
.doOnSuccess(client::create)
|
||||
.map(unstructured ->
|
||||
client.fetch(scheme.type(), unstructured.getMetadata().getName())
|
||||
.flatMap(extToCreate -> Mono.fromCallable(() -> {
|
||||
var name = extToCreate.getMetadata().getName();
|
||||
client.create(extToCreate);
|
||||
return client.fetch(scheme.type(), name)
|
||||
.orElseThrow(() -> new ExtensionNotFoundException(
|
||||
scheme.groupVersionKind() + " " + unstructured.getMetadata().getName()
|
||||
+ "was not found")))
|
||||
.flatMap(extension -> ServerResponse
|
||||
.ok()
|
||||
"Extension with name " + name + " was not found"));
|
||||
}))
|
||||
.flatMap(createdExt -> ServerResponse
|
||||
.created(URI.create(pathPattern() + "/" + createdExt.getMetadata().getName()))
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(extension))
|
||||
.bodyValue(createdExt))
|
||||
.cast(ServerResponse.class);
|
||||
}
|
||||
|
||||
|
@ -159,4 +176,81 @@ public class ExtensionRouterFunctionFactory {
|
|||
}
|
||||
}
|
||||
|
||||
static class ExtensionUpdateHandler implements UpdateHandler {
|
||||
|
||||
private final Scheme scheme;
|
||||
|
||||
private final ExtensionClient client;
|
||||
|
||||
ExtensionUpdateHandler(Scheme scheme, ExtensionClient client) {
|
||||
this.scheme = scheme;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ServerResponse> handle(ServerRequest request) {
|
||||
String name = request.pathVariable("name");
|
||||
return request.bodyToMono(Unstructured.class)
|
||||
.filter(unstructured -> unstructured.getMetadata() != null
|
||||
&& StringUtils.hasText(unstructured.getMetadata().getName())
|
||||
&& Objects.equals(unstructured.getMetadata().getName(), name))
|
||||
.switchIfEmpty(Mono.error(() -> new ExtensionConvertException(
|
||||
"Cannot read body to " + scheme.groupVersionKind())))
|
||||
.flatMap(extToUpdate -> Mono.fromCallable(() -> {
|
||||
client.update(extToUpdate);
|
||||
return client.fetch(scheme.type(), name)
|
||||
.orElseThrow(() -> new ExtensionNotFoundException(
|
||||
"Extension with name " + name + " was not found"));
|
||||
}))
|
||||
.flatMap(updated -> ServerResponse
|
||||
.ok()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(updated));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String pathPattern() {
|
||||
return PathPatternGenerator.buildExtensionPathPattern(scheme) + "/{name}";
|
||||
}
|
||||
}
|
||||
|
||||
static class ExtensionDeleteHandler implements DeleteHandler {
|
||||
|
||||
private final Scheme scheme;
|
||||
|
||||
private final ExtensionClient client;
|
||||
|
||||
ExtensionDeleteHandler(Scheme scheme, ExtensionClient client) {
|
||||
this.scheme = scheme;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ServerResponse> handle(ServerRequest request) {
|
||||
String name = request.pathVariable("name");
|
||||
return getExtension(name)
|
||||
.flatMap(extension ->
|
||||
Mono.fromRunnable(() -> {
|
||||
extension.getMetadata().setDeletionTimestamp(Instant.now());
|
||||
client.update(extension);
|
||||
}).thenReturn(extension))
|
||||
.flatMap(extension -> this.getExtension(name))
|
||||
.flatMap(extension -> ServerResponse
|
||||
.ok()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(extension));
|
||||
}
|
||||
|
||||
private Mono<? extends Extension> getExtension(String name) {
|
||||
return Mono.justOrEmpty(client.fetch(scheme.type(), name))
|
||||
.switchIfEmpty(Mono.error(() -> new ExtensionNotFoundException(
|
||||
"Extension with name " + name + " was not found")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String pathPattern() {
|
||||
return PathPatternGenerator.buildExtensionPathPattern(scheme) + "/{name}";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,30 @@
|
|||
package run.halo.app.config;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
|
||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import run.halo.app.core.extension.Role;
|
||||
import run.halo.app.core.extension.service.RoleService;
|
||||
import run.halo.app.extension.ExtensionClient;
|
||||
import run.halo.app.extension.FakeExtension;
|
||||
import run.halo.app.extension.Metadata;
|
||||
import run.halo.app.extension.Scheme;
|
||||
|
@ -27,7 +32,6 @@ import run.halo.app.extension.SchemeManager;
|
|||
|
||||
@SpringBootTest
|
||||
@AutoConfigureWebTestClient
|
||||
@AutoConfigureTestDatabase
|
||||
class ExtensionConfigurationTest {
|
||||
|
||||
@Autowired
|
||||
|
@ -50,17 +54,18 @@ class ExtensionConfigurationTest {
|
|||
var role = new Role();
|
||||
role.setRules(List.of(rule));
|
||||
when(roleService.getRole(anyString())).thenReturn(role);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void cleanUp() {
|
||||
schemeManager.fetch(Scheme.buildFromType(FakeExtension.class).groupVersionKind())
|
||||
.ifPresent(schemeManager::unregister);
|
||||
// register scheme
|
||||
schemeManager.register(FakeExtension.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void shouldReturnNotFoundWhenSchemeNotRegistered() {
|
||||
// unregister the Extension if necessary
|
||||
schemeManager.fetch(Scheme.buildFromType(FakeExtension.class).groupVersionKind())
|
||||
.ifPresent(schemeManager::unregister);
|
||||
|
||||
webClient.get()
|
||||
.uri("/apis/fake.halo.run/v1alpha1/fakes")
|
||||
.exchange()
|
||||
|
@ -76,71 +81,158 @@ class ExtensionConfigurationTest {
|
|||
.bodyValue(new FakeExtension())
|
||||
.exchange()
|
||||
.expectStatus().isNotFound();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void shouldListExtensionsWhenSchemeRegistered() {
|
||||
schemeManager.register(FakeExtension.class);
|
||||
|
||||
webClient.get()
|
||||
.uri("/apis/fake.halo.run/v1alpha1/fakes")
|
||||
webClient.put()
|
||||
.uri("/apis/fake.halo.run/v1alpha1/fakes/my-fake")
|
||||
.bodyValue(new FakeExtension())
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
}
|
||||
.expectStatus().isNotFound();
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
@DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD)
|
||||
void shouldCreateExtensionWhenSchemeRegistered() {
|
||||
schemeManager.register(FakeExtension.class);
|
||||
|
||||
getCreateExtensionResponse()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(FakeExtension.class)
|
||||
.consumeWith(result -> {
|
||||
var gotFake = result.getResponseBody();
|
||||
assertNotNull(gotFake);
|
||||
assertEquals("my-fake", gotFake.getMetadata().getName());
|
||||
assertNotNull(gotFake.getMetadata().getVersion());
|
||||
assertNotNull(gotFake.getMetadata().getCreationTimestamp());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
@DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD)
|
||||
void shouldGetExtensionWhenSchemeRegistered() {
|
||||
schemeManager.register(FakeExtension.class);
|
||||
|
||||
// create the Extension
|
||||
getCreateExtensionResponse().expectStatus().isOk();
|
||||
|
||||
webClient.get()
|
||||
webClient.delete()
|
||||
.uri("/apis/fake.halo.run/v1alpha1/fakes/my-fake")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(FakeExtension.class)
|
||||
.consumeWith(result -> {
|
||||
var gotFake = result.getResponseBody();
|
||||
assertNotNull(gotFake);
|
||||
assertEquals("my-fake", gotFake.getMetadata().getName());
|
||||
assertNotNull(gotFake.getMetadata().getVersion());
|
||||
assertNotNull(gotFake.getMetadata().getCreationTimestamp());
|
||||
});
|
||||
.expectStatus().isNotFound();
|
||||
}
|
||||
|
||||
WebTestClient.ResponseSpec getCreateExtensionResponse() {
|
||||
var metadata = new Metadata();
|
||||
metadata.setName("my-fake");
|
||||
var fake = new FakeExtension();
|
||||
fake.setMetadata(metadata);
|
||||
@Nested
|
||||
@DisplayName("After creating extension")
|
||||
class AfterCreatingExtension {
|
||||
|
||||
@Autowired
|
||||
ExtensionClient extClient;
|
||||
|
||||
FakeExtension createdFake;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
|
||||
var metadata = new Metadata();
|
||||
metadata.setName("my-fake");
|
||||
var fake = new FakeExtension();
|
||||
fake.setMetadata(metadata);
|
||||
|
||||
createdFake = webClient.post()
|
||||
.uri("/apis/fake.halo.run/v1alpha1/fakes")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(fake)
|
||||
.exchange()
|
||||
.expectStatus().isCreated()
|
||||
.expectHeader().location("/apis/fake.halo.run/v1alpha1/fakes/my-fake")
|
||||
.expectBody(FakeExtension.class)
|
||||
.consumeWith(result -> {
|
||||
var gotFake = result.getResponseBody();
|
||||
assertNotNull(gotFake);
|
||||
assertEquals("my-fake", gotFake.getMetadata().getName());
|
||||
assertNotNull(gotFake.getMetadata().getVersion());
|
||||
assertNotNull(gotFake.getMetadata().getCreationTimestamp());
|
||||
})
|
||||
.returnResult()
|
||||
.getResponseBody();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void cleanUp() {
|
||||
FakeExtension fakeToDelete = getFakeExtension(createdFake.getMetadata().getName());
|
||||
extClient.delete(fakeToDelete);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void shouldDeleteExtensionWhenSchemeRegistered() {
|
||||
webClient.delete()
|
||||
.uri("/apis/fake.halo.run/v1alpha1/fakes/{name}",
|
||||
createdFake.getMetadata().getName())
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType(MediaType.APPLICATION_JSON)
|
||||
.expectBody(FakeExtension.class)
|
||||
.consumeWith(result -> {
|
||||
var deletedFake = result.getResponseBody();
|
||||
assertNotNull(deletedFake);
|
||||
assertNotNull(deletedFake.getMetadata().getDeletionTimestamp());
|
||||
assertTrue(deletedFake.getMetadata().getDeletionTimestamp()
|
||||
.isBefore(Instant.now()));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void shouldListExtensionsWhenSchemeRegistered() {
|
||||
webClient.get()
|
||||
.uri("/apis/fake.halo.run/v1alpha1/fakes")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBodyList(FakeExtension.class)
|
||||
.hasSize(1);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void shouldUpdateExtensionWhenSchemeRegistered() {
|
||||
var name = createdFake.getMetadata().getName();
|
||||
FakeExtension fakeToUpdate = getFakeExtension(name);
|
||||
fakeToUpdate.getMetadata().setLabels(Map.of("updated", "true"));
|
||||
|
||||
webClient.put()
|
||||
.uri("/apis/fake.halo.run/v1alpha1/fakes/{name}", name)
|
||||
.bodyValue(fakeToUpdate)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentType(MediaType.APPLICATION_JSON)
|
||||
.expectBody(FakeExtension.class)
|
||||
.consumeWith(result -> {
|
||||
var updatedFake = result.getResponseBody();
|
||||
assertNotNull(updatedFake);
|
||||
assertNotEquals(fakeToUpdate.getMetadata().getVersion(),
|
||||
updatedFake.getMetadata().getVersion());
|
||||
assertEquals(Map.of("updated", "true"),
|
||||
updatedFake.getMetadata().getLabels());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void shouldGetExtensionWhenSchemeRegistered() {
|
||||
var name = createdFake.getMetadata().getName();
|
||||
webClient.get()
|
||||
.uri("/apis/fake.halo.run/v1alpha1/fakes/{name}", name)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(FakeExtension.class)
|
||||
.consumeWith(result -> {
|
||||
var gotFake = result.getResponseBody();
|
||||
assertNotNull(gotFake);
|
||||
assertEquals(name, gotFake.getMetadata().getName());
|
||||
assertNotNull(gotFake.getMetadata().getVersion());
|
||||
assertNotNull(gotFake.getMetadata().getCreationTimestamp());
|
||||
});
|
||||
}
|
||||
|
||||
FakeExtension getFakeExtension(String name) {
|
||||
return webClient.get()
|
||||
.uri("/apis/fake.halo.run/v1alpha1/fakes/{name}", name)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(FakeExtension.class)
|
||||
.returnResult()
|
||||
.getResponseBody();
|
||||
}
|
||||
|
||||
|
||||
WebTestClient.ResponseSpec getCreateExtensionResponse() {
|
||||
var metadata = new Metadata();
|
||||
metadata.setName("my-fake");
|
||||
var fake = new FakeExtension();
|
||||
fake.setMetadata(metadata);
|
||||
|
||||
return webClient.post()
|
||||
.uri("/apis/fake.halo.run/v1alpha1/fakes")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(fake)
|
||||
.exchange();
|
||||
}
|
||||
|
||||
return webClient.post()
|
||||
.uri("/apis/fake.halo.run/v1alpha1/fakes")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(fake)
|
||||
.exchange();
|
||||
}
|
||||
|
||||
}
|
|
@ -2,11 +2,16 @@ package run.halo.app.extension;
|
|||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
@ -31,8 +36,8 @@ class ExtensionCreateHandlerTest {
|
|||
@Test
|
||||
void shouldBuildPathPatternCorrectly() {
|
||||
var scheme = Scheme.buildFromType(FakeExtension.class);
|
||||
var getHandler = new ExtensionCreateHandler(scheme, client);
|
||||
var pathPattern = getHandler.pathPattern();
|
||||
var createHandler = new ExtensionCreateHandler(scheme, client);
|
||||
var pathPattern = createHandler.pathPattern();
|
||||
assertEquals("/apis/fake.halo.run/v1alpha1/fakes", pathPattern);
|
||||
}
|
||||
|
||||
|
@ -58,7 +63,9 @@ class ExtensionCreateHandlerTest {
|
|||
|
||||
StepVerifier.create(responseMono)
|
||||
.consumeNextWith(response -> {
|
||||
assertEquals(HttpStatus.OK, response.statusCode());
|
||||
assertEquals(HttpStatus.CREATED, response.statusCode());
|
||||
assertEquals("/apis/fake.halo.run/v1alpha1/fakes/my-fake",
|
||||
response.headers().getLocation().toString());
|
||||
assertEquals(MediaType.APPLICATION_JSON, response.headers().getContentType());
|
||||
assertTrue(response instanceof EntityResponse<?>);
|
||||
assertEquals(fake, ((EntityResponse<?>) response).entity());
|
||||
|
@ -90,13 +97,16 @@ class ExtensionCreateHandlerTest {
|
|||
|
||||
var serverRequest = MockServerRequest.builder()
|
||||
.body(Mono.just(unstructured));
|
||||
when(client.fetch(eq(FakeExtension.class), eq("my-fake"))).thenReturn(Optional.empty());
|
||||
doThrow(ExtensionNotFoundException.class).when(client).create(any());
|
||||
|
||||
var scheme = Scheme.buildFromType(FakeExtension.class);
|
||||
var getHandler = new ExtensionCreateHandler(scheme, client);
|
||||
var responseMono = getHandler.handle(serverRequest);
|
||||
var createHandler = new ExtensionCreateHandler(scheme, client);
|
||||
var responseMono = createHandler.handle(serverRequest);
|
||||
|
||||
StepVerifier.create(responseMono)
|
||||
.verifyError(ExtensionNotFoundException.class);
|
||||
verify(client, times(1)).create(
|
||||
argThat(extension -> Objects.equals("my-fake", extension.getMetadata().getName())));
|
||||
verify(client, times(0)).fetch(any(), anyString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
package run.halo.app.extension;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.reactive.function.server.MockServerRequest;
|
||||
import org.springframework.web.reactive.function.server.EntityResponse;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
import run.halo.app.extension.ExtensionRouterFunctionFactory.ExtensionDeleteHandler;
|
||||
import run.halo.app.extension.exception.ExtensionNotFoundException;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ExtensionDeleteHandlerTest {
|
||||
|
||||
@Mock
|
||||
ExtensionClient client;
|
||||
|
||||
@Test
|
||||
void shouldBuildPathPatternCorrectly() {
|
||||
var scheme = Scheme.buildFromType(FakeExtension.class);
|
||||
var deleteHandler = new ExtensionDeleteHandler(scheme, client);
|
||||
var pathPattern = deleteHandler.pathPattern();
|
||||
assertEquals("/apis/fake.halo.run/v1alpha1/fakes/{name}", pathPattern);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHandleCorrectly() {
|
||||
final var fake = new FakeExtension();
|
||||
var metadata = new Metadata();
|
||||
metadata.setName("my-fake");
|
||||
fake.setMetadata(metadata);
|
||||
|
||||
var unstructured = new Unstructured();
|
||||
unstructured.setMetadata(metadata);
|
||||
unstructured.setApiVersion("fake.halo.run/v1alpha1");
|
||||
unstructured.setKind("Fake");
|
||||
|
||||
var serverRequest = MockServerRequest.builder()
|
||||
.pathVariable("name", "my-fake")
|
||||
.body(Mono.just(unstructured));
|
||||
when(client.fetch(eq(FakeExtension.class), eq("my-fake"))).thenReturn(Optional.of(fake));
|
||||
doNothing().when(client).update(any());
|
||||
|
||||
var scheme = Scheme.buildFromType(FakeExtension.class);
|
||||
var deleteHandler = new ExtensionDeleteHandler(scheme, client);
|
||||
var responseMono = deleteHandler.handle(serverRequest);
|
||||
|
||||
StepVerifier.create(responseMono)
|
||||
.assertNext(response -> {
|
||||
assertEquals(HttpStatus.OK, response.statusCode());
|
||||
assertEquals(MediaType.APPLICATION_JSON, response.headers().getContentType());
|
||||
assertTrue(response instanceof EntityResponse<?>);
|
||||
assertEquals(fake, ((EntityResponse<?>) response).entity());
|
||||
})
|
||||
.verifyComplete();
|
||||
verify(client, times(2)).fetch(eq(FakeExtension.class), eq("my-fake"));
|
||||
verify(client, times(1)).update(
|
||||
argThat(fakeToDelete -> fakeToDelete.getMetadata().getDeletionTimestamp() != null));
|
||||
verify(client, times(0)).delete(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnErrorWhenNoNameProvided() {
|
||||
var serverRequest = MockServerRequest.builder()
|
||||
.body(Mono.empty());
|
||||
var scheme = Scheme.buildFromType(FakeExtension.class);
|
||||
var deleteHandler = new ExtensionDeleteHandler(scheme, client);
|
||||
assertThrows(IllegalArgumentException.class, () -> deleteHandler.handle(serverRequest));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnErrorWhenExtensionNotFound() {
|
||||
var serverRequest = MockServerRequest.builder()
|
||||
.pathVariable("name", "my-fake")
|
||||
.build();
|
||||
when(client.fetch(FakeExtension.class, "my-fake")).thenReturn(Optional.empty());
|
||||
|
||||
var scheme = Scheme.buildFromType(FakeExtension.class);
|
||||
var deleteHandler = new ExtensionDeleteHandler(scheme, client);
|
||||
var responseMono = deleteHandler.handle(serverRequest);
|
||||
|
||||
StepVerifier.create(responseMono)
|
||||
.verifyError(ExtensionNotFoundException.class);
|
||||
|
||||
verify(client, times(1)).fetch(any(), anyString());
|
||||
verify(client, times(0)).update(any());
|
||||
verify(client, times(0)).delete(any());
|
||||
}
|
||||
}
|
|
@ -27,20 +27,20 @@ class ExtensionListHandlerTest {
|
|||
@Test
|
||||
void shouldBuildPathPatternCorrectly() {
|
||||
var scheme = Scheme.buildFromType(FakeExtension.class);
|
||||
var getHandler = new ExtensionListHandler(scheme, client);
|
||||
var pathPattern = getHandler.pathPattern();
|
||||
var listHandler = new ExtensionListHandler(scheme, client);
|
||||
var pathPattern = listHandler.pathPattern();
|
||||
assertEquals("/apis/fake.halo.run/v1alpha1/fakes", pathPattern);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHandleCorrectly() {
|
||||
var scheme = Scheme.buildFromType(FakeExtension.class);
|
||||
var getHandler = new ExtensionListHandler(scheme, client);
|
||||
var listHandler = new ExtensionListHandler(scheme, client);
|
||||
var serverRequest = MockServerRequest.builder().build();
|
||||
final var fake = new FakeExtension();
|
||||
when(client.list(eq(FakeExtension.class), any(), any())).thenReturn(List.of(fake));
|
||||
|
||||
var responseMono = getHandler.handle(serverRequest);
|
||||
var responseMono = listHandler.handle(serverRequest);
|
||||
|
||||
StepVerifier.create(responseMono)
|
||||
.consumeNextWith(response -> {
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.springframework.web.server.ServerWebExchange;
|
|||
import run.halo.app.extension.ExtensionRouterFunctionFactory.CreateHandler;
|
||||
import run.halo.app.extension.ExtensionRouterFunctionFactory.GetHandler;
|
||||
import run.halo.app.extension.ExtensionRouterFunctionFactory.ListHandler;
|
||||
import run.halo.app.extension.ExtensionRouterFunctionFactory.UpdateHandler;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ExtensionRouterFunctionFactoryTest {
|
||||
|
@ -53,10 +54,15 @@ class ExtensionRouterFunctionFactoryTest {
|
|||
MockServerHttpRequest.post("/apis/fake.halo.run/v1alpha1/fakes").body("{}")
|
||||
);
|
||||
|
||||
var updateWebExchange = MockServerWebExchange.from(
|
||||
MockServerHttpRequest.put("/apis/fake.halo.run/v1alpha1/fakes/my-fake").body("{}")
|
||||
);
|
||||
|
||||
return List.of(
|
||||
new TestCase(listWebExchange, ListHandler.class),
|
||||
new TestCase(getWebExchange, GetHandler.class),
|
||||
new TestCase(createWebExchange, CreateHandler.class)
|
||||
new TestCase(createWebExchange, CreateHandler.class),
|
||||
new TestCase(updateWebExchange, UpdateHandler.class)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
package run.halo.app.extension;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.reactive.function.server.MockServerRequest;
|
||||
import org.springframework.web.reactive.function.server.EntityResponse;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
import run.halo.app.extension.ExtensionRouterFunctionFactory.ExtensionUpdateHandler;
|
||||
import run.halo.app.extension.exception.ExtensionConvertException;
|
||||
import run.halo.app.extension.exception.ExtensionNotFoundException;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ExtensionUpdateHandlerTest {
|
||||
|
||||
@Mock
|
||||
ExtensionClient client;
|
||||
|
||||
@Test
|
||||
void shouldBuildPathPatternCorrectly() {
|
||||
var scheme = Scheme.buildFromType(FakeExtension.class);
|
||||
var updateHandler = new ExtensionUpdateHandler(scheme, client);
|
||||
var pathPattern = updateHandler.pathPattern();
|
||||
assertEquals("/apis/fake.halo.run/v1alpha1/fakes/{name}", pathPattern);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHandleCorrectly() {
|
||||
final var fake = new FakeExtension();
|
||||
var metadata = new Metadata();
|
||||
metadata.setName("my-fake");
|
||||
fake.setMetadata(metadata);
|
||||
|
||||
var unstructured = new Unstructured();
|
||||
unstructured.setMetadata(metadata);
|
||||
unstructured.setApiVersion("fake.halo.run/v1alpha1");
|
||||
unstructured.setKind("Fake");
|
||||
|
||||
var serverRequest = MockServerRequest.builder()
|
||||
.pathVariable("name", "my-fake")
|
||||
.body(Mono.just(unstructured));
|
||||
when(client.fetch(eq(FakeExtension.class), eq("my-fake"))).thenReturn(Optional.of(fake));
|
||||
|
||||
var scheme = Scheme.buildFromType(FakeExtension.class);
|
||||
var updateHandler = new ExtensionUpdateHandler(scheme, client);
|
||||
var responseMono = updateHandler.handle(serverRequest);
|
||||
|
||||
StepVerifier.create(responseMono)
|
||||
.assertNext(response -> {
|
||||
assertEquals(HttpStatus.OK, response.statusCode());
|
||||
assertEquals(MediaType.APPLICATION_JSON, response.headers().getContentType());
|
||||
assertTrue(response instanceof EntityResponse<?>);
|
||||
assertEquals(fake, ((EntityResponse<?>) response).entity());
|
||||
})
|
||||
.verifyComplete();
|
||||
verify(client, times(1)).fetch(eq(FakeExtension.class), eq("my-fake"));
|
||||
verify(client, times(1)).update(eq(unstructured));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnErrorWhenNoBodyProvided() {
|
||||
var serverRequest = MockServerRequest.builder()
|
||||
.pathVariable("name", "my-fake")
|
||||
.body(Mono.empty());
|
||||
var scheme = Scheme.buildFromType(FakeExtension.class);
|
||||
var updateHandler = new ExtensionUpdateHandler(scheme, client);
|
||||
var responseMono = updateHandler.handle(serverRequest);
|
||||
StepVerifier.create(responseMono)
|
||||
.verifyError(ExtensionConvertException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnErrorWhenNoNameProvided() {
|
||||
var serverRequest = MockServerRequest.builder()
|
||||
.body(Mono.empty());
|
||||
var scheme = Scheme.buildFromType(FakeExtension.class);
|
||||
var updateHandler = new ExtensionUpdateHandler(scheme, client);
|
||||
assertThrows(IllegalArgumentException.class, () -> updateHandler.handle(serverRequest));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnErrorWhenExtensionNotFound() {
|
||||
final var unstructured = new Unstructured();
|
||||
var metadata = new Metadata();
|
||||
metadata.setName("my-fake");
|
||||
unstructured.setMetadata(metadata);
|
||||
unstructured.setApiVersion("fake.halo.run/v1alpha1");
|
||||
unstructured.setKind("Fake");
|
||||
|
||||
var serverRequest = MockServerRequest.builder()
|
||||
.pathVariable("name", "my-fake")
|
||||
.body(Mono.just(unstructured));
|
||||
doThrow(ExtensionNotFoundException.class).when(client).update(any());
|
||||
|
||||
var scheme = Scheme.buildFromType(FakeExtension.class);
|
||||
var updateHandler = new ExtensionUpdateHandler(scheme, client);
|
||||
var responseMono = updateHandler.handle(serverRequest);
|
||||
|
||||
StepVerifier.create(responseMono)
|
||||
.verifyError(ExtensionNotFoundException.class);
|
||||
|
||||
verify(client, times(1)).update(
|
||||
argThat(extension -> Objects.equals("my-fake", extension.getMetadata().getName())));
|
||||
verify(client, times(0)).fetch(any(), anyString());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue