Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
the generated project content (with immutable mocked data) using snapshot testing
*
the generated project build/run (with real data) with helpers to run the build
*
*
* Before all tests, the extension will generate Quarkus projects in the specified languages with the given codestart,
* with mocked data and with real data.
*
* You can find those generated project in `target/quarkus-codestart-test`.
*
* You can open the `real-data` ones in your IDE or play with them using the terminal.
*
* Running those tests is the easiest way to iterate on your extension codestart dev
*/
public class QuarkusCodestartTest implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback {
private static final String DEFAULT_PACKAGE_DIR = "org.acme";
private final Set codestarts;
private final Set languages;
private final Map data;
private final AtomicReference currentTestContext = new AtomicReference<>();
private final BuildTool buildTool;
private final Set hasGeneratedProjectsWithMockedData = new HashSet<>();
private final Set hasGeneratedProjectsWithRealData = new HashSet<>();
private final boolean enableRegistryClient;
private final Collection artifacts;
private final Collection extensions;
private final String quarkusBomGroupId;
private final String quarkusBomVersion;
private Path targetDir;
private ExtensionCatalog extensionCatalog;
private QuarkusCodestartCatalog quarkusCodestartCatalog;
private String packageName;
QuarkusCodestartTest(QuarkusCodestartTestBuilder builder) {
this.codestarts = builder.codestarts;
this.languages = builder.languages;
this.buildTool = builder.buildTool;
this.quarkusCodestartCatalog = builder.quarkusCodestartCatalog;
this.quarkusBomGroupId = builder.quarkusBomGroupId;
this.quarkusBomVersion = builder.quarkusBomVersion;
this.extensionCatalog = builder.extensionCatalog;
this.enableRegistryClient = builder.extensionCatalog == null;
this.data = builder.data;
this.artifacts = builder.artifacts;
this.extensions = builder.extensions;
this.packageName = builder.packageName;
}
public static QuarkusCodestartTestBuilder builder() {
return new QuarkusCodestartTestBuilder();
}
@Override
public void beforeAll(ExtensionContext extensionContext) throws Exception {
if (enableRegistryClient) {
if (quarkusBomVersion != null) {
enableRegistryClientTestConfig(quarkusBomGroupId != null ? quarkusBomGroupId : "io.quarkus", quarkusBomVersion);
} else {
enableRegistryClientTestConfig();
}
}
targetDir = Paths.get("target/quarkus-codestart-test/" + getTestId());
SnapshotTesting.deleteTestDirectory(targetDir.toFile());
}
public QuarkusCodestartCatalog getQuarkusCodestartCatalog() throws IOException {
return quarkusCodestartCatalog == null
? quarkusCodestartCatalog = QuarkusCodestartCatalog.fromExtensionsCatalog(getExtensionsCatalog(),
getCodestartsResourceLoaders())
: quarkusCodestartCatalog;
}
public ExtensionCatalog getExtensionsCatalog() {
if (extensionCatalog == null) {
try {
ExtensionCatalog baseExtensionCatalog = QuarkusProjectHelper.getCatalogResolver().resolveExtensionCatalog();
extensionCatalog = completeCatalogWithCoords(baseExtensionCatalog, extensions, artifactResolver());
} catch (Exception e) {
throw new RuntimeException("Failed to resolve extension catalog", e);
}
}
return extensionCatalog;
}
/**
* This will run the build on all generated projects (with real data)
*
* @throws IOException
*/
public void buildAllProjects() throws IOException {
for (Language language : languages) {
buildProject(language);
}
}
/**
* This will run the build on the generated projects (with real data) in the specified language.
*
*
* @param language the language
* @throws IOException
*/
public void buildProject(Language language) throws IOException {
final int exitCode = WrapperRunner.run(getProjectWithRealDataDir(language));
Assertions.assertThat(exitCode).as("Run project return status is zero").isZero();
}
/**
* Check that the given full qualified className is valid in all generated projects (with fake data)
*
*
* See {@link QuarkusCodestartTest#checkGeneratedSource(Language language, String className)}
*
* @param className the full qualified className (using `org.acme.ClassName` also works, it will be replaced by the project
* package name)
* @throws Throwable
*/
public void checkGeneratedSource(String className) throws Throwable {
for (Language language : languages) {
checkGeneratedSource(language, className);
}
}
/**
* Check that the given full qualified test className is valid in all generated projects (with fake data)
*
*
* See {@link QuarkusCodestartTest#checkGeneratedSource(Language language, String className)}
*
* @param className the full qualified test class name (using `org.acme.ClassName` also works, it will be replaced by the
* project package name)
* @throws Throwable
*/
public void checkGeneratedTestSource(String className) throws Throwable {
for (Language language : languages) {
checkGeneratedTestSource(language, className);
}
}
/**
* It will validate (compare and check package name) the class against the snapshots in all the projects for the given
* language
*
* @param language the language to check
* @param className the full qualified className (using `org.acme.ClassName` also works, it will be replaced by the project
* package name)
* @return
* @throws Throwable
*/
public AbstractPathAssert> checkGeneratedSource(Language language, String className) throws Throwable {
return checkGeneratedSource("main", language, className);
}
/**
* It will validate (compare and check package name) the test class against the snapshots in all the projects for the given
* language
*
* @param language the language to check
* @param className the full qualified test className (using `org.acme.ClassName` also works, it will be replaced by the
* project package name)
* @return
* @throws Throwable
*/
public AbstractPathAssert> checkGeneratedTestSource(Language language, String className) throws Throwable {
return checkGeneratedSource("test", language, className);
}
/**
* Get a PathAssert on a generated mocked file for a specific language
*
*
*
*
* Very usefull to check if a file contains a specific String:
*
* Example:
* codestartTest.assertThatGeneratedFile(JAVA, "README.md").satisfies(checkContains("./mvnw compile quarkus:dev
* -Dquarkus.args='Quarky"));
*
* @param language the language
* @param fileRelativePath the relative path for the file in the generated project
* @return the PathAssert
* @throws Throwable
*/
public AbstractPathAssert> assertThatGeneratedFile(Language language, String fileRelativePath) throws Throwable {
return Assertions.assertThat(this.getProjectWithMockedDataDir(language).resolve(fileRelativePath));
}
/**
* See {@link #assertThatGeneratedFile(Language language, String fileRelativePath)}
* but also compare it with its snapshots
*
* @param language the language
* @param fileRelativePath the relative path for the file in the generated project
* @return
* @throws Throwable
*/
public AbstractPathAssert> assertThatGeneratedFileMatchSnapshot(Language language, String fileRelativePath)
throws Throwable {
ExtensionContext context = Objects.requireNonNull(currentTestContext.get(), "Context must be present");
final String snapshotDirName = context.getTestClass().get().getSimpleName() + "/"
+ context.getTestMethod().get().getName();
final String normalizedFileName = snapshotDirName + "/" + normalizePathAsName(fileRelativePath);
return SnapshotTesting.assertThatMatchSnapshot(getProjectWithMockedDataDir(language).resolve(fileRelativePath),
normalizedFileName);
}
/**
* This let you compare the project file structure (tree) for a specific language against its snapshot
*
* @param language the language
* @return the ListAssert
* @throws Throwable
*/
public ListAssert assertThatGeneratedTreeMatchSnapshots(Language language) throws Throwable {
return assertThatGeneratedTreeMatchSnapshots(language, null);
}
/**
* see {link #assertThatGeneratedTreeMatchSnapshots(Language language)}
* but for a specific sub directory
*
* @param language the language
* @param dirRelativePath the sub directory
* @return the ListAssert
* @throws Throwable
*/
public ListAssert assertThatGeneratedTreeMatchSnapshots(Language language, String dirRelativePath)
throws Throwable {
ExtensionContext context = Objects.requireNonNull(currentTestContext.get(), "Context must be present");
final String snapshotDirName = context.getTestClass().get().getSimpleName() + "/"
+ context.getTestMethod().get().getName();
final Path dir = dirRelativePath != null ? getProjectWithMockedDataDir(language).resolve(dirRelativePath)
: getProjectWithMockedDataDir(language);
return SnapshotTesting.assertThatDirectoryTreeMatchSnapshots(snapshotDirName, dir);
}
private AbstractPathAssert> checkGeneratedSource(String sourceDir, Language language, String className) throws Throwable {
final String modifiedClassName = className.replace(DEFAULT_PACKAGE_DIR, packageName).replace('.', '/');
final String fileRelativePath = "src/" + sourceDir + "/" + language.key() + "/" + modifiedClassName
+ getSourceFileExtension(language);
return assertThatGeneratedFileMatchSnapshot(language, fileRelativePath)
.satisfies(checkContains("package " + packageName));
}
private String getTestId() {
final String id = Stream.of(
buildTool != null ? Stream.of(buildTool.getKey()) : Stream. empty(),
this.extensions.stream().map(ArtifactCoords::getArtifactId),
this.codestarts.stream(),
Stream.of(UUID.randomUUID().toString())).flatMap(Function.identity()).collect(Collectors.joining("-"));
return id;
}
private void generateRealDataProjectIfNeeded(Path path, Language language) throws IOException {
if (!hasGeneratedProjectsWithRealData.contains(language)) {
generateProject(path, language,
getRealTestInputData(getExtensionsCatalog(), Collections.emptyMap()));
}
hasGeneratedProjectsWithRealData.add(language);
}
private void generateMockedDataProjectIfNeeded(Path path, Language language) throws IOException {
if (!hasGeneratedProjectsWithMockedData.contains(language)) {
generateProject(path, language, getMockedTestInputData(Collections.emptyMap()));
}
hasGeneratedProjectsWithMockedData.add(language);
}
private void generateProject(Path projectDir, Language language, Map inputData) throws IOException {
final QuarkusCodestartProjectInput input = QuarkusCodestartProjectInput.builder()
.addCodestart(language.key())
.buildTool(buildTool)
.addCodestarts(codestarts)
.addData(inputData)
.addData(data)
.addBoms(QuarkusCodestartTesting.getBoms(inputData))
.addExtensions(extensions)
.putData(PROJECT_PACKAGE_NAME, packageName)
.build();
getQuarkusCodestartCatalog().createProject(input).generate(projectDir);
}
private Path getProjectWithRealDataDir(Language language) throws IOException {
final Path dir = targetDir.resolve("real-data").resolve(language.key());
generateRealDataProjectIfNeeded(dir, language);
return dir;
}
private Path getProjectWithMockedDataDir(Language language) throws IOException {
final Path dir = targetDir.resolve("mocked-data").resolve(language.key());
generateMockedDataProjectIfNeeded(dir, language);
return dir;
}
@Override
public void afterAll(ExtensionContext extensionContext) throws Exception {
if (enableRegistryClient) {
disableRegistryClientTestConfig();
}
}
protected List getCodestartsResourceLoaders() {
return codestartLoadersBuilder()
.catalog(getExtensionsCatalog())
.addExtraCodestartsArtifactCoords(artifacts)
.build();
}
@Override
public void afterEach(ExtensionContext extensionContext) throws Exception {
currentTestContext.set(null);
}
@Override
public void beforeEach(ExtensionContext extensionContext) throws Exception {
currentTestContext.set(extensionContext);
}
private String getSourceFileExtension(Language language) {
return Language.KOTLIN.equals(language) ? ".kt" : "." + language.key();
}
}