From ecec979b3b2d560bd809fe95277c5440d65415b5 Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Mon, 23 Oct 2023 16:32:07 +0200 Subject: [PATCH 01/14] Regression tests --- test/Project.toml | 7 +- test/regressionTests.jl | 150 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 test/regressionTests.jl diff --git a/test/Project.toml b/test/Project.toml index 92f937e..35d05b0 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,6 +1,11 @@ [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" -OMJulia = "0f4fe800-344e-11e9-2949-fb537ad918e1" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[weakdeps] +FMI = "14a09403-18e3-468f-ad8a-74f8dda2d9ac" + +[compat] +FMI = "0.10" diff --git a/test/regressionTests.jl b/test/regressionTests.jl new file mode 100644 index 0000000..11bbdae --- /dev/null +++ b/test/regressionTests.jl @@ -0,0 +1,150 @@ +#= +This file is part of OpenModelica. +Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), +c/o Linköpings universitet, Department of Computer and Information Science, +SE-58183 Linköping, Sweden. + +All rights reserved. + +THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE +GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. +ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES +RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, +ACCORDING TO RECIPIENTS CHOICE. + +The OpenModelica software and the OSMC (Open Source Modelica Consortium) +Public License (OSMC-PL) are obtained from OSMC, either from the above +address, from the URLs: http://www.openmodelica.org or +http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica +distribution. GNU version 3 is obtained from: +http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: +http://www.opensource.org/licenses/BSD-3-Clause. + +This program is distributed WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS +EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE +CONDITIONS OF OSMC-PL. +=# + +import Pkg; Pkg.activate(joinpath(@__DIR__)) # TODO: Remove +using SafeTestsets +using Test +using DataFrames +using CSV + +import OMJulia +import FMI + +""" +Simulate single model to generate a result file. +""" +function testSimulation(omc::OMJulia.OMCSession, className::String) + @info "\tSimulation" + @testset verbose=false failfast=false "Simulation" begin + res = OMJulia.API.simulate(omc, className; outputFormat="csv") + resultFile = res["resultFile"] + + @test isfile(resultFile) + return resultFile + end +end + +""" +Build a FMU for a single model, import the generated FMU, simulate it and compare to given reference results. +""" +function testFmuExport(omc::OMJulia.OMCSession, className::String, referenceResult, recordValues) + local fmuPath + @info "\tFMU Export" + @testset "Export" begin + fmuPath = OMJulia.API.buildModelFMU(omc, className) + @test isfile(fmuPath) + @test splitext(splitpath(fmuPath)[end]) == (className, ".fmu") + end + + @info "\tFMU Import" + @testset "Import" begin + if isfile(fmuPath) + fmu = FMI.fmiLoad(fmuPath) + results = FMI.fmiSimulate(fmu; recordValues = recordValues) + @test true + else + @test false + end + end +end + +""" +Run Simulation and FMU export/import test for all models. +""" +function testModels(omc::OMJulia.OMCSession, models::Vector{S}; libdir) where S<:AbstractString + local resultFile + + for model in models + @testset verbose=false failfast=false "$model" begin + modeldir = joinpath(libdir, model) + mkpath(modeldir) + @info "Testing $model" + OMJulia.API.cd(omc, modeldir) + resultFile = testSimulation(omc, model) + @testset verbose=false failfast=false "FMI" begin + if isfile(resultFile) + recordValues = names(CSV.read(resultFile, DataFrame))[2:end] + testFmuExport(omc, model, resultFile, recordValues) + else + @test false + end + end + end + end +end + +""" +Run test for all libraries. +""" +function runTests(libraries::Vector{Tuple{S,S}}, + models::Vector{Vector{S}}; + workdir) where S<:AbstractString + + rm(workdir, recursive=true, force=true) + mkpath(workdir) + + @testset verbose=true failfast=false "OpenModelica" begin + for (i, (library, version)) in enumerate(libraries) + @testset verbose = true failfast=false "$library" begin + libdir = joinpath(workdir, library) + mkpath(libdir) + + omc = OMJulia.OMCSession() + v = OMJulia.API.getVersion(omc) + + @test OMJulia.API.loadModel(omc, library; priorityVersion = [version], requireExactVersion = true) + testModels(omc, models[i]; libdir=libdir) + + OMJulia.quit(omc) + end + end + end + + return +end + +libraries = [ + ("Modelica", "4.0.0") + ("Buildings", "10.0.0") +] + +models = [ + [ + "Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", + "Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", + "Modelica.Fluid.Examples.DrumBoiler.DrumBoiler" + ], + [ + "Buildings.Applications.DataCenters.ChillerCooled.Examples.IntegratedPrimaryLoadSideEconomizer" + ] +] + +# Change working directory +workdir = abspath(joinpath(@__DIR__, "test-regressionTests")) + +runTests(libraries[1:1], models[1:1]; workdir=workdir) From 960ac37dd5686dacf2ce4381f26066b916145a57 Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Tue, 31 Oct 2023 14:51:36 +0100 Subject: [PATCH 02/14] Regression tests and activating API tests --- test/Project.toml | 2 -- test/regressionTests.jl | 32 +++++++++++++++++++++++--------- test/runtests.jl | 1 + 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/test/Project.toml b/test/Project.toml index 35d05b0..d5abc7d 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -3,8 +3,6 @@ CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[weakdeps] FMI = "14a09403-18e3-468f-ad8a-74f8dda2d9ac" [compat] diff --git a/test/regressionTests.jl b/test/regressionTests.jl index 11bbdae..b58e323 100644 --- a/test/regressionTests.jl +++ b/test/regressionTests.jl @@ -26,7 +26,6 @@ EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. =# -import Pkg; Pkg.activate(joinpath(@__DIR__)) # TODO: Remove using SafeTestsets using Test using DataFrames @@ -52,7 +51,7 @@ end """ Build a FMU for a single model, import the generated FMU, simulate it and compare to given reference results. """ -function testFmuExport(omc::OMJulia.OMCSession, className::String, referenceResult, recordValues) +function testFmuExport(omc::OMJulia.OMCSession, className::String, referenceResult, recordValues; workdir::String) local fmuPath @info "\tFMU Export" @testset "Export" begin @@ -65,12 +64,31 @@ function testFmuExport(omc::OMJulia.OMCSession, className::String, referenceResu @testset "Import" begin if isfile(fmuPath) fmu = FMI.fmiLoad(fmuPath) - results = FMI.fmiSimulate(fmu; recordValues = recordValues) + solution = FMI.fmiSimulate(fmu; recordValues = recordValues) + + # Own implementation of CSV export, workaround for https://github.com/ThummeTo/FMI.jl/issues/198 + df = DataFrames.DataFrame(time = solution.values.t) + for i in 1:length(solution.values.saveval[1]) + for var in FMI.fmi2ValueReferenceToString(fmu, solution.valueReferences[i]) + if in(var, recordValues) + df[!, Symbol(var)] = [val[i] for val in solution.values.saveval] + end + end + end + fmiResult = joinpath(workdir, "FMI_results.csv") + CSV.write(fmiResult, df) + + #FMI.fmiSaveSolution(solution, "FMI_results.csv") @test true else @test false end end + + @info "\tCheck Results" + @testset "Verification" begin + @test (true, String[]) == OMJulia.API.diffSimulationResults(omc, "FMI_results.csv", referenceResult, "diff") + end end """ @@ -89,7 +107,7 @@ function testModels(omc::OMJulia.OMCSession, models::Vector{S}; libdir) where S< @testset verbose=false failfast=false "FMI" begin if isfile(resultFile) recordValues = names(CSV.read(resultFile, DataFrame))[2:end] - testFmuExport(omc, model, resultFile, recordValues) + testFmuExport(omc, model, resultFile, recordValues; workdir=modeldir) else @test false end @@ -135,16 +153,12 @@ libraries = [ models = [ [ - "Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", "Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", "Modelica.Fluid.Examples.DrumBoiler.DrumBoiler" ], [ - "Buildings.Applications.DataCenters.ChillerCooled.Examples.IntegratedPrimaryLoadSideEconomizer" + "Buildings.Applications.DataCenters.ChillerCooled.Examples.IntegratedPrimaryLoadSideEconomizer" ] ] -# Change working directory workdir = abspath(joinpath(@__DIR__, "test-regressionTests")) - -runTests(libraries[1:1], models[1:1]; workdir=workdir) diff --git a/test/runtests.jl b/test/runtests.jl index 9904429..6645e83 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -34,4 +34,5 @@ using Test @safetestset "OMCSession" begin include("omcTest.jl") end @safetestset "ModelicaSystem" begin include("modelicaSystemTest.jl") end @safetestset "API" begin include("apiTest.jl") end + @safetestset "Regression" begin include("regressionTests.jl"); runTests(libraries[1:1], models[1:2]; workdir=workdir) end end From 70e67ff40e2d36c388ddd6c7d441ea75d80c0ada Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Fri, 10 Nov 2023 13:46:37 +0100 Subject: [PATCH 03/14] Removinf failfast from regression tests - Adding some models to regression tests --- .github/workflows/regressionTests.yml | 55 +++++++++++++++++++++++++++ test/Project.toml | 3 +- test/regressionTests.jl | 33 ++++++++-------- test/runtests.jl | 2 +- 4 files changed, 75 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/regressionTests.yml diff --git a/.github/workflows/regressionTests.yml b/.github/workflows/regressionTests.yml new file mode 100644 index 0000000..01f81ad --- /dev/null +++ b/.github/workflows/regressionTests.yml @@ -0,0 +1,55 @@ +name: Regression Test + +on: + push: + branches: ['master', 'maintenance/*'] + schedule: + - cron: "25 4 * * 3" # Every Wednesday at 04:25 + workflow_dispatch: + +jobs: + regression-test: + if: github.repository == 'OpenModelica/OMJulia.jl' # Run only on OpenModelica/OMJulia.jl to prevent spamming forks + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + julia-version: ['1.8', '1.9'] + julia-arch: ['x64'] + os: ['ubuntu-latest', 'windows-latest'] + omc-version: ['stable', 'nightly', '1.12'] + + + steps: + - uses: actions/checkout@v4 + + - name: "Set up OpenModelica Compiler" + uses: AnHeuermann/setup-openmodelica@v0.6 + with: + version: ${{ matrix.omc-version }} + packages: | + omc + libraries: | + 'Modelica 4.0.0' + 'Buildings 10.0.0' + + - run: "omc --version" + + - name: "Set up Julia" + uses: julia-actions/setup-julia@v1 + with: + version: ${{ matrix.julia-version }} + arch: ${{ matrix.julia-arch }} + + - name: Cache Julia + uses: julia-actions/cache@v1 + + - name: "Build OMJulia" + uses: julia-actions/julia-buildpkg@v1 + + - name: Install dependencies + run: julia --project=test/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' + + - name: "Run regression test" + run: julia --project=test/. -e "include(\"test/regressionTests.jl\"); runTests(libraries, models)" diff --git a/test/Project.toml b/test/Project.toml index d5abc7d..65530a3 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,9 +1,10 @@ [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +FMI = "14a09403-18e3-468f-ad8a-74f8dda2d9ac" +OMJulia = "0f4fe800-344e-11e9-2949-fb537ad918e1" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -FMI = "14a09403-18e3-468f-ad8a-74f8dda2d9ac" [compat] FMI = "0.10" diff --git a/test/regressionTests.jl b/test/regressionTests.jl index b58e323..6f38286 100644 --- a/test/regressionTests.jl +++ b/test/regressionTests.jl @@ -26,7 +26,6 @@ EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. =# -using SafeTestsets using Test using DataFrames using CSV @@ -39,7 +38,7 @@ Simulate single model to generate a result file. """ function testSimulation(omc::OMJulia.OMCSession, className::String) @info "\tSimulation" - @testset verbose=false failfast=false "Simulation" begin + @testset "Simulation" begin res = OMJulia.API.simulate(omc, className; outputFormat="csv") resultFile = res["resultFile"] @@ -64,7 +63,7 @@ function testFmuExport(omc::OMJulia.OMCSession, className::String, referenceResu @testset "Import" begin if isfile(fmuPath) fmu = FMI.fmiLoad(fmuPath) - solution = FMI.fmiSimulate(fmu; recordValues = recordValues) + solution = FMI.fmiSimulate(fmu; recordValues = recordValues, showProgress=false) # Own implementation of CSV export, workaround for https://github.com/ThummeTo/FMI.jl/issues/198 df = DataFrames.DataFrame(time = solution.values.t) @@ -98,13 +97,13 @@ function testModels(omc::OMJulia.OMCSession, models::Vector{S}; libdir) where S< local resultFile for model in models - @testset verbose=false failfast=false "$model" begin + @testset "$model" begin modeldir = joinpath(libdir, model) mkpath(modeldir) @info "Testing $model" OMJulia.API.cd(omc, modeldir) resultFile = testSimulation(omc, model) - @testset verbose=false failfast=false "FMI" begin + @testset "FMI" begin if isfile(resultFile) recordValues = names(CSV.read(resultFile, DataFrame))[2:end] testFmuExport(omc, model, resultFile, recordValues; workdir=modeldir) @@ -121,19 +120,18 @@ Run test for all libraries. """ function runTests(libraries::Vector{Tuple{S,S}}, models::Vector{Vector{S}}; - workdir) where S<:AbstractString + workdir=abspath(joinpath(@__DIR__, "test-regressionTests"))) where S<:AbstractString rm(workdir, recursive=true, force=true) mkpath(workdir) - @testset verbose=true failfast=false "OpenModelica" begin + @testset "OpenModelica" begin for (i, (library, version)) in enumerate(libraries) - @testset verbose = true failfast=false "$library" begin + @testset verbose=true "$library" begin libdir = joinpath(workdir, library) mkpath(libdir) omc = OMJulia.OMCSession() - v = OMJulia.API.getVersion(omc) @test OMJulia.API.loadModel(omc, library; priorityVersion = [version], requireExactVersion = true) testModels(omc, models[i]; libdir=libdir) @@ -148,17 +146,20 @@ end libraries = [ ("Modelica", "4.0.0") - ("Buildings", "10.0.0") ] models = [ [ + "Modelica.Blocks.Examples.Filter", + "Modelica.Blocks.Examples.RealNetwork1", "Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", - "Modelica.Fluid.Examples.DrumBoiler.DrumBoiler" - ], - [ - "Buildings.Applications.DataCenters.ChillerCooled.Examples.IntegratedPrimaryLoadSideEconomizer" + "Modelica.Electrical.Digital.Examples.FlipFlop", + "Modelica.Mechanics.Rotational.Examples.FirstGrounded", + "Modelica.Mechanics.Rotational.Examples.CoupledClutches", + "Modelica.Mechanics.MultiBody.Examples.Elementary.DoublePendulum", + "Modelica.Mechanics.MultiBody.Examples.Elementary.FreeBody", + "Modelica.Fluid.Examples.PumpingSystem", + "Modelica.Fluid.Examples.TraceSubstances.RoomCO2WithControls", + "Modelica.Clocked.Examples.SimpleControlledDrive.ClockedWithDiscreteTextbookController" ] ] - -workdir = abspath(joinpath(@__DIR__, "test-regressionTests")) diff --git a/test/runtests.jl b/test/runtests.jl index 6645e83..c817ae6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -34,5 +34,5 @@ using Test @safetestset "OMCSession" begin include("omcTest.jl") end @safetestset "ModelicaSystem" begin include("modelicaSystemTest.jl") end @safetestset "API" begin include("apiTest.jl") end - @safetestset "Regression" begin include("regressionTests.jl"); runTests(libraries[1:1], models[1:2]; workdir=workdir) end + @safetestset "Fast regressions test" begin include("regressionTests.jl"); runTests(libraries, [models[1][1:2]]) end end From 51b4d4e357f27655ee5257f67d58f09765623afe Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Mon, 20 Nov 2023 12:44:54 +0100 Subject: [PATCH 04/14] Adding regression test Testing - Simulation - FMU export - FMU import with FMI.jl ^v0.13 --- .github/workflows/regressionTests.yml | 9 +++++++-- README.md | 5 ++++- test/Project.toml | 2 +- test/regressionTests.jl | 3 ++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/regressionTests.yml b/.github/workflows/regressionTests.yml index 01f81ad..9bb6b7a 100644 --- a/.github/workflows/regressionTests.yml +++ b/.github/workflows/regressionTests.yml @@ -1,4 +1,4 @@ -name: Regression Test +name: Regression Tests on: push: @@ -20,7 +20,6 @@ jobs: os: ['ubuntu-latest', 'windows-latest'] omc-version: ['stable', 'nightly', '1.12'] - steps: - uses: actions/checkout@v4 @@ -53,3 +52,9 @@ jobs: - name: "Run regression test" run: julia --project=test/. -e "include(\"test/regressionTests.jl\"); runTests(libraries, models)" + + - name: Archive FMUs + uses: actions/upload-artifact@v3 + with: + name: fmu-export + path: test/test-regressionTests/**/*.fmu diff --git a/README.md b/README.md index a7f8da3..45c9f7f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ *Julia scripting [OpenModelica](https://openmodelica.org/) interface.* -[![][docs-dev-img]][docs-dev-url] [![][GHA-test-img]][GHA-test-url] +[![][docs-dev-img]][docs-dev-url] [![][GHA-test-img]][GHA-test-url] [![][GHA-regressions-img]][GHA-regressions-url] ## Requirements @@ -82,3 +82,6 @@ CONDITIONS OF OSMC-PL. [GHA-test-img]: https://github.com/OpenModelica/OMJulia.jl/actions/workflows/Test.yml/badge.svg?branch=master [GHA-test-url]: https://github.com/OpenModelica/OMJulia.jl/actions/workflows/Test.yml + +[GHA-regressions-img]: https://github.com/OpenModelica/OMJulia.jl/actions/workflows/regressionTests.yml/badge.svg?branch=master +[GHA-regressions-url]: https://github.com/OpenModelica/OMJulia.jl/actions/workflows/regressionTests.yml diff --git a/test/Project.toml b/test/Project.toml index 65530a3..0aca53d 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -7,4 +7,4 @@ SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] -FMI = "0.10" +FMI = "0.13" diff --git a/test/regressionTests.jl b/test/regressionTests.jl index 6f38286..6fe04b7 100644 --- a/test/regressionTests.jl +++ b/test/regressionTests.jl @@ -106,6 +106,7 @@ function testModels(omc::OMJulia.OMCSession, models::Vector{S}; libdir) where S< @testset "FMI" begin if isfile(resultFile) recordValues = names(CSV.read(resultFile, DataFrame))[2:end] + filter!(val -> !startswith(val, "\$"), recordValues) # Filter internal variables testFmuExport(omc, model, resultFile, recordValues; workdir=modeldir) else @test false @@ -151,8 +152,8 @@ libraries = [ models = [ [ "Modelica.Blocks.Examples.Filter", - "Modelica.Blocks.Examples.RealNetwork1", "Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", + "Modelica.Blocks.Examples.RealNetwork1", "Modelica.Electrical.Digital.Examples.FlipFlop", "Modelica.Mechanics.Rotational.Examples.FirstGrounded", "Modelica.Mechanics.Rotational.Examples.CoupledClutches", From 9859a2732675e18ba30dc7b45ef23fe0a72aecdc Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Mon, 20 Nov 2023 16:17:36 +0100 Subject: [PATCH 05/14] Test each model in a new process - Can surive segmentation faults --- test/regressionTests.jl | 160 ++++++++++++++++++++-------------------- test/runSingleTest.jl | 145 ++++++++++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+), 82 deletions(-) create mode 100644 test/runSingleTest.jl diff --git a/test/regressionTests.jl b/test/regressionTests.jl index 6fe04b7..08295ce 100644 --- a/test/regressionTests.jl +++ b/test/regressionTests.jl @@ -27,97 +27,93 @@ CONDITIONS OF OSMC-PL. =# using Test -using DataFrames -using CSV -import OMJulia -import FMI +include("runSingleTest.jl") """ -Simulate single model to generate a result file. +Timeout error. """ -function testSimulation(omc::OMJulia.OMCSession, className::String) - @info "\tSimulation" - @testset "Simulation" begin - res = OMJulia.API.simulate(omc, className; outputFormat="csv") - resultFile = res["resultFile"] - - @test isfile(resultFile) - return resultFile - end +struct TimeOutError <: Exception + cmd::Cmd +end +function Base.showerror(io::IO, e::TimeOutError) + println(io, "Timeout reached running command") + println(io, e.cmd) end """ -Build a FMU for a single model, import the generated FMU, simulate it and compare to given reference results. -""" -function testFmuExport(omc::OMJulia.OMCSession, className::String, referenceResult, recordValues; workdir::String) - local fmuPath - @info "\tFMU Export" - @testset "Export" begin - fmuPath = OMJulia.API.buildModelFMU(omc, className) - @test isfile(fmuPath) - @test splitext(splitpath(fmuPath)[end]) == (className, ".fmu") - end +Run single test process. - @info "\tFMU Import" - @testset "Import" begin - if isfile(fmuPath) - fmu = FMI.fmiLoad(fmuPath) - solution = FMI.fmiSimulate(fmu; recordValues = recordValues, showProgress=false) - - # Own implementation of CSV export, workaround for https://github.com/ThummeTo/FMI.jl/issues/198 - df = DataFrames.DataFrame(time = solution.values.t) - for i in 1:length(solution.values.saveval[1]) - for var in FMI.fmi2ValueReferenceToString(fmu, solution.valueReferences[i]) - if in(var, recordValues) - df[!, Symbol(var)] = [val[i] for val in solution.values.saveval] - end - end - end - fmiResult = joinpath(workdir, "FMI_results.csv") - CSV.write(fmiResult, df) +Start a new Julia process. +Kill process and throw TimeOutError when timeout is reached. +Catch InterruptException, kill process and rethorw InterruptException. - #FMI.fmiSaveSolution(solution, "FMI_results.csv") - @test true - else - @test false - end - end - - @info "\tCheck Results" - @testset "Verification" begin - @test (true, String[]) == OMJulia.API.diffSimulationResults(omc, "FMI_results.csv", referenceResult, "diff") - end -end +# Arguments + - `library`: Modelica library name. + - `version`: Library version. + - `model`: Modelica model from library to test. + - `testdir`: Test working directory. +# Keywords + - `timeout=10*60::Integer`: Timeout in seconds. Defaults to 10 minutes. """ -Run Simulation and FMU export/import test for all models. -""" -function testModels(omc::OMJulia.OMCSession, models::Vector{S}; libdir) where S<:AbstractString - local resultFile - - for model in models - @testset "$model" begin - modeldir = joinpath(libdir, model) - mkpath(modeldir) - @info "Testing $model" - OMJulia.API.cd(omc, modeldir) - resultFile = testSimulation(omc, model) - @testset "FMI" begin - if isfile(resultFile) - recordValues = names(CSV.read(resultFile, DataFrame))[2:end] - filter!(val -> !startswith(val, "\$"), recordValues) # Filter internal variables - testFmuExport(omc, model, resultFile, recordValues; workdir=modeldir) - else - @test false - end +function singleTest(library, version, model, testdir; + timeout=10*60::Integer) + + mkpath(testdir) + logFile = joinpath(testdir, "runSingleTest.log") + rm(logFile, force=true) + + @info "Testing $model" + + cmd = Cmd(`julia runSingleTest.jl $(library) $(version) $(model) $(testdir)`, dir=@__DIR__) + @info cmd + plp = pipeline(cmd, stdout=logFile, stderr=logFile) + process = run(plp, wait=false) + + try + timer = Timer(0; interval=1) + for _ in 1:timeout + wait(timer) + if !process_running(process) + close(timer) + break end end + if process_running(process) + @error "Killing $(process)" + kill(process) + end + catch e + if isa(e, InterruptException) && process_running(p) + @error "Killing process $(cmd)." + kill(p) + end + rethrow(e) end + + println(read(logFile, String)) + + status = (process.exitcode == 0) && + isfile(joinpath(testdir, "$(model).fmu")) && + isfile(joinpath(testdir, "FMI_results.csv")) + + return status end """ -Run test for all libraries. +Run all tests. + +Start a new Julia process for each test. +Kill process and throw TimeOutError when timeout is reached. +Catch InterruptException, kill process and rethorw InterruptException. + +# Arguments + - `libraries::Vector{Tuple{S,S}}`: Vector of tuples with library and version to test. + - `models::Vector{Vector{S}}`: Vector of vectors with models to test for each library. + +# Keywords + - `workdir`: Root working directory. """ function runTests(libraries::Vector{Tuple{S,S}}, models::Vector{Vector{S}}; @@ -132,12 +128,12 @@ function runTests(libraries::Vector{Tuple{S,S}}, libdir = joinpath(workdir, library) mkpath(libdir) - omc = OMJulia.OMCSession() - - @test OMJulia.API.loadModel(omc, library; priorityVersion = [version], requireExactVersion = true) - testModels(omc, models[i]; libdir=libdir) - - OMJulia.quit(omc) + for model in models[i] + modeldir = joinpath(libdir, model) + @testset "$model" begin + @test singleTest(library, version, model, modeldir) + end + end end end end @@ -159,8 +155,8 @@ models = [ "Modelica.Mechanics.Rotational.Examples.CoupledClutches", "Modelica.Mechanics.MultiBody.Examples.Elementary.DoublePendulum", "Modelica.Mechanics.MultiBody.Examples.Elementary.FreeBody", - "Modelica.Fluid.Examples.PumpingSystem", "Modelica.Fluid.Examples.TraceSubstances.RoomCO2WithControls", - "Modelica.Clocked.Examples.SimpleControlledDrive.ClockedWithDiscreteTextbookController" + "Modelica.Clocked.Examples.SimpleControlledDrive.ClockedWithDiscreteTextbookController", + "Modelica.Fluid.Examples.PumpingSystem" ] ] diff --git a/test/runSingleTest.jl b/test/runSingleTest.jl new file mode 100644 index 0000000..98b67d8 --- /dev/null +++ b/test/runSingleTest.jl @@ -0,0 +1,145 @@ +#= +This file is part of OpenModelica. +Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), +c/o Linköpings universitet, Department of Computer and Information Science, +SE-58183 Linköping, Sweden. + +All rights reserved. + +THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE +GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. +ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES +RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, +ACCORDING TO RECIPIENTS CHOICE. + +The OpenModelica software and the OSMC (Open Source Modelica Consortium) +Public License (OSMC-PL) are obtained from OSMC, either from the above +address, from the URLs: http://www.openmodelica.org or +http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica +distribution. GNU version 3 is obtained from: +http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: +http://www.opensource.org/licenses/BSD-3-Clause. + +This program is distributed WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS +EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE +CONDITIONS OF OSMC-PL. +=# + +import Pkg; Pkg.activate(@__DIR__) +import OMJulia +import FMI + +using Test +using DataFrames +using CSV + +""" +Simulate single model to generate a result file. +""" +function testSimulation(omc::OMJulia.OMCSession, className::String) + @info "\tSimulation" + @testset "Simulation" begin + res = OMJulia.API.simulate(omc, className; outputFormat="csv") + resultFile = res["resultFile"] + + @test isfile(resultFile) + return resultFile + end +end + +""" +Build a FMU for a single model, import the generated FMU, simulate it and compare to given reference results. +""" +function testFmuExport(omc::OMJulia.OMCSession, className::String, referenceResult, recordValues; workdir::String) + local fmuPath + fmuImportSuccess = false + @info "\tFMU Export" + @testset "Export" begin + fmuPath = OMJulia.API.buildModelFMU(omc, className) + @test isfile(fmuPath) + @test splitext(splitpath(fmuPath)[end]) == (className, ".fmu") + end + + @info "\tFMU Import" + @testset "Import" begin + if isfile(fmuPath) + fmu = FMI.fmiLoad(fmuPath) + solution = FMI.fmiSimulate(fmu; recordValues = recordValues, showProgress=false) + + # Own implementation of CSV export, workaround for https://github.com/ThummeTo/FMI.jl/issues/198 + df = DataFrames.DataFrame(time = solution.values.t) + for i in 1:length(solution.values.saveval[1]) + for var in FMI.fmi2ValueReferenceToString(fmu, solution.valueReferences[i]) + if in(var, recordValues) + df[!, Symbol(var)] = [val[i] for val in solution.values.saveval] + end + end + end + fmiResult = joinpath(workdir, "FMI_results.csv") + CSV.write(fmiResult, df) + + #FMI.fmiSaveSolution(solution, "FMI_results.csv") + fmuImportSuccess = true + end + @test fmuImportSuccess + end + + @info "\tCheck Results" + @testset "Verification" begin + if fmuImportSuccess + @test (true, String[]) == OMJulia.API.diffSimulationResults(omc, "FMI_results.csv", referenceResult, "diff") + else + @test false + end + end +end + +""" +Run Simulation and FMU export/import test for all models. +""" +function runSingleTest(library, version, model, modeldir) + local resultFile + + @info "Testing library: $library, model $model" + mkpath(modeldir) + omc = OMJulia.OMCSession() + + try + @testset "$model" verbose=true begin + @testset "Simulation" begin + OMJulia.API.cd(omc, modeldir) + + @test OMJulia.API.loadModel(omc, library; priorityVersion = [version], requireExactVersion = true) + resultFile = testSimulation(omc, model) + end + + @testset "FMI" begin + if isfile(resultFile) + recordValues = names(CSV.read(resultFile, DataFrame))[2:end] + filter!(val -> !startswith(val, "\$"), recordValues) # Filter internal variables + testFmuExport(omc, model, resultFile, recordValues; workdir=modeldir) + else + @test false + end + end + end + finally + OMJulia.quit(omc) + end +end + +# Comand-line interface +if !isempty(PROGRAM_FILE) + if length(ARGS) == 4 + library = ARGS[1] + version = ARGS[2] + model = ARGS[3] + modeldir = ARGS[4] + runSingleTest(library, version, model, modeldir) + else + @error "Wrong number of arguments" + for a in ARGS; println(a); end + return -1 + end +end From fb15d1eefef5c4385aa137341659e1ce2ee4ad64 Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Mon, 20 Nov 2023 16:37:55 +0100 Subject: [PATCH 06/14] Adding Pkg to test --- test/Project.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Project.toml b/test/Project.toml index 0aca53d..9d9285f 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -3,6 +3,7 @@ CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" FMI = "14a09403-18e3-468f-ad8a-74f8dda2d9ac" OMJulia = "0f4fe800-344e-11e9-2949-fb537ad918e1" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" From bc29975473c1fd975cd3004b9bddf3ef1a724c6f Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Tue, 21 Nov 2023 12:00:58 +0100 Subject: [PATCH 07/14] Moving regression tests in separate directory --- .github/workflows/regressionTests.yml | 8 +- regression-tests/.gitignore | 1 + regression-tests/Project.toml | 6 + regression-tests/regressionTests.jl | 160 ++++++++++++++++++++++++++ regression-tests/runSingleTest.jl | 145 +++++++++++++++++++++++ test/Project.toml | 5 - test/runtests.jl | 1 - 7 files changed, 316 insertions(+), 10 deletions(-) create mode 100644 regression-tests/.gitignore create mode 100644 regression-tests/Project.toml create mode 100644 regression-tests/regressionTests.jl create mode 100644 regression-tests/runSingleTest.jl diff --git a/.github/workflows/regressionTests.yml b/.github/workflows/regressionTests.yml index 9bb6b7a..6d72ab2 100644 --- a/.github/workflows/regressionTests.yml +++ b/.github/workflows/regressionTests.yml @@ -3,6 +3,7 @@ name: Regression Tests on: push: branches: ['master', 'maintenance/*'] + pull_request: schedule: - cron: "25 4 * * 3" # Every Wednesday at 04:25 workflow_dispatch: @@ -31,7 +32,6 @@ jobs: omc libraries: | 'Modelica 4.0.0' - 'Buildings 10.0.0' - run: "omc --version" @@ -48,13 +48,13 @@ jobs: uses: julia-actions/julia-buildpkg@v1 - name: Install dependencies - run: julia --project=test/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' + run: julia --project=regression-tests/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' - name: "Run regression test" - run: julia --project=test/. -e "include(\"test/regressionTests.jl\"); runTests(libraries, models)" + run: julia --project=regression-tests/. -e "include(\"regression-tests/regressionTests.jl\"); runTests(libraries, models)" - name: Archive FMUs uses: actions/upload-artifact@v3 with: name: fmu-export - path: test/test-regressionTests/**/*.fmu + path: regression-tests/temp/**/*.fmu diff --git a/regression-tests/.gitignore b/regression-tests/.gitignore new file mode 100644 index 0000000..a6d7ecd --- /dev/null +++ b/regression-tests/.gitignore @@ -0,0 +1 @@ +temp/ diff --git a/regression-tests/Project.toml b/regression-tests/Project.toml new file mode 100644 index 0000000..ea1db10 --- /dev/null +++ b/regression-tests/Project.toml @@ -0,0 +1,6 @@ +[deps] +CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" +DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +FMI = "14a09403-18e3-468f-ad8a-74f8dda2d9ac" +OMJulia = "0f4fe800-344e-11e9-2949-fb537ad918e1" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/regression-tests/regressionTests.jl b/regression-tests/regressionTests.jl new file mode 100644 index 0000000..26a0499 --- /dev/null +++ b/regression-tests/regressionTests.jl @@ -0,0 +1,160 @@ +#= +This file is part of OpenModelica. +Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), +c/o Linköpings universitet, Department of Computer and Information Science, +SE-58183 Linköping, Sweden. + +All rights reserved. + +THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE +GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. +ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES +RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, +ACCORDING TO RECIPIENTS CHOICE. + +The OpenModelica software and the OSMC (Open Source Modelica Consortium) +Public License (OSMC-PL) are obtained from OSMC, either from the above +address, from the URLs: http://www.openmodelica.org or +http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica +distribution. GNU version 3 is obtained from: +http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: +http://www.opensource.org/licenses/BSD-3-Clause. + +This program is distributed WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS +EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE +CONDITIONS OF OSMC-PL. +=# + +using Test + +""" +Timeout error. +""" +struct TimeOutError <: Exception + cmd::Cmd +end +function Base.showerror(io::IO, e::TimeOutError) + println(io, "Timeout reached running command") + println(io, e.cmd) +end + +""" +Run single test process. + +Start a new Julia process. +Kill process and throw TimeOutError when timeout is reached. +Catch InterruptException, kill process and rethorw InterruptException. + +# Arguments + - `library`: Modelica library name. + - `version`: Library version. + - `model`: Modelica model from library to test. + - `testdir`: Test working directory. + +# Keywords + - `timeout=10*60::Integer`: Timeout in seconds. Defaults to 10 minutes. +""" +function singleTest(library, version, model, testdir; + timeout=10*60::Integer) + + mkpath(testdir) + logFile = joinpath(testdir, "runSingleTest.log") + rm(logFile, force=true) + + @info "Testing $model" + + cmd = Cmd(`$(joinpath(Sys.BINDIR, "julia")) runSingleTest.jl $(library) $(version) $(model) $(testdir)`, dir=@__DIR__) + @info cmd + plp = pipeline(cmd, stdout=logFile, stderr=logFile) + process = run(plp, wait=false) + + try + timer = Timer(0; interval=1) + for _ in 1:timeout + wait(timer) + if !process_running(process) + close(timer) + break + end + end + if process_running(process) + @error "Killing $(process)" + kill(process) + end + catch e + if isa(e, InterruptException) && process_running(p) + @error "Killing process $(cmd)." + kill(p) + end + rethrow(e) + end + + println(read(logFile, String)) + + status = (process.exitcode == 0) && + isfile(joinpath(testdir, "$(model).fmu")) && + isfile(joinpath(testdir, "FMI_results.csv")) + + return status +end + +""" +Run all tests. + +Start a new Julia process for each test. +Kill process and throw TimeOutError when timeout is reached. +Catch InterruptException, kill process and rethorw InterruptException. + +# Arguments + - `libraries::Vector{Tuple{S,S}}`: Vector of tuples with library and version to test. + - `models::Vector{Vector{S}}`: Vector of vectors with models to test for each library. + +# Keywords + - `workdir`: Root working directory. +""" +function runTests(libraries::Vector{Tuple{S,S}}, + models::Vector{Vector{S}}; + workdir=abspath(joinpath(@__DIR__, "temp"))) where S<:AbstractString + + rm(workdir, recursive=true, force=true) # This can break on Windows when some program or file is still open + mkpath(workdir) + + @testset "OpenModelica" begin + for (i, (library, version)) in enumerate(libraries) + @testset verbose=true "$library" begin + libdir = joinpath(workdir, library) + mkpath(libdir) + + for model in models[i] + modeldir = joinpath(libdir, model) + @testset "$model" begin + @test singleTest(library, version, model, modeldir) + end + end + end + end + end + + return +end + +libraries = [ + ("Modelica", "4.0.0") +] + +models = [ + [ + "Modelica.Blocks.Examples.Filter", + "Modelica.Electrical.Analog.Examples.CauerLowPassAnalog" + "Modelica.Blocks.Examples.RealNetwork1", + "Modelica.Electrical.Digital.Examples.FlipFlop", + "Modelica.Mechanics.Rotational.Examples.FirstGrounded", + "Modelica.Mechanics.Rotational.Examples.CoupledClutches", + "Modelica.Mechanics.MultiBody.Examples.Elementary.DoublePendulum", + "Modelica.Mechanics.MultiBody.Examples.Elementary.FreeBody", + "Modelica.Fluid.Examples.TraceSubstances.RoomCO2WithControls", + "Modelica.Clocked.Examples.SimpleControlledDrive.ClockedWithDiscreteTextbookController", + "Modelica.Fluid.Examples.PumpingSystem" + ] +] diff --git a/regression-tests/runSingleTest.jl b/regression-tests/runSingleTest.jl new file mode 100644 index 0000000..68fa605 --- /dev/null +++ b/regression-tests/runSingleTest.jl @@ -0,0 +1,145 @@ +#= +This file is part of OpenModelica. +Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), +c/o Linköpings universitet, Department of Computer and Information Science, +SE-58183 Linköping, Sweden. + +All rights reserved. + +THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE +GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. +ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES +RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, +ACCORDING TO RECIPIENTS CHOICE. + +The OpenModelica software and the OSMC (Open Source Modelica Consortium) +Public License (OSMC-PL) are obtained from OSMC, either from the above +address, from the URLs: http://www.openmodelica.org or +http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica +distribution. GNU version 3 is obtained from: +http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: +http://www.opensource.org/licenses/BSD-3-Clause. + +This program is distributed WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS +EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE +CONDITIONS OF OSMC-PL. +=# + +import Pkg; Pkg.activate(@__DIR__) +import OMJulia +import FMI + +using Test +using DataFrames +using CSV + +""" +Simulate single model to generate a result file. +""" +function testSimulation(omc::OMJulia.OMCSession, className::String) + @info "\tSimulation" + @testset "Simulation" begin + res = OMJulia.API.simulate(omc, className; outputFormat="csv") + resultFile = res["resultFile"] + + @test isfile(resultFile) + return resultFile + end +end + +""" +Build a FMU for a single model, import the generated FMU, simulate it and compare to given reference results. +""" +function testFmuExport(omc::OMJulia.OMCSession, className::String, referenceResult, recordValues; workdir::String) + fmuPath = "" + fmuImportSuccess = false + @info "\tFMU Export" + @testset "Export" begin + fmuPath = OMJulia.API.buildModelFMU(omc, className) + @test isfile(fmuPath) + @test splitext(splitpath(fmuPath)[end]) == (className, ".fmu") + end + + @info "\tFMU Import" + @testset "Import" begin + if isfile(fmuPath) + fmu = FMI.fmiLoad(fmuPath) + solution = FMI.fmiSimulate(fmu; recordValues = recordValues, showProgress=false) + + # Own implementation of CSV export, workaround for https://github.com/ThummeTo/FMI.jl/issues/198 + df = DataFrames.DataFrame(time = solution.values.t) + for i in 1:length(solution.values.saveval[1]) + for var in FMI.fmi2ValueReferenceToString(fmu, solution.valueReferences[i]) + if in(var, recordValues) + df[!, Symbol(var)] = [val[i] for val in solution.values.saveval] + end + end + end + fmiResult = joinpath(workdir, "FMI_results.csv") + CSV.write(fmiResult, df) + + #FMI.fmiSaveSolution(solution, "FMI_results.csv") + fmuImportSuccess = true + end + @test fmuImportSuccess + end + + @info "\tCheck Results" + @testset "Verification" begin + if fmuImportSuccess + @test (true, String[]) == OMJulia.API.diffSimulationResults(omc, "FMI_results.csv", referenceResult, "diff") + else + @test false + end + end +end + +""" +Run Simulation and FMU export/import test for all models. +""" +function runSingleTest(library, version, model, modeldir) + local resultFile + + @info "Testing library: $library, model $model" + mkpath(modeldir) + omc = OMJulia.OMCSession() + + try + @testset "$model" verbose=true begin + @testset "Simulation" begin + OMJulia.API.cd(omc, modeldir) + + @test OMJulia.API.loadModel(omc, library; priorityVersion = [version], requireExactVersion = true) + resultFile = testSimulation(omc, model) + end + + @testset "FMI" begin + if isfile(resultFile) + recordValues = names(CSV.read(resultFile, DataFrame))[2:end] + filter!(val -> !startswith(val, "\$"), recordValues) # Filter internal variables + testFmuExport(omc, model, resultFile, recordValues; workdir=modeldir) + else + @test false + end + end + end + finally + OMJulia.quit(omc) + end +end + +# Comand-line interface +if !isempty(PROGRAM_FILE) + if length(ARGS) == 4 + library = ARGS[1] + version = ARGS[2] + model = ARGS[3] + modeldir = ARGS[4] + runSingleTest(library, version, model, modeldir) + else + @error "Wrong number of arguments" + for a in ARGS; println(a); end + return -1 + end +end diff --git a/test/Project.toml b/test/Project.toml index 9d9285f..92f937e 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,11 +1,6 @@ [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" -FMI = "14a09403-18e3-468f-ad8a-74f8dda2d9ac" OMJulia = "0f4fe800-344e-11e9-2949-fb537ad918e1" -Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[compat] -FMI = "0.13" diff --git a/test/runtests.jl b/test/runtests.jl index c817ae6..9904429 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -34,5 +34,4 @@ using Test @safetestset "OMCSession" begin include("omcTest.jl") end @safetestset "ModelicaSystem" begin include("modelicaSystemTest.jl") end @safetestset "API" begin include("apiTest.jl") end - @safetestset "Fast regressions test" begin include("regressionTests.jl"); runTests(libraries, [models[1][1:2]]) end end From e3b7abd16485bf36a45cc06901c6a7632cf6d95f Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Tue, 21 Nov 2023 12:04:58 +0100 Subject: [PATCH 08/14] Spam forks --- .github/workflows/regressionTests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/regressionTests.yml b/.github/workflows/regressionTests.yml index 6d72ab2..09d8820 100644 --- a/.github/workflows/regressionTests.yml +++ b/.github/workflows/regressionTests.yml @@ -10,7 +10,7 @@ on: jobs: regression-test: - if: github.repository == 'OpenModelica/OMJulia.jl' # Run only on OpenModelica/OMJulia.jl to prevent spamming forks + #if: github.repository == 'OpenModelica/OMJulia.jl' # Run only on OpenModelica/OMJulia.jl to prevent spamming forks runs-on: ${{ matrix.os }} timeout-minutes: 60 strategy: From b984c476d26d02e87d9f2d02944005c69f72060e Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Tue, 21 Nov 2023 12:11:59 +0100 Subject: [PATCH 09/14] Fixing workflow --- .github/workflows/regressionTests.yml | 2 +- regression-tests/regressionTests.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/regressionTests.yml b/.github/workflows/regressionTests.yml index 09d8820..487b7fc 100644 --- a/.github/workflows/regressionTests.yml +++ b/.github/workflows/regressionTests.yml @@ -19,7 +19,7 @@ jobs: julia-version: ['1.8', '1.9'] julia-arch: ['x64'] os: ['ubuntu-latest', 'windows-latest'] - omc-version: ['stable', 'nightly', '1.12'] + omc-version: ['stable', 'nightly', '1.21'] steps: - uses: actions/checkout@v4 diff --git a/regression-tests/regressionTests.jl b/regression-tests/regressionTests.jl index 26a0499..d0e04b9 100644 --- a/regression-tests/regressionTests.jl +++ b/regression-tests/regressionTests.jl @@ -146,7 +146,7 @@ libraries = [ models = [ [ "Modelica.Blocks.Examples.Filter", - "Modelica.Electrical.Analog.Examples.CauerLowPassAnalog" + "Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", "Modelica.Blocks.Examples.RealNetwork1", "Modelica.Electrical.Digital.Examples.FlipFlop", "Modelica.Mechanics.Rotational.Examples.FirstGrounded", From fca7168841f8185860dce29708ad4f5c83d6b0c4 Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Tue, 21 Nov 2023 12:38:16 +0100 Subject: [PATCH 10/14] No premature end on Windows? --- .github/workflows/regressionTests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/regressionTests.yml b/.github/workflows/regressionTests.yml index 487b7fc..221a55b 100644 --- a/.github/workflows/regressionTests.yml +++ b/.github/workflows/regressionTests.yml @@ -51,7 +51,7 @@ jobs: run: julia --project=regression-tests/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' - name: "Run regression test" - run: julia --project=regression-tests/. -e "include(\"regression-tests/regressionTests.jl\"); runTests(libraries, models)" + run: julia --project=regression-tests/. -e 'include(\"regression-tests/regressionTests.jl\"); runTests(libraries, models)' - name: Archive FMUs uses: actions/upload-artifact@v3 From 2c3b9de6b2b7769f73f1a13fb1ed25e774025164 Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Tue, 21 Nov 2023 12:54:51 +0100 Subject: [PATCH 11/14] Stupid shell escape stuff --- .github/workflows/regressionTests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/regressionTests.yml b/.github/workflows/regressionTests.yml index 221a55b..e2dca02 100644 --- a/.github/workflows/regressionTests.yml +++ b/.github/workflows/regressionTests.yml @@ -51,7 +51,8 @@ jobs: run: julia --project=regression-tests/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' - name: "Run regression test" - run: julia --project=regression-tests/. -e 'include(\"regression-tests/regressionTests.jl\"); runTests(libraries, models)' + shell: bash + run: julia --project=regression-tests/. -e 'include("regression-tests/regressionTests.jl"); runTests(libraries, models)' - name: Archive FMUs uses: actions/upload-artifact@v3 From c672a670a9513a0f59b016d2bd7e5e525298290f Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Tue, 21 Nov 2023 13:28:36 +0100 Subject: [PATCH 12/14] Reactivating if --- .github/workflows/regressionTests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/regressionTests.yml b/.github/workflows/regressionTests.yml index e2dca02..c599a5e 100644 --- a/.github/workflows/regressionTests.yml +++ b/.github/workflows/regressionTests.yml @@ -10,7 +10,7 @@ on: jobs: regression-test: - #if: github.repository == 'OpenModelica/OMJulia.jl' # Run only on OpenModelica/OMJulia.jl to prevent spamming forks + if: github.repository == 'OpenModelica/OMJulia.jl' # Run only on OpenModelica/OMJulia.jl to prevent spamming forks runs-on: ${{ matrix.os }} timeout-minutes: 60 strategy: From e131c7ee7f4d5b72132b81f727ba79c8943d4860 Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Tue, 21 Nov 2023 13:30:53 +0100 Subject: [PATCH 13/14] Remove unneeded stuff --- regression-tests/regressionTests.jl | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/regression-tests/regressionTests.jl b/regression-tests/regressionTests.jl index d0e04b9..df3dd85 100644 --- a/regression-tests/regressionTests.jl +++ b/regression-tests/regressionTests.jl @@ -28,22 +28,11 @@ CONDITIONS OF OSMC-PL. using Test -""" -Timeout error. -""" -struct TimeOutError <: Exception - cmd::Cmd -end -function Base.showerror(io::IO, e::TimeOutError) - println(io, "Timeout reached running command") - println(io, e.cmd) -end - """ Run single test process. Start a new Julia process. -Kill process and throw TimeOutError when timeout is reached. +Kill process and throw an error when timeout is reached. Catch InterruptException, kill process and rethorw InterruptException. # Arguments @@ -102,10 +91,6 @@ end """ Run all tests. -Start a new Julia process for each test. -Kill process and throw TimeOutError when timeout is reached. -Catch InterruptException, kill process and rethorw InterruptException. - # Arguments - `libraries::Vector{Tuple{S,S}}`: Vector of tuples with library and version to test. - `models::Vector{Vector{S}}`: Vector of vectors with models to test for each library. From 0e4c92d4a265568816f0cde7c5eaa40c5fe84aa1 Mon Sep 17 00:00:00 2001 From: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com> Date: Tue, 21 Nov 2023 13:32:18 +0100 Subject: [PATCH 14/14] Removing duplicate tests --- test/regressionTests.jl | 162 ---------------------------------------- test/runSingleTest.jl | 145 ----------------------------------- 2 files changed, 307 deletions(-) delete mode 100644 test/regressionTests.jl delete mode 100644 test/runSingleTest.jl diff --git a/test/regressionTests.jl b/test/regressionTests.jl deleted file mode 100644 index 08295ce..0000000 --- a/test/regressionTests.jl +++ /dev/null @@ -1,162 +0,0 @@ -#= -This file is part of OpenModelica. -Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), -c/o Linköpings universitet, Department of Computer and Information Science, -SE-58183 Linköping, Sweden. - -All rights reserved. - -THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE -GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. -ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES -RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, -ACCORDING TO RECIPIENTS CHOICE. - -The OpenModelica software and the OSMC (Open Source Modelica Consortium) -Public License (OSMC-PL) are obtained from OSMC, either from the above -address, from the URLs: http://www.openmodelica.org or -http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica -distribution. GNU version 3 is obtained from: -http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: -http://www.opensource.org/licenses/BSD-3-Clause. - -This program is distributed WITHOUT ANY WARRANTY; without even the implied -warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS -EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE -CONDITIONS OF OSMC-PL. -=# - -using Test - -include("runSingleTest.jl") - -""" -Timeout error. -""" -struct TimeOutError <: Exception - cmd::Cmd -end -function Base.showerror(io::IO, e::TimeOutError) - println(io, "Timeout reached running command") - println(io, e.cmd) -end - -""" -Run single test process. - -Start a new Julia process. -Kill process and throw TimeOutError when timeout is reached. -Catch InterruptException, kill process and rethorw InterruptException. - -# Arguments - - `library`: Modelica library name. - - `version`: Library version. - - `model`: Modelica model from library to test. - - `testdir`: Test working directory. - -# Keywords - - `timeout=10*60::Integer`: Timeout in seconds. Defaults to 10 minutes. -""" -function singleTest(library, version, model, testdir; - timeout=10*60::Integer) - - mkpath(testdir) - logFile = joinpath(testdir, "runSingleTest.log") - rm(logFile, force=true) - - @info "Testing $model" - - cmd = Cmd(`julia runSingleTest.jl $(library) $(version) $(model) $(testdir)`, dir=@__DIR__) - @info cmd - plp = pipeline(cmd, stdout=logFile, stderr=logFile) - process = run(plp, wait=false) - - try - timer = Timer(0; interval=1) - for _ in 1:timeout - wait(timer) - if !process_running(process) - close(timer) - break - end - end - if process_running(process) - @error "Killing $(process)" - kill(process) - end - catch e - if isa(e, InterruptException) && process_running(p) - @error "Killing process $(cmd)." - kill(p) - end - rethrow(e) - end - - println(read(logFile, String)) - - status = (process.exitcode == 0) && - isfile(joinpath(testdir, "$(model).fmu")) && - isfile(joinpath(testdir, "FMI_results.csv")) - - return status -end - -""" -Run all tests. - -Start a new Julia process for each test. -Kill process and throw TimeOutError when timeout is reached. -Catch InterruptException, kill process and rethorw InterruptException. - -# Arguments - - `libraries::Vector{Tuple{S,S}}`: Vector of tuples with library and version to test. - - `models::Vector{Vector{S}}`: Vector of vectors with models to test for each library. - -# Keywords - - `workdir`: Root working directory. -""" -function runTests(libraries::Vector{Tuple{S,S}}, - models::Vector{Vector{S}}; - workdir=abspath(joinpath(@__DIR__, "test-regressionTests"))) where S<:AbstractString - - rm(workdir, recursive=true, force=true) - mkpath(workdir) - - @testset "OpenModelica" begin - for (i, (library, version)) in enumerate(libraries) - @testset verbose=true "$library" begin - libdir = joinpath(workdir, library) - mkpath(libdir) - - for model in models[i] - modeldir = joinpath(libdir, model) - @testset "$model" begin - @test singleTest(library, version, model, modeldir) - end - end - end - end - end - - return -end - -libraries = [ - ("Modelica", "4.0.0") -] - -models = [ - [ - "Modelica.Blocks.Examples.Filter", - "Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", - "Modelica.Blocks.Examples.RealNetwork1", - "Modelica.Electrical.Digital.Examples.FlipFlop", - "Modelica.Mechanics.Rotational.Examples.FirstGrounded", - "Modelica.Mechanics.Rotational.Examples.CoupledClutches", - "Modelica.Mechanics.MultiBody.Examples.Elementary.DoublePendulum", - "Modelica.Mechanics.MultiBody.Examples.Elementary.FreeBody", - "Modelica.Fluid.Examples.TraceSubstances.RoomCO2WithControls", - "Modelica.Clocked.Examples.SimpleControlledDrive.ClockedWithDiscreteTextbookController", - "Modelica.Fluid.Examples.PumpingSystem" - ] -] diff --git a/test/runSingleTest.jl b/test/runSingleTest.jl deleted file mode 100644 index 98b67d8..0000000 --- a/test/runSingleTest.jl +++ /dev/null @@ -1,145 +0,0 @@ -#= -This file is part of OpenModelica. -Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), -c/o Linköpings universitet, Department of Computer and Information Science, -SE-58183 Linköping, Sweden. - -All rights reserved. - -THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE -GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. -ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES -RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, -ACCORDING TO RECIPIENTS CHOICE. - -The OpenModelica software and the OSMC (Open Source Modelica Consortium) -Public License (OSMC-PL) are obtained from OSMC, either from the above -address, from the URLs: http://www.openmodelica.org or -http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica -distribution. GNU version 3 is obtained from: -http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: -http://www.opensource.org/licenses/BSD-3-Clause. - -This program is distributed WITHOUT ANY WARRANTY; without even the implied -warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS -EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE -CONDITIONS OF OSMC-PL. -=# - -import Pkg; Pkg.activate(@__DIR__) -import OMJulia -import FMI - -using Test -using DataFrames -using CSV - -""" -Simulate single model to generate a result file. -""" -function testSimulation(omc::OMJulia.OMCSession, className::String) - @info "\tSimulation" - @testset "Simulation" begin - res = OMJulia.API.simulate(omc, className; outputFormat="csv") - resultFile = res["resultFile"] - - @test isfile(resultFile) - return resultFile - end -end - -""" -Build a FMU for a single model, import the generated FMU, simulate it and compare to given reference results. -""" -function testFmuExport(omc::OMJulia.OMCSession, className::String, referenceResult, recordValues; workdir::String) - local fmuPath - fmuImportSuccess = false - @info "\tFMU Export" - @testset "Export" begin - fmuPath = OMJulia.API.buildModelFMU(omc, className) - @test isfile(fmuPath) - @test splitext(splitpath(fmuPath)[end]) == (className, ".fmu") - end - - @info "\tFMU Import" - @testset "Import" begin - if isfile(fmuPath) - fmu = FMI.fmiLoad(fmuPath) - solution = FMI.fmiSimulate(fmu; recordValues = recordValues, showProgress=false) - - # Own implementation of CSV export, workaround for https://github.com/ThummeTo/FMI.jl/issues/198 - df = DataFrames.DataFrame(time = solution.values.t) - for i in 1:length(solution.values.saveval[1]) - for var in FMI.fmi2ValueReferenceToString(fmu, solution.valueReferences[i]) - if in(var, recordValues) - df[!, Symbol(var)] = [val[i] for val in solution.values.saveval] - end - end - end - fmiResult = joinpath(workdir, "FMI_results.csv") - CSV.write(fmiResult, df) - - #FMI.fmiSaveSolution(solution, "FMI_results.csv") - fmuImportSuccess = true - end - @test fmuImportSuccess - end - - @info "\tCheck Results" - @testset "Verification" begin - if fmuImportSuccess - @test (true, String[]) == OMJulia.API.diffSimulationResults(omc, "FMI_results.csv", referenceResult, "diff") - else - @test false - end - end -end - -""" -Run Simulation and FMU export/import test for all models. -""" -function runSingleTest(library, version, model, modeldir) - local resultFile - - @info "Testing library: $library, model $model" - mkpath(modeldir) - omc = OMJulia.OMCSession() - - try - @testset "$model" verbose=true begin - @testset "Simulation" begin - OMJulia.API.cd(omc, modeldir) - - @test OMJulia.API.loadModel(omc, library; priorityVersion = [version], requireExactVersion = true) - resultFile = testSimulation(omc, model) - end - - @testset "FMI" begin - if isfile(resultFile) - recordValues = names(CSV.read(resultFile, DataFrame))[2:end] - filter!(val -> !startswith(val, "\$"), recordValues) # Filter internal variables - testFmuExport(omc, model, resultFile, recordValues; workdir=modeldir) - else - @test false - end - end - end - finally - OMJulia.quit(omc) - end -end - -# Comand-line interface -if !isempty(PROGRAM_FILE) - if length(ARGS) == 4 - library = ARGS[1] - version = ARGS[2] - model = ARGS[3] - modeldir = ARGS[4] - runSingleTest(library, version, model, modeldir) - else - @error "Wrong number of arguments" - for a in ARGS; println(a); end - return -1 - end -end