From fc89c9479c00464121b360c9b60ebab0875eec4e Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Mon, 24 Jan 2022 09:57:40 +0100 Subject: [PATCH] Add behave tests --- .gitattributes | 1 + behave/KankuFile | 91 +++++++ behave/README.md | 73 +++++ behave/features/add.feature | 24 ++ behave/features/checkout.feature | 76 ++++++ behave/features/environment.py | 57 ++++ ...ies-project-package-repo-arch-file.feature | 67 +++++ ...binaries-project-package-repo-arch.feature | 59 ++++ .../getbinaries-project-repo-arch.feature | 71 +++++ .../getbinaries-repo-arch-pkgcheckout.feature | 44 +++ .../getbinaries-repo-arch-prjcheckout.feature | 105 +++++++ .../getbinaries-repo-pkgcheckout.feature | 50 ++++ .../getbinaries-repo-prjcheckout.feature | 118 ++++++++ behave/features/list.feature | 33 +++ behave/features/steps/__init__.py | 0 behave/features/steps/common.py | 257 ++++++++++++++++++ behave/features/steps/kanku.py | 76 ++++++ behave/features/steps/osc.py | 75 +++++ .../fixtures/pac/multibuild-pkg-1._multibuild | 4 + behave/fixtures/pac/multibuild-pkg-1.changes | 4 + behave/fixtures/pac/multibuild-pkg-1.spec | 98 +++++++ behave/fixtures/pac/test-pkgA-1.changes | 4 + behave/fixtures/pac/test-pkgA-1.spec | 25 ++ behave/fixtures/pac/test-pkgA-2.changes | 4 + behave/fixtures/pac/test-pkgA-2.spec | 25 ++ behave/fixtures/pac/test-pkgA-3.changes | 4 + behave/fixtures/pac/test-pkgA-3.spec | 25 ++ behave/fixtures/pac/test-pkgB-1.changes | 4 + behave/fixtures/pac/test-pkgB-1.spec | 25 ++ behave/fixtures/pac/test-pkgB-2.changes | 4 + behave/fixtures/pac/test-pkgB-2.spec | 25 ++ behave/fixtures/prj/home_Admin.xml | 14 + behave/fixtures/prj/openSUSE.org.xml | 8 + behave/fixtures/prj/openSUSE_Factory.xml | 15 + behave/obs-setup/environment.py | 20 ++ behave/obs-setup/obs-setup.feature | 113 ++++++++ behave/obs-setup/steps | 1 + behave/requirements.spec | 46 ++++ behave/requirements.txt | 1 + 39 files changed, 1746 insertions(+) create mode 100644 behave/KankuFile create mode 100644 behave/README.md create mode 100644 behave/features/add.feature create mode 100644 behave/features/checkout.feature create mode 100644 behave/features/environment.py create mode 100644 behave/features/getbinaries-project-package-repo-arch-file.feature create mode 100644 behave/features/getbinaries-project-package-repo-arch.feature create mode 100644 behave/features/getbinaries-project-repo-arch.feature create mode 100644 behave/features/getbinaries-repo-arch-pkgcheckout.feature create mode 100644 behave/features/getbinaries-repo-arch-prjcheckout.feature create mode 100644 behave/features/getbinaries-repo-pkgcheckout.feature create mode 100644 behave/features/getbinaries-repo-prjcheckout.feature create mode 100644 behave/features/list.feature create mode 100644 behave/features/steps/__init__.py create mode 100644 behave/features/steps/common.py create mode 100644 behave/features/steps/kanku.py create mode 100644 behave/features/steps/osc.py create mode 100644 behave/fixtures/pac/multibuild-pkg-1._multibuild create mode 100644 behave/fixtures/pac/multibuild-pkg-1.changes create mode 100644 behave/fixtures/pac/multibuild-pkg-1.spec create mode 100644 behave/fixtures/pac/test-pkgA-1.changes create mode 100644 behave/fixtures/pac/test-pkgA-1.spec create mode 100644 behave/fixtures/pac/test-pkgA-2.changes create mode 100644 behave/fixtures/pac/test-pkgA-2.spec create mode 100644 behave/fixtures/pac/test-pkgA-3.changes create mode 100644 behave/fixtures/pac/test-pkgA-3.spec create mode 100644 behave/fixtures/pac/test-pkgB-1.changes create mode 100644 behave/fixtures/pac/test-pkgB-1.spec create mode 100644 behave/fixtures/pac/test-pkgB-2.changes create mode 100644 behave/fixtures/pac/test-pkgB-2.spec create mode 100644 behave/fixtures/prj/home_Admin.xml create mode 100644 behave/fixtures/prj/openSUSE.org.xml create mode 100644 behave/fixtures/prj/openSUSE_Factory.xml create mode 100644 behave/obs-setup/environment.py create mode 100644 behave/obs-setup/obs-setup.feature create mode 120000 behave/obs-setup/steps create mode 100644 behave/requirements.spec create mode 100644 behave/requirements.txt diff --git a/.gitattributes b/.gitattributes index c5bf40da..b657a8d6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,6 @@ .gitattributes export-ignore .github export-ignore +behave export-ignore contrib/build_rpm.py export-ignore contrib/osc.spec export-ignore osc/util/git_version.py export-subst diff --git a/behave/KankuFile b/behave/KankuFile new file mode 100644 index 00000000..176f3247 --- /dev/null +++ b/behave/KankuFile @@ -0,0 +1,91 @@ +domain_name: obs-server +default_job: kanku-job +login_user: root +login_pass: opensuse + +jobs: + kanku-job: + - + use_module: Kanku::Handler::SetJobContext + options: + host_interface: eth0 + - + use_module: Kanku::Handler::OBSCheck + options: + api_url: https://api.opensuse.org/public + # Please have a look at + # kanku lsi + # to find more official Images + project: OBS:Server:Unstable + package: OBS-Appliance:qcow2 + repository: images + arch: x86_64 + use_oscrc: 0 + - + use_module: Kanku::Handler::ImageDownload + - + use_module: Kanku::Handler::CreateDomain + options: + memory: 5G + vcpu: 4 + use_9p: 1 + - + use_module: Kanku::Handler::PrepareSSH + - + use_module: Kanku::Handler::ExecuteCommandViaSSH + options: + commands: + # fix the following error in scheduler: unknown host 'obs-server.kanku.site' + - echo "127.0.0.1 obs-server.kanku.site" >> /etc/hosts + - echo "::1 obs-server.kanku.site" >> /etc/hosts + + # disable OBS:Server:Unstable, we want to install only stable packages from now on + - zypper --non-interactive modifyrepo --disable OBS:Server:Unstable + + # refresh repodata and install additional packages + - zypper --non-interactive --gpg-auto-import-keys refresh + - zypper --non-interactive install bash-completion rpm-build sudo + + # reinstall osc with a stable version + - zypper --non-interactive install --force osc + + # install test requirements + - rpmbuild -bs --define='_srcrpmdir /opt/' --without=host_only_packages /tmp/kanku/requirements.spec + - zypper --non-interactive source-install --build-deps-only /opt/osc-behave-requirements-1-0.src.rpm + + # zramswap for more available memory + - zypper --non-interactive install systemd-zram-service + - systemctl enable zramswap + + # decrease number of workers + - sed -i 's@^OBS_WORKER_INSTANCES=.*@OBS_WORKER_INSTANCES="1"@' /etc/sysconfig/obs-server + + # configure OBS URL (for osc browse) + - echo "UPDATE configurations SET obs_url='https://obs-server.kanku.site';" | mysql api_production + + # configure download URL + - echo "UPDATE configurations SET download_url='http://obs-server.kanku.site:82';" | mysql api_production + + # write configuration from the database on disk + - cd /srv/www/obs/api; RAILS_ENV=production SAFETY_ASSURED=1 bin/rails writeconfiguration + - + use_module: Kanku::Handler::Reboot + # Reboot to restart obs services. + # Restarting them via systemctl doesn't always work, it ends up with the following error: + # > scheduler is already running for ! + # We also need them restarted because they're failing on unresolvable obs-server.kanku.site. + - + use_module: Kanku::Handler::ExecuteCommandViaSSH + options: + commands: + # use behave to setup OBS - create projects and packages + - cd /tmp/kanku && behave obs-setup + + # unmount /tmp/kanku so we are able to create a snapshot of the VM + - umount /tmp/kanku + - + use_module: Kanku::Handler::DomainSnapshot + options: + # create a snapshot we'll use as a starting point for running tests + command: create + name: current diff --git a/behave/README.md b/behave/README.md new file mode 100644 index 00000000..f2a95256 --- /dev/null +++ b/behave/README.md @@ -0,0 +1,73 @@ +Prerequisities +-------------- +First of all, we need to install requirements: +``` +# optional step in case we want to use the latest kanku packages +$ zypper ar obs://devel:kanku:staging devel:kanku:staging + +$ cd behave +$ rpmbuild -bs --define='_srcrpmdir .' requirements.spec +$ sudo zypper source-install --build-deps-only ./osc-behave-requirements-1-0.src.rpm +``` + +Then we need to build 'obs-server' VM using kanku: +``` +# necessary if the 'obs-server' domain exists already +$ kanku destroy + +$ kanku up [--skip_all_checks] +``` + + +Running tests +------------- + +Run all tests +``` +$ cd behave +$ behave +``` + +Run selected tests +``` +$ cd behave +$ behave features/.feature +``` + +Run tests being worked on (decorated with `@wip`) +``` +$ cd behave +behave --wip -k +``` + +Run tests with the selected `osc` executable +``` +$ cd behave +behave -Dosc=../osc-wrapper.py +``` + + +Filesystem layout +----------------- + +``` + ++- behave + +- features + +- *.feature # tests (that use steps defined in the `steps` directory) + # * https://behave.readthedocs.io/en/stable/tutorial.html#feature-files + +- environment.py # code that runs before/after certain events (steps, features, etc.) + # * https://behave.readthedocs.io/en/stable/tutorial.html#environmental-controls + # * frequently used to modify ``context`` + +- steps # step definitions, support code + # * https://behave.readthedocs.io/en/stable/tutorial.html#python-step-implementations + +- fixtures # test data + +- * # additional support files +``` + + +Good to know +------------ +* `context` provides state information to the tests; you can think of it as passing `self` to python methods. +* `context.config.userdata` contains values of defines specified on the command-line: + ``-D NAME=VALUE`` -> ``context.config.userdata[NAME] = VALUE`` diff --git a/behave/features/add.feature b/behave/features/add.feature new file mode 100644 index 00000000..91bd63e6 --- /dev/null +++ b/behave/features/add.feature @@ -0,0 +1,24 @@ +@no-snapshot +Feature: `osc add` command + + +Scenario: Run `osc add` on a new file in a package + Given I set working directory to "{context.osc.temp}" + And I execute osc with args "checkout openSUSE:Factory test-pkgA" + And I set working directory to "{context.osc.temp}/openSUSE:Factory/test-pkgA" + And I copy file "{context.fixtures}/pac/test-pkgA-1.spec" to "{context.osc.temp}/openSUSE:Factory/test-pkgA/new_file" + And I execute osc with args "status --verbose" + And stdout is + """ + ? new_file + test-pkgA.changes + test-pkgA.spec + """ + When I execute osc with args "add new_file" + And I execute osc with args "status --verbose" + Then stdout is + """ + A new_file + test-pkgA.changes + test-pkgA.spec + """ diff --git a/behave/features/checkout.feature b/behave/features/checkout.feature new file mode 100644 index 00000000..a9f307ca --- /dev/null +++ b/behave/features/checkout.feature @@ -0,0 +1,76 @@ +@no-snapshot +Feature: `osc checkout` command + + +Scenario: Run `osc checkout` on a project + Given I set working directory to "{context.osc.temp}" + When I execute osc with args "checkout openSUSE:Factory" + Then directory "{context.osc.temp}/openSUSE:Factory" exists + And directory "{context.osc.temp}/openSUSE:Factory/.osc" exists + And directory "{context.osc.temp}/openSUSE:Factory/test-pkgA" exists + And directory "{context.osc.temp}/openSUSE:Factory/test-pkgA/.osc" exists + And file "{context.osc.temp}/openSUSE:Factory/test-pkgA/test-pkgA.spec" exists + And file "{context.osc.temp}/openSUSE:Factory/test-pkgA/test-pkgA.changes" exists + And directory "{context.osc.temp}/openSUSE:Factory/test-pkgB" exists + And directory "{context.osc.temp}/openSUSE:Factory/test-pkgB/.osc" exists + And file "{context.osc.temp}/openSUSE:Factory/test-pkgB/test-pkgB.spec" exists + And file "{context.osc.temp}/openSUSE:Factory/test-pkgB/test-pkgB.changes" exists + + +Scenario: Run `osc checkout` on a package + Given I set working directory to "{context.osc.temp}" + When I execute osc with args "checkout openSUSE:Factory test-pkgA" + Then directory "{context.osc.temp}/openSUSE:Factory" exists + And directory "{context.osc.temp}/openSUSE:Factory/.osc" exists + And directory "{context.osc.temp}/openSUSE:Factory/test-pkgA" exists + And directory "{context.osc.temp}/openSUSE:Factory/test-pkgA/.osc" exists + And file "{context.osc.temp}/openSUSE:Factory/test-pkgA/test-pkgA.spec" exists + And file "{context.osc.temp}/openSUSE:Factory/test-pkgA/test-pkgA.changes" exists + And directory "{context.osc.temp}/openSUSE:Factory/test-pkgB" does not exist + + +# Unlike other checkouts, file checkout doesn't create any subdirs +# and puts files directly in the working directory. +Scenario: Run `osc checkout` on a file + Given I set working directory to "{context.osc.temp}" + When I execute osc with args "checkout openSUSE:Factory test-pkgA test-pkgA.spec" + Then directory "{context.osc.temp}/openSUSE:Factory" does not exist + And file "{context.osc.temp}/test-pkgA.spec" exists + And file "{context.osc.temp}/test-pkgA.changes" does not exist + + +Scenario: Run `osc checkout` on a package, use a file size limit + Given I set working directory to "{context.osc.temp}" + When I execute osc with args "checkout openSUSE:Factory test-pkgA --limit-size=200" + And file "{context.osc.temp}/openSUSE:Factory/test-pkgA/test-pkgA.spec" does not exist + And file "{context.osc.temp}/openSUSE:Factory/test-pkgA/test-pkgA.changes" exists + + +Scenario: Run `osc checkout` on a package in a specified revision + Given I set working directory to "{context.osc.temp}" + When I execute osc with args "checkout openSUSE:Factory test-pkgA --revision=2" + Then file "{context.osc.temp}/openSUSE:Factory/test-pkgA/test-pkgA.spec" is identical to "{context.fixtures}/pac/test-pkgA-2.spec" + And file "{context.osc.temp}/openSUSE:Factory/test-pkgA/test-pkgA.changes" is identical to "{context.fixtures}/pac/test-pkgA-2.changes" + + +Scenario: Run `osc checkout` on a package, place the files in a specified output directory + Given I set working directory to "{context.osc.temp}" + When I execute osc with args "checkout openSUSE:Factory test-pkgA --output-dir=pkgA" + And directory "{context.osc.temp}/openSUSE:Factory/test-pkgA" does not exist + And directory "{context.osc.temp}/pkgA" exists + And directory "{context.osc.temp}/pkgA/.osc" exists + And file "{context.osc.temp}/pkgA/test-pkgA.spec" exists + And file "{context.osc.temp}/pkgA/test-pkgA.changes" exists + + +# TODO(dmach): revisit this functionality +# Working dir becomes a project dir, package goes into a subdirectory. +# One would expect the package to go to the working dir. +Scenario: Run `osc checkout` on a package, place the files in the working directory + Given I set working directory to "{context.osc.temp}" + When I execute osc with args "checkout openSUSE:Factory test-pkgA --current-dir" + And directory "{context.osc.temp}/openSUSE:Factory/test-pkgA" does not exist + And directory "{context.osc.temp}/.osc" exists + And directory "{context.osc.temp}/test-pkgA/.osc" exists + And file "{context.osc.temp}/test-pkgA/test-pkgA.spec" exists + And file "{context.osc.temp}/test-pkgA/test-pkgA.changes" exists diff --git a/behave/features/environment.py b/behave/features/environment.py new file mode 100644 index 00000000..a8723b14 --- /dev/null +++ b/behave/features/environment.py @@ -0,0 +1,57 @@ +import os + +from steps import kanku +from steps import osc +from steps import common + + +def before_step(context, step): + pass + + +def after_step(context, step): + pass + + +def before_scenario(context, scenario): + context.osc = osc.Osc(context) + + +def after_scenario(context, scenario): + common.check_exit_code(context) + del context.osc + + +def before_feature(context, feature): + # decorate Feature with @no-snapshot to avoid doing a snapshot rollback + if "no-snapshot" not in feature.tags: + context.kanku.revert_to_snapshot() + + +def after_feature(context, feature): + pass + + +def after_tag(context, tag): + pass + + +def before_all(context): + # convert path to osc executable to an absolute path to avoid relative path issues + if "osc" in context.config.userdata: + context.config.userdata["osc"] = os.path.abspath(os.path.expanduser(context.config.userdata["osc"])) + + # absolute path to .../behave/fixtures + context.fixtures = os.path.join(os.path.dirname(__file__), "..", "fixtures") + + kankufile = os.path.join(os.path.dirname(__file__), "..", "KankuFile") + context.kanku = kanku.Kanku(context, kankufile) + + # This fails if the snapshot exists already. + # It's ok in most cases, because it's the same snapshot we'd normally create. + context.kanku.create_snapshot() + + +def after_all(context): + del context.kanku + del context.fixtures diff --git a/behave/features/getbinaries-project-package-repo-arch-file.feature b/behave/features/getbinaries-project-package-repo-arch-file.feature new file mode 100644 index 00000000..3e0ef601 --- /dev/null +++ b/behave/features/getbinaries-project-package-repo-arch-file.feature @@ -0,0 +1,67 @@ +@no-snapshot +Feature: `osc getbinaries ` command + + +# common steps for all scenarios +Background: + Given I set working directory to "{context.osc.temp}" + + +Scenario: Run `osc getbinaries ` + When I execute osc with args "getbinaries openSUSE:Factory multibuild-pkg standard x86_64 multibuild-pkg-1-1.1.x86_64.rpm" + Then directory listing of "{context.osc.temp}/binaries/" is + """ + multibuild-pkg-1-1.1.x86_64.rpm + """ + + +Scenario: Run `osc getbinaries --multibuild-package=` + When I execute osc with args "getbinaries openSUSE:Factory multibuild-pkg standard x86_64 multibuild-pkg-flavor1-1-1.1.x86_64.rpm --multibuild-package=flavor1" + # the option is allowed only in a package checkout + Then the exit code is 2 + + +Scenario: Run `osc getbinaries : ` where file is a package + When I execute osc with args "getbinaries openSUSE:Factory multibuild-pkg:flavor1 standard x86_64 multibuild-pkg-flavor1-1-1.1.x86_64.rpm" + Then directory listing of "{context.osc.temp}/binaries/" is + """ + multibuild-pkg-flavor1-1-1.1.x86_64.rpm + """ + + +Scenario: Run `osc getbinaries ` where file is a source package + When I execute osc with args "getbinaries openSUSE:Factory multibuild-pkg standard x86_64 multibuild-pkg-1-1.1.src.rpm" + Then directory listing of "{context.osc.temp}/binaries/" is + """ + """ + + +Scenario: Run `osc getbinaries --source` where file is a source package + When I execute osc with args "getbinaries openSUSE:Factory multibuild-pkg standard x86_64 multibuild-pkg-1-1.1.src.rpm --source" + Then directory listing of "{context.osc.temp}/binaries/" is + """ + multibuild-pkg-1-1.1.src.rpm + """ + + +Scenario: Run `osc getbinaries ` where file is a debuginfo package + When I execute osc with args "getbinaries openSUSE:Factory multibuild-pkg standard x86_64 multibuild-pkg-debuginfo-1-1.1.x86_64.rpm" + Then directory listing of "{context.osc.temp}/binaries/" is + """ + """ + + +Scenario: Run `osc getbinaries --debuginfo` where file is a debuginfo package + When I execute osc with args "getbinaries openSUSE:Factory multibuild-pkg standard x86_64 multibuild-pkg-debuginfo-1-1.1.x86_64.rpm --debuginfo" + Then directory listing of "{context.osc.temp}/binaries/" is + """ + multibuild-pkg-debuginfo-1-1.1.x86_64.rpm + """ + + +Scenario: Run `osc getbinaries ` where file is a log file + When I execute osc with args "getbinaries openSUSE:Factory multibuild-pkg standard x86_64 rpmlint.log" + Then directory listing of "{context.osc.temp}/binaries/" is + """ + rpmlint.log + """ diff --git a/behave/features/getbinaries-project-package-repo-arch.feature b/behave/features/getbinaries-project-package-repo-arch.feature new file mode 100644 index 00000000..8fbe4808 --- /dev/null +++ b/behave/features/getbinaries-project-package-repo-arch.feature @@ -0,0 +1,59 @@ +@no-snapshot +Feature: `osc getbinaries ` command + + +# common steps for all scenarios +Background: + Given I set working directory to "{context.osc.temp}" + + +Scenario: Run `osc getbinaries ` + When I execute osc with args "getbinaries openSUSE:Factory multibuild-pkg standard x86_64" + Then directory listing of "{context.osc.temp}/binaries/" is + """ + multibuild-pkg-1-1.1.x86_64.rpm + _buildenv + _statistics + rpmlint.log + """ + + +Scenario: Run `osc getbinaries --multibuild-package=` + When I execute osc with args "getbinaries openSUSE:Factory multibuild-pkg standard x86_64 --multibuild-package=flavor1" + # the option is allowed only in a package checkout + Then the exit code is 2 + + +Scenario: Run `osc getbinaries : ` + When I execute osc with args "getbinaries openSUSE:Factory multibuild-pkg:flavor1 standard x86_64" + Then directory listing of "{context.osc.temp}/binaries/" is + """ + multibuild-pkg-flavor1-1-1.1.x86_64.rpm + _buildenv + _statistics + rpmlint.log + """ + + +Scenario: Run `osc getbinaries : --source` + When I execute osc with args "getbinaries openSUSE:Factory multibuild-pkg:flavor1 standard x86_64 --source" + Then directory listing of "{context.osc.temp}/binaries/" is + """ + multibuild-pkg-1-1.1.src.rpm + multibuild-pkg-flavor1-1-1.1.x86_64.rpm + _buildenv + _statistics + rpmlint.log + """ + + +Scenario: Run `osc getbinaries : --debuginfo` + When I execute osc with args "getbinaries openSUSE:Factory multibuild-pkg:flavor1 standard x86_64 --debuginfo" + Then directory listing of "{context.osc.temp}/binaries/" is + """ + multibuild-pkg-flavor1-1-1.1.x86_64.rpm + multibuild-pkg-flavor1-debuginfo-1-1.1.x86_64.rpm + _buildenv + _statistics + rpmlint.log + """ diff --git a/behave/features/getbinaries-project-repo-arch.feature b/behave/features/getbinaries-project-repo-arch.feature new file mode 100644 index 00000000..8e149e64 --- /dev/null +++ b/behave/features/getbinaries-project-repo-arch.feature @@ -0,0 +1,71 @@ +@no-snapshot +Feature: `osc getbinaries ` command + + +# common steps for all scenarios +Background: + Given I set working directory to "{context.osc.temp}" + + +Scenario: Run `osc getbinaries ` + When I execute osc with args "getbinaries openSUSE:Factory standard x86_64" + Then directory tree in "{context.osc.temp}/binaries/" is + """ + multibuild-pkg-1-1.1.x86_64.rpm + multibuild-pkg-flavor1-1-1.1.x86_64.rpm + multibuild-pkg-flavor2-1-1.1.x86_64.rpm + test-pkgA-3-1.1.noarch.rpm + test-pkgB-2-1.1.noarch.rpm + multibuild-pkg/_buildenv + multibuild-pkg/_statistics + multibuild-pkg/rpmlint.log + multibuild-pkg:flavor1/_buildenv + multibuild-pkg:flavor1/_statistics + multibuild-pkg:flavor1/rpmlint.log + multibuild-pkg:flavor2/_buildenv + multibuild-pkg:flavor2/_statistics + multibuild-pkg:flavor2/rpmlint.log + test-pkgA/_buildenv + test-pkgA/_statistics + test-pkgA/rpmlint.log + test-pkgB/_buildenv + test-pkgB/_statistics + test-pkgB/rpmlint.log + """ + + +Scenario: Run `osc getbinaries --multibuild-package=` + When I execute osc with args "getbinaries openSUSE:Factory standard x86_64 --multibuild-package=flavor1" + # the option is allowed only in a package checkout + Then the exit code is 2 + + +Scenario: Run `osc getbinaries --debuginfo` + When I execute osc with args "getbinaries openSUSE:Factory standard x86_64 --debuginfo" + Then directory tree in "{context.osc.temp}/binaries/" is + """ + multibuild-pkg-1-1.1.x86_64.rpm + multibuild-pkg-debuginfo-1-1.1.x86_64.rpm + multibuild-pkg-debugsource-1-1.1.x86_64.rpm + multibuild-pkg-flavor1-1-1.1.x86_64.rpm + multibuild-pkg-flavor1-debuginfo-1-1.1.x86_64.rpm + multibuild-pkg-flavor2-1-1.1.x86_64.rpm + multibuild-pkg-flavor2-debuginfo-1-1.1.x86_64.rpm + test-pkgA-3-1.1.noarch.rpm + test-pkgB-2-1.1.noarch.rpm + multibuild-pkg/_buildenv + multibuild-pkg/_statistics + multibuild-pkg/rpmlint.log + multibuild-pkg:flavor1/_buildenv + multibuild-pkg:flavor1/_statistics + multibuild-pkg:flavor1/rpmlint.log + multibuild-pkg:flavor2/_buildenv + multibuild-pkg:flavor2/_statistics + multibuild-pkg:flavor2/rpmlint.log + test-pkgA/_buildenv + test-pkgA/_statistics + test-pkgA/rpmlint.log + test-pkgB/_buildenv + test-pkgB/_statistics + test-pkgB/rpmlint.log + """ diff --git a/behave/features/getbinaries-repo-arch-pkgcheckout.feature b/behave/features/getbinaries-repo-arch-pkgcheckout.feature new file mode 100644 index 00000000..0dbc132c --- /dev/null +++ b/behave/features/getbinaries-repo-arch-pkgcheckout.feature @@ -0,0 +1,44 @@ +@no-snapshot +Feature: `osc getbinaries ` command from a package checkout + + +# common steps for all scenarios +Background: + Given I set working directory to "{context.osc.temp}" + And I execute osc with args "checkout openSUSE:Factory multibuild-pkg" + And I set working directory to "{context.osc.temp}/openSUSE:Factory/multibuild-pkg" + + +Scenario: Run `osc getbinaries ` from a package checkout + When I execute osc with args "getbinaries standard x86_64" + Then directory listing of "{context.osc.temp}/openSUSE:Factory/multibuild-pkg/binaries/" is + """ + multibuild-pkg-1-1.1.x86_64.rpm + _buildenv + _statistics + rpmlint.log + """ + + +Scenario: Run `osc getbinaries --multibuild-package=` from a package checkout + When I execute osc with args "getbinaries standard x86_64 --multibuild-package=flavor1" + Then directory listing of "{context.osc.temp}/openSUSE:Factory/multibuild-pkg/binaries/" is + """ + multibuild-pkg-flavor1-1-1.1.x86_64.rpm + _buildenv + _statistics + rpmlint.log + """ + + +Scenario: Run `osc getbinaries --debuginfo` from a package checkout + When I execute osc with args "getbinaries standard x86_64 --debuginfo" + Then directory listing of "{context.osc.temp}/openSUSE:Factory/multibuild-pkg/binaries/" is + """ + multibuild-pkg-1-1.1.x86_64.rpm + multibuild-pkg-debuginfo-1-1.1.x86_64.rpm + multibuild-pkg-debugsource-1-1.1.x86_64.rpm + _buildenv + _statistics + rpmlint.log + """ diff --git a/behave/features/getbinaries-repo-arch-prjcheckout.feature b/behave/features/getbinaries-repo-arch-prjcheckout.feature new file mode 100644 index 00000000..ae185843 --- /dev/null +++ b/behave/features/getbinaries-repo-arch-prjcheckout.feature @@ -0,0 +1,105 @@ +@no-snapshot +Feature: `osc getbinaries ` command from a project checkout + + +# common steps for all scenarios +Background: + Given I set working directory to "{context.osc.temp}" + And I execute osc with args "checkout openSUSE:Factory" + And I set working directory to "{context.osc.temp}/openSUSE:Factory" + + +Scenario: Run `osc getbinaries ` from a project checkout + When I execute osc with args "getbinaries standard x86_64" + Then directory tree in "{context.osc.temp}/openSUSE:Factory/binaries/" is + """ + multibuild-pkg-1-1.1.x86_64.rpm + multibuild-pkg-flavor1-1-1.1.x86_64.rpm + multibuild-pkg-flavor2-1-1.1.x86_64.rpm + test-pkgA-3-1.1.noarch.rpm + test-pkgB-2-1.1.noarch.rpm + multibuild-pkg/_buildenv + multibuild-pkg/_statistics + multibuild-pkg/rpmlint.log + multibuild-pkg:flavor1/_buildenv + multibuild-pkg:flavor1/_statistics + multibuild-pkg:flavor1/rpmlint.log + multibuild-pkg:flavor2/_buildenv + multibuild-pkg:flavor2/_statistics + multibuild-pkg:flavor2/rpmlint.log + test-pkgA/_buildenv + test-pkgA/_statistics + test-pkgA/rpmlint.log + test-pkgB/_buildenv + test-pkgB/_statistics + test-pkgB/rpmlint.log + """ + + +Scenario: Run `osc getbinaries --multibuild-package=` from a project checkout + When I execute osc with args "getbinaries standard x86_64 --multibuild-package=flavor1" + # the option is allowed only in a package checkout + Then the exit code is 2 + + +Scenario: Run `osc getbinaries --sources` from a project checkout + When I execute osc with args "getbinaries standard x86_64 --sources" + Then directory tree in "{context.osc.temp}/openSUSE:Factory/binaries/" is + """ + multibuild-pkg-1-1.1.src.rpm + multibuild-pkg-1-1.1.x86_64.rpm + multibuild-pkg-1-1.1.src.rpm + multibuild-pkg-flavor1-1-1.1.x86_64.rpm + multibuild-pkg-1-1.1.src.rpm + multibuild-pkg-flavor2-1-1.1.x86_64.rpm + test-pkgA-3-1.1.noarch.rpm + test-pkgA-3-1.1.src.rpm + test-pkgB-2-1.1.noarch.rpm + test-pkgB-2-1.1.src.rpm + multibuild-pkg/_buildenv + multibuild-pkg/_statistics + multibuild-pkg/rpmlint.log + multibuild-pkg:flavor1/_buildenv + multibuild-pkg:flavor1/_statistics + multibuild-pkg:flavor1/rpmlint.log + multibuild-pkg:flavor2/_buildenv + multibuild-pkg:flavor2/_statistics + multibuild-pkg:flavor2/rpmlint.log + test-pkgA/_buildenv + test-pkgA/_statistics + test-pkgA/rpmlint.log + test-pkgB/_buildenv + test-pkgB/_statistics + test-pkgB/rpmlint.log + """ + + +Scenario: Run `osc getbinaries --debuginfo` from a project checkout + When I execute osc with args "getbinaries standard x86_64 --debuginfo" + Then directory tree in "{context.osc.temp}/openSUSE:Factory/binaries/" is + """ + multibuild-pkg-1-1.1.x86_64.rpm + multibuild-pkg-debuginfo-1-1.1.x86_64.rpm + multibuild-pkg-debugsource-1-1.1.x86_64.rpm + multibuild-pkg-flavor1-1-1.1.x86_64.rpm + multibuild-pkg-flavor1-debuginfo-1-1.1.x86_64.rpm + multibuild-pkg-flavor2-1-1.1.x86_64.rpm + multibuild-pkg-flavor2-debuginfo-1-1.1.x86_64.rpm + test-pkgA-3-1.1.noarch.rpm + test-pkgB-2-1.1.noarch.rpm + multibuild-pkg/_buildenv + multibuild-pkg/_statistics + multibuild-pkg/rpmlint.log + multibuild-pkg:flavor1/_buildenv + multibuild-pkg:flavor1/_statistics + multibuild-pkg:flavor1/rpmlint.log + multibuild-pkg:flavor2/_buildenv + multibuild-pkg:flavor2/_statistics + multibuild-pkg:flavor2/rpmlint.log + test-pkgA/_buildenv + test-pkgA/_statistics + test-pkgA/rpmlint.log + test-pkgB/_buildenv + test-pkgB/_statistics + test-pkgB/rpmlint.log + """ diff --git a/behave/features/getbinaries-repo-pkgcheckout.feature b/behave/features/getbinaries-repo-pkgcheckout.feature new file mode 100644 index 00000000..8ed0e43e --- /dev/null +++ b/behave/features/getbinaries-repo-pkgcheckout.feature @@ -0,0 +1,50 @@ +@no-snapshot +Feature: `osc getbinaries ` command from a project checkout + + +# common steps for all scenarios +Background: + Given I set working directory to "{context.osc.temp}" + And I execute osc with args "checkout openSUSE:Factory multibuild-pkg" + And I set working directory to "{context.osc.temp}/openSUSE:Factory/multibuild-pkg" + + +Scenario: Run `osc getbinaries ` from a package checkout + Given I set working directory to "{context.osc.temp}/openSUSE:Factory/multibuild-pkg" + When I execute osc with args "getbinaries standard" + Then directory listing of "{context.osc.temp}/openSUSE:Factory/multibuild-pkg/binaries/" is + """ + multibuild-pkg-1-1.1.i586.rpm + multibuild-pkg-1-1.1.x86_64.rpm + _buildenv + _statistics + rpmlint.log + """ + + +Scenario: Run `osc getbinaries --multibuild-package=` from a package checkout + When I execute osc with args "getbinaries standard --multibuild-package=flavor1" + Then directory listing of "{context.osc.temp}/openSUSE:Factory/multibuild-pkg/binaries/" is + """ + multibuild-pkg-flavor1-1-1.1.i586.rpm + multibuild-pkg-flavor1-1-1.1.x86_64.rpm + _buildenv + _statistics + rpmlint.log + """ + + +Scenario: Run `osc getbinaries --debuginfo` from a package checkout + When I execute osc with args "getbinaries standard --debuginfo" + Then directory listing of "{context.osc.temp}/openSUSE:Factory/multibuild-pkg/binaries/" is + """ + multibuild-pkg-1-1.1.i586.rpm + multibuild-pkg-1-1.1.x86_64.rpm + multibuild-pkg-debuginfo-1-1.1.i586.rpm + multibuild-pkg-debuginfo-1-1.1.x86_64.rpm + multibuild-pkg-debugsource-1-1.1.i586.rpm + multibuild-pkg-debugsource-1-1.1.x86_64.rpm + _buildenv + _statistics + rpmlint.log + """ diff --git a/behave/features/getbinaries-repo-prjcheckout.feature b/behave/features/getbinaries-repo-prjcheckout.feature new file mode 100644 index 00000000..fb56025b --- /dev/null +++ b/behave/features/getbinaries-repo-prjcheckout.feature @@ -0,0 +1,118 @@ +@no-snapshot +Feature: `osc getbinaries ` command from a project checkout + + +# common steps for all scenarios +Background: + Given I set working directory to "{context.osc.temp}" + And I execute osc with args "checkout openSUSE:Factory" + And I set working directory to "{context.osc.temp}/openSUSE:Factory" + + +Scenario: Run `osc getbinaries ` from a project checkout + When I execute osc with args "getbinaries standard" + Then directory tree in "{context.osc.temp}/openSUSE:Factory/binaries/" is + """ + multibuild-pkg-1-1.1.i586.rpm + multibuild-pkg-1-1.1.x86_64.rpm + multibuild-pkg-flavor1-1-1.1.i586.rpm + multibuild-pkg-flavor1-1-1.1.x86_64.rpm + multibuild-pkg-flavor2-1-1.1.i586.rpm + multibuild-pkg-flavor2-1-1.1.x86_64.rpm + test-pkgA-3-1.1.noarch.rpm + test-pkgB-2-1.1.noarch.rpm + multibuild-pkg/_buildenv + multibuild-pkg/_statistics + multibuild-pkg/rpmlint.log + multibuild-pkg:flavor1/_buildenv + multibuild-pkg:flavor1/_statistics + multibuild-pkg:flavor1/rpmlint.log + multibuild-pkg:flavor2/_buildenv + multibuild-pkg:flavor2/_statistics + multibuild-pkg:flavor2/rpmlint.log + test-pkgA/_buildenv + test-pkgA/_statistics + test-pkgA/rpmlint.log + test-pkgB/_buildenv + test-pkgB/_statistics + test-pkgB/rpmlint.log + """ + + +Scenario: Run `osc getbinaries --multibuild-package=` from a project checkout + When I execute osc with args "getbinaries standard --multibuild-package=flavor1" + # the option is allowed only in a package checkout + Then the exit code is 2 + + +Scenario: Run `osc getbinaries --sources` from a project checkout + When I execute osc with args "getbinaries standard --sources" + Then directory tree in "{context.osc.temp}/openSUSE:Factory/binaries/" is + """ + multibuild-pkg-1-1.1.i586.rpm + multibuild-pkg-1-1.1.src.rpm + multibuild-pkg-1-1.1.x86_64.rpm + multibuild-pkg-1-1.1.src.rpm + multibuild-pkg-flavor1-1-1.1.i586.rpm + multibuild-pkg-flavor1-1-1.1.x86_64.rpm + multibuild-pkg-1-1.1.src.rpm + multibuild-pkg-flavor2-1-1.1.i586.rpm + multibuild-pkg-flavor2-1-1.1.x86_64.rpm + test-pkgA-3-1.1.noarch.rpm + test-pkgA-3-1.1.src.rpm + test-pkgB-2-1.1.noarch.rpm + test-pkgB-2-1.1.src.rpm + multibuild-pkg/_buildenv + multibuild-pkg/_statistics + multibuild-pkg/rpmlint.log + multibuild-pkg:flavor1/_buildenv + multibuild-pkg:flavor1/_statistics + multibuild-pkg:flavor1/rpmlint.log + multibuild-pkg:flavor2/_buildenv + multibuild-pkg:flavor2/_statistics + multibuild-pkg:flavor2/rpmlint.log + test-pkgA/_buildenv + test-pkgA/_statistics + test-pkgA/rpmlint.log + test-pkgB/_buildenv + test-pkgB/_statistics + test-pkgB/rpmlint.log + """ + + +Scenario: Run `osc getbinaries --debuginfo` from a project checkout + When I execute osc with args "getbinaries standard --debuginfo" + Then directory tree in "{context.osc.temp}/openSUSE:Factory/binaries/" is + """ + multibuild-pkg-1-1.1.i586.rpm + multibuild-pkg-1-1.1.x86_64.rpm + multibuild-pkg-debuginfo-1-1.1.i586.rpm + multibuild-pkg-debuginfo-1-1.1.x86_64.rpm + multibuild-pkg-debugsource-1-1.1.i586.rpm + multibuild-pkg-debugsource-1-1.1.x86_64.rpm + multibuild-pkg-flavor1-1-1.1.i586.rpm + multibuild-pkg-flavor1-1-1.1.x86_64.rpm + multibuild-pkg-flavor1-debuginfo-1-1.1.i586.rpm + multibuild-pkg-flavor1-debuginfo-1-1.1.x86_64.rpm + multibuild-pkg-flavor2-1-1.1.i586.rpm + multibuild-pkg-flavor2-1-1.1.x86_64.rpm + multibuild-pkg-flavor2-debuginfo-1-1.1.i586.rpm + multibuild-pkg-flavor2-debuginfo-1-1.1.x86_64.rpm + test-pkgA-3-1.1.noarch.rpm + test-pkgB-2-1.1.noarch.rpm + multibuild-pkg/_buildenv + multibuild-pkg/_statistics + multibuild-pkg/rpmlint.log + multibuild-pkg:flavor1/_buildenv + multibuild-pkg:flavor1/_statistics + multibuild-pkg:flavor1/rpmlint.log + multibuild-pkg:flavor2/_buildenv + multibuild-pkg:flavor2/_statistics + multibuild-pkg:flavor2/rpmlint.log + test-pkgA/_buildenv + test-pkgA/_statistics + test-pkgA/rpmlint.log + test-pkgB/_buildenv + test-pkgB/_statistics + test-pkgB/rpmlint.log + """ diff --git a/behave/features/list.feature b/behave/features/list.feature new file mode 100644 index 00000000..e0dc8453 --- /dev/null +++ b/behave/features/list.feature @@ -0,0 +1,33 @@ +@no-snapshot +Feature: `osc list` command + + +Scenario: Run `osc list` with no arguments to display all projects + When I execute osc with args "list" + Then stdout is + """ + home:Admin + openSUSE.org + openSUSE:Factory + """ + + +Scenario: Run `osc list` on a project to display project packages + When I execute osc with args "list openSUSE:Factory" + Then stdout is + """ + multibuild-pkg + multibuild-pkg:flavor1 + multibuild-pkg:flavor2 + test-pkgA + test-pkgB + """ + + +Scenario: Run `osc list` on a project package to display package files + When I execute osc with args "list openSUSE:Factory test-pkgA" + Then stdout is + """ + test-pkgA.changes + test-pkgA.spec + """ diff --git a/behave/features/steps/__init__.py b/behave/features/steps/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/behave/features/steps/common.py b/behave/features/steps/common.py new file mode 100644 index 00000000..4f2c7644 --- /dev/null +++ b/behave/features/steps/common.py @@ -0,0 +1,257 @@ +import errno +import os +import shutil +import subprocess + +import behave + + +def makedirs(path): + try: + os.makedirs(path) + except OSError as e: + if e.errno != errno.EEXIST: + raise + + +def run(cmd, shell=True, cwd=None, env=None): + """ + Run a command. + Return exitcode, stdout, stderr + """ + + proc = subprocess.Popen( + cmd, + shell=shell, + cwd=cwd, + env=env, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + encoding="utf-8", + universal_newlines=True, + errors="surrogateescape", + ) + + stdout, stderr = proc.communicate() + return proc.returncode, stdout, stderr + + +def check_exit_code(context): + # check if the previous command finished successfully + # or if the exit code was tested in a scenario + if not getattr(context, "cmd", None): + return + + if context.cmd_exitcode_checked: + return + + the_exit_code_is(context, 0) + + +def run_in_context(context, cmd, can_fail=False, **run_args): + check_exit_code(context) + + context.cmd = cmd + + if hasattr(context.scenario, "working_dir") and 'cwd' not in run_args: + run_args['cwd'] = context.scenario.working_dir + + if hasattr(context.scenario, "PATH"): + env = os.environ.copy() + path = context.scenario.PATH + env["PATH"] = path.replace("$PATH", env["PATH"]) + run_args["env"] = env + + if context.config.userdata.get("DEBUG", False): + print(f"DEBUG: command: {cmd}") + + context.cmd_exitcode, context.cmd_stdout, context.cmd_stderr = run(cmd, **run_args) + context.cmd_exitcode_checked = False + + if context.config.userdata.get("DEBUG", False): + print(f"DEBUG: exit code: {context.cmd_exitcode}") + print(f"DEBUG: stdout: {context.cmd_stdout}") + print(f"DEBUG: stderr: {context.cmd_stderr}") + + if not can_fail and context.cmd_exitcode != 0: + raise AssertionError('Running command "%s" failed: %s' % (cmd, context.cmd_exitcode)) + + +@behave.step("stdout contains \"{text}\"") +def step_impl(context, text): + if re.search(text.format(context=context), context.cmd_stdout): + return + raise AssertionError("Stdout doesn't contain: %s" % text) + + +@behave.step("stderr contains \"{text}\"") +def step_impl(context, text): + if re.search(text.format(context=context), context.cmd_stderr): + return + raise AssertionError("Stderr doesn't contain: %s" % text) + + +@behave.step("stdout is") +def step_impl(context): + expected = context.text.format(context=context).rstrip().split('\n') + found = context.cmd_stdout.rstrip().split('\n') + + if found == expected: + return + + expected_str = "\n".join(expected) + found_str = "\n".join(found) + raise AssertionError(f"Stdout is not:\n{expected_str}\n\nActual stdout:\n{found_str}") + + +@behave.step('I set working directory to "{path}"') +def step_impl(context, path): + path = path.format(context=context) + context.scenario.working_dir = path + + +@behave.step('I set PATH to "{path}"') +def step_impl(context, path): + path = path.format(context=context) + context.scenario.PATH = path + + +@behave.step('I copy file "{source}" to "{destination}"') +def step_impl(context, source, destination): + # substitutions + source = source.format(context=context) + destination = destination.format(context=context) + + # if destination is a directory, append the source filename + if destination.endswith("/"): + destination = os.path.join(destination, os.path.basename(source)) + + # copy file without attributes + makedirs(os.path.dirname(destination)) + shutil.copyfile(source, destination) + + +@behave.step('file "{path}" exists') +def step_impl(context, path): + path = path.format(context=context) + if not os.path.isfile(path): + raise AssertionError(f"File doesn't exist: {path}") + + +@behave.step('file "{path}" does not exist') +def step_impl(context, path): + path = path.format(context=context) + if os.path.isfile(path): + raise AssertionError(f"File exists: {path}") + + +@behave.step('file "{one}" is identical to "{two}"') +def step_impl(context, one, two): + one = one.format(context=context) + two = two.format(context=context) + data_one = open(one, "r").read() + data_two = open(two, "r").read() + if data_one != data_two: + raise AssertionError(f"Files differ: {one} != {two}") + + +@behave.step('directory "{path}" exists') +def step_impl(context, path): + path = path.format(context=context) + if not os.path.isdir(path): + raise AssertionError(f"Directory doesn't exist: {path}") + + +@behave.step('directory "{path}" does not exist') +def step_impl(context, path): + path = path.format(context=context) + if os.path.isdir(path): + raise AssertionError(f"Directory exists: {path}") + + +@behave.step('I create file "{path}" with perms "{mode}"') +def step_impl(context, path, mode): + path = path.format(context=context) + mode = int(mode, 8) + content = context.text.format(context=context).rstrip() + + makedirs(os.path.dirname(path)) + open(path, "w").write(content) + os.chmod(path, mode) + + +@behave.step("the exit code is {exitcode}") +def the_exit_code_is(context, exitcode): + if context.cmd_exitcode != int(exitcode): + raise AssertionError(f"Command has exited with code {context.cmd_exitcode}: {context.cmd}") + context.cmd_exitcode_checked = True + + +@behave.step('directory listing of "{path}" is') +def step_impl(context, path): + path = path.format(context=context) + expected = context.text.format(context=context).rstrip().split('\n') + expected = [i for i in expected if i.strip()] + found = os.listdir(path) + + expected = set(expected) + found = set(found) + + if found == expected: + return + + extra = sorted(set(found) - set(expected)) + missing = sorted(set(expected) - set(found)) + + msg = [] + if extra: + msg.append("Unexpected files found on disk:") + for fn in extra: + msg.append(f" {fn}") + if missing: + msg.append("Files missing on disk:") + for fn in missing: + msg.append(f" {fn}") + + msg = "\n".join(msg) + + raise AssertionError(f"Directory listing does not match:\n{msg}") + + +@behave.step('directory tree in "{path}" is') +def step_impl(context, path): + path = path.format(context=context) + path = os.path.abspath(path) + expected = context.text.format(context=context).rstrip().split('\n') + expected = [i for i in expected if i.strip()] + + found = [] + for root, dirs, files in os.walk(path): + for fn in files: + file_abspath = os.path.join(root, fn) + file_relpath = file_abspath[len(path) + 1:] + found.append(file_relpath) +# found = os.listdir(path) + + expected = set(expected) + found = set(found) + + if found == expected: + return + + extra = sorted(set(found) - set(expected)) + missing = sorted(set(expected) - set(found)) + + msg = [] + if extra: + msg.append("Unexpected files found on disk:") + for fn in extra: + msg.append(f" {fn}") + if missing: + msg.append("Files missing on disk:") + for fn in missing: + msg.append(f" {fn}") + + msg = "\n".join(msg) + + raise AssertionError(f"Directory listing does not match:\n{msg}") diff --git a/behave/features/steps/kanku.py b/behave/features/steps/kanku.py new file mode 100644 index 00000000..98328838 --- /dev/null +++ b/behave/features/steps/kanku.py @@ -0,0 +1,76 @@ +#!/usr/bin/python3 + + +import os +import re +import subprocess + +import behave +from ruamel.yaml import YAML + + +class Kanku: + def __init__(self, context, kankufile): + self.kankufile = kankufile + self.kankudir = os.path.dirname(self.kankufile) + self.domain_name = self._get_domain_name() + self.ip = self._get_ip() + + def _get_domain_name(self): + """ + Get domain name directly from KankuFile yaml + """ + yaml = YAML(typ='safe') + doc = yaml.load(open(self.kankufile, "r")) + return doc["domain_name"] + + def _run_kanku(self, args): + cmd = ["kanku"] + args + env = os.environ.copy() + env["KANKU_CONFIG"] = self.kankufile + proc = subprocess.Popen( + cmd, + cwd=self.kankudir, + env=env, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + encoding="utf-8" + ) + return proc + + def _get_ip(self): + """ + Get IP from calling `kanku ip` + """ + proc = self._run_kanku(["ip"]) + stdout, stderr = proc.communicate() + match = re.search(r"IP Address: ([\d\.]+)", stderr) + return match.group(1) + + def create_snapshot(self): + # unmount /tmp/kanku so we are able to create a snapshot of the VM + self.run_command("umount /tmp/kanku") + proc = self._run_kanku(["snapshot", "--create", "--name", "current"]) + proc.communicate() + + def revert_to_snapshot(self): + proc = self._run_kanku(["snapshot", "--revert", "--name", "current"]) + proc.communicate() + + def delete_snapshot(self): + proc = self._run_kanku(["snapshot", "--remove", "--name", "current"]) + proc.communicate() + + def run_command(self, ssh_cmd, user="root"): + proc = self._run_kanku(["ssh", "-u", user, "--execute", ssh_cmd]) + proc.wait() + + +@behave.step("I create VM snapshot") +def func(context, args): + context.kanku.create_snapshot(sudo=True) + + +@behave.step("I revert to VM snapshot") +def func(context, args): + context.kanku.revert_to_snapshot(sudo=True) diff --git a/behave/features/steps/osc.py b/behave/features/steps/osc.py new file mode 100644 index 00000000..f6b5e4e1 --- /dev/null +++ b/behave/features/steps/osc.py @@ -0,0 +1,75 @@ +import os +import shutil +import tempfile +import time + +import behave + +from steps.common import run_in_context + + +class Osc: + def __init__(self, context): + self.temp = tempfile.mkdtemp(prefix="osc_behave_") + + if not hasattr(context, "kanku"): + raise RuntimeError("context doesn't have kanku object set") + + self.oscrc = os.path.join(self.temp, "oscrc") + with open(self.oscrc, "w") as f: + f.write("[general]\n") + f.write("\n") + f.write(f"[https://{context.kanku.ip}]\n") + f.write("user=Admin\n") + f.write("pass=opensuse\n") + f.write("credentials_mgr_class=osc.credentials.PlaintextConfigFileCredentialsManager\n") + f.write("sslcertck=0\n") + f.write("trusted_prj=openSUSE.org:openSUSE:Tumbleweed\n") + + def __del__(self): + try: + shutil.rmtree(self.temp) + except Exception: + pass + + def get_cmd(self, context): + osc_cmd = context.config.userdata.get("osc", "osc") + cmd = [osc_cmd] + cmd += ["--config", self.oscrc] + cmd += ["-A", f"https://{context.kanku.ip}"] + return cmd + + +@behave.step("I execute osc with args \"{args}\"") +def step_impl(context, args): + args = args.format(context=context) + cmd = context.osc.get_cmd(context) + [args] + cmd = " ".join(cmd) + run_in_context(context, cmd, can_fail=True) + + +@behave.step('I wait for osc results for "{project}" "{package}"') +def step_impl(context, project, package): + args = f"results {project} {package} --csv --format='%(code)s,%(dirty)s'" + cmd = context.osc.get_cmd(context) + [args] + cmd = " ".join(cmd) + + while True: + # wait for a moment before checking the status even for the first time + # for some reason, packages appear to be "broken" for a while after they get commited + time.sleep(5) + + run_in_context(context, cmd, can_fail=True) + results = [] + for line in context.cmd_stdout.splitlines(): + code, dirty = line.split(",") + dirty = dirty.lower() == "true" + results.append((code, dirty)) + + if all((code == "succeeded" and not dirty for code, dirty in results)): + # all builds have succeeded and all dirty flags are false + break + + if any((code in ("unresolvable", "failed", "broken", "blocked", "locked", "excluded") and not dirty for code, dirty in results)): + # failed build with dirty flag false + raise AssertionError("Package build failed:\n" + context.cmd_stdout) diff --git a/behave/fixtures/pac/multibuild-pkg-1._multibuild b/behave/fixtures/pac/multibuild-pkg-1._multibuild new file mode 100644 index 00000000..4ad5ea04 --- /dev/null +++ b/behave/fixtures/pac/multibuild-pkg-1._multibuild @@ -0,0 +1,4 @@ + + flavor1 + flavor2 + diff --git a/behave/fixtures/pac/multibuild-pkg-1.changes b/behave/fixtures/pac/multibuild-pkg-1.changes new file mode 100644 index 00000000..6bc25114 --- /dev/null +++ b/behave/fixtures/pac/multibuild-pkg-1.changes @@ -0,0 +1,4 @@ +------------------------------------------------------------------- +Tue Feb 1 11:22:33 UTC 2022 - Geeko Packager + +- Release upstream version 1 diff --git a/behave/fixtures/pac/multibuild-pkg-1.spec b/behave/fixtures/pac/multibuild-pkg-1.spec new file mode 100644 index 00000000..89c75c47 --- /dev/null +++ b/behave/fixtures/pac/multibuild-pkg-1.spec @@ -0,0 +1,98 @@ +%define flavor @BUILD_FLAVOR@%{nil} + +# create own debug packages, because the auto-generated would get removed due to being empty +%undefine _debuginfo_subpackages + + +Name: multibuild-pkg +Version: 1 +Release: 0 +License: GPL-2.0 +Summary: Test package +URL: https://example.com/test-package/ + + +%description +desc + + +%prep + + +%build + + +%install + + + + +# no flavor +%if "%{flavor}" == "%{nil}" +%files + + +%package debuginfo +Summary: Test debuginfo package + +%description debuginfo +desc + +%files debuginfo +%ghost /usr/lib/debug/multibuild-pkg.debug + + +%package debugsource +Summary: Test debugsource package + +%description debugsource +desc + +%files debugsource +%ghost %{_prefix}/src/debug/%{name}-%{version}-%{release}.%{arch}/main.c +%endif + + +# flavor1 +%if "%{flavor}" == "flavor1" +%package -n %{name}-%{flavor} +Summary: Multibuild test package, flavor1 + +%description -n %{name}-%{flavor} +desc + +%files -n %{name}-%{flavor} + +%package -n %{name}-%{flavor}-debuginfo +Summary: Test debuginfo package + +%description -n %{name}-%{flavor}-debuginfo +desc + +%files -n %{name}-%{flavor}-debuginfo +%ghost %{_prefix}/lib/debug/multibuild-pkg.debug +%endif + + +# flavor2 +%if "%{flavor}" == "flavor2" +%package -n %{name}-%{flavor} +Summary: Multibuild test package, flavor2 + +%description -n %{name}-%{flavor} +desc + +%files -n %{name}-%{flavor} + +%package -n %{name}-%{flavor}-debuginfo +Summary: Test debuginfo package + +%description -n %{name}-%{flavor}-debuginfo +desc + +%files -n %{name}-%{flavor}-debuginfo +%ghost %{_prefix}/lib/debug/multibuild-pkg.debug +%endif + + +%changelog diff --git a/behave/fixtures/pac/test-pkgA-1.changes b/behave/fixtures/pac/test-pkgA-1.changes new file mode 100644 index 00000000..0abbd70a --- /dev/null +++ b/behave/fixtures/pac/test-pkgA-1.changes @@ -0,0 +1,4 @@ +------------------------------------------------------------------- +Mon Jan 3 11:22:33 UTC 2022 - Geeko Packager + +- Release upstream version 1 diff --git a/behave/fixtures/pac/test-pkgA-1.spec b/behave/fixtures/pac/test-pkgA-1.spec new file mode 100644 index 00000000..aeb4a71c --- /dev/null +++ b/behave/fixtures/pac/test-pkgA-1.spec @@ -0,0 +1,25 @@ +Name: test-pkgA +Version: 1 +Release: 0 +License: GPL-2.0 +Summary: Test package +URL: https://example.com/test-package/ + + +BuildArch: noarch + + +%description +desc + + +%prep + + +%install + + +%files + + +%changelog diff --git a/behave/fixtures/pac/test-pkgA-2.changes b/behave/fixtures/pac/test-pkgA-2.changes new file mode 100644 index 00000000..c950d335 --- /dev/null +++ b/behave/fixtures/pac/test-pkgA-2.changes @@ -0,0 +1,4 @@ +------------------------------------------------------------------- +Tue Jan 4 11:22:33 UTC 2022 - Geeko Packager + +- Release upstream version 2 diff --git a/behave/fixtures/pac/test-pkgA-2.spec b/behave/fixtures/pac/test-pkgA-2.spec new file mode 100644 index 00000000..7652fccc --- /dev/null +++ b/behave/fixtures/pac/test-pkgA-2.spec @@ -0,0 +1,25 @@ +Name: test-pkgA +Version: 2 +Release: 0 +License: GPL-2.0 +Summary: Test package +URL: https://example.com/test-package/ + + +BuildArch: noarch + + +%description +desc + + +%prep + + +%install + + +%files + + +%changelog diff --git a/behave/fixtures/pac/test-pkgA-3.changes b/behave/fixtures/pac/test-pkgA-3.changes new file mode 100644 index 00000000..2a85a6b1 --- /dev/null +++ b/behave/fixtures/pac/test-pkgA-3.changes @@ -0,0 +1,4 @@ +------------------------------------------------------------------- +Wed Jan 5 11:22:33 UTC 2022 - Geeko Packager + +- Release upstream version 3 diff --git a/behave/fixtures/pac/test-pkgA-3.spec b/behave/fixtures/pac/test-pkgA-3.spec new file mode 100644 index 00000000..2d0f1152 --- /dev/null +++ b/behave/fixtures/pac/test-pkgA-3.spec @@ -0,0 +1,25 @@ +Name: test-pkgA +Version: 3 +Release: 0 +License: GPL-2.0 +Summary: Test package +URL: https://example.com/test-package/ + + +BuildArch: noarch + + +%description +desc + + +%prep + + +%install + + +%files + + +%changelog diff --git a/behave/fixtures/pac/test-pkgB-1.changes b/behave/fixtures/pac/test-pkgB-1.changes new file mode 100644 index 00000000..6bc25114 --- /dev/null +++ b/behave/fixtures/pac/test-pkgB-1.changes @@ -0,0 +1,4 @@ +------------------------------------------------------------------- +Tue Feb 1 11:22:33 UTC 2022 - Geeko Packager + +- Release upstream version 1 diff --git a/behave/fixtures/pac/test-pkgB-1.spec b/behave/fixtures/pac/test-pkgB-1.spec new file mode 100644 index 00000000..b5c64e67 --- /dev/null +++ b/behave/fixtures/pac/test-pkgB-1.spec @@ -0,0 +1,25 @@ +Name: test-pkgB +Version: 1 +Release: 0 +License: GPL-2.0 +Summary: Test package +URL: https://example.com/test-package/ + + +BuildArch: noarch + + +%description +desc + + +%prep + + +%install + + +%files + + +%changelog diff --git a/behave/fixtures/pac/test-pkgB-2.changes b/behave/fixtures/pac/test-pkgB-2.changes new file mode 100644 index 00000000..10139abc --- /dev/null +++ b/behave/fixtures/pac/test-pkgB-2.changes @@ -0,0 +1,4 @@ +------------------------------------------------------------------- +Wed Feb 2 11:22:33 UTC 2022 - Geeko Packager + +- Release upstream version 2 diff --git a/behave/fixtures/pac/test-pkgB-2.spec b/behave/fixtures/pac/test-pkgB-2.spec new file mode 100644 index 00000000..51cfb015 --- /dev/null +++ b/behave/fixtures/pac/test-pkgB-2.spec @@ -0,0 +1,25 @@ +Name: test-pkgB +Version: 2 +Release: 0 +License: GPL-2.0 +Summary: Test package +URL: https://example.com/test-package/ + + +BuildArch: noarch + + +%description +desc + + +%prep + + +%install + + +%files + + +%changelog diff --git a/behave/fixtures/prj/home_Admin.xml b/behave/fixtures/prj/home_Admin.xml new file mode 100644 index 00000000..3782b5df --- /dev/null +++ b/behave/fixtures/prj/home_Admin.xml @@ -0,0 +1,14 @@ + + + + <description/> + + <person userid="Admin" role="maintainer"/> + + <repository name="openSUSE_Tumbleweed"> + <path project="openSUSE.org:openSUSE:Tumbleweed" repository="standard"/> + <arch>x86_64</arch> + <arch>i586</arch> + </repository> + +</project> diff --git a/behave/fixtures/prj/openSUSE.org.xml b/behave/fixtures/prj/openSUSE.org.xml new file mode 100644 index 00000000..15e0a8ed --- /dev/null +++ b/behave/fixtures/prj/openSUSE.org.xml @@ -0,0 +1,8 @@ +<project name="openSUSE.org"> + + <title>Remote OBS instance + This project is representing a remote build service instance. + + https://api.opensuse.org/public + + diff --git a/behave/fixtures/prj/openSUSE_Factory.xml b/behave/fixtures/prj/openSUSE_Factory.xml new file mode 100644 index 00000000..cf20d7ec --- /dev/null +++ b/behave/fixtures/prj/openSUSE_Factory.xml @@ -0,0 +1,15 @@ + + + The next openSUSE distribution + + + + + + + x86_64 + i586 + + + + diff --git a/behave/obs-setup/environment.py b/behave/obs-setup/environment.py new file mode 100644 index 00000000..f8cd63f2 --- /dev/null +++ b/behave/obs-setup/environment.py @@ -0,0 +1,20 @@ +import os + +from steps import osc + + +# doesn't do anything, just points osc to localhost +class FakeKanku: + ip = "localhost" + + +def before_all(context): + context.fixtures = os.path.join(os.path.dirname(__file__), "..", "fixtures") + context.kanku = FakeKanku() + context.osc = osc.Osc(context) + + +def after_all(context): + del context.osc + del context.kanku + del context.fixtures diff --git a/behave/obs-setup/obs-setup.feature b/behave/obs-setup/obs-setup.feature new file mode 100644 index 00000000..4f45a02c --- /dev/null +++ b/behave/obs-setup/obs-setup.feature @@ -0,0 +1,113 @@ +# This is a special feature that should be used only in kanku VM to create initial OBS configuration. +# The scenarios follow each other and there is NO CLEANUP between them. + + +Feature: Setup OBS. + + +# Using interconnect feature is a must. +# We tried to configure projects from scratch (with download-on-demand repos), +# but there are simply too many settings that must be configured properly to make it work. +# +Scenario: Create openSUSE.org project that interconnects to another OBS instance + Given I execute osc with args "api -X PUT '/source/openSUSE.org/_meta' --file {context.fixtures}/prj/openSUSE.org.xml" + When I execute osc with args "list" + Then stdout is + """ + openSUSE.org + """ + + +Scenario: Create openSUSE:Factory project + Given I execute osc with args "api -X PUT '/source/openSUSE:Factory/_meta' --file {context.fixtures}/prj/openSUSE_Factory.xml" + When I execute osc with args "list" + Then stdout is + """ + openSUSE.org + openSUSE:Factory + """ + + +Scenario: Create home:Admin project + Given I execute osc with args "api -X PUT '/source/home:Admin/_meta' --file {context.fixtures}/prj/home_Admin.xml" + When I execute osc with args "list" + Then stdout is + """ + home:Admin + openSUSE.org + openSUSE:Factory + """ + + +Scenario: Create and build package 'test-pkgA' in 'openSUSE:Factory' project + # checkout project + Given I set working directory to "{context.osc.temp}" + When I execute osc with args "checkout openSUSE:Factory" + Then directory "{context.osc.temp}/openSUSE:Factory" exists + And directory "{context.osc.temp}/openSUSE:Factory/.osc" exists + + # create package + Given I set working directory to "{context.osc.temp}/openSUSE:Factory" + When I execute osc with args "mkpac test-pkgA" + Then directory "{context.osc.temp}/openSUSE:Factory/test-pkgA" exists + And directory "{context.osc.temp}/openSUSE:Factory/test-pkgA/.osc" exists + + # add and commit new package content + Given I set working directory to "{context.osc.temp}/openSUSE:Factory/test-pkgA" + # revision 1 + When I copy file "{context.fixtures}/pac/test-pkgA-1.spec" to "{context.osc.temp}/openSUSE:Factory/test-pkgA/test-pkgA.spec" + And I copy file "{context.fixtures}/pac/test-pkgA-1.changes" to "{context.osc.temp}/openSUSE:Factory/test-pkgA/test-pkgA.changes" + And I execute osc with args "add test-pkgA.spec test-pkgA.changes" + And I execute osc with args "commit -m 'Initial commit'" + # revision 2 + And I copy file "{context.fixtures}/pac/test-pkgA-2.spec" to "{context.osc.temp}/openSUSE:Factory/test-pkgA/test-pkgA.spec" + And I copy file "{context.fixtures}/pac/test-pkgA-2.changes" to "{context.osc.temp}/openSUSE:Factory/test-pkgA/test-pkgA.changes" + And I execute osc with args "commit -m 'Version 2'" + # revision 3 + And I copy file "{context.fixtures}/pac/test-pkgA-3.spec" to "{context.osc.temp}/openSUSE:Factory/test-pkgA/test-pkgA.spec" + And I copy file "{context.fixtures}/pac/test-pkgA-3.changes" to "{context.osc.temp}/openSUSE:Factory/test-pkgA/test-pkgA.changes" + And I execute osc with args "commit -m 'Version 3'" + Then I wait for osc results for "openSUSE:Factory" "test-pkgA" + + +Scenario: Create and build package 'test-pkgB' in 'openSUSE:Factory' project + # project checkout exists in temp already, no need to run checkout again + + # create package + Given I set working directory to "{context.osc.temp}/openSUSE:Factory" + When I execute osc with args "mkpac test-pkgB" + Then directory "{context.osc.temp}/openSUSE:Factory/test-pkgB" exists + And directory "{context.osc.temp}/openSUSE:Factory/test-pkgB/.osc" exists + + # add and commit new package content + Given I set working directory to "{context.osc.temp}/openSUSE:Factory/test-pkgB" + # revision 1 + When I copy file "{context.fixtures}/pac/test-pkgB-1.spec" to "{context.osc.temp}/openSUSE:Factory/test-pkgB/test-pkgB.spec" + And I copy file "{context.fixtures}/pac/test-pkgB-1.changes" to "{context.osc.temp}/openSUSE:Factory/test-pkgB/test-pkgB.changes" + And I execute osc with args "add test-pkgB.spec test-pkgB.changes" + And I execute osc with args "commit -m 'Initial commit'" + # revision 2 + And I copy file "{context.fixtures}/pac/test-pkgB-2.spec" to "{context.osc.temp}/openSUSE:Factory/test-pkgB/test-pkgB.spec" + And I copy file "{context.fixtures}/pac/test-pkgB-2.changes" to "{context.osc.temp}/openSUSE:Factory/test-pkgB/test-pkgB.changes" + And I execute osc with args "commit -m 'Version 2'" + Then I wait for osc results for "openSUSE:Factory" "test-pkgB" + + +Scenario: Create and build package 'multibuild-pkg' in 'openSUSE:Factory' project + # project checkout exists in temp already, no need to run checkout again + + # create package + Given I set working directory to "{context.osc.temp}/openSUSE:Factory" + When I execute osc with args "mkpac multibuild-pkg" + Then directory "{context.osc.temp}/openSUSE:Factory/multibuild-pkg" exists + And directory "{context.osc.temp}/openSUSE:Factory/multibuild-pkg/.osc" exists + + # add and commit new package content + Given I set working directory to "{context.osc.temp}/openSUSE:Factory/multibuild-pkg" + # revision 1 + When I copy file "{context.fixtures}/pac/multibuild-pkg-1.spec" to "{context.osc.temp}/openSUSE:Factory/multibuild-pkg/multibuild-pkg.spec" + And I copy file "{context.fixtures}/pac/multibuild-pkg-1.changes" to "{context.osc.temp}/openSUSE:Factory/multibuild-pkg/multibuild-pkg.changes" + And I copy file "{context.fixtures}/pac/multibuild-pkg-1._multibuild" to "{context.osc.temp}/openSUSE:Factory/multibuild-pkg/_multibuild" + And I execute osc with args "add multibuild-pkg.spec multibuild-pkg.changes _multibuild" + And I execute osc with args "commit -m 'Initial commit'" + Then I wait for osc results for "openSUSE:Factory" "multibuild-pkg" diff --git a/behave/obs-setup/steps b/behave/obs-setup/steps new file mode 120000 index 00000000..3a547014 --- /dev/null +++ b/behave/obs-setup/steps @@ -0,0 +1 @@ +../features/steps \ No newline at end of file diff --git a/behave/requirements.spec b/behave/requirements.spec new file mode 100644 index 00000000..5a09d31e --- /dev/null +++ b/behave/requirements.spec @@ -0,0 +1,46 @@ +# This package is not meant to be built and installed. +# It is for installing the test suite dependencies. +# +# Please follow the instructions in README.md. + + +# packages needed to manage virtual machines +%bcond_without host_only_packages + +# minimal required behave version +%define behave_version 1.2.6 + + +Name: osc-behave-requirements +Version: 1 +Release: 0 +Summary: Requirements for the OSC Behave tests +License: GPLv2 + + +# don't install kanku inside a kanku VM +%if %{with host_only_packages} +BuildRequires: kanku +%endif + +# osc +BuildRequires: osc + +# behave +BuildRequires: (python3dist(behave) >= %{behave_version} or python3-behave >= %{behave_version}) + +# needed by steps/kanku.py +BuildRequires: (python3dist(ruamel.yaml) or python3-ruamel.yaml) + +# fixes: ModuleNotFoundError: No module named 'pkg_resources' +BuildRequires: (python3dist(setuptools) or python3-setuptools) + + +%description +%{summary} + + +%files + + +%changelog diff --git a/behave/requirements.txt b/behave/requirements.txt new file mode 100644 index 00000000..620958e6 --- /dev/null +++ b/behave/requirements.txt @@ -0,0 +1 @@ +behave >= 1.2.6