Skip to content

Commit

Permalink
Checktool
Browse files Browse the repository at this point in the history
  • Loading branch information
adrienlauer authored and Nheverest committed Apr 27, 2021
1 parent ac1a2ac commit 60dcfa4
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 86 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,6 @@
# Version 3.12.1 (2021-04-30)
* [new] CheckTool to analyze class mapping between configuration files and source code.

# Version 3.12.0 (2021-01-31)

* [new] Java 15 support
Expand Down
@@ -1,11 +1,10 @@
/*
* Copyright © 2013-2019, The SeedStack authors <http://seedstack.org>
* Copyright © 2013-2021, The SeedStack authors <http://seedstack.org>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

package org.seedstack.seed.core.internal.configuration.tool;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
Expand Down
@@ -1,14 +1,12 @@
/*
* Copyright © 2013-2019, The SeedStack authors <http://seedstack.org>
* Copyright © 2013-2021, The SeedStack authors <http://seedstack.org>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

package org.seedstack.seed.core.internal.configuration.tool;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.nuun.kernel.api.plugin.InitState;
import io.nuun.kernel.api.plugin.context.InitContext;
import io.nuun.kernel.api.plugin.request.ClasspathScanRequest;
Expand Down Expand Up @@ -68,13 +66,13 @@ public String toolName() {
public Collection<ClasspathScanRequest> classpathScanRequests() {
return classpathScanRequestBuilder()
.annotationType(Config.class)
.specification(SeedConfigurationAnnotationSpecification.INSTANCE)
.predicate(SeedConfigurationAnnotationSpecification.INSTANCE)
.build();
}

@Override
protected InitState initialize(InitContext initContext) {
initContext.scannedTypesBySpecification()
initContext.scannedTypesByPredicate()
.get(SeedConfigurationAnnotationSpecification.INSTANCE)
.forEach(myClass -> {
// Find list of Configuration-annotated fields
Expand Down Expand Up @@ -163,9 +161,9 @@ private void walk(TreeNode coffigTree, String path, Class parentClass) {
return;
}

// There is no entry in root (but we are in a class referenced by a @Config class)
// There is no entry in root
if (parentClass == null) {
// There is no associated class in root, we look into @Configuration fields
// There is no associated class in root, we look into @Configuration fields for fullPath
if (annotationValues.containsKey(fullPath)) {
// There is an @Configuration-field in parent class. We consider first entry as the new parentClass
Optional<Field> optionalField = getField(annotationValues.get(fullPath).get(0), nn.name(), Configuration.class);
Expand All @@ -177,7 +175,11 @@ private void walk(TreeNode coffigTree, String path, Class parentClass) {
// Non-primitive class: keep walking
walk(nn.node(), path + nn.name() + ".", associatedClass);
}
} else {
// we look for an Configuration-annotated field whose value starts with fullPath
} else if (annotationValues.keySet().stream().anyMatch(n -> n.startsWith(fullPath+ "."))) {
walk(nn.node(), path + nn.name() + ".", null);
}
else {
results.add(new EntrySearchResult(SeverityEnum.WARNING, fullPath, StatusEnum.NOT_FOUND));
}
} else {
Expand Down
@@ -1,24 +1,25 @@
/*
* Copyright © 2013-2019, The SeedStack authors <http://seedstack.org>
* Copyright © 2013-2021, The SeedStack authors <http://seedstack.org>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.seedstack.seed.core.internal.configuration.tool;

import org.kametic.specifications.AbstractSpecification;
import org.seedstack.seed.Configuration;
import org.seedstack.shed.reflect.AnnotationPredicates;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.function.Predicate;

/**
* Matches all classes containing fields annotated by {@link org.seedstack.seed.Configuration}.
* It also matches classes extending or implementing a class/interface with a Configuration-annotated field.
* <p>
*/
class SeedConfigurationAnnotationSpecification extends AbstractSpecification<Class<?>> {
class SeedConfigurationAnnotationSpecification implements Predicate<Class<?>> {
private static final Logger LOGGER = LoggerFactory.getLogger(SeedConfigurationAnnotationSpecification.class);

static final SeedConfigurationAnnotationSpecification INSTANCE = new SeedConfigurationAnnotationSpecification();
Expand All @@ -28,7 +29,7 @@ private SeedConfigurationAnnotationSpecification() {
}

@Override
public boolean isSatisfiedBy(Class<?> candidate) {
public boolean test(Class<?> candidate) {
try {
return AnnotationPredicates.atLeastOneFieldAnnotatedWith(Configuration.class, true)
.test(candidate);
Expand Down
@@ -1,11 +1,10 @@
/*
* Copyright © 2013-2019, The SeedStack authors <http://seedstack.org>
* Copyright © 2013-2021, The SeedStack authors <http://seedstack.org>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

package org.seedstack.seed.core.internal.configuration.tool.utils;

import org.seedstack.seed.Configuration;
Expand All @@ -31,14 +30,21 @@ public static Optional<Field> getField(Class<?> configClass, String name) {
}
}

/**
* Return Field from configClass annotated with {link org.seedstack.seed.Configuration) and named with name
* @param configClass class to search into
* @param name name of the field to be looked for
* @param annotation annotation type (@Configuration here)
* @return
*/
public static Optional<Field> getField(Class<?> configClass, String name, Class<Configuration> annotation) {
if (configClass == null) {
return Optional.empty();
} else {
List<Field> fields = Classes.from(configClass).traversingSuperclasses().traversingInterfaces().fields().collect(Collectors.toList());
for (Field field : fields) {
if (field.isAnnotationPresent(annotation)) {
if (field.getAnnotation(annotation).value()[0].equals(name)) {
if (field.getAnnotation(annotation).value().length > 0 && field.getAnnotation(annotation).value()[0].equals(name)) {
return Optional.of(field);
}
}
Expand Down
@@ -1,11 +1,10 @@
/*
* Copyright © 2013-2019, The SeedStack authors <http://seedstack.org>
* Copyright © 2013-2021, The SeedStack authors <http://seedstack.org>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

package org.seedstack.seed.core.internal.configuration.tool.utils;

import org.seedstack.seed.Configuration;
Expand Down
Expand Up @@ -3,4 +3,4 @@ org.seedstack.seed.core.internal.configuration.tool.CheckTool
org.seedstack.seed.core.internal.diagnostic.tool.ErrorsTool
org.seedstack.seed.core.internal.crypto.CryptTool
org.seedstack.seed.core.internal.configuration.tool.EffectiveConfigTool
org.seedstack.seed.core.internal.diagnostic.tool.DiagTool
org.seedstack.seed.core.internal.diagnostic.tool.DiagTool
@@ -0,0 +1,44 @@
/*
* Copyright © 2013-2021, The SeedStack authors <http://seedstack.org>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.seedstack.seed.core.internal.configuration.tool;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.seedstack.seed.core.internal.configuration.tool.fixtures.ExitExceptionSecurityManager;
import org.seedstack.seed.testing.junit4.SeedITRunner;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

@RunWith(SeedITRunner.class)
public abstract class AbstractToolIT {

final static ByteArrayOutputStream output = new ByteArrayOutputStream();

private final static PrintStream savedOut = System.out;
private static SecurityManager savedSecurityManager = System.getSecurityManager();

@BeforeClass
public static void beforeClass() {
System.setOut(new PrintStream(output));
System.setSecurityManager(new ExitExceptionSecurityManager());
}

@AfterClass
public static void afterClass() {
System.setOut(savedOut);
System.setSecurityManager(savedSecurityManager);
}

@After
public void afterTest() {
output.reset();
}
}
@@ -1,83 +1,24 @@
/*
* Copyright © 2013-2019, The SeedStack authors <http://seedstack.org>
* Copyright © 2013-2021, The SeedStack authors <http://seedstack.org>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.seedstack.seed.core.internal.configuration.tool;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.seedstack.coffig.Config;
import org.seedstack.seed.Configuration;
import org.seedstack.seed.SeedException;
import org.seedstack.seed.core.internal.ToolLauncher;
import org.seedstack.seed.core.internal.configuration.tool.fixtures.Credentials;
import org.seedstack.seed.core.internal.configuration.tool.fixtures.ExitException;
import org.seedstack.seed.core.internal.configuration.tool.fixtures.ExitExceptionSecurityManager;
import org.seedstack.seed.core.internal.ToolLauncher;
import org.seedstack.seed.testing.junit4.SeedITRunner;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

@RunWith(SeedITRunner.class)
public class SeedToolIT {

private final static ByteArrayOutputStream output = new ByteArrayOutputStream();

private final static PrintStream savedOut = System.out;
private static SecurityManager savedSecurityManager = System.getSecurityManager();

@BeforeClass
public static void beforeClass() {
System.setOut(new PrintStream(output));
System.setSecurityManager(new ExitExceptionSecurityManager());
}

@AfterClass
public static void afterClass() {
System.setOut(savedOut);
System.setSecurityManager(savedSecurityManager);
}

@After
public void afterTest() {
output.reset();
}

@Test
public void nonExistentSeedTool() {
ToolLauncher launcher = new ToolLauncher("non-existentSeedTool");
assertThatExceptionOfType(SeedException.class).isThrownBy(() -> launcher.launch(new String[]{"jta"}));
}

@Test
public void validConfigToolWithParameters() throws Exception {
ToolLauncher launcher = new ToolLauncher("config");
try {
launcher.launch(new String[]{"transaction.jta"});
} catch (ExitException e) {
assertThat(output.toString()).contains("Configuration options");
}
}
import static org.assertj.core.api.Assertions.*;

@Test
public void validConfigToolWithoutParameters() throws Exception {
ToolLauncher launcher = new ToolLauncher("config");
try {
launcher.launch(new String[]{});
} catch (ExitException e) {
assertThat(output.toString()).contains("Configuration options");
}
}
public class CheckToolIT extends AbstractToolIT {

@Test
public void runCheckToolInStandardMode() throws Exception {
Expand Down Expand Up @@ -120,6 +61,9 @@ private void runInfoChecks() {
assertThat(output.toString()).contains(new CheckTool.EntrySearchResult(CheckTool.SeverityEnum.INFO, "application.basePackages", CheckTool.StatusEnum.FOUND, org.seedstack.seed.ApplicationConfig.class).toString());
// Arrays of user objects are correctly analyzed
assertThat(output.toString()).contains(new CheckTool.EntrySearchResult(CheckTool.SeverityEnum.INFO, "arrayOfMapContainer.credentials.username", CheckTool.StatusEnum.FOUND, org.seedstack.seed.core.internal.configuration.tool.fixtures.Credentials.class).toString());
// Configuration annotations are correctly analyzed
assertThat(output.toString()).contains(new CheckTool.EntrySearchResult(CheckTool.SeverityEnum.INFO, "entry.for.configurationAnnotation", CheckTool.StatusEnum.FOUND, CheckToolIT.class).toString());
assertThat(output.toString()).contains(new CheckTool.EntrySearchResult(CheckTool.SeverityEnum.INFO, "firstLevelEntry", CheckTool.StatusEnum.FOUND, CheckToolIT.class).toString());
}

private void runWarningChecks() {
Expand Down Expand Up @@ -150,4 +94,10 @@ Credentials[] getCredentials() {

@Configuration
private AnonymousMapContainer anonymousMapContainer;

@Configuration("entry.for.configurationAnnotation")
private String configurationAnnotation;

@Configuration("firstLevelEntry")
private String[] someProperty;
}
@@ -0,0 +1,45 @@
/*
* Copyright © 2013-2021, The SeedStack authors <http://seedstack.org>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.seedstack.seed.core.internal.configuration.tool;

import org.junit.Test;
import org.seedstack.seed.SeedException;
import org.seedstack.seed.core.internal.ToolLauncher;
import org.seedstack.seed.core.internal.configuration.tool.fixtures.ExitException;

import static org.assertj.core.api.Assertions.*;

public class GenericToolIT extends AbstractToolIT {

@Test
public void nonExistentSeedTool() {
ToolLauncher launcher = new ToolLauncher("non-existentSeedTool");
assertThatExceptionOfType(SeedException.class).isThrownBy(() -> launcher.launch(new String[]{"jta"}));
}

@Test
public void validConfigToolWithParameters() throws Exception {
ToolLauncher launcher = new ToolLauncher("config");
try {
launcher.launch(new String[]{"transaction.jta"});
} catch (ExitException e) {
assertThat(output.toString()).contains("Configuration options");
}
}

@Test
public void validConfigToolWithoutParameters() throws Exception {
ToolLauncher launcher = new ToolLauncher("config");
try {
launcher.launch(new String[]{});
} catch (ExitException e) {
assertThat(output.toString()).contains("Configuration options");
}
}

}
@@ -1,5 +1,5 @@
/*
* Copyright © 2013-2019, The SeedStack authors <http://seedstack.org>
* Copyright © 2013-2021, The SeedStack authors <http://seedstack.org>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright © 2013-2019, The SeedStack authors <http://seedstack.org>
* Copyright © 2013-2021, The SeedStack authors <http://seedstack.org>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright © 2013-2019, The SeedStack authors <http://seedstack.org>
* Copyright © 2013-2021, The SeedStack authors <http://seedstack.org>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
Expand Down

0 comments on commit 60dcfa4

Please sign in to comment.