Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added unit test to compile add generated class. #513

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions avro-builder/tests/tests-allavro/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ dependencies {
exclude group: "org.slf4j"
}

testImplementation project(":test-common")

avro15 "org.apache.avro:avro:1.5.4"
avro15 "org.apache.avro:avro-compiler:1.5.4"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@
import com.linkedin.avroutil1.compatibility.RandomRecordGenerator;
import com.linkedin.avroutil1.compatibility.RecordGenerationConfig;
import com.linkedin.avroutil1.compatibility.StringConverterUtil;
import com.linkedin.avroutil1.testcommon.CommonCompilerHelper;
import java.io.File;
import java.io.FilenameFilter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -1829,6 +1833,29 @@ public void testNewBuilder() throws Exception {
compareIndexedRecords(instance, builder.build());
}

@DataProvider
private Object[][] testGeneratedCompilationProvider(){
String projectPath = System.getProperty("user.dir");
List<String> list = Arrays.stream(new File(projectPath + "/../").list(new FilenameFilter() {
@Override
public boolean accept(File current, String name) {
return name.matches("codegen-[\\w\\-]+") && new File(current, name).isDirectory();
}
})).map(dir -> projectPath + "/../" + dir + "/build/generated/sources/avro").collect(Collectors.toList());

Object[][] res = new Object[list.size()][1];

for(int i = 0; i< list.size(); i++) {
res[i][0] = list.get(i);
}
return res;
}

@Test(dataProvider = "testGeneratedCompilationProvider")
public void testGeneratedCompilation(String genPath) throws Exception {
CommonCompilerHelper.assertCompiles(Paths.get(genPath));
}

@BeforeClass
public void setup() {
System.setProperty("org.apache.avro.specific.use_custom_coders", "true");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import com.linkedin.avroutil1.model.AvroRecordSchema;
import com.linkedin.avroutil1.parser.avsc.AvscParseResult;
import com.linkedin.avroutil1.parser.avsc.AvscParser;
import com.linkedin.avroutil1.testcommon.CommonCompilerHelper;
import com.linkedin.avroutil1.testcommon.TestUtil;
import com.linkedin.avroutil1.testutil.CompilerHelper;
import java.io.IOException;
import javax.tools.JavaFileObject;
import org.testng.Assert;
Expand Down Expand Up @@ -56,7 +56,7 @@ public void testSchema(String path, boolean checkCompiles) throws Exception {
generator.generateSpecificClass(schema, SpecificRecordGenerationConfig.BROAD_COMPATIBILITY);

if (checkCompiles) {
CompilerHelper.assertCompiles(javaFileObject);
CommonCompilerHelper.assertCompiles(javaFileObject);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@

/**
* utility class for dealing with the java compiler in unit tests
* @deprecated Use test-common -> CommonCompilerHelper
*/
@Deprecated
public class CompilerHelper {

public static void assertCompiles(JavaFileObject sourceFile) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
* Copyright 2023 LinkedIn Corp.
* Licensed under the BSD 2-Clause License (the "License").
* See License in the project root for license information.
*/

package com.linkedin.avroutil1.testcommon;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import org.apache.commons.io.IOUtils;
import org.testng.Assert;


/**
* utility class for dealing with the java compiler in unit tests
*/
public class CommonCompilerHelper {

public static void assertCompiles(JavaFileObject sourceFile) throws Exception {
List<JavaFileObject> fileObjects = Arrays.asList(sourceFile);
assertCompiles(fileObjects);
}

public static void assertCompiles(Path sourceRoot) throws Exception {
List<JavaFileObject> fileObjects = listSourceFiles(sourceRoot);
assertCompiles(fileObjects);
}

public static void assertCompiles(List<JavaFileObject> fileObjects) throws Exception {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
ClassFileManager manager = new ClassFileManager(compiler.getStandardFileManager(null, null, null));
CompilationListener listener = new CompilationListener();
JavaCompiler.CompilationTask compilationTask = compiler.getTask(null, manager, listener, null, null, fileObjects);
Boolean success = compilationTask.call();

if (!Boolean.TRUE.equals(success) || !listener.errors.isEmpty()) {
Assert.fail("failed to compile code: " + listener.errors);
}
}

private static List<JavaFileObject> listSourceFiles(Path root) throws IOException {
List<JavaFileObject> fileObjects = new ArrayList<>();
//noinspection Convert2Diamond because java 8 isnt smart enough to figure this out
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (attrs.isRegularFile()) {
fileObjects.add(new JavaSourceFile(file));
}
return FileVisitResult.CONTINUE;
}
});
return fileObjects;
}

private static String summarize(Diagnostic<? extends JavaFileObject> diagnostic) {
StringBuilder sb = new StringBuilder();
sb.append(diagnostic.getKind()).append(": ");
JavaFileObject sourceObject = diagnostic.getSource();
if (sourceObject != null) {
sb.append("file ").append(sourceObject.toString()).append(" ");
}
String message = diagnostic.getMessage(Locale.ROOT);
if (message != null && !message.isEmpty()) {
sb.append(message).append(" ");
}
long line = diagnostic.getLineNumber();
long column = diagnostic.getColumnNumber();
if (line != -1 || column != -1) {
sb.append("at line ").append(line).append(" column ").append(column);
}
return sb.toString().trim();
}

private static class ClassFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
private final Map<String, JavaClassObject> classObjects = new ConcurrentHashMap<>();

ClassFileManager(StandardJavaFileManager m) {
super(m);
}

@Override
public JavaFileObject getJavaFileForOutput(
Location location,
String className,
JavaFileObject.Kind kind,
FileObject sibling
) throws IOException {
if (kind != JavaFileObject.Kind.CLASS) {
throw new UnsupportedOperationException("unhandled kind " + kind);
}
return classObjects.computeIfAbsent(className, s -> new JavaClassObject((JavaFileObject) sibling, className));
}

}

private static class JavaSourceFile extends SimpleJavaFileObject {
private final Path file;

JavaSourceFile(Path file) {
super(file.toUri(), Kind.SOURCE);
this.file = file;
}

@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return IOUtils.toString(file.toUri(), StandardCharsets.UTF_8);
}

@Override
public String toString() {
return file.getFileName().toString();
}
}

private static class JavaClassObject extends SimpleJavaFileObject {
private final JavaFileObject sourceFile;
private final String fqcn;
private volatile ByteArrayOutputStream outputStream;

public JavaClassObject(JavaFileObject sourceFile, String fqcn) {
super(URI.create("mem:///" + fqcn.replace('.', '/')), Kind.CLASS);
this.sourceFile = sourceFile;
this.fqcn = fqcn;
}

@Override
public synchronized OutputStream openOutputStream() {
if (outputStream == null) {
outputStream = new ByteArrayOutputStream();
}
return outputStream;
}
}

private static class CompilationListener implements DiagnosticListener<JavaFileObject> {
private final List<String> warnings = new ArrayList<>();
private final List<String> errors = new ArrayList<>();

@Override
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
Diagnostic.Kind kind = diagnostic.getKind();
String desc = summarize(diagnostic);
switch (kind) {
case NOTE:
case WARNING:
case MANDATORY_WARNING:
warnings.add(desc);
break;
case ERROR:
case OTHER:
errors.add(desc);
break;
default:
throw new IllegalStateException("unhandled " + kind);
}
}
}
}
Loading