Skip to content

Commit

Permalink
Merge pull request #1692 from lnash94/error-message-bto
Browse files Browse the repository at this point in the history
[master] Fix providing error message for openapi spec generation when bal service has compilation issues
  • Loading branch information
lnash94 committed Apr 20, 2024
2 parents 1a86975 + ac08ab9 commit f304d88
Show file tree
Hide file tree
Showing 18 changed files with 347 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import io.ballerina.tools.diagnostics.DiagnosticSeverity;

import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand Down Expand Up @@ -68,6 +69,11 @@
* @since 2.0.0
*/
public class HttpServiceAnalysisTask implements AnalysisTask<SyntaxNodeAnalysisContext> {
static boolean isErrorPrinted = false;

static void setIsWarningPrinted() {
HttpServiceAnalysisTask.isErrorPrinted = true;
}

@Override
public void perform(SyntaxNodeAnalysisContext context) {
Expand All @@ -83,8 +89,18 @@ public void perform(SyntaxNodeAnalysisContext context) {
boolean hasErrors = context.compilation().diagnosticResult()
.diagnostics().stream()
.anyMatch(d -> DiagnosticSeverity.ERROR.equals(d.diagnosticInfo().severity()));

// if there are any compilation errors, do not proceed
if (!isErrorPrinted && hasErrors) {
setIsWarningPrinted();
PrintStream outStream = System.out;
outStream.println("openapi contract generation is skipped because of the following compilation " +
"error(s) in the ballerina package:");
return;
}

if (hasErrors) {
// if there are any compilation errors, do not proceed

return;
}
Path outPath = project.targetDir();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,12 @@ public void generateOAS3DefinitionsAllService(Path servicePath, Path outPath, St
.diagnostics().stream()
.anyMatch(d -> DiagnosticSeverity.ERROR.equals(d.diagnosticInfo().severity()));
if (hasCompilationErrors || hasErrorsFromCodeGenAndModify) {
// if there are any compilation errors, do not proceed
// if there are any compilation errors, do not proceed and those diagnostic will display to user
outStream.println("openapi contract generation is skipped because of the Ballerina file/package has the" +
" following compilation error(s):");
compilation.diagnosticResult().diagnostics().forEach(diagnostic -> {
outStream.println(diagnostic.toString());
});
return;
}
semanticModel = compilation.getSemanticModel(docId.moduleId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
package io.ballerina.openapi;

import org.apache.commons.lang3.StringUtils;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterTest;
Expand All @@ -30,9 +31,14 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static io.ballerina.openapi.TestUtil.OUT;
import static io.ballerina.openapi.TestUtil.TEST_DISTRIBUTION_PATH;
import static io.ballerina.openapi.extension.build.BuildExtensionTests.DISTRIBUTION_FILE_NAME;

/**
* This is abstract class for containing the main common test methods for the other subclasses.
*/
Expand Down Expand Up @@ -95,4 +101,17 @@ public void compareGeneratedSyntaxTreewithExpectedSyntaxTree(String generated, S
expectedBallerinaContent = (expectedBallerinaContent.trim()).replaceAll("\\s+", "");
Assert.assertTrue(generatedFile.contains(expectedBallerinaContent));
}

public Process getProcess(List<String> buildArgs, Path testResourcePath) throws IOException {
String balFile = "bal";
if (System.getProperty("os.name").startsWith("Windows")) {
balFile = "bal.bat";
}
buildArgs.add(0, TEST_DISTRIBUTION_PATH.resolve(DISTRIBUTION_FILE_NAME).resolve("bin")
.resolve(balFile).toString());
OUT.println("Executing: " + StringUtils.join(buildArgs, ' '));
ProcessBuilder pb = new ProcessBuilder(buildArgs);
pb.directory(testResourcePath.toFile());
return pb.start();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package io.ballerina.openapi.cmd;

import io.ballerina.openapi.OpenAPITest;
import io.ballerina.openapi.TestUtil;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.List;

import static io.ballerina.openapi.TestUtil.DISTRIBUTIONS_DIR;
import static io.ballerina.openapi.TestUtil.RESOURCES_PATH;
import static io.ballerina.openapi.TestUtil.assertOnErrorStream;

/**
* This class contains all the ballerina to OpenAPI command related negative tests.
*/
public class BallerinaToOpenAPICLINegativeTests extends OpenAPITest {
public static final String DISTRIBUTION_FILE_NAME = DISTRIBUTIONS_DIR.toString();
public static final Path TEST_RESOURCE = Paths.get(RESOURCES_PATH.toString() + "/ballerina_sources");

@BeforeClass
public void setupDistributions() throws IOException {
TestUtil.cleanDistribution();
}

@Test(description = "Test for given bal service file contains compilation issues")
public void testForGivenBalServiceHasCompilationIssue() throws IOException, InterruptedException {
String balFilePath = "bal_service_has_compilation_issue/service.bal";
List<String> buildArgs = new LinkedList<>();
buildArgs.add(0, "openapi");
buildArgs.add("-i");
buildArgs.add(balFilePath);
buildArgs.add("-o");
buildArgs.add(tmpDir.toString());

Process process = getProcess(buildArgs, TEST_RESOURCE);

String out = "openapi contract generation is skipped because of the Ballerina file/package has the " +
" following compilation error(s):\n" +
"ERROR [service.bal:(11:1,11:2)] invalid token '}'";
//Thread for wait out put generate
Thread.sleep(5000);
// compare generated file has not included constraint annotation for scenario record field.
Assert.assertFalse(Files.exists(TEST_RESOURCE.resolve("cpi_openapi.yaml")));
process.waitFor();
assertOnErrorStream(process, out);
}

@AfterClass
public void cleanUp() throws IOException {
TestUtil.cleanDistribution();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 Inc. licenses this file to you under the Apache License,
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
Expand All @@ -17,7 +17,9 @@
*/
package io.ballerina.openapi.cmd;

import io.ballerina.openapi.OpenAPITest;
import io.ballerina.openapi.TestUtil;
import org.apache.commons.lang3.StringUtils;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
Expand All @@ -29,18 +31,18 @@
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static io.ballerina.openapi.TestUtil.DISTRIBUTIONS_DIR;
import static io.ballerina.openapi.TestUtil.OUT;
import static io.ballerina.openapi.TestUtil.RESOURCES_PATH;
import static io.ballerina.openapi.TestUtil.TEST_DISTRIBUTION_PATH;

/**
* This {@code BallerinaToOpenAPITests} contains all the ballerina to openapi command with compiler annotation.
*/
public class BallerinaToOpenAPITests {
public class BallerinaToOpenAPITests extends OpenAPITest {
public static final String DISTRIBUTION_FILE_NAME = DISTRIBUTIONS_DIR.toString();
public static final Path TEST_RESOURCE = Paths.get(RESOURCES_PATH.toString() + "/ballerina_sources");

Expand Down Expand Up @@ -149,20 +151,6 @@ public void cleanUp() throws IOException {
TestUtil.cleanDistribution();
}

//Replace contract file path in generated service file with common URL.
public String replaceContractPath(Stream<String> expectedServiceLines, String expectedService,
String generatedService) {

Pattern pattern = Pattern.compile("\\bcontract\\b: \"(.*?)\"");
Matcher matcher = pattern.matcher(generatedService);
matcher.find();
String contractPath = "contract: " + "\"" + matcher.group(1) + "\"";
expectedService = expectedService.replaceAll("\\bcontract\\b: \"(.*?)\"",
Matcher.quoteReplacement(contractPath));
expectedServiceLines.close();
return expectedService;
}

private String getStringFromGivenBalFile(Path expectedServiceFile) throws IOException {
Stream<String> expectedServiceLines = Files.lines(expectedServiceFile);
String expectedServiceContent = expectedServiceLines.collect(Collectors.joining(System.lineSeparator()));
Expand All @@ -181,4 +169,25 @@ private void executeCommand(String resourcePath, String generatedFile, String ex
String expectedYaml = getStringFromGivenBalFile(TEST_RESOURCE.resolve(expectedPath));
Assert.assertEquals(expectedYaml, generatedOpenAPI);
}

public Process getProcessForOpenAPISpecGeneration(String ballerinaFilePath) throws IOException {
List<String> buildArgs = new LinkedList<>();
buildArgs.add(0, "openapi");
buildArgs.add("-i");
buildArgs.add(ballerinaFilePath);
buildArgs.add("-o");
buildArgs.add(tmpDir.toString());

String balFile = "bal";

if (System.getProperty("os.name").startsWith("Windows")) {
balFile = "bal.bat";
}
buildArgs.add(0, TEST_DISTRIBUTION_PATH.resolve(DISTRIBUTION_FILE_NAME).resolve("bin")
.resolve(balFile).toString());
OUT.println("Executing: " + StringUtils.join(buildArgs, ' '));
ProcessBuilder pb = new ProcessBuilder(buildArgs);
pb.directory(TEST_RESOURCE.toFile());
return pb.start();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package io.ballerina.openapi.extension.build;

import io.ballerina.openapi.OpenAPITest;
import io.ballerina.openapi.TestUtil;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.List;

import static io.ballerina.openapi.TestUtil.DISTRIBUTIONS_DIR;
import static io.ballerina.openapi.TestUtil.RESOURCE;
import static io.ballerina.openapi.TestUtil.RESOURCES_PATH;
import static io.ballerina.openapi.TestUtil.assertOnErrorStream;

/**
* These negative tests are related to the `--export-openapi` flag for `bal build` command.
*/
public class BuildExtensionNegativeTests extends OpenAPITest {
public static final String DISTRIBUTION_FILE_NAME = DISTRIBUTIONS_DIR.toString();
public static final Path TEST_RESOURCE = Paths.get(RESOURCES_PATH.toString() + "/build");

@BeforeClass
public void setupDistributions() throws IOException {
TestUtil.cleanDistribution();
}

//TODO: Fix the test case , verified manually
@Test(description = "Ballerina package has compilation error", enabled = false)
public void packageHasCompilationErrors() throws IOException, InterruptedException {
List<String> buildArgs = new LinkedList<>();
buildArgs.add(0, "build");
buildArgs.add("--export-openapi");
Process process = getProcess(buildArgs, TEST_RESOURCE.resolve("package_with_compilation_issue"));
String out = "openapi contract generation is skipped because of the following compilation error(s) in " +
"the ballerina package:\n" +
" ERROR [service.bal:(10:1,10:2)] invalid token '}'";
// compare generated file has not included constraint annotation for scenario record field.
Assert.assertFalse(Files.exists(RESOURCE.resolve("\"build/package_with_compilation_issue/target" +
"/openapi/")));
process.waitFor();
assertOnErrorStream(process, out);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
/**
* These tests are for capture the `--export-openapi` flag in distribution.
*/
public class BuildExtensionTests {
public class BuildExtensionTests {
public static final String DISTRIBUTION_FILE_NAME = DISTRIBUTIONS_DIR.toString();
public static final Path TEST_RESOURCE = Paths.get(RESOURCES_PATH.toString() + "/build");

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
org = "openapi_gen_test"
name = "compilation_issue"
version = "0.1.0"

[build-options]
observabilityIncluded = true

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
openapi: 3.0.1
info:
title: Mock Yaml
version: 2.0.0
servers:
- url: "{server}:{port}/"
variables:
server:
default: http://localhost
port:
default: "9090"
paths:
/greeting:
get:
operationId: getGreeting
responses:
"200":
description: Ok
content:
text/plain:
schema:
type: string
components: {}
Loading

0 comments on commit f304d88

Please sign in to comment.