diff --git a/.github/workflows/SimPathsBuild.yml b/.github/workflows/SimPathsBuild.yml index e2fccf9fd..1beb3c9ad 100644 --- a/.github/workflows/SimPathsBuild.yml +++ b/.github/workflows/SimPathsBuild.yml @@ -14,9 +14,7 @@ on: jobs: build: - runs-on: [ ubuntu-latest ] - steps: - uses: actions/checkout@v4 - name: Set up JDK 19 @@ -27,18 +25,13 @@ jobs: cache: maven - name: Build with Maven run: mvn -B package --file pom.xml - - uses: actions/upload-artifact@v4 with: name: simpaths_jars path: ./*.jar - run-simpaths: - needs: build - + run-integration-tests: runs-on: [ ubuntu-latest ] - - steps: - uses: actions/checkout@v4 - name: Set up JDK 19 @@ -46,30 +39,13 @@ jobs: with: java-version: '19' distribution: 'temurin' + cache: maven + - name: Run integration tests + run: mvn verify - - uses: actions/download-artifact@v4 - with: - name: simpaths_jars - path: . - - - name: Setup run - run: java -jar singlerun.jar -c UK -s 2017 -Setup -g false --rewrite-policy-schedule - - - name: Check input db exists - id: check_file - uses: thebinaryfelix/check-file-existence-action@1.0.0 - with: - files: 'input/input.mv.db, input/EUROMODpolicySchedule.xlsx, input/DatabaseCountryYear.xlsx' - - - name: Do two runs with persistence to root database - run: java -jar multirun.jar -p 20000 -s 2019 -e 2022 -r 100 -n 2 -g false --persist=root - - run-simpaths-no-persist: + run-simpaths-persist-root: needs: build - runs-on: [ ubuntu-latest ] - - steps: - uses: actions/checkout@v4 - name: Set up JDK 19 @@ -77,30 +53,23 @@ jobs: with: java-version: '19' distribution: 'temurin' - - uses: actions/download-artifact@v4 with: name: simpaths_jars path: . - - name: Setup run run: java -jar singlerun.jar -c UK -s 2017 -Setup -g false --rewrite-policy-schedule - - name: Check input db exists id: check_file uses: thebinaryfelix/check-file-existence-action@1.0.0 with: files: 'input/input.mv.db, input/EUROMODpolicySchedule.xlsx, input/DatabaseCountryYear.xlsx' + - name: Do two runs with persistence to root database + run: java -jar multirun.jar -p 20000 -s 2019 -e 2022 -r 100 -n 2 -g false --persist=root - - name: Do two runs with no persistence - run: java -jar multirun.jar -p 20000 -s 2019 -e 2022 -r 100 -n 2 -g false --persist=none - - run-simpaths-run-persist: + run-simpaths-no-persist: needs: build - runs-on: [ ubuntu-latest ] - - steps: - uses: actions/checkout@v4 - name: Set up JDK 19 @@ -108,20 +77,16 @@ jobs: with: java-version: '19' distribution: 'temurin' - - uses: actions/download-artifact@v4 with: name: simpaths_jars path: . - - name: Setup run run: java -jar singlerun.jar -c UK -s 2017 -Setup -g false --rewrite-policy-schedule - - name: Check input db exists id: check_file uses: thebinaryfelix/check-file-existence-action@1.0.0 with: files: 'input/input.mv.db, input/EUROMODpolicySchedule.xlsx, input/DatabaseCountryYear.xlsx' - - - name: Do two runs with persistence to run-specific database - run: java -jar multirun.jar -p 20000 -s 2019 -e 2022 -r 100 -n 2 -g false --persist=run + - name: Do two runs with no persistence + run: java -jar multirun.jar -p 20000 -s 2019 -e 2022 -r 100 -n 2 -g false --persist=none diff --git a/pom.xml b/pom.xml index 3c05c45cd..419303538 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,29 @@ org.apache.maven.plugins maven-surefire-plugin 3.2.2 + + + **/*IntegrationTest.java + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 3.5.2 + + + **/*IntegrationTest.java + + + + + + integration-test + verify + + + org.apache.maven.plugins diff --git a/src/test/java/simpaths/integrationtest/RunSimPathsIntegrationTest.java b/src/test/java/simpaths/integrationtest/RunSimPathsIntegrationTest.java new file mode 100644 index 000000000..77b88102c --- /dev/null +++ b/src/test/java/simpaths/integrationtest/RunSimPathsIntegrationTest.java @@ -0,0 +1,156 @@ +package simpaths.integrationtest; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Comparator; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class RunSimPathsIntegrationTest { + @Test + @DisplayName("Initial database setup runs successfully") + @Order(1) + void testRunSetup() { + runCommand( + "java", "-jar", "singlerun.jar", + "-c", "UK", + "-s", "2017", + "-Setup", + "-g", "false", + "--rewrite-policy-schedule" + ); + } + + @Test + @DisplayName("Database and configuration files are created") + @Order(2) + void testVerifySetupOutput() { + assertFileExists("input/input.mv.db"); + assertFileExists("input/EUROMODpolicySchedule.xlsx"); + assertFileExists("input/DatabaseCountryYear.xlsx"); + } + + @Test + @DisplayName("Simulation runs successfully") + @Order(3) + void testRunSimulation() { + runCommand( + "java", "-jar", "multirun.jar", + "-p", "20000", + "-s", "2019", + "-e", "2022", + "-r", "100", + "-n", "2", + "-g", "false" + ); + } + + @Test + @DisplayName("Simulation runs successfully") + @Order(4) + void testVerifySimulationOutput() throws IOException { + Path outputDir = Paths.get("output"); + + Path latestOutputDir = Files.list(outputDir) + .filter(Files::isDirectory) + .max(Comparator.comparingLong(p -> p.toFile().lastModified())) + .get(); + + compareFiles( + latestOutputDir.resolve("csv/Statistics1.csv"), + Paths.get("src/test/java/simpaths/integrationtest/expected/Statistics1.csv") + ); + compareFiles( + latestOutputDir.resolve("csv/Statistics21.csv"), + Paths.get("src/test/java/simpaths/integrationtest/expected/Statistics21.csv") + ); + compareFiles( + latestOutputDir.resolve("csv/Statistics31.csv"), + Paths.get("src/test/java/simpaths/integrationtest/expected/Statistics31.csv") + ); + } + + void compareFiles(Path actualFile, Path expectedFile) throws IOException { + assertTrue(Files.exists(actualFile), "Expected output file is missing: " + actualFile); + assertEquals(-1, Files.mismatch(actualFile, expectedFile), fileMismatchMessage(actualFile, expectedFile)); + } + + String fileMismatchMessage(Path actualFile, Path expectedFile) throws IOException { + List actualLines = Files.readAllLines(actualFile); + List expectedLines = Files.readAllLines(expectedFile); + int maxLines = Math.max(expectedLines.size(), actualLines.size()); + + StringBuilder differences = new StringBuilder(); + for (int i = 0; i < maxLines; i++) { + String expectedLine = (i < expectedLines.size()) ? expectedLines.get(i) : ""; + String actualLine = (i < actualLines.size()) ? actualLines.get(i) : ""; + + if (!expectedLine.equals(actualLine)) { + differences.append(String.format(""" + Line %d: + Expected: %s + Actual : %s + """, + i + 1, expectedLine, actualLine)); + } + } + + return String.format(""" + + The actual output from the integration test does not match the expected output. + + Actual output file : %s + Expected output file: %s + + Differences: + + %s + IF THIS IS EXPECTED - for example, if you have changed substantive processes within the model + or the structure of the output, please: + + 1. Verify that the output is correct and as expected. + 2. Replace the expected output file with the new output file: + cp %s %s + 3. Commit this change to Git, so that the changes are visible in your pull request and this test passes. + + """, actualFile, expectedFile, differences, actualFile, expectedFile); + } + + private void runCommand(String... args) { + try { + ProcessBuilder processBuilder = new ProcessBuilder(); + processBuilder.command(args); + processBuilder.redirectErrorStream(true); + + Process process = processBuilder.start(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + String line; + while ((line = reader.readLine()) != null) { + System.out.println(line); // Log output to console when running in Maven + } + } + int exitCode = process.waitFor(); + + assertEquals(0, exitCode, "Process exited with error code: " + exitCode); + } catch (Exception e) { + throw new RuntimeException("Failed to run: " + e.getMessage(), e); + } + } + + private void assertFileExists(String path) { + assertTrue(new File(path).exists(), "Missing file " + path); + } +} diff --git a/src/test/java/simpaths/integrationtest/expected/Statistics1.csv b/src/test/java/simpaths/integrationtest/expected/Statistics1.csv new file mode 100644 index 000000000..2e6790512 --- /dev/null +++ b/src/test/java/simpaths/integrationtest/expected/Statistics1.csv @@ -0,0 +1,9 @@ +run,time,id_Statistics1,edi_p50,giniEquivalisedHouseholdDisposableIncomeNational,giniMarketIncomeNational,grossLabourIncome_p20,grossLabourIncome_p40,grossLabourIncome_p60,grossLabourIncome_p80,medianEquivalisedHouseholdDisposableIncome,sIndex_p50,ydses_p20,ydses_p40,ydses_p60,ydses_p80, +1,2019.0,1,15821.533927783616,0.0,0.0,550.9273100009311,1241.072684429107,1871.9785671138638,2917.6001010999994,15821.533927783616,NaN,4.644275167916929,7.202009369217633,7.938329235436884,8.433367878823699, +1,2020.0,1,15302.169127034864,0.0,0.0,497.8512484990045,1181.2129305157202,1849.317037722947,2867.221413086943,15316.535245299372,NaN,4.428690615767187,7.180409935837804,7.88772968539383,8.407828035828372, +1,2021.0,1,14836.908629480247,0.0,0.0,415.20419564116474,1166.6135408685843,1845.4573862136563,2886.905481056861,14836.770070660388,NaN,4.254945112063328,7.120204693368841,7.873993907961184,8.410507643901697, +1,2022.0,1,14389.524123695042,0.0,0.0,301.97112957549587,1127.810403992741,1805.733382327959,2831.2034546100617,14391.627502447598,NaN,3.9573795256564988,6.985578509742779,7.831815226311819,8.372988907990512, +2,2019.0,1,15815.082139142574,0.0,0.0,549.5416591591883,1240.2623222557143,1871.3546692540415,2917.3538321571423,15815.082139142574,NaN,4.646224220395427,7.2011089363001535,7.938329235436884,8.433367878823699, +2,2020.0,1,15338.252421949051,0.0,0.0,496.37758974109727,1180.6984668871455,1843.9576536876648,2857.0845529925655,15344.118142661051,NaN,4.44937705574516,7.179705874096919,7.885359913843702,8.408146624151875, +2,2021.0,1,14870.896487221973,0.0,0.0,390.5432072149816,1162.4188856647052,1838.4241230467915,2890.8938093614424,14870.896487221973,NaN,4.3154011202811615,7.125296654804398,7.874445860536206,8.406014151635143, +2,2022.0,1,14475.367012692648,0.0,0.0,320.7305333284853,1138.3487273253334,1822.0427985799836,2842.4653286144,14476.019431411754,NaN,4.0356762677064415,6.984368958669483,7.8373497019151115,8.370694584722846, \ No newline at end of file diff --git a/src/test/java/simpaths/integrationtest/expected/Statistics21.csv b/src/test/java/simpaths/integrationtest/expected/Statistics21.csv new file mode 100644 index 000000000..0926782fc --- /dev/null +++ b/src/test/java/simpaths/integrationtest/expected/Statistics21.csv @@ -0,0 +1,9 @@ +run,time,id_Statistics21,aaconsToLeisRatio,aadisposableIncome18to29,aadisposableIncome30to54,aadisposableIncome55to74,aaexpenditure18to29,aaexpenditure18to54,aaexpenditure30to54,aaexpenditure55to74,aaworkNone18to29,aaworkNone18to74,aaworkNone30to54,aaworkNone55to74,avkids18to29,avkids30to54,avkids55to74,aworkFulltime18to29,aworkFulltime30to54,aworkFulltime55to74,aworkParttime18to29,aworkParttime30to54,aworkParttime55to74,dispIncomeGrossOfLosses18to29,dispIncomeGrossOfLosses30to54,dispIncomeGrossOfLosses55to74,health18to29,health30to54,health55to74,investmentIncome18to29,investmentIncome30to54,investmentIncome55to74,investmentLosses18to29,investmentLosses30to54,investmentLosses55to74,labourIncome18to29,labourIncome30to54,labourIncome55to74,pensionIncome18to29,pensionIncome30to54,pensionIncome55to74,population18to29,population30to54,population55to74,prDisabled18to29,prDisabled30to54,prDisabled55to74,prMarried18to29,prMarried30to54,prMarried55to74,wealth18to29,wealth30to54,wealth55to74, +1,2019.0,1,0.49942254062093516,-33.73101474668738,-378.70699059771414,-358.990747481301,-720.129872139352,-1107.8896451022185,-1343.0218605747868,-1403.867961567552,-0.0305705065934066,-0.018622995360786876,-0.0323501316800992,0.08305196858417474,0.3083791208791209,0.9406385616862988,0.07443061751584878,0.5552884615384616,0.6498760074395536,0.22728339985912185,0.13255494505494506,0.17792932424054556,0.08851843155670346,1252.4812066818838,1720.8139281522858,1719.854847161556,3.7317994505494507,3.461717296962182,3.1127025123268375,0.0,0.0,0.0,0.0,0.0,0.0,382.209720485393,529.3977413357179,472.64981558124515,0.0,0.0,0.0,2912.0,6452.0,4259.0,0.021291208791208792,0.03812771233725976,0.045550598732096735,0.2620192307692308,0.6649101053936763,0.6283165062221179,0.0,0.0,0.0, +1,2020.0,1,0.04286046322096415,-17.7562768388691,-442.5865608435886,-423.30797114653,-720.1041964144326,-1107.8497800059847,-1342.9763448156436,-1403.8053324715233,-0.011376505178446461,-0.008114661601642703,-0.01422422732648615,0.06797144705882352,0.34079776067179846,0.997510115157174,0.08295036764705882,0.523442967109867,0.6296296296296297,0.21806066176470587,0.1452064380685794,0.18004979769685653,0.11282169117647059,1268.455944589702,1656.9343579064114,1655.5376234963271,3.611966410076977,3.3727046374105196,3.0762867647058822,0.0,0.0,0.0,0.0,0.0,0.0,409.0935705732144,519.0087475987967,467.18291266015996,0.0,0.0,0.0,2858.0,6426.0,4352.0,0.013995801259622114,0.03112356053532524,0.038832720588235295,0.32470258922323303,0.7902272019919079,0.8120404411764706,0.0,0.0,0.0, +1,2021.0,1,-0.38471954801744424,-16.26404362043172,-476.23799448587556,-487.19132516838135,-720.1432053128243,-1107.8829432099851,-1343.0068487641072,-1403.8162707822491,6.823903339191473E-4,-0.003049527747774061,-0.01244565205267234,0.07104825706497053,0.3360281195079086,0.9979860573199071,0.093139482053612,0.4899824253075571,0.6136328427575523,0.20990458882326216,0.16660808435852373,0.19426800929512006,0.11790095411176738,1269.9481778081395,1623.2829242641244,1591.6542694744758,3.476274165202109,3.268319132455461,2.9745570195365745,0.0,0.0,0.0,0.0,0.0,0.0,422.7864555822083,518.1311416817845,484.68083739764717,0.0,0.0,0.0,2845.0,6455.0,4402.0,0.020035149384885764,0.032997676219984506,0.07155838255338483,0.30263620386643236,0.8077459333849729,0.8155383916401635,0.0,0.0,0.0, +1,2022.0,1,-0.534137469412203,-28.574948751705506,-532.521088322042,-570.6211552919635,-720.1646916690079,-1107.9167263515353,-1343.0475845683459,-1403.7567299148886,0.0041181590764892695,0.010464835725235433,0.00784458053097345,0.07924285225062211,0.31723651744800846,0.9925477410340009,0.10337027821759782,0.4821995065209729,0.5828287532991772,0.2040262384076001,0.1709552344025379,0.2047818661698494,0.11558470934177788,1257.6372726768657,1566.999830427958,1508.2244393508936,3.350370109270356,3.2026082906380995,2.9328206288170096,0.0,0.0,0.0,0.0,0.0,0.0,426.5549373497604,511.6466261201334,488.9104176164915,0.0,0.0,0.0,2837.0,6441.0,4421.0,0.022911526260133944,0.038348082595870206,0.08663198371409184,0.2767007402185407,0.8177301661232728,0.8179144989821308,0.0,0.0,0.0, +2,2019.0,1,0.5060168046481752,-31.94314618113617,-378.3827697153938,-359.077373586759,-720.1275007137027,-1107.8886527728484,-1343.0218741993517,-1403.8664898404,-0.030806797698385457,-0.01904939013795126,-0.032611714498141264,0.08226145078620051,0.307110958433528,0.9422242874845105,0.07439568176484393,0.556166265888011,0.6499380421313506,0.22764609246655715,0.13191343181037443,0.1781288723667906,0.08894625674724244,1254.269075247435,1721.1381490346062,1719.7682210560981,3.731707317073171,3.4618959107806693,3.1124149260736917,0.0,0.0,0.0,0.0,0.0,0.0,382.88408385296765,528.7951509629854,472.55161747989047,0.0,0.0,0.0,2911.0,6456.0,4261.0,0.021298522844383373,0.038258983890954154,0.04529453180004694,0.26245276537272416,0.6660470879801735,0.6259094109364,0.0,0.0,0.0, +2,2020.0,1,0.9262566226103026,-15.167395051240419,-441.1045247449654,-424.7474816106285,-720.1051749568214,-1107.8533296651106,-1342.9805966965123,-1403.8134064246738,-0.008232326480836216,-0.007353921598826529,-0.014387503628718268,0.0689735053406999,0.3425087108013937,0.9942376576857187,0.08425414364640885,0.5181184668989547,0.6294969630898614,0.21938305709023942,0.14738675958188152,0.18034574053885688,0.11049723756906077,1271.0448263773308,1658.4163940050346,1654.0981130322286,3.6094076655052265,3.37097025385454,3.0734346224677718,0.0,0.0,0.0,0.0,0.0,0.0,408.9082193888339,519.6172173986924,472.5889108205191,0.0,0.0,0.0,2870.0,6421.0,4344.0,0.014285714285714285,0.030524840367543996,0.03867403314917127,0.32473867595818817,0.7899081140009344,0.809622467771639,0.0,0.0,0.0, +2,2021.0,1,0.29280294322608635,-18.593101160001652,-475.77491255996074,-497.61942239209134,-720.1391844797338,-1107.8726530970741,-1342.9934280545856,-1403.8236676897627,3.1043069098563025E-4,-0.004858181828771124,-0.014655774106041936,0.070675496611326,0.3416345142055419,1.000462392108508,0.09438253354559928,0.4938618028761838,0.6177558569667078,0.20695929042528996,0.16310066643283058,0.19235511713933415,0.12121901296338412,1267.6191202685695,1623.7460061900392,1581.2261722507658,3.4573833742546474,3.2623304562268802,2.972481237207187,0.0,0.0,0.0,0.0,0.0,0.0,420.753939479227,519.0356075107037,487.8305121846748,0.0,0.0,0.0,2851.0,6488.0,4397.0,0.01929147667485093,0.03313810110974106,0.06936547646122355,0.3019992984917573,0.8071824907521579,0.8144189219922675,0.0,0.0,0.0, +2,2022.0,1,0.2598761514684089,-20.376123734328303,-524.4938675833075,-573.5174610294162,-720.1477107699054,-1107.9182893634902,-1343.0594508662698,-1403.7676387169777,0.004838178757939293,0.010846809740022001,0.008390678831432602,0.07758683167420821,0.31792519407198305,0.9862521481018591,0.10294117647058823,0.48659139026111503,0.5858459615685049,0.20203619909502263,0.16584333098094567,0.2012185596000625,0.11923076923076924,1265.8360976942429,1575.0270511666924,1505.328133613441,3.3454481298517997,3.189657865958444,2.9221719457013573,0.0,0.0,0.0,0.0,0.0,0.0,431.7282761325976,514.8693670780849,486.8212002949399,0.0,0.0,0.0,2834.0,6401.0,4420.0,0.022935779816513763,0.03890017184814873,0.08710407239819004,0.27240649258997884,0.8176847367598813,0.8138009049773756,0.0,0.0,0.0, \ No newline at end of file diff --git a/src/test/java/simpaths/integrationtest/expected/Statistics31.csv b/src/test/java/simpaths/integrationtest/expected/Statistics31.csv new file mode 100644 index 000000000..97228c4ce --- /dev/null +++ b/src/test/java/simpaths/integrationtest/expected/Statistics31.csv @@ -0,0 +1,9 @@ +run,time,id_Statistics31,fertilityAdjustmentFactor,fertilityRateSimulated,fertilityRateTarget,partnershipAdjustmentFactor,shareCohabitingSimulated,shareCohabitingTarget,socialCareAdjustmentFactor,utilityAdjustmentFactorCouples,utilityAdjustmentFactorSfemales,utilityAdjustmentFactorSmales, +1,2019.0,1,-0.279462622342386,0.059583211036102146,0.06092462518117112,-0.613869665517935,0.5415412796022504,0.639752445827121,0.0,0.0,0.0,0.0, +1,2020.0,1,-0.2659197918000082,0.06558823529411764,0.059320659210062375,-0.5988444469664678,0.6783352781019059,0.6494882472052341,0.0,0.0,0.0,0.0, +1,2021.0,1,-0.25543875103684177,0.0669772859638905,0.0570746110314559,-0.5821259283872153,0.6836030691856342,0.6444373367775469,0.0,0.0,0.0,0.0, +1,2022.0,1,-0.24930347300809638,0.05998835177635411,0.05798520015481514,-0.584760268520426,0.6825478361371516,0.6442540414107724,0.0,0.0,0.0,0.0, +2,2019.0,1,-0.279462622342386,0.05961820851688693,0.06092462518117112,-0.613869665517935,0.5420181806291282,0.639752445827121,0.0,0.0,0.0,0.0, +2,2020.0,1,-0.2659197918000082,0.06547269524368761,0.059320659210062375,-0.5988444469664678,0.6775679709298553,0.6494882472052341,0.0,0.0,0.0,0.0, +2,2021.0,1,-0.25543875103684177,0.06896551724137931,0.0570746110314559,-0.5821259283872153,0.6828514392427072,0.6444373367775469,0.0,0.0,0.0,0.0, +2,2022.0,1,-0.24930347300809638,0.057962529274004686,0.05798520015481514,-0.584760268520426,0.6787668147003926,0.6442540414107724,0.0,0.0,0.0,0.0, \ No newline at end of file