/* * Copyright 2020 ETSI * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package fr.mines_stetienne.ci.saref.checkers; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystems; import java.nio.file.PathMatcher; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.Resource; import org.apache.jena.vocabulary.RDF; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import com.opencsv.CSVParser; import com.opencsv.CSVParserBuilder; import com.opencsv.CSVReader; import com.opencsv.CSVReaderBuilder; import fr.mines_stetienne.ci.saref.SAREFPipelineException; import fr.mines_stetienne.ci.saref.managers.GenerateRDFaManager; import fr.mines_stetienne.ci.saref.managers.RepositoryManager; import fr.mines_stetienne.ci.saref.managers.ThemisManager; import fr.mines_stetienne.ci.saref.utils.Languages; import fr.mines_stetienne.ci.saref.vocabs.VTC; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; /** * Checks TS 103 673 Clause 9.5: Ontology tests * */ public class Clause_9_5_Checker extends AbstractClauseChecker { private static final PathMatcher csvMatcher = FileSystems.getDefault().getPathMatcher("glob:**/*.csv"); private static final String FIRST_LINE = "Id;Requirement;Category;Test"; private static enum MESSAGE { missing, ioexception, line, themis, themisError; } /** * @param errorLogger * @param config */ public Clause_9_5_Checker(RepositoryManager repositoryManager) { super(repositoryManager, Clause_9_5_Checker.class); } @Override public void checkClause() throws SAREFPipelineException { File dir = new File(repository.getDirectory(), "tests"); if (!dir.isDirectory()) { return; } try { File file = new File(dir, "tests.csv"); if (!file.exists()) { logError(getMessage(MESSAGE.missing)); return; } List lines = FileUtils.readLines(file, StandardCharsets.UTF_8); if (lines.size() < 1 || !lines.get(0).equals(FIRST_LINE)) { logError(getMessage(MESSAGE.line)); return; } readTests(); // generates the RDF model for the tests try { callThemis(); // uses the RDF model for the tests and sends it to ThemisOWL profile, consistency, lack of pitfalls and class satisfiability testsRDFaGenerator(); // this generates the html file with rdfa embedded. } catch (Exception ex) { logWarning(getMessage(MESSAGE.themis), ex); } } catch (IOException ex) { logError(getMessage(MESSAGE.ioexception)); } } public void readTests() throws SAREFPipelineException { Model requirements = version.getRequirements(); File file = new File(repository.getDirectory(), "tests/tests.csv"); CSVParser parser = new CSVParserBuilder().withSeparator(';').withQuoteChar('"').build(); try (FileReader filereader = new FileReader(file); CSVReader csvReader = new CSVReaderBuilder(filereader).withCSVParser(parser).build()) { csvReader.forEach(row -> { String id = row[0]; // WATR-TEST-17 Resource testResource = requirements.getResource(String.format("%stests#%s", version.getIRI(), id)); String requirementId = row[1]; // WATR-9 Resource requirementResource = requirements .getResource(String.format("%srequirements#", version.getIRI(), requirementId)); String category = row[2]; // Water meter String test = row[3]; // WaterMeter hasManufacturer Literal requirements.add(testResource, RDF.type, VTC.TestCaseDesign); requirements.add(testResource, VTC.testId, id); requirements.add(testResource, VTC.comesFromRequirement, requirementResource); requirements.add(testResource, VTC.desiredBehaviour, test); }); } catch (Exception e) { logWarning(getMessage(MESSAGE.ioexception), e); } } public void callThemis() throws SAREFPipelineException { StringWriter versionRDFXML = new StringWriter(); version.getModel().write(versionRDFXML); StringWriter requirementsRDFXML = new StringWriter(); version.getRequirements().write(requirementsRDFXML); OkHttpClient httpClient = new OkHttpClient().newBuilder().build(); MediaType mediaType = MediaType.parse("application/json"); String jsonRequest = "{\"ontologiesCode\":[\"" + versionRDFXML.toString().replaceAll("\\\"", "\\\\\"").replaceAll("\"", "\\\"").replaceAll("\t", " ") + "\"]," + "\"testfile\":[\"" + requirementsRDFXML.toString().replaceAll("\\\"", "\\\\\"") .replaceAll("\"", "\\\"").replaceAll("\t", " ") + "\"]," + "\"format\":\"junit\"}"; RequestBody body = RequestBody.create(jsonRequest, mediaType); Request request = new Request.Builder().url("http://themis.linkeddata.es/rest/api/results").method("POST", body) .addHeader("accept", "application/json").addHeader("Content-Type", "application/json").build(); try (Response response = httpClient.newCall(request).execute();) { if (response.code() != 200) { throw new SAREFPipelineException("response", "Unexpected response code " + response.code()); } String responseBody = response.body().string(); Document doc = ThemisManager.convertStringToXMLDocument(responseBody); NodeList nodeList = doc.getElementsByTagName("testcase"); ArrayList themisErrors = new ArrayList(); for (int temp = 0; temp < nodeList.getLength(); temp++) { org.w3c.dom.Node node = nodeList.item(temp); if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) { Element element = (Element) node; if (((Element) node).getElementsByTagName("error").item(0) != null) { String id = element.getAttributeNode("id").toString(); String name = element.getAttributeNode("name").toString(); String message = ((Element) node).getElementsByTagName("error").item(0).getAttributes().getNamedItem("message").toString(); String themisError = String.format("%s, %s, %s", id, name, message); themisErrors.add(themisError); } } } if (!themisErrors.isEmpty()) { String data = themisErrors.stream().map(e -> e.toString()) .collect(Collectors.joining("\n- ", "\n\n- ", "\n\n")); logWarning(getMessage(MESSAGE.themis, data)); } } catch (IOException | SAREFPipelineException e) { logWarning(getMessage(MESSAGE.themisError), e); } } private void testsRDFaGenerator() throws SAREFPipelineException, IOException { if (pipeline.ignoreSite) { return; } String categoryChanger = ""; String repoName = project.getName(); String href = project.getNamespace(); File testCSV = new File(repository.getDirectory(), "/tests/tests.csv"); File versionSite = new File(siteManager.siteDir, version.getVersionPath()); FileUtils.forceMkdir(versionSite); File testHTML = new File(versionSite, "tests.html"); GenerateRDFaManager.GenerateRDFa(categoryChanger, repoName, href, testCSV, testHTML, "tests"); Model model = version.getRequirements(); for (Languages l : Languages.values()) { String fileName = String.format("tests.%s", l.getExt()); File file = new File(versionSite, fileName); try (FileOutputStream fos = new FileOutputStream(file)) { model.write(fos, l.getLang()); } catch (IOException ex) { String msg = getMessage(MESSAGE.ioexception, ex); errorLogger.warn(msg, ex); } } } }