mirror of https://github.com/halo-dev/halo
feat: add role reconciler (#2212)
* feat: add role reconciler * refactor: get role by name * refactor: reconcile * refactor: reconciler * fix: testpull/2217/head
parent
f7945081a5
commit
f62d089237
|
@ -5,7 +5,9 @@ import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
|
import run.halo.app.core.extension.Role;
|
||||||
import run.halo.app.core.extension.User;
|
import run.halo.app.core.extension.User;
|
||||||
|
import run.halo.app.core.extension.reconciler.RoleReconciler;
|
||||||
import run.halo.app.core.extension.reconciler.UserReconciler;
|
import run.halo.app.core.extension.reconciler.UserReconciler;
|
||||||
import run.halo.app.extension.DefaultExtensionClient;
|
import run.halo.app.extension.DefaultExtensionClient;
|
||||||
import run.halo.app.extension.DefaultSchemeManager;
|
import run.halo.app.extension.DefaultSchemeManager;
|
||||||
|
@ -52,4 +54,12 @@ public class ExtensionConfiguration {
|
||||||
.extension(new User())
|
.extension(new User())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
Controller roleController(ExtensionClient client) {
|
||||||
|
return new ControllerBuilder("role-controller", client)
|
||||||
|
.reconciler(new RoleReconciler(client))
|
||||||
|
.extension(new Role())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package run.halo.app.core.extension;
|
package run.halo.app.core.extension;
|
||||||
|
|
||||||
|
import static java.util.Arrays.compare;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -23,7 +25,7 @@ import run.halo.app.extension.GVK;
|
||||||
singular = "role")
|
singular = "role")
|
||||||
public class Role extends AbstractExtension {
|
public class Role extends AbstractExtension {
|
||||||
|
|
||||||
@Schema(minLength = 1)
|
@Schema(required = true)
|
||||||
List<PolicyRule> rules;
|
List<PolicyRule> rules;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,7 +36,7 @@ public class Role extends AbstractExtension {
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public static class PolicyRule {
|
public static class PolicyRule implements Comparable {
|
||||||
/**
|
/**
|
||||||
* APIGroups is the name of the APIGroup that contains the resources.
|
* APIGroups is the name of the APIGroup that contains the resources.
|
||||||
* If multiple API groups are specified, any action requested against one of the enumerated
|
* If multiple API groups are specified, any action requested against one of the enumerated
|
||||||
|
@ -94,6 +96,31 @@ public class Role extends AbstractExtension {
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Object o) {
|
||||||
|
if (o instanceof PolicyRule other) {
|
||||||
|
int result = compare(apiGroups, other.apiGroups);
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = compare(resources, other.resources);
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = compare(resourceNames, other.resourceNames);
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = compare(nonResourceURLs, other.nonResourceURLs);
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = compare(verbs, other.verbs);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
String[] apiGroups;
|
String[] apiGroups;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
package run.halo.app.core.extension.reconciler;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import run.halo.app.core.extension.Role;
|
||||||
|
import run.halo.app.extension.ExtensionClient;
|
||||||
|
import run.halo.app.extension.controller.Reconciler;
|
||||||
|
import run.halo.app.infra.utils.JsonUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Role reconcile.
|
||||||
|
*
|
||||||
|
* @author guqing
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class RoleReconciler implements Reconciler {
|
||||||
|
public static final String ROLE_DEPENDENCIES = "halo.run/dependencies";
|
||||||
|
public static final String ROLE_DEPENDENCY_RULES = "halo.run/dependency-rules";
|
||||||
|
|
||||||
|
private final ExtensionClient client;
|
||||||
|
|
||||||
|
public RoleReconciler(ExtensionClient client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result reconcile(Request request) {
|
||||||
|
client.fetch(Role.class, request.name()).ifPresent(role -> {
|
||||||
|
Map<String, String> annotations = role.getMetadata().getAnnotations();
|
||||||
|
if (annotations == null) {
|
||||||
|
annotations = new HashMap<>();
|
||||||
|
role.getMetadata().setAnnotations(annotations);
|
||||||
|
}
|
||||||
|
Map<String, String> oldAnnotations = Map.copyOf(annotations);
|
||||||
|
|
||||||
|
String s = annotations.get(ROLE_DEPENDENCIES);
|
||||||
|
List<String> roleDependencies = readValue(s);
|
||||||
|
List<Role.PolicyRule> dependencyRules = listDependencyRoles(roleDependencies)
|
||||||
|
.stream()
|
||||||
|
.map(Role::getRules)
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.sorted()
|
||||||
|
.toList();
|
||||||
|
// override dependency rules to annotations
|
||||||
|
annotations.put(ROLE_DEPENDENCY_RULES, JsonUtils.objectToJson(dependencyRules));
|
||||||
|
if (!Objects.deepEquals(oldAnnotations, annotations)) {
|
||||||
|
client.update(role);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return new Result(false, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> readValue(String json) {
|
||||||
|
if (StringUtils.isBlank(json)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return JsonUtils.DEFAULT_JSON_MAPPER.readValue(json, new TypeReference<>() {
|
||||||
|
});
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Role> listDependencyRoles(List<String> dependencies) {
|
||||||
|
List<Role> result = new ArrayList<>();
|
||||||
|
if (dependencies == null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Set<String> visited = new HashSet<>();
|
||||||
|
Deque<String> queue = new ArrayDeque<>(dependencies);
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
String roleName = queue.poll();
|
||||||
|
// detecting cycle in role dependencies
|
||||||
|
if (visited.contains(roleName)) {
|
||||||
|
log.warn("Detected a cycle in role dependencies: {},and skipped automatically",
|
||||||
|
roleName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
visited.add(roleName);
|
||||||
|
client.fetch(Role.class, roleName).ifPresent(role -> {
|
||||||
|
result.add(role);
|
||||||
|
// add role dependencies to queue
|
||||||
|
Map<String, String> annotations = role.getMetadata().getAnnotations();
|
||||||
|
if (annotations != null) {
|
||||||
|
String roleNameDependencies = annotations.get(ROLE_DEPENDENCIES);
|
||||||
|
List<String> roleDependencies = readValue(roleNameDependencies);
|
||||||
|
queue.addAll(roleDependencies);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -70,14 +70,15 @@ public class JsonUtils {
|
||||||
*
|
*
|
||||||
* @param source source object must not be null
|
* @param source source object must not be null
|
||||||
* @return json format of the source object
|
* @return json format of the source object
|
||||||
* @throws JsonProcessingException throws when fail to convert
|
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public static String objectToJson(@NonNull Object source)
|
public static String objectToJson(@NonNull Object source) {
|
||||||
throws JsonProcessingException {
|
|
||||||
Assert.notNull(source, "Source object must not be null");
|
Assert.notNull(source, "Source object must not be null");
|
||||||
|
try {
|
||||||
return DEFAULT_JSON_MAPPER.writeValueAsString(source);
|
return DEFAULT_JSON_MAPPER.writeValueAsString(source);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,15 +1,22 @@
|
||||||
package run.halo.app.security.authorization;
|
package run.halo.app.security.authorization;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import run.halo.app.core.extension.Role;
|
import run.halo.app.core.extension.Role;
|
||||||
|
import run.halo.app.core.extension.reconciler.RoleReconciler;
|
||||||
import run.halo.app.core.extension.service.DefaultRoleBindingService;
|
import run.halo.app.core.extension.service.DefaultRoleBindingService;
|
||||||
import run.halo.app.core.extension.service.RoleBindingService;
|
import run.halo.app.core.extension.service.RoleBindingService;
|
||||||
import run.halo.app.core.extension.service.RoleService;
|
import run.halo.app.core.extension.service.RoleService;
|
||||||
|
import run.halo.app.extension.MetadataOperator;
|
||||||
|
import run.halo.app.infra.utils.JsonUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author guqing
|
* @author guqing
|
||||||
|
@ -49,7 +56,8 @@ public class DefaultRuleResolver implements AuthorizationRuleResolver {
|
||||||
for (String roleName : roleNames) {
|
for (String roleName : roleNames) {
|
||||||
try {
|
try {
|
||||||
Role role = roleService.getRole(roleName);
|
Role role = roleService.getRole(roleName);
|
||||||
rules = role.getRules();
|
// fetch rules from role
|
||||||
|
rules = fetchRules(role);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (visitor.visit(null, null, e)) {
|
if (visitor.visit(null, null, e)) {
|
||||||
return;
|
return;
|
||||||
|
@ -65,6 +73,31 @@ public class DefaultRuleResolver implements AuthorizationRuleResolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Role.PolicyRule> fetchRules(Role role) {
|
||||||
|
MetadataOperator metadata = role.getMetadata();
|
||||||
|
if (metadata == null || metadata.getAnnotations() == null) {
|
||||||
|
return role.getRules();
|
||||||
|
}
|
||||||
|
// merge policy rules
|
||||||
|
String roleDependencyRules = metadata.getAnnotations()
|
||||||
|
.get(RoleReconciler.ROLE_DEPENDENCY_RULES);
|
||||||
|
List<Role.PolicyRule> rules = convertFrom(roleDependencyRules);
|
||||||
|
rules.addAll(role.getRules());
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Role.PolicyRule> convertFrom(String json) {
|
||||||
|
if (StringUtils.isBlank(json)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return JsonUtils.DEFAULT_JSON_MAPPER.readValue(json, new TypeReference<>() {
|
||||||
|
});
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String roleBindingDescriber(String roleName, String subject) {
|
String roleBindingDescriber(String roleName, String subject) {
|
||||||
return String.format("Binding role [%s] to [%s]", roleName, subject);
|
return String.format("Binding role [%s] to [%s]", roleName, subject);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
package run.halo.app.core.extension.reconciler;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.doNothing;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.skyscreamer.jsonassert.JSONAssert;
|
||||||
|
import run.halo.app.core.extension.Role;
|
||||||
|
import run.halo.app.extension.ExtensionClient;
|
||||||
|
import run.halo.app.extension.controller.Reconciler;
|
||||||
|
import run.halo.app.infra.utils.JsonUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link RoleReconciler}.
|
||||||
|
*
|
||||||
|
* @author guqing
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class RoleReconcilerTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ExtensionClient extensionClient;
|
||||||
|
|
||||||
|
private RoleReconciler roleReconciler;
|
||||||
|
|
||||||
|
private String roleOther;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
roleReconciler = new RoleReconciler(extensionClient);
|
||||||
|
Role roleManage = JsonUtils.jsonToObject("""
|
||||||
|
{
|
||||||
|
"apiVersion": "v1alpha1",
|
||||||
|
"kind": "Role",
|
||||||
|
"metadata": {
|
||||||
|
"name": "role-template-apple-manage",
|
||||||
|
"annotations": {
|
||||||
|
"halo.run/dependencies": "[\\"role-template-apple-view\\"]",
|
||||||
|
"halo.run/module": "Apple Management",
|
||||||
|
"halo.run/display-name": "苹果管理"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rules": [{
|
||||||
|
"resources": ["apples"],
|
||||||
|
"verbs": ["create"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
""", Role.class);
|
||||||
|
|
||||||
|
Role roleView = JsonUtils.jsonToObject("""
|
||||||
|
{
|
||||||
|
"apiVersion": "v1alpha1",
|
||||||
|
"kind": "Role",
|
||||||
|
"metadata": {
|
||||||
|
"name": "role-template-apple-view",
|
||||||
|
"annotations": {
|
||||||
|
"halo.run/dependencies": "[\\"role-template-apple-other\\"]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rules": [{
|
||||||
|
"resources": ["apples"],
|
||||||
|
"verbs": ["list"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
""", Role.class);
|
||||||
|
|
||||||
|
roleOther = """
|
||||||
|
{
|
||||||
|
"apiVersion": "v1alpha1",
|
||||||
|
"kind": "Role",
|
||||||
|
"metadata": {
|
||||||
|
"name": "role-template-apple-other"
|
||||||
|
},
|
||||||
|
"rules": [{
|
||||||
|
"resources": ["apples"],
|
||||||
|
"verbs": ["update"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
when(extensionClient.fetch(eq(Role.class), eq("role-template-apple-manage"))).thenReturn(
|
||||||
|
Optional.of(roleManage));
|
||||||
|
when(extensionClient.fetch(eq(Role.class), eq("role-template-apple-view"))).thenReturn(
|
||||||
|
Optional.of(roleView));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void reconcile() throws JSONException {
|
||||||
|
when(extensionClient.fetch(eq(Role.class), eq("role-template-apple-other"))).thenReturn(
|
||||||
|
Optional.of(JsonUtils.jsonToObject(roleOther, Role.class)));
|
||||||
|
assertReconcile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void detectingCycle() throws JSONException {
|
||||||
|
Role roleToUse = JsonUtils.jsonToObject(roleOther, Role.class);
|
||||||
|
// build a cycle in the dependency
|
||||||
|
Map<String, String> annotations =
|
||||||
|
Map.of("halo.run/dependencies", "[\"role-template-apple-view\"]");
|
||||||
|
roleToUse.getMetadata().setAnnotations(annotations);
|
||||||
|
when(extensionClient.fetch(eq(Role.class), eq("role-template-apple-other"))).thenReturn(
|
||||||
|
Optional.of(roleToUse));
|
||||||
|
|
||||||
|
assertReconcile();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertReconcile() throws JSONException {
|
||||||
|
ArgumentCaptor<Role> roleCaptor = ArgumentCaptor.forClass(Role.class);
|
||||||
|
doNothing().when(extensionClient).update(roleCaptor.capture());
|
||||||
|
|
||||||
|
Reconciler.Request request = new Reconciler.Request("role-template-apple-manage");
|
||||||
|
roleReconciler.reconcile(request);
|
||||||
|
String expected = """
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"resources": ["apples"],
|
||||||
|
"verbs": ["list"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resources": ["apples"],
|
||||||
|
"verbs": ["update"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
""";
|
||||||
|
Role updateArgs = roleCaptor.getValue();
|
||||||
|
assertThat(updateArgs).isNotNull();
|
||||||
|
JSONAssert.assertEquals(expected, updateArgs.getMetadata().getAnnotations()
|
||||||
|
.get(RoleReconciler.ROLE_DEPENDENCY_RULES), false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package run.halo.app.infra.utils;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -17,7 +16,7 @@ import org.junit.jupiter.api.Test;
|
||||||
public class JsonUtilsTest {
|
public class JsonUtilsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void serializerTime() throws JsonProcessingException {
|
public void serializerTime() {
|
||||||
Instant now = Instant.now();
|
Instant now = Instant.now();
|
||||||
String instantStr = JsonUtils.objectToJson(now);
|
String instantStr = JsonUtils.objectToJson(now);
|
||||||
assertThat(instantStr).isNotNull();
|
assertThat(instantStr).isNotNull();
|
||||||
|
|
|
@ -2,7 +2,6 @@ package run.halo.app.infra.utils;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
@ -63,7 +62,7 @@ class YamlUnstructuredLoaderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void loadTest() throws JsonProcessingException {
|
void loadTest() {
|
||||||
Resource[] resources = yamlResources.toArray(Resource[]::new);
|
Resource[] resources = yamlResources.toArray(Resource[]::new);
|
||||||
YamlUnstructuredLoader yamlUnstructuredLoader = new YamlUnstructuredLoader(resources);
|
YamlUnstructuredLoader yamlUnstructuredLoader = new YamlUnstructuredLoader(resources);
|
||||||
List<Unstructured> unstructuredList = yamlUnstructuredLoader.load();
|
List<Unstructured> unstructuredList = yamlUnstructuredLoader.load();
|
||||||
|
|
|
@ -2,7 +2,6 @@ package run.halo.app.plugin;
|
||||||
|
|
||||||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -60,7 +59,7 @@ class YamlPluginDescriptorFinderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void find() throws JsonProcessingException, JSONException {
|
void find() throws JSONException {
|
||||||
PluginDescriptor pluginDescriptor = yamlPluginDescriptorFinder.find(testFile.toPath());
|
PluginDescriptor pluginDescriptor = yamlPluginDescriptorFinder.find(testFile.toPath());
|
||||||
String actual = JsonUtils.objectToJson(pluginDescriptor);
|
String actual = JsonUtils.objectToJson(pluginDescriptor);
|
||||||
JSONAssert.assertEquals("""
|
JSONAssert.assertEquals("""
|
||||||
|
|
|
@ -123,7 +123,7 @@ class YamlPluginFinderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void acceptArrayLicense() throws JSONException, JsonProcessingException {
|
void acceptArrayLicense() throws JSONException {
|
||||||
Resource pluginResource = new InMemoryResource("""
|
Resource pluginResource = new InMemoryResource("""
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Plugin
|
kind: Plugin
|
||||||
|
@ -143,7 +143,7 @@ class YamlPluginFinderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void acceptMultipleItemArrayLicense() throws JsonProcessingException, JSONException {
|
void acceptMultipleItemArrayLicense() throws JSONException {
|
||||||
Resource pluginResource = new InMemoryResource("""
|
Resource pluginResource = new InMemoryResource("""
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Plugin
|
kind: Plugin
|
||||||
|
@ -167,7 +167,7 @@ class YamlPluginFinderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void acceptArrayObjectLicense() throws JSONException, JsonProcessingException {
|
void acceptArrayObjectLicense() throws JSONException {
|
||||||
Resource pluginResource = new InMemoryResource("""
|
Resource pluginResource = new InMemoryResource("""
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Plugin
|
kind: Plugin
|
||||||
|
|
Loading…
Reference in New Issue