Skip to content

Adds test automation and fixes misc. readme issues #7

Adds test automation and fixes misc. readme issues

Adds test automation and fixes misc. readme issues #7

name: Validation Tests
on:
# Run every Monday at 8:00 AM UTC (early Monday morning)
schedule:
- cron: '0 8 * * 1'
# Run on pull requests
pull_request:
branches:
- main
- master
# Allow manual trigger
workflow_dispatch:
permissions:
contents: read
pull-requests: write
issues: write
jobs:
dotnet-tests:
name: .NET Tests
runs-on: ubuntu-latest
outputs:
status: ${{ steps.test.outcome }}
results: ${{ steps.test-details.outputs.results }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Run .NET tests
id: test
continue-on-error: true
working-directory: ./libraryValidations/Dotnet
run: dotnet test --logger trx --results-directory ./TestResults
- name: Parse .NET test results
id: test-details
if: always()
working-directory: ./libraryValidations/Dotnet
run: |
echo "=== Listing all files in TestResults directory ==="
find ./TestResults -type f 2>/dev/null || echo "No TestResults directory"
echo "=========================================="
echo 'results<<EOF' >> $GITHUB_OUTPUT
TRX_FILE=$(find ./TestResults -name "*.trx" -type f 2>/dev/null | head -1)
if [ ! -z "$TRX_FILE" ]; then
echo "Found TRX file: $TRX_FILE"
export TRX_FILE
python3 <<'PYTHON'
import xml.etree.ElementTree as ET
import json
import os
trx_file = os.environ.get('TRX_FILE')
if trx_file:
tree = ET.parse(trx_file)
root = tree.getroot()
ns = {'ns': 'http://microsoft.com/schemas/VisualStudio/TeamTest/2010'}
results = {}
for test in root.findall('.//ns:UnitTestResult', ns):
test_name = test.get('testName')
outcome = test.get('outcome')
results[test_name] = '✅' if outcome == 'Passed' else '❌'
print(json.dumps(results))
else:
print("{}")
PYTHON
else
echo "No TRX file found"
echo "{}"
fi
echo 'EOF' >> $GITHUB_OUTPUT
python-tests:
name: Python Tests
runs-on: ubuntu-latest
outputs:
status: ${{ steps.test.outcome }}
results: ${{ steps.test-details.outputs.results }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
working-directory: ./libraryValidations/Python
run: |
pip install -r requirements.txt
- name: Run Python tests
id: test
continue-on-error: true
working-directory: ./libraryValidations/Python
run: |
pytest test_json_validations.py --junitxml=results.xml --verbose || true
if [ ! -z "${{ secrets.APP_CONFIG_VALIDATION_CONNECTION_STRING }}" ]; then
pytest test_json_validations_with_provider.py --junitxml=results_provider.xml --verbose || true
fi
- name: Parse Python test results
id: test-details
if: always()
working-directory: ./libraryValidations/Python
run: |
echo "=== Listing Python test output files ==="
ls -la *.xml 2>/dev/null || echo "No XML files found"
echo "=========================================="
echo 'results<<EOF' >> $GITHUB_OUTPUT
python3 <<'PYTHON'
import xml.etree.ElementTree as ET
import json
import os
results = {}
for xml_file in ['results.xml', 'results_provider.xml']:
if os.path.exists(xml_file):
print(f"Parsing {xml_file}", flush=True)
tree = ET.parse(xml_file)
root = tree.getroot()
for testcase in root.findall('.//testcase'):
test_name = testcase.get('name')
failed = testcase.find('failure') is not None or testcase.find('error') is not None
results[test_name] = '❌' if failed else '✅'
print(json.dumps(results), flush=True)
PYTHON
echo 'EOF' >> $GITHUB_OUTPUT
javascript-tests:
name: JavaScript Tests
runs-on: ubuntu-latest
outputs:
status: ${{ steps.test.outcome }}
results: ${{ steps.test-details.outputs.results }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
working-directory: ./libraryValidations/JavaScript
run: npm install
- name: Build
working-directory: ./libraryValidations/JavaScript
run: npm run build
- name: Run JavaScript tests
id: test
continue-on-error: true
working-directory: ./libraryValidations/JavaScript
run: |
npm install --save-dev jest-junit
npx jest --reporters=jest-junit --testResultsProcessor=jest-junit || true
- name: Parse JavaScript test results
id: test-details
if: always()
working-directory: ./libraryValidations/JavaScript
run: |
echo "=== Listing JavaScript test output files ==="
ls -la junit.xml 2>/dev/null || echo "No junit.xml found"
find . -maxdepth 2 -name "*.xml" -type f 2>/dev/null | head -10
echo "=========================================="
echo 'results<<EOF' >> $GITHUB_OUTPUT
XML_FILE=""
if [ -f "junit.xml" ]; then
XML_FILE="junit.xml"
elif [ -f "test-results/junit.xml" ]; then
XML_FILE="test-results/junit.xml"
fi
if [ ! -z "$XML_FILE" ]; then
echo "Parsing JavaScript $XML_FILE"
export XML_FILE
python3 <<'PYTHON'
import xml.etree.ElementTree as ET
import json
import os
xml_file = os.environ.get('XML_FILE')
if xml_file and os.path.exists(xml_file):
tree = ET.parse(xml_file)
root = tree.getroot()
results = {}
for testcase in root.findall('.//testcase'):
test_name = testcase.get('name')
failed = testcase.find('failure') is not None or testcase.find('error') is not None
results[test_name] = '❌' if failed else '✅'
print(json.dumps(results), flush=True)
else:
print("{}")
PYTHON
else
echo "No JavaScript test results XML found"
echo "{}"
fi
echo 'EOF' >> $GITHUB_OUTPUT
spring-tests:
name: Spring Tests
runs-on: ubuntu-latest
outputs:
status: ${{ steps.test.outcome }}
results: ${{ steps.test-details.outputs.results }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Run Spring tests
id: test
continue-on-error: true
working-directory: ./libraryValidations/Spring/validation-tests
run: mvn test
- name: Parse Spring test results
id: test-details
if: always()
working-directory: ./libraryValidations/Spring/validation-tests
run: |
echo "=== Listing Spring test output files ==="
ls -la target/surefire-reports/ 2>/dev/null || echo "No surefire-reports directory"
find target -name "*.xml" -type f 2>/dev/null | head -10
echo "=========================================="
echo 'results<<EOF' >> $GITHUB_OUTPUT
python3 <<'PYTHON'
import xml.etree.ElementTree as ET
import json
import os
import glob
results = {}
xml_files = glob.glob('target/surefire-reports/TEST-*.xml')
print(f"Found {len(xml_files)} Spring test result files", flush=True)
for xml_file in xml_files:
print(f"Parsing {xml_file}", flush=True)
tree = ET.parse(xml_file)
root = tree.getroot()
for testcase in root.findall('.//testcase'):
test_name = testcase.get('name')
failed = testcase.find('failure') is not None or testcase.find('error') is not None
results[test_name] = '❌' if failed else '✅'
print(json.dumps(results), flush=True)
PYTHON
echo 'EOF' >> $GITHUB_OUTPUT
test-summary:
name: Test Summary
runs-on: ubuntu-latest
needs: [dotnet-tests, python-tests, javascript-tests, spring-tests]
if: always()
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Generate test matrix
id: matrix
env:
DOTNET_RESULTS: ${{ needs.dotnet-tests.outputs.results }}
PYTHON_RESULTS: ${{ needs.python-tests.outputs.results }}
JAVASCRIPT_RESULTS: ${{ needs.javascript-tests.outputs.results }}
SPRING_RESULTS: ${{ needs.spring-tests.outputs.results }}
run: |
python3 <<'PYTHON'
import json
import os
# Debug: print raw results
print("=== Debug: Raw Results ===")
print(f"DOTNET: {os.environ.get('DOTNET_RESULTS', 'EMPTY')}")
print(f"PYTHON: {os.environ.get('PYTHON_RESULTS', 'EMPTY')}")
print(f"JAVASCRIPT: {os.environ.get('JAVASCRIPT_RESULTS', 'EMPTY')}")
print(f"SPRING: {os.environ.get('SPRING_RESULTS', 'EMPTY')}")
print("========================\n")
# Parse results from each language
try:
dotnet_results = json.loads(os.environ.get('DOTNET_RESULTS', '{}'))
except:
dotnet_results = {}
try:
python_results = json.loads(os.environ.get('PYTHON_RESULTS', '{}'))
except:
python_results = {}
try:
javascript_results = json.loads(os.environ.get('JAVASCRIPT_RESULTS', '{}'))
except:
javascript_results = {}
try:
spring_results = json.loads(os.environ.get('SPRING_RESULTS', '{}'))
except:
spring_results = {}
# Collect all unique test names across all languages
all_tests = set()
all_tests.update(dotnet_results.keys())
all_tests.update(python_results.keys())
all_tests.update(javascript_results.keys())
all_tests.update(spring_results.keys())
# Sort tests for consistent output
sorted_tests = sorted(all_tests)
print(f"Found {len(sorted_tests)} unique tests")
# Generate markdown table
with open('summary.md', 'w') as f:
f.write("## 🧪 Validation Test Results\n\n")
if not sorted_tests:
f.write("⚠️ No test results found. Check individual job outputs for details.\n\n")
else:
f.write("| Test Name | .NET | Python | JavaScript | Spring |\n")
f.write("|-----------|------|--------|------------|--------|\n")
for test in sorted_tests:
# Get result for each language, default to ⚠️ if not found
dotnet = dotnet_results.get(test, '⚠️')
python = python_results.get(test, '⚠️')
javascript = javascript_results.get(test, '⚠️')
spring = spring_results.get(test, '⚠️')
f.write(f"| {test} | {dotnet} | {python} | {javascript} | {spring} |\n")
f.write(f"\n_Workflow run: ${{ github.run_id }}_\n")
# Print to console
with open('summary.md', 'r') as f:
print(f.read())
PYTHON
cat summary.md >> $GITHUB_STEP_SUMMARY
- name: Comment on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const summary = fs.readFileSync('summary.md', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: summary
});