diff --git a/README.md b/README.md index 237085f6..e4b0225d 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ 1. Для запуска шагов, работающих с 1С (подготовка, синтаксический контроль и т.д.) требуется агент с меткой, совпадающей со значением в поле `v8version` файла конфигурации. 1. В качестве ИБ используется файловая база, создаваемая в каталоге `./build/ib`. При необходимости вы можете создать пользователей на фазе инициализации ИБ. 1. Для замеров покрытия на агентах должны быть установлены [Coverage41C](https://github.com/1c-syntax/Coverage41C), EDT и сервер отладки dbgs. Вместо установки EDT целиком можно использовать только отдельные ее компоненты, см. [Coverage41C/README.md](https://github.com/1c-syntax/Coverage41C). +1. На данный момент ошибка в [vanessa-add](https://github.com/vanessa-opensource/add/issues/1152) не позволяет собирать замеры производительности в дымовых тестах по открытию всех форм на клиенте тестирования. 1. Для параллельного выполнения шагов `bdd` и `smoke` с включенными замерами покрытия на одной ноде необходимо, чтобы в `jobConfiguration.json` были указаны **разные** порты сервера отладки для каждого шага. Параллельные билды с замерами покрытия на одной ноде не поддерживаются. ## Возможности diff --git a/src/ru/pulsar/jenkins/library/configuration/BddOptions.groovy b/src/ru/pulsar/jenkins/library/configuration/BddOptions.groovy index 47f0547b..88d10f61 100644 --- a/src/ru/pulsar/jenkins/library/configuration/BddOptions.groovy +++ b/src/ru/pulsar/jenkins/library/configuration/BddOptions.groovy @@ -5,7 +5,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonPropertyDescription @JsonIgnoreProperties(ignoreUnknown = true) -class BddOptions implements Serializable { +class BddOptions extends StepCoverageOptions implements Serializable { @JsonPropertyDescription("""Шаги, запускаемые через vrunner. В каждой строке передается отдельная команда diff --git a/src/ru/pulsar/jenkins/library/configuration/CoverageOptions.groovy b/src/ru/pulsar/jenkins/library/configuration/GlobalCoverageOptions.groovy similarity index 93% rename from src/ru/pulsar/jenkins/library/configuration/CoverageOptions.groovy rename to src/ru/pulsar/jenkins/library/configuration/GlobalCoverageOptions.groovy index 665f3dca..9a4fcda7 100644 --- a/src/ru/pulsar/jenkins/library/configuration/CoverageOptions.groovy +++ b/src/ru/pulsar/jenkins/library/configuration/GlobalCoverageOptions.groovy @@ -5,7 +5,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonPropertyDescription @JsonIgnoreProperties(ignoreUnknown = true) -class CoverageOptions implements Serializable { +class GlobalCoverageOptions implements Serializable { @JsonPropertyDescription('''Путь к исполняемому файлу dbgs. По умолчанию равен /opt/1cv8/current/dbgs. diff --git a/src/ru/pulsar/jenkins/library/configuration/JobConfiguration.groovy b/src/ru/pulsar/jenkins/library/configuration/JobConfiguration.groovy index accba947..cfedcede 100644 --- a/src/ru/pulsar/jenkins/library/configuration/JobConfiguration.groovy +++ b/src/ru/pulsar/jenkins/library/configuration/JobConfiguration.groovy @@ -58,7 +58,7 @@ class JobConfiguration implements Serializable { @JsonProperty("coverage") @JsonPropertyDescription("Настройки замеров покрытия") - CoverageOptions coverageOptions; + GlobalCoverageOptions coverageOptions @JsonProperty("yaxunit") @JsonPropertyDescription("Настройки YAXUnit") diff --git a/src/ru/pulsar/jenkins/library/configuration/SmokeTestOptions.groovy b/src/ru/pulsar/jenkins/library/configuration/SmokeTestOptions.groovy index 562678c3..58514e7f 100644 --- a/src/ru/pulsar/jenkins/library/configuration/SmokeTestOptions.groovy +++ b/src/ru/pulsar/jenkins/library/configuration/SmokeTestOptions.groovy @@ -5,7 +5,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonPropertyDescription @JsonIgnoreProperties(ignoreUnknown = true) -class SmokeTestOptions implements Serializable { +class SmokeTestOptions extends StepCoverageOptions implements Serializable { @JsonPropertyDescription("""Путь к конфигурационному файлу vanessa-runner. По умолчанию содержит значение "./tools/vrunner.json". diff --git a/src/ru/pulsar/jenkins/library/configuration/StepCoverageOptions.groovy b/src/ru/pulsar/jenkins/library/configuration/StepCoverageOptions.groovy new file mode 100644 index 00000000..fbffe09c --- /dev/null +++ b/src/ru/pulsar/jenkins/library/configuration/StepCoverageOptions.groovy @@ -0,0 +1,13 @@ +package ru.pulsar.jenkins.library.configuration + +import com.fasterxml.jackson.annotation.JsonPropertyDescription + +class StepCoverageOptions { + + @JsonPropertyDescription("Выполнять замер покрытия") + Boolean coverage = false + + @JsonPropertyDescription("Порт, на котором будет запущен сервер отладки для замера покрытия") + int dbgsPort = 1550 + +} diff --git a/src/ru/pulsar/jenkins/library/configuration/YaxunitOptions.groovy b/src/ru/pulsar/jenkins/library/configuration/YaxunitOptions.groovy index c45ae2cc..86d8e183 100644 --- a/src/ru/pulsar/jenkins/library/configuration/YaxunitOptions.groovy +++ b/src/ru/pulsar/jenkins/library/configuration/YaxunitOptions.groovy @@ -5,7 +5,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonPropertyDescription @JsonIgnoreProperties(ignoreUnknown = true) -class YaxunitOptions implements Serializable { +class YaxunitOptions extends StepCoverageOptions implements Serializable { @JsonPropertyDescription("""Путь к конфигурационному файлу vanessa-runner. По умолчанию содержит значение "./tools/vrunner.json". diff --git a/src/ru/pulsar/jenkins/library/steps/Bdd.groovy b/src/ru/pulsar/jenkins/library/steps/Bdd.groovy index 68200476..165c2bf0 100644 --- a/src/ru/pulsar/jenkins/library/steps/Bdd.groovy +++ b/src/ru/pulsar/jenkins/library/steps/Bdd.groovy @@ -6,10 +6,9 @@ import ru.pulsar.jenkins.library.ioc.ContextRegistry import ru.pulsar.jenkins.library.utils.CoverageUtils import ru.pulsar.jenkins.library.utils.FileUtils import ru.pulsar.jenkins.library.utils.Logger -import org.apache.commons.lang3.RandomStringUtils import ru.pulsar.jenkins.library.utils.VRunner -class Bdd implements Serializable { +class Bdd implements Serializable, Coverable { private final JobConfiguration config @@ -44,34 +43,11 @@ class Bdd implements Serializable { List returnStatuses = [] def coverageOpts = config.coverageOptions - def port = options.dbgsPort - def currentDbgsPids = CoverageUtils.getPIDs("dbgs") - def currentCoverage41CPids = CoverageUtils.getPIDs("Coverage41C") - def lockableResource = RandomStringUtils.random(9, true, false) - - if (options.coverage) { - lockableResource = "${env.NODE_NAME}_$port" - } - - steps.lock(lockableResource) { - if (options.coverage) { - steps.start("${coverageOpts.dbgsPath} --addr=127.0.0.1 --port=$port") - steps.start("${coverageOpts.coverage41CPath} start -i DefAlias -u http://127.0.0.1:$port -P $workspaceDir -s $srcDir -o $COVERAGE_STASH_PATH") - steps.cmd("${coverageOpts.coverage41CPath} check -i DefAlias -u http://127.0.0.1:$port") - - def newDbgsPids = CoverageUtils.getPIDs("dbgs") - def newCoverage41CPids = CoverageUtils.getPIDs("Coverage41C") - - newDbgsPids.removeAll(currentDbgsPids) - newCoverage41CPids.removeAll(currentCoverage41CPids) - - newDbgsPids.addAll(newCoverage41CPids) - def pids = newDbgsPids.join(" ") - - steps.writeFile(COVERAGE_PIDS_PATH, pids, 'UTF-8') - - Logger.println("Coverage PIDs for cleanup: $pids") + def coverageContext = CoverageUtils.prepareContext(config, options) + steps.lock(coverageContext.lockableResource) { + if (coverageContext != null) { + CoverageUtils.startCoverage(steps, coverageOpts, coverageContext, workspaceDir, srcDir, this) } config.bddOptions.vrunnerSteps.each { @@ -89,8 +65,8 @@ class Bdd implements Serializable { Logger.println("Тестирование сценариев завершилось успешно") } - if (options.coverage) { - steps.cmd("${coverageOpts.coverage41CPath} stop -i DefAlias -u http://127.0.0.1:$port") + if (coverageContext != null) { + CoverageUtils.stopCoverage(steps, coverageOpts, coverageContext) } } } @@ -102,4 +78,12 @@ class Bdd implements Serializable { } } + + String getCoverageStashPath() { + return COVERAGE_STASH_PATH + } + + String getCoveragePidsPath() { + return COVERAGE_PIDS_PATH + } } diff --git a/src/ru/pulsar/jenkins/library/steps/Coverable.groovy b/src/ru/pulsar/jenkins/library/steps/Coverable.groovy new file mode 100644 index 00000000..54271bb8 --- /dev/null +++ b/src/ru/pulsar/jenkins/library/steps/Coverable.groovy @@ -0,0 +1,8 @@ +package ru.pulsar.jenkins.library.steps + +interface Coverable { + + String getCoverageStashPath(); + String getCoveragePidsPath(); + +} \ No newline at end of file diff --git a/src/ru/pulsar/jenkins/library/steps/CoverageContext.groovy b/src/ru/pulsar/jenkins/library/steps/CoverageContext.groovy new file mode 100644 index 00000000..36d47286 --- /dev/null +++ b/src/ru/pulsar/jenkins/library/steps/CoverageContext.groovy @@ -0,0 +1,23 @@ +package ru.pulsar.jenkins.library.steps + +import ru.pulsar.jenkins.library.configuration.GlobalCoverageOptions + +class CoverageContext { + + String lockableResource + GlobalCoverageOptions coverageOptions + int port + ArrayList pids + ArrayList dbgsPids + ArrayList coverage41CPids + + CoverageContext(String lockableResource, GlobalCoverageOptions coverageOptions, int port, ArrayList dbgsPids, ArrayList coverage41CPids) { + this.lockableResource = lockableResource + this.coverageOptions = coverageOptions + this.port = port + this.pids = dbgsPids + coverage41CPids + this.dbgsPids = dbgsPids + this.coverage41CPids = coverage41CPids + } + +} diff --git a/src/ru/pulsar/jenkins/library/steps/GetExtensions.groovy b/src/ru/pulsar/jenkins/library/steps/GetExtensions.groovy index 4fac658e..d0ec31f4 100644 --- a/src/ru/pulsar/jenkins/library/steps/GetExtensions.groovy +++ b/src/ru/pulsar/jenkins/library/steps/GetExtensions.groovy @@ -16,7 +16,7 @@ class GetExtensions implements Serializable { public static final String EXTENSIONS_STASH = 'extensions' public static final String EXTENSIONS_OUT_DIR = 'build/out/cfe' - private final JobConfiguration config; + private final JobConfiguration config GetExtensions(JobConfiguration config) { this.config = config @@ -29,9 +29,9 @@ class GetExtensions implements Serializable { def env = steps.env() - steps.installLocalDependencies(); + steps.installLocalDependencies() - String vrunnerPath = initVRunnerPath(); + String vrunnerPath = initVRunnerPath() Logger.println("Сборка расширений") @@ -88,7 +88,7 @@ class GetExtensions implements Serializable { private void extractConvertedExtensions(String sourceDirName, IStepExecutor steps) { if (config.sourceFormat == SourceFormat.EDT) { - // usntash and unzip the edt to designer format transformation + // unstash and unzip the edt to designer format transformation steps.unstash(EdtToDesignerFormatTransformation.EXTENSION_ZIP_STASH) steps.unzip(sourceDirName, EdtToDesignerFormatTransformation.EXTENSION_ZIP) } diff --git a/src/ru/pulsar/jenkins/library/steps/SmokeTest.groovy b/src/ru/pulsar/jenkins/library/steps/SmokeTest.groovy index 74e220e3..aeab4e5d 100644 --- a/src/ru/pulsar/jenkins/library/steps/SmokeTest.groovy +++ b/src/ru/pulsar/jenkins/library/steps/SmokeTest.groovy @@ -1,7 +1,6 @@ package ru.pulsar.jenkins.library.steps import hudson.FilePath -import org.apache.commons.lang3.RandomStringUtils import ru.pulsar.jenkins.library.IStepExecutor import ru.pulsar.jenkins.library.configuration.JobConfiguration import ru.pulsar.jenkins.library.ioc.ContextRegistry @@ -11,7 +10,7 @@ import ru.pulsar.jenkins.library.utils.Logger import ru.pulsar.jenkins.library.utils.StringJoiner import ru.pulsar.jenkins.library.utils.VRunner -class SmokeTest implements Serializable { +class SmokeTest implements Serializable, Coverable { public static final String ALLURE_STASH = 'smoke-allure' public static final String COVERAGE_STASH_NAME = 'smoke-coverage' @@ -109,41 +108,19 @@ class SmokeTest implements Serializable { } def coverageOpts = config.coverageOptions - def port = options.dbgsPort - def currentDbgsPids = CoverageUtils.getPIDs("dbgs") - def currentCoverage41CPids = CoverageUtils.getPIDs("Coverage41C") - def lockableResource = RandomStringUtils.random(9, true, false) - if (options.coverage) { - lockableResource = "${env.NODE_NAME}_$port" - } - - steps.lock(lockableResource) { - if (options.coverage) { - steps.start("${coverageOpts.dbgsPath} --addr=127.0.0.1 --port=$port") - steps.start("${coverageOpts.coverage41CPath} start -i DefAlias -u http://127.0.0.1:$port -P $workspaceDir -s $srcDir -o $COVERAGE_STASH_PATH") - steps.cmd("${coverageOpts.coverage41CPath} check -i DefAlias -u http://127.0.0.1:$port") - - def newDbgsPids = CoverageUtils.getPIDs("dbgs") - def newCoverage41CPids = CoverageUtils.getPIDs("Coverage41C") - - newDbgsPids.removeAll(currentDbgsPids) - newCoverage41CPids.removeAll(currentCoverage41CPids) - - newDbgsPids.addAll(newCoverage41CPids) - def pids = newDbgsPids.join(" ") - - steps.writeFile(COVERAGE_PIDS_PATH, pids, 'UTF-8') - - Logger.println("Coverage PIDs for cleanup: $pids") + def coverageContext = CoverageUtils.prepareContext(config, options) + steps.lock(coverageContext.lockableResource) { + if (coverageContext != null) { + CoverageUtils.startCoverage(steps, coverageOpts, coverageContext, workspaceDir, srcDir, this) } steps.withEnv(logosConfig) { VRunner.exec(command, true) } - if (options.coverage) { - steps.cmd("${coverageOpts.coverage41CPath} stop -i DefAlias -u http://127.0.0.1:$port") + if (coverageContext != null) { + CoverageUtils.stopCoverage(steps, coverageOpts, coverageContext) } } @@ -162,4 +139,12 @@ class SmokeTest implements Serializable { } } + + String getCoverageStashPath() { + return COVERAGE_STASH_PATH + } + + String getCoveragePidsPath() { + return COVERAGE_PIDS_PATH + } } diff --git a/src/ru/pulsar/jenkins/library/steps/Yaxunit.groovy b/src/ru/pulsar/jenkins/library/steps/Yaxunit.groovy index d704731c..624fe20c 100644 --- a/src/ru/pulsar/jenkins/library/steps/Yaxunit.groovy +++ b/src/ru/pulsar/jenkins/library/steps/Yaxunit.groovy @@ -1,9 +1,7 @@ package ru.pulsar.jenkins.library.steps import hudson.FilePath -import org.apache.commons.lang3.RandomStringUtils import ru.pulsar.jenkins.library.IStepExecutor - import ru.pulsar.jenkins.library.configuration.JobConfiguration import ru.pulsar.jenkins.library.ioc.ContextRegistry import ru.pulsar.jenkins.library.utils.CoverageUtils @@ -11,7 +9,7 @@ import ru.pulsar.jenkins.library.utils.FileUtils import ru.pulsar.jenkins.library.utils.Logger import ru.pulsar.jenkins.library.utils.VRunner -class Yaxunit implements Serializable { +class Yaxunit implements Serializable, Coverable { private final JobConfiguration config @@ -72,33 +70,11 @@ class Yaxunit implements Serializable { } def coverageOpts = config.coverageOptions - def port = options.dbgsPort - def currentDbgsPids = CoverageUtils.getPIDs("dbgs") - def currentCoverage41CPids = CoverageUtils.getPIDs("Coverage41C") - def lockableResource = RandomStringUtils.random(9, true, false) - if (options.coverage) { - lockableResource = "${env.NODE_NAME}_$port" - } - - steps.lock(lockableResource) { - if (options.coverage) { - steps.start("${coverageOpts.dbgsPath} --addr=127.0.0.1 --port=$port") - steps.start("${coverageOpts.coverage41CPath} start -i DefAlias -u http://127.0.0.1:$port -P $workspaceDir -s $srcDir -o $COVERAGE_STASH_PATH") - steps.cmd("${coverageOpts.coverage41CPath} check -i DefAlias -u http://127.0.0.1:$port") - - def newDbgsPids = CoverageUtils.getPIDs("dbgs") - def newCoverage41CPids = CoverageUtils.getPIDs("Coverage41C") - - newDbgsPids.removeAll(currentDbgsPids) - newCoverage41CPids.removeAll(currentCoverage41CPids) - - newDbgsPids.addAll(newCoverage41CPids) - def pids = newDbgsPids.join(" ") - - steps.writeFile(COVERAGE_PIDS_PATH, pids, 'UTF-8') - - Logger.println("Coverage PIDs for cleanup: $pids") + def coverageContext = CoverageUtils.prepareContext(config, options) + steps.lock(coverageContext.lockableResource) { + if (coverageContext != null) { + CoverageUtils.startCoverage(steps, coverageOpts, coverageContext, workspaceDir, srcDir, this) } // Выполняем команды @@ -106,8 +82,8 @@ class Yaxunit implements Serializable { VRunner.exec(runTestsCommand, true) } - if (options.coverage) { - steps.cmd("${coverageOpts.coverage41CPath} stop -i DefAlias -u http://127.0.0.1:$port") + if (coverageContext != null) { + CoverageUtils.stopCoverage(steps, coverageOpts, coverageContext) } } @@ -137,4 +113,14 @@ class Yaxunit implements Serializable { steps.stash(COVERAGE_STASH_NAME, COVERAGE_STASH_PATH, true) } } + + String getCoverageStashPath() { + return COVERAGE_STASH_PATH + } + + String getCoveragePidsPath() { + return COVERAGE_PIDS_PATH + } + + } diff --git a/src/ru/pulsar/jenkins/library/utils/CoverageUtils.groovy b/src/ru/pulsar/jenkins/library/utils/CoverageUtils.groovy index e897ae46..71624cff 100644 --- a/src/ru/pulsar/jenkins/library/utils/CoverageUtils.groovy +++ b/src/ru/pulsar/jenkins/library/utils/CoverageUtils.groovy @@ -1,7 +1,14 @@ package ru.pulsar.jenkins.library.utils +import hudson.FilePath +import org.apache.commons.lang3.RandomStringUtils import ru.pulsar.jenkins.library.IStepExecutor +import ru.pulsar.jenkins.library.configuration.GlobalCoverageOptions +import ru.pulsar.jenkins.library.configuration.JobConfiguration +import ru.pulsar.jenkins.library.configuration.StepCoverageOptions import ru.pulsar.jenkins.library.ioc.ContextRegistry +import ru.pulsar.jenkins.library.steps.Coverable +import ru.pulsar.jenkins.library.steps.CoverageContext class CoverageUtils { static ArrayList getPIDs(String name) { @@ -17,4 +24,46 @@ class CoverageUtils { } return pids.split('\n').toList() } + + static CoverageContext prepareContext(JobConfiguration config, StepCoverageOptions options) { + + IStepExecutor steps = ContextRegistry.getContext().getStepExecutor() + def env = steps.env() + + def coverageOpts = config.coverageOptions + def port = options.dbgsPort + def currentDbgsPids = getPIDs("dbgs") + def currentCoverage41CPids = getPIDs("Coverage41C") + def lockableResource = RandomStringUtils.random(9, true, false) + if (options.coverage) { + lockableResource = "${env.NODE_NAME}_$port" + } + + return new CoverageContext(lockableResource, coverageOpts, port, currentDbgsPids, currentCoverage41CPids) + + } + + static void startCoverage(IStepExecutor steps, GlobalCoverageOptions coverageOpts, CoverageContext coverageContext, FilePath workspaceDir, String srcDir, Coverable coverable) { + steps.start("${coverageOpts.dbgsPath} --addr=127.0.0.1 --port=$coverageContext.port") + steps.start("${coverageOpts.coverage41CPath} start -i DefAlias -u http://127.0.0.1:$coverageContext.port -P $workspaceDir -s $srcDir -o ${coverable.getCoverageStashPath()}") + steps.cmd("${coverageOpts.coverage41CPath} check -i DefAlias -u http://127.0.0.1:$coverageContext.port") + + def newDbgsPids = getPIDs("dbgs") + def newCoverage41CPids = getPIDs("Coverage41C") + + newDbgsPids.removeAll(coverageContext.dbgsPids) + newCoverage41CPids.removeAll(coverageContext.coverage41CPids) + + newDbgsPids.addAll(newCoverage41CPids) + def pids = newDbgsPids.join(" ") + + steps.writeFile(coverable.getCoveragePidsPath(), pids, 'UTF-8') + + Logger.println("Coverage PIDs for cleanup: $pids") + } + + static void stopCoverage(IStepExecutor steps, GlobalCoverageOptions coverageOpts, CoverageContext coverageContext) { + steps.cmd("${coverageOpts.coverage41CPath} stop -i DefAlias -u http://127.0.0.1:$coverageContext.port") + } + }