Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
08a05b8
Improve coverage module for TCK
NicoLaval Apr 14, 2025
412f2c4
Update pom.xml
NicoLaval Apr 14, 2025
7395e5c
Improve CSVDataset
NicoLaval Apr 14, 2025
36c9ce7
Handle more types in ComponentDeserializer
NicoLaval Apr 14, 2025
e26e703
Add VIRALATTRIBUTE
NicoLaval Apr 14, 2025
79989ce
Merge pull request #387 from Making-Sense-Info/Feat/TCK
NicoLaval Apr 14, 2025
0857b6b
Improve TCK
NicoLaval Apr 14, 2025
add7f70
Use dynamic test
hadrienk Apr 18, 2025
4d5b072
Implement a first eval test
hadrienk Apr 18, 2025
7eef39e
Add Spark mode to engine to run TCK tests
NicoLaval Apr 21, 2025
406d2b1
Create coverage README
NicoLaval Apr 21, 2025
ab463ec
Run TCK tests only if input zip is provided
NicoLaval Apr 24, 2025
2e19b30
Create TCK workflow
NicoLaval Apr 24, 2025
ff2c699
Update tck-vtl-tf.yml
NicoLaval Apr 24, 2025
caa7d58
Update tck-vtl-tf.yml
NicoLaval Apr 24, 2025
cca8f47
Fix coverage input zip path
NicoLaval Apr 24, 2025
2ac1470
Improve runTCK
NicoLaval Apr 24, 2025
107c7f4
Update TCKTest.java
NicoLaval Apr 27, 2025
ad8fb8d
Fix coverage pom
NicoLaval Apr 28, 2025
be67791
Update TCKTest.java
NicoLaval Apr 28, 2025
3370605
Use junit-bom
NicoLaval Apr 28, 2025
adf847f
Update tck-vtl-tf.yml
NicoLaval Apr 28, 2025
cc2878e
Try an other reporter for TCK
NicoLaval Apr 28, 2025
fcb85cd
Restore dorny/test-reporter for TCK
NicoLaval Apr 28, 2025
dba6b15
Update tck-vtl-tf.yml
NicoLaval Apr 28, 2025
1c1adaf
Update pom.xml
NicoLaval Apr 28, 2025
11e9f4b
Update coverage/README.md
NicoLaval May 13, 2025
f74af7c
Merge branch 'develop' into Feat/TCK
NicoLaval May 13, 2025
d9f26ef
Fix import issue
NicoLaval May 13, 2025
9b4b166
Fix maven-surefire-plugin issues
NicoLaval May 13, 2025
d706790
Fix CSVDataset constructor
NicoLaval May 13, 2025
22c8761
Update tck-vtl-tf.yml
NicoLaval May 13, 2025
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
70 changes: 70 additions & 0 deletions .github/workflows/tck-vtl-tf.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Run VTL TF TCK

on:
push:
branches: [ '**' ]
pull_request:
branches: [ master, develop ]

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout main project
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Clone vtl spec repo (branch fix/tck-2.1)
run: git clone --branch fix/tck-2.1 https://github.com/sdmx-twg/vtl.git

- name: Install Python 3
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Run TCK generator script
run: |
DOC_VERSION=v2.1 python3 vtl/scripts/generate_tck_files.py

- name: Move generated TCK zip to resources
run: |
mkdir -p coverage/src/main/resources
mv vtl/tck/v2.1.zip coverage/src/main/resources/

- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'

- uses: s4u/maven-settings-action@v3.0.0
with:
githubServer: false
servers: |
[{
"id": "Github",
"username": "${{ secrets.GH_PACKAGES_USERNAME }}",
"password": "${{ secrets.GH_PACKAGES_PASSWORD }}"
}]

- name: Cache Maven packages
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-

- name: Build and run tests
run: mvn clean test --batch-mode

- name: Publish JUnit test results
uses: dorny/test-reporter@v2
if: always()
with:
name: JUnit Test Report
path: coverage/target/surefire-reports/*.xml
reporter: java-junit
fail-on-error: 'false'
32 changes: 32 additions & 0 deletions coverage/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# 📊 Coverage

## 🧪 TCK (Technology Compatibility Kit)

We are working on a suite of compatibility tests to ensure conformance with the VTL specification across implementations.

🛠️ _Work in Progress_

### Issues/discussions to follow

- [junit5](https://github.com/junit-team/junit5/discussions/4504#discussioncomment-13046641)
- [surefire](https://github.com/apache/maven-surefire/issues/835)

### Temporary run procedure

While [TCK](https://github.com/sdmx-twg/vtl/pull/565) is not automated in the VTL TF repository, we have to build the input source manually.

```shell
git clone https://github.com/sdmx-twg/vtl.git
cd vtl/scripts
DOC_VERSION=v2.1 python3 generate_tck_files.py
```

A zip will be created at `tck/v2.1.zip`.

Move it in Trevas resources:

```shell
mv vtl/tck/v2.1.zip trevas/coverage/src/main/resources
```

You are now able to run `TCKTest`.
18 changes: 18 additions & 0 deletions coverage/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,27 @@
<artifactId>vtl-spark</artifactId>
<version>1.9.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>fr.insee.trevas</groupId>
<artifactId>vtl-csv</artifactId>
<version>1.9.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.3</version>
<configuration>
<argLine>--add-exports java.base/sun.nio.ch=ALL-UNNAMED</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
Expand Down
139 changes: 139 additions & 0 deletions coverage/src/main/java/fr/insee/vtl/coverage/TCK.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package fr.insee.vtl.coverage;

import com.fasterxml.jackson.databind.ObjectMapper;
import fr.insee.vtl.coverage.model.Folder;
import fr.insee.vtl.coverage.model.Test;
import fr.insee.vtl.coverage.utils.JSONStructureLoader;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class TCK {
private static final ObjectMapper objectMapper = new ObjectMapper();

public static List<Folder> runTCK(InputStream zipInputStream) {
File extractedFolder;
try {
extractedFolder = init(zipInputStream);
} catch (IOException e) {
throw new RuntimeException("Error unzipping input stream", e);
}

try {
return loadInput(extractedFolder);
} catch (Exception e) {
throw new RuntimeException("Error loading input from extracted folder", e);
} finally {
deleteDirectory(extractedFolder);
}
}

public static List<Folder> runTCK(File zipFile) {
try (InputStream in = Files.newInputStream(zipFile.toPath())) {
return runTCK(in);
} catch (IOException e) {
throw new RuntimeException("Error reading zip file: " + zipFile, e);
}
}

public static List<Folder> runTCK(String zipPath) {
return runTCK(new File(zipPath));
}

private static File init(InputStream zipInputStream) throws IOException {
Path tempDir = Files.createTempDirectory("tck-unzip-");
try (ZipInputStream zis = new ZipInputStream(zipInputStream)) {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
Path newPath = zipSlipProtect(entry, tempDir);
if (entry.isDirectory()) {
Files.createDirectories(newPath);
} else {
Files.createDirectories(newPath.getParent());
Files.copy(zis, newPath, StandardCopyOption.REPLACE_EXISTING);
}
}
}
return tempDir.toFile();
}

private static Path zipSlipProtect(ZipEntry entry, Path targetDir) throws IOException {
Path target = targetDir.resolve(entry.getName()).normalize();
if (!target.startsWith(targetDir)) {
throw new IOException("Entry is outside of the target dir: " + entry.getName());
}
return target;
}

private static void deleteDirectory(File dir) {
if (dir.isDirectory()) {
for (File file : Objects.requireNonNull(dir.listFiles())) {
deleteDirectory(file);
}
}
dir.delete();
}

public static List<Folder> loadInput(File path) throws Exception {
List<Folder> folders = new ArrayList<>();
File[] files = path.listFiles();
if (files != null) {
boolean isTestFolder = containsTestFiles(files);

if (isTestFolder) {
Folder folder = new Folder();
folder.setName(path.getName());
Test test = new Test();

for (File file : files) {
switch (file.getName()) {
case "input.json":
test.setInput(JSONStructureLoader.loadDatasetsFromCSV(file));
break;
case "output.json":
test.setOutputs(JSONStructureLoader.loadDatasetsFromCSV(file));
break;
case "transformation.vtl":
String script = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
test.setScript(script);
break;
}
}
folder.setTest(test);
folders.add(folder);
} else {
for (File file : files) {
if (file.isDirectory()) {
Folder folder = new Folder();
folder.setName(file.getName());
folder.setFolders(loadInput(file));
folders.add(folder);
}
}
}
}
return folders;
}

private static boolean containsTestFiles(File[] files) {
Set<String> required = new HashSet<>(Arrays.asList(
"input.json", "output.json", "transformation.vtl"
));
Set<String> found = new HashSet<>();
for (File file : files) {
if (required.contains(file.getName())) {
found.add(file.getName());
}
}
return found.containsAll(required);
}
}
34 changes: 34 additions & 0 deletions coverage/src/main/java/fr/insee/vtl/coverage/model/Folder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package fr.insee.vtl.coverage.model;

import java.util.List;

public class Folder {

private String name;
private List<Folder> folders;
private Test test;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Test getTest() {
return test;
}

public void setTest(Test test) {
this.test = test;
}

public List<Folder> getFolders() {
return folders;
}

public void setFolders(List<Folder> folders) {
this.folders = folders;
}
}
36 changes: 36 additions & 0 deletions coverage/src/main/java/fr/insee/vtl/coverage/model/Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package fr.insee.vtl.coverage.model;

import fr.insee.vtl.model.Dataset;

import java.util.Map;

public class Test {

private String script;
private Map<String, Dataset> input;
private Map<String, Dataset> outputs;

public String getScript() {
return script;
}

public void setScript(String script) {
this.script = script;
}

public Map<String, Dataset> getInput() {
return input;
}

public void setInput(Map<String, Dataset> input) {
this.input = input;
}

public Map<String, Dataset> getOutputs() {
return outputs;
}

public void setOutputs(Map<String, Dataset> outputs) {
this.outputs = outputs;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* This package contains tools for TCK.
*/
package fr.insee.vtl.coverage;
Loading
Loading