From ceed09fc1834cea7c314682c0e772e4a49f9abe6 Mon Sep 17 00:00:00 2001 From: "Maxim [maxirmx] Samsonov" Date: Tue, 17 Dec 2024 20:45:10 +0300 Subject: [PATCH] test: create tests for separate runtime/application packaging feature --- .cirrus.yml | 4 +- .github/actions/setup-tebako/action.yml | 9 +- .github/workflows/alpine.yml | 56 ++++ .github/workflows/gem-test-and-release.yml | 2 +- .github/workflows/macos.yml | 57 +++- .github/workflows/ubuntu.yml | 51 ++- .github/workflows/windows-msys.yml | 5 +- .gitignore | 1 + README.adoc | 5 +- lib/tebako/cli.rb | 31 +- lib/tebako/cli_helpers.rb | 9 +- lib/tebako/codegen.rb | 2 +- lib/tebako/options_manager.rb | 71 ++++- lib/tebako/packager.rb | 21 +- lib/tebako/packager_lite.rb | 25 +- lib/tebako/scenario_manager.rb | 2 +- spec/cli_helpers_spec.rb | 67 +++- spec/deploy_helper_spec.rb | 92 ++++++ spec/options_manager_spec.rb | 87 ++++- spec/packager_lite_spec.rb | 41 ++- spec/packager_spec.rb | 355 +++++++++++++++++++++ spec/stripper_spec.rb | 175 ++++++++++ tests/scripts/functional-tests-app.sh | 275 ++++++++++++++++ tests/scripts/functional-tests.sh | 3 +- 24 files changed, 1372 insertions(+), 74 deletions(-) create mode 100644 spec/packager_spec.rb create mode 100644 spec/stripper_spec.rb create mode 100755 tests/scripts/functional-tests-app.sh diff --git a/.cirrus.yml b/.cirrus.yml index 0cfb84ef..0d97facd 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -27,10 +27,12 @@ test_task_template: &TEST_TASK_TEMPLATE testset-1_script: | RUBY_VER=3.2.5 tests/scripts/functional-tests.sh + testset-1-app_script: | + RUBY_VER=3.3.5 tests/scripts/functional-tests-app.sh + testset-2_script: | RUBY_VER=3.2.5 ruby tests-2/tebako-test.rb - checkout-packed-mn_script: | git clone https://github.com/metanorma/packed-mn.git packed-mn diff --git a/.github/actions/setup-tebako/action.yml b/.github/actions/setup-tebako/action.yml index 93b4e23d..4a689bf3 100644 --- a/.github/actions/setup-tebako/action.yml +++ b/.github/actions/setup-tebako/action.yml @@ -160,10 +160,15 @@ runs: if: runner.os == 'macOS' shell: bash run: | - pushd $(mktemp -d) + brew update + if [ ! -f Brewfile ]; then + pushd $(mktemp -d) curl https://raw.githubusercontent.com/tamatebako/tebako/refs/heads/main/Brewfile > Brewfile brew bundle -f - popd + popd + else + brew bundle -f + fi echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH - name: Install pacman packages diff --git a/.github/workflows/alpine.yml b/.github/workflows/alpine.yml index a5ae122d..4d71e73f 100644 --- a/.github/workflows/alpine.yml +++ b/.github/workflows/alpine.yml @@ -166,6 +166,62 @@ jobs: with: upload: "${{ steps.shall-upload.outputs.upload }}" + tests-1-app: + needs: setup + name: tests-1-app alpine-${{ matrix.env.ALPINE_VER }} Ruby ${{ matrix.package_ruby_ver }} CC ${{ matrix.env.CC }} + runs-on: ubuntu-latest + container: + image: alpine:${{ matrix.env.ALPINE_VER }} + strategy: + fail-fast: false + matrix: + env: + - { CC: gcc, CXX: g++, ALPINE_VER: "3.17" } + - { CC: clang, CXX: clang++, ALPINE_VER: "3.17" } + package_ruby_ver: [ '3.1.6', '3.2.5', '3.3.4', '3.3.5' ] + env: ${{ matrix.env }} + steps: + - name: Install packages + run: | + apk --no-cache --upgrade add git bash + git config --global --add safe.directory $PWD + + - name: Checkout tebako packaging environment + uses: actions/checkout@v4 + with: + fetch-depth: 1 + submodules: true + + - name: Setup ci environment + uses: ./.github/actions/setup-tebako + with: + cache: off + cc: ${{ env.CC }} + cxx: ${{ env.CXX }} + install: off + verbose: ${{ env.VERBOSE }} + + - name: Setup development environment + uses: ./.github/actions/setup-tebako-development + with: + path: deps + os: alpine-${{ matrix.env.ALPINE_VER }} + cc: ${{ env.CC }} + version: ${{ env.CACHE_VER }} + + - name: Checkout shell test framework + uses: actions/checkout@v4 + with: + repository: kward/shunit2 + path: ${{github.workspace}}/tests/shunit2 + fetch-depth: 1 + + - name: Run tebako tests (set no. 1) for separately packaged application + shell: bash + run: | + bundle install + RUBY_VER=${{ matrix.package_ruby_ver }} tests/scripts/functional-tests-app.sh + tests-2: needs: setup name: tests-2 alpine-${{ matrix.env.ALPINE_VER }} Ruby ${{ matrix.package_ruby_ver }} CC ${{ matrix.env.CC }} diff --git a/.github/workflows/gem-test-and-release.yml b/.github/workflows/gem-test-and-release.yml index f2503639..0f869a42 100644 --- a/.github/workflows/gem-test-and-release.yml +++ b/.github/workflows/gem-test-and-release.yml @@ -49,7 +49,7 @@ concurrency: cancel-in-progress: true env: - CACHE_VER: 12 + CACHE_VER: 15 DEBIAN_FRONTEND: "noninteractive" TZ: "Etc/UTC" # show cmake output diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 19f98d3b..ba656aeb 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -58,7 +58,7 @@ concurrency: cancel-in-progress: true env: - CACHE_VER: 11 + CACHE_VER: 15 VERBOSE: no jobs: @@ -116,8 +116,6 @@ jobs: package_ruby_ver: [ '3.1.6', '3.2.5', '3.3.5' ] ruby_ver: ['3.2.5'] - include: - - { env: { os: macos-14, xcode: 15.4 }, ruby_ver: '3.3.4', package_ruby_ver: '3.3.4' } steps: - name: Checkout tebako packaging environment uses: actions/checkout@v4 @@ -157,6 +155,57 @@ jobs: upload: "${{ steps.shall-upload.outputs.upload }}" verbose: ${{ env.VERBOSE }} + tests-1-app: + needs: setup + name: tests-1-app package Ruby ${{ matrix.package_ruby_ver }} on ${{ matrix.env.os }}, XCode ${{ matrix.env.xcode }}, Ruby ${{ matrix.ruby_ver }} + runs-on: ${{ matrix.env.os }} + strategy: + fail-fast: false + matrix: + env: + - { os: macos-13, xcode: 14.3.1 } + - { os: macos-14, xcode: 15.4 } + - { os: macos-15, xcode: 16.1 } + + package_ruby_ver: [ '3.3.5' ] + ruby_ver: ['3.2.5'] + steps: + - name: Checkout tebako packaging environment + uses: actions/checkout@v4 + with: + fetch-depth: 1 + submodules: true + + - name: Setup ci environment + uses: ./.github/actions/setup-tebako + with: + cache: off + install: off + ruby_version: ${{ matrix.ruby_ver }} + xcode: ${{ matrix.env.xcode }} + verbose: ${{ env.VERBOSE }} + + - name: Setup development environment + uses: ./.github/actions/setup-tebako-development + with: + path: deps + os: ${{ matrix.env.os }} + cc: ruby-${{ matrix.ruby_ver }}-XCode-${{ matrix.env.xcode }} + version: ${{ env.CACHE_VER }} + + - name: Checkout shell test framework + uses: actions/checkout@v4 + with: + repository: kward/shunit2 + path: ${{github.workspace}}/tests/shunit2 + fetch-depth: 1 + + - name: Run tebako tests (set no. 1) for separately packaged application + shell: bash + run: | + bundle install + RUBY_VER=${{ matrix.package_ruby_ver }} tests/scripts/functional-tests-app.sh + tests-2: needs: setup name: tests-2 package Ruby ${{ matrix.package_ruby_ver }} on ${{ matrix.env.os }}, XCode ${{ matrix.env.xcode }}, Ruby ${{ matrix.ruby_ver }} @@ -171,8 +220,6 @@ jobs: - { os: macos-15, xcode: 16.1 } package_ruby_ver: [ '3.1.6', '3.2.5', '3.3.5' ] ruby_ver: ['3.2.5'] - include: - - { env: { os: macos-14, xcode: 15.4 }, ruby_ver: '3.3.4', package_ruby_ver: '3.3.4' } steps: - name: Checkout tebako packaging environment uses: actions/checkout@v4 diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 4dbd733d..d116cfe3 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -52,7 +52,7 @@ on: - .github/workflows/macos.yml - .github/workflows/windows-msys.yml - .cirrus.yml - - Brewfile + - Brewfile workflow_dispatch: concurrency: @@ -155,6 +155,55 @@ jobs: with: upload: "${{ steps.shall-upload.outputs.upload }}" + tests-1-app: + needs: setup + name: tests-1-app ${{ matrix.env.os }} Ruby ${{ matrix.package_ruby_ver }} CC ${{ matrix.env.CC }} + runs-on: ${{ matrix.env.os }} + strategy: + fail-fast: false + matrix: + package_ruby_ver: [ '2.7.8', '3.0.7', '3.1.6', '3.2.5', '3.3.5' ] + env: + - { os: ubuntu-20.04, CC: gcc-10, CXX: g++-10 } + - { os: ubuntu-20.04, CC: clang-12, CXX: clang++-12 } + env: ${{ matrix.env }} + steps: + - name: Checkout tebako packaging environment + uses: actions/checkout@v4 + with: + fetch-depth: 1 + submodules: true + + - name: Setup ci environment + uses: ./.github/actions/setup-tebako + with: + cache: off + cc: ${{ env.CC }} + cxx: ${{ env.CXX }} + install: off + verbose: ${{ env.VERBOSE }} + + - name: Setup development environment + uses: ./.github/actions/setup-tebako-development + with: + path: deps + os: ${{ matrix.env.os }} + cc: ${{ env.CC }} + version: ${{ env.CACHE_VER }} + + - name: Checkout shell test framework + uses: actions/checkout@v4 + with: + repository: kward/shunit2 + path: ${{github.workspace}}/tests/shunit2 + fetch-depth: 1 + + - name: Run tebako tests (set no. 1) for separately packaged application + shell: bash + run: | + bundle install + RUBY_VER=${{ matrix.package_ruby_ver }} tests/scripts/functional-tests-app.sh + tests-2: needs: setup name: tests-2 ${{ matrix.env.os }} Ruby ${{ matrix.package_ruby_ver }} CC ${{ matrix.env.CC }} diff --git a/.github/workflows/windows-msys.yml b/.github/workflows/windows-msys.yml index 74c5096e..0d802187 100644 --- a/.github/workflows/windows-msys.yml +++ b/.github/workflows/windows-msys.yml @@ -140,7 +140,7 @@ jobs: tests-1: needs: setup - name: tests-1 windows-msys [${{ matrix.env.sys }}, Ruby ${{ matrix.package_ruby_ver }} CC ${{ matrix.env.CC }}] + name: tests-1${{ matrix.script }} windows-msys [${{ matrix.env.sys }}, Ruby ${{ matrix.package_ruby_ver }} CC ${{ matrix.env.CC }}] runs-on: windows-latest strategy: fail-fast: false @@ -150,6 +150,7 @@ jobs: CC: gcc CXX: g++ package_ruby_ver: [ '3.1.6', '3.2.5', '3.3.5' ] + script: ['', '-app'] env: ${{ matrix.env }} defaults: @@ -218,7 +219,7 @@ jobs: fetch-depth: 1 - name: Run tebako tests (set no. 1) - run: RUBY_VER=${{ matrix.package_ruby_ver }} tests/scripts/functional-tests.sh + run: RUBY_VER=${{ matrix.package_ruby_ver }} tests/scripts/functional-tests${{ matrix.script }}.sh tests-2: needs: setup diff --git a/.gitignore b/.gitignore index 04f4c99c..df358dbc 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,7 @@ tebako_test.log tests-actions/ .environment.version *.tebako +tebako-runtime # rspec .rspec_status diff --git a/README.adoc b/README.adoc index 00ee13c7..83121ef2 100644 --- a/README.adoc +++ b/README.adoc @@ -760,11 +760,12 @@ this parameter defines Ruby version that will be packaged (optional, defaults to `3.1.6`) `project-root`:: -a folder at the host source file system where project files are located +a folder at the host source file system where project files are located. +This parameter is not required if the operation mode is 'runtime'. `entry-point`:: an executable file (binary executable or script) that shall be started when -packaged file is called +packaged file is called. This parameter is not required if the operation mode is 'runtime'. `output`:: the output file name (optional, defaults to `/` diff --git a/lib/tebako/cli.rb b/lib/tebako/cli.rb index 11e463d3..2683124d 100755 --- a/lib/tebako/cli.rb +++ b/lib/tebako/cli.rb @@ -43,7 +43,7 @@ module Tebako DEFAULT_TEBAFILE = ".tebako.yml" # Tebako packager front-end - class Cli < Thor + class Cli < Thor # rubocop:disable Metrics/ClassLength package_name "Tebako" class_option :prefix, type: :string, aliases: "-p", required: false, desc: "A path to tebako packaging environment, '~/.tebako' ('$HOME/.tebako') by default" @@ -82,28 +82,35 @@ def hash #{" " * 65}# If this parameter is not set, the application will start in the current directory of the host file system. DESC + REF_DESCRIPTION = <<~DESC + "Referenced tebako run-time package; 'tebako-runtime' by default". + This option specifies the tebako runtime to be used by the application on Windows and if mode is 'application' only . + DESC + RGP_DESCRIPTION = <<~DESC - Activates removal a reference to GLIBC_PRIVATE version of libpthread from tebako package. This allows Linux Gnu packages to run against versions of - #{" " * 65}# libpthread that differ from the version used for packaging. For example, package created at Ubuntu 20 system can be used on Ubuntu 22. This option works on Gnu Linux with - #{" " * 65}# Gnu toolchain only (not for LLVM/clang). The feature is exeprimental, we may consider other approach in the future. + Current working directory for packaged application. This directory shall be specified relative to root. + #{" " * 65}# If this parameter is not set, the application will start in the current directory of the host file system. DESC desc "press", "Press tebako image" method_option :cwd, type: :string, aliases: "-c", required: false, desc: CWD_DESCRIPTION - method_option :"entry-point", type: :string, aliases: ["-e", "--entry"], required: true, - desc: "Ruby application entry point" method_option :"log-level", type: :string, aliases: "-l", required: false, enum: %w[error warn debug trace], desc: "Tebako memfs logging level, 'error' by default" method_option :output, type: :string, aliases: "-o", required: false, desc: "Tebako package file name, entry point base file name in the current folder by default" - method_option :root, type: :string, aliases: "-r", required: true, desc: "Root folder of the Ruby application" + method_option :"entry-point", type: :string, aliases: ["-e", "--entry"], required: false, + desc: "Ruby application entry point" + method_option :root, type: :string, aliases: "-r", required: false, desc: "Root folder of the Ruby application" method_option :Ruby, type: :string, aliases: "-R", required: false, enum: Tebako::RubyVersion::RUBY_VERSIONS.keys, desc: "Tebako package Ruby version, #{Tebako::RubyVersion::DEFAULT_RUBY_VERSION} by default" method_option :patchelf, aliases: "-P", type: :boolean, desc: RGP_DESCRIPTION method_option :mode, type: :string, aliases: "-m", required: false, enum: %w[bundle both runtime application], desc: "Tebako press mode, 'bundle' by default" + method_option :ref, type: :string, aliases: "-u", required: false, desc: REF_DESCRIPTION + def press + validate_press_options (om, cm) = bootstrap do_press(om) @@ -159,6 +166,16 @@ def options end end + no_commands do + def validate_press_options + return unless options["mode"] != "runtime" + + opts = "" + opts += " '--root'" if options["root"].nil? + opts += " '--entry-point'" if options["entry-point"].nil? + raise Thor::Error, "No value provided for required options #{opts}" unless opts.empty? + end + end no_commands do include Tebako::CliHelpers end diff --git a/lib/tebako/cli_helpers.rb b/lib/tebako/cli_helpers.rb index a1082cd0..bb2efdf2 100644 --- a/lib/tebako/cli_helpers.rb +++ b/lib/tebako/cli_helpers.rb @@ -42,16 +42,17 @@ module Tebako # Cli helpers module CliHelpers def do_press(options_manager) - puts options_manager.press_announce scenario_manager = Tebako::ScenarioManager.new(options_manager.root, options_manager.fs_entrance) + puts options_manager.press_announce(scenario_manager.msys?) + + if options_manager.mode == "both" || options_manager.mode == "runtime" || options_manager.mode == "bundle" + do_press_runtime(options_manager, scenario_manager) + end if options_manager.mode == "both" || options_manager.mode == "application" do_press_application(options_manager, scenario_manager) end - if options_manager.mode == "both" || options_manager.mode == "runtime" || options_manager.mode == "bundle" - do_press_runtime(options_manager, scenario_manager) - end true end diff --git a/lib/tebako/codegen.rb b/lib/tebako/codegen.rb index daeaaed9..743fac36 100644 --- a/lib/tebako/codegen.rb +++ b/lib/tebako/codegen.rb @@ -55,7 +55,7 @@ def deploy_crt_implib(opt, scm) if scm.msys? crt = <<~SUBST Tebako::Packager.create_implib("#{opt.ruby_src_dir}", "#{opt.data_src_dir}", - "#{File.basename(opt.package)}", rv) + "#{opt.package}", rv) SUBST end crt diff --git a/lib/tebako/options_manager.rb b/lib/tebako/options_manager.rb index 22d6011c..c932572d 100644 --- a/lib/tebako/options_manager.rb +++ b/lib/tebako/options_manager.rb @@ -73,6 +73,10 @@ def cwd @cwd ||= f_cwd end + def cwd_announce + @cwd_announce ||= cwd.nil? ? "" : cwd + end + # DATA_BIN_DIR folder is used to create packaged filesystem # set(DATA_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}/p) def data_bin_dir @@ -191,10 +195,57 @@ def prefix end end - def press_announce - cwd_announce = cwd.nil? ? "" : cwd - @press_announce ||= <<~ANN + def press_announce(is_msys) + case mode + when "application" + press_announce_application(is_msys) + when "both" + press_announce_both + when "bundle" + press_announce_bundle + when "runtime" + press_announce_runtime + end + end + + def press_announce_ref(is_msys) + if is_msys + " referencing runtime at '#{ref}'" + else + "" + end + end + + def press_announce_application(is_msys) + <<~ANN + Running tebako press at #{prefix} + Mode: 'application' + Ruby version: '#{@ruby_ver}' + Project root: '#{root}' + Application entry point: '#{fs_entrance}' + Package file name: '#{package}.tebako'#{press_announce_ref(is_msys)} + Package working directory: '#{cwd_announce}' + ANN + end + + def press_announce_both + <<~ANN Running tebako press at #{prefix} + Mode: 'both' + Ruby version: '#{@ruby_ver}' + Project root: '#{root}' + Application entry point: '#{fs_entrance}' + Runtime file name: '#{package}' + Package file name: '#{package}.tebako' + Loging level: '#{l_level}' + Package working directory: '#{cwd_announce}' + ANN + end + + def press_announce_bundle + <<~ANN + Running tebako press at #{prefix} + Mode: 'bundle' Ruby version: '#{@ruby_ver}' Project root: '#{root}' Application entry point: '#{fs_entrance}' @@ -204,6 +255,16 @@ def press_announce ANN end + def press_announce_runtime + <<~ANN + Running tebako press at #{prefix} + Mode: 'runtime' + Ruby version: '#{@ruby_ver}' + Runtime file name: '#{package}' + Loging level: '#{l_level}' + ANN + end + def press_options @press_options ||= "-DPCKG:STRING='#{package}' -DLOG_LEVEL:STRING='#{l_level}' " \ end @@ -212,6 +273,10 @@ def relative?(path) Pathname.new(path).relative? end + def ref + @ref ||= @options["ref"].nil? ? "tebako-runtime" : @options["ref"].gsub("\\", "/") + end + def remove_glibc_private @remove_glibc_private ||= if RUBY_PLATFORM.end_with?("linux") || RUBY_PLATFORM.end_with?("linux-gnu") "-DREMOVE_GLIBC_PRIVATE=#{@options["patchelf"] ? "ON" : "OFF"}" diff --git a/lib/tebako/packager.rb b/lib/tebako/packager.rb index 8282ad81..17df8048 100644 --- a/lib/tebako/packager.rb +++ b/lib/tebako/packager.rb @@ -64,12 +64,13 @@ module Packager thread_pthread.c ].freeze - class << self # rubocop:disable Metrics/ClassLength + class << self # Create implib def create_implib(src_dir, package_src_dir, app_name, ruby_ver) - create_def(src_dir, app_name) + a_name = File.basename(app_name, ".*") + create_def(src_dir, a_name) puts " ... creating Windows import library" - params = ["dlltool", "-d", def_fname(src_dir, app_name), "-D", out_fname(app_name), "--output-lib", + params = ["dlltool", "-d", def_fname(src_dir, a_name), "-D", out_fname(a_name), "--output-lib", lib_fname(package_src_dir, ruby_ver)] BuildHelpers.run_with_capture(params) end @@ -196,20 +197,6 @@ def patchelf(src_name, patchelf) BuildHelpers.run_with_capture(params) end - def ruby_version(tbd) - ruby_version = nil - PatchHelpers.with_env(DEPLOY_ENV) do - out, st = Open3.capture2e("#{tbd}/ruby", "--version") - raise Tebako::Error, "Failed to run ruby --version" unless st.exitstatus.zero? - - match = out.match(/ruby (\d+\.\d+\.\d+)/) - raise Tebako::Error, "Failed to parse Ruby version from #{out}" unless match - - ruby_version = match[1] - end - ruby_version - end - def strip_or_copy(os_type, src_name, package_name) # [TODO] On MSys strip sometimes creates a broken executable # https://github.com/tamatebako/tebako/issues/172 diff --git a/lib/tebako/packager_lite.rb b/lib/tebako/packager_lite.rb index b06866a8..76dc7078 100644 --- a/lib/tebako/packager_lite.rb +++ b/lib/tebako/packager_lite.rb @@ -26,6 +26,7 @@ # POSSIBILITY OF SUCH DAMAGE. require "pathname" +require "fileutils" require_relative "options_manager" require_relative "scenario_manager" @@ -46,16 +47,32 @@ def codegen Tebako::Codegen.generate_package_descriptor(@opts, @scm) end + def create_implib + rv = Tebako::RubyVersion.new(@opts.ruby_ver) + bname = if @opts.mode == "application" + @opts.ref + else # @opts.mode == "both" + @opts.package + end + Tebako::Packager.create_implib(@opts.ruby_src_dir, @opts.data_src_dir, bname, rv) + end + def create_package - Tebako::Packager.init(@opts.stash_dir, @opts.data_src_dir, @opts.data_pre_dir, @opts.data_bin_dir) - Tebako::Packager.deploy(@opts.data_src_dir, @opts.data_pre_dir, @opts.rv, - @opts.root, @scm.fs_entrance, @opts.cwd) + deploy + FileUtils.rm_f(name) Tebako::Packager.mkdwarfs(@opts.deps_bin_dir, name, @opts.data_src_dir, codegen) + puts "Created tebako package at \"#{name}\"" + end + + def deploy + Tebako::Packager.init(@opts.stash_dir, @opts.data_src_dir, @opts.data_pre_dir, @opts.data_bin_dir) + create_implib if @scm.msys? + Tebako::Packager.deploy(@opts.data_src_dir, @opts.data_pre_dir, @opts.rv, @opts.root, @scm.fs_entrance, @opts.cwd) end def name bname = Pathname.new(@opts.package).cleanpath.to_s - "#{bname}.tebako" + @name ||= "#{bname}.tebako" end end end diff --git a/lib/tebako/scenario_manager.rb b/lib/tebako/scenario_manager.rb index 1aa8142b..a1bfaa70 100644 --- a/lib/tebako/scenario_manager.rb +++ b/lib/tebako/scenario_manager.rb @@ -35,7 +35,7 @@ module Tebako class ScenarioManager def initialize(fs_root, fs_entrance) initialize_root(fs_root) - initialize_entry_point(fs_entrance) + initialize_entry_point(fs_entrance || "stub.rb") end attr_reader :fs_entry_point, :fs_mount_point, :fs_entrance diff --git a/spec/cli_helpers_spec.rb b/spec/cli_helpers_spec.rb index 2ac543c7..aedad140 100644 --- a/spec/cli_helpers_spec.rb +++ b/spec/cli_helpers_spec.rb @@ -49,25 +49,68 @@ end describe "#do_press" do - let(:options_manager) { Tebako::OptionsManager.new(options) } - before do stub_const("RUBY_PLATFORM", "x86_64-linux") end - it "executes the press command successfully" do - allow(FileUtils).to receive(:rm_rf) - allow(self).to receive(:system).and_return(true) - allow(Tebako::Codegen).to receive(:generate_tebako_version_h).and_return(true) - allow(Tebako::Codegen).to receive(:generate_tebako_fs_cpp).and_return(true) + context "when mode is set to 'application'" do + before do + options["mode"] = "application" + end + + let(:options_manager) { Tebako::OptionsManager.new(options) } + + it "executes the press command successfully" do + allow_any_instance_of(Tebako::PackagerLite).to receive(:create_package).and_return(true) + expect(do_press(options_manager)).to be_truthy + end + end + + context "when mode is set to 'bundle'" do + before do + options["mode"] = "bundle" + end + + let(:options_manager) { Tebako::OptionsManager.new(options) } + + it "executes the press command successfully" do + allow(FileUtils).to receive(:rm_rf) + allow(self).to receive(:system).and_return(true) + allow(Tebako::Codegen).to receive(:generate_tebako_version_h).and_return(true) + allow(Tebako::Codegen).to receive(:generate_tebako_fs_cpp).and_return(true) + + expect(do_press(options_manager)).to be_truthy + end - expect(do_press(options_manager)).to be_truthy + it "raises an error if the press command fails" do + allow(FileUtils).to receive(:rm_rf) + allow(self).to receive(:system).and_return(false) + expect { do_press(options_manager) }.to raise_error(Tebako::Error) + end end - it "raises an error if the press command fails" do - allow(FileUtils).to receive(:rm_rf) - allow(self).to receive(:system).and_return(false) - expect { do_press(options_manager) }.to raise_error(Tebako::Error) + context "when mode is set to 'runtime'" do + before do + options["mode"] = "bundle" + end + + let(:options_manager) { Tebako::OptionsManager.new(options) } + + it "executes the press command successfully" do + allow(FileUtils).to receive(:rm_rf) + allow(self).to receive(:system).and_return(true) + allow(Tebako::Codegen).to receive(:generate_tebako_version_h).and_return(true) + allow(Tebako::Codegen).to receive(:generate_tebako_fs_cpp).and_return(true) + allow(Tebako::Codegen).to receive(:generate_package_header).and_return(true) + + expect(do_press(options_manager)).to be_truthy + end + + it "raises an error if the press command fails" do + allow(FileUtils).to receive(:rm_rf) + allow(self).to receive(:system).and_return(false) + expect { do_press(options_manager) }.to raise_error(Tebako::Error) + end end end diff --git a/spec/deploy_helper_spec.rb b/spec/deploy_helper_spec.rb index a5b0d30d..76f36f16 100644 --- a/spec/deploy_helper_spec.rb +++ b/spec/deploy_helper_spec.rb @@ -26,6 +26,7 @@ # POSSIBILITY OF SUCH DAMAGE. require_relative "../lib/tebako/deploy_helper" +require "open3" # rubocop:disable Metrics/BlockLength RSpec.describe Tebako::DeployHelper do @@ -165,6 +166,55 @@ end end + describe "#deploy_env" do + let(:gem_home) { File.join(target_dir, "gems") } + + before do + deploy_helper.instance_variable_set(:@gem_home, gem_home) + end + + it "returns the correct environment variables" do + expected_env = { + "GEM_HOME" => gem_home, + "GEM_PATH" => gem_home, + "GEM_SPEC_CACHE" => File.join(target_dir, "spec_cache"), + "TEBAKO_PASS_THROUGH" => "1" + } + expect(deploy_helper.deploy_env).to eq(expected_env) + end + end + + describe "#install_gem" do + let(:gem_name) { "some_gem" } + let(:gem_version) { "1.0.0" } + let(:gem_command) { "/path/to/gem" } + let(:bundler_command) { "/path/to/bundle" } + + before do + deploy_helper.instance_variable_set(:@tgd, "/path/to/tgd") + deploy_helper.instance_variable_set(:@gem_command, gem_command) + deploy_helper.instance_variable_set(:@bundler_command, bundler_command) + allow(Open3).to receive(:capture2e).and_return(["", double("status", signaled?: false, exitstatus: 0)]) + end + + context "when gem version is provided" do + it "installs the gem with the specified version" do + expect(Open3).to receive(:capture2e) + .with(gem_command, "install", gem_name, "-v", gem_version, "--no-document", + "--install-dir", "/path/to/tgd") + deploy_helper.install_gem(gem_name, gem_version) + end + end + + context "when gem version is not provided" do + it "installs the gem without specifying the version" do + expect(Open3).to receive(:capture2e) + .with(gem_command, "install", gem_name, "--no-document", "--install-dir", "/path/to/tgd") + deploy_helper.install_gem(gem_name) + end + end + end + describe "#needs_bundler?" do context "when @gf_length is greater than 0" do before do @@ -229,5 +279,47 @@ end end end + + describe "#update_rubygems" do + let(:ruby_ver) { instance_double("RubyVersion", ruby31?: false, api_version: "2.7.0") } + let(:gem_command) { "/path/to/gem" } + + before do + deploy_helper.instance_variable_set(:@ruby_ver, ruby_ver) + deploy_helper.instance_variable_set(:@gem_command, gem_command) + allow(Open3).to receive(:capture2e).and_return(["", double("status", signaled?: false, exitstatus: 0)]) + allow(Tebako::Packager::PatchHelpers).to receive(:patch_file).and_return(true) + end + + context "when ruby version is 3.1 or higher" do + before do + allow(ruby_ver).to receive(:ruby31?).and_return(true) + end + + it "does not update rubygems" do + expect(Tebako::BuildHelpers).not_to receive(:run_with_capture_v) + deploy_helper.update_rubygems + end + end + + context "when ruby version is lower than 3.1" do + before do + allow(ruby_ver).to receive(:ruby31?).and_return(false) + end + + it "updates rubygems to the specified version" do + expect(Open3).to receive(:capture2e) + .with("/path/to/gem", "update", "--no-doc", "--system", Tebako::RUBYGEMS_VERSION) + .and_return(["", double("status", signaled?: false, exitstatus: 0)]) + deploy_helper.update_rubygems + end + + it "calls patch_after_rubygems_update with the correct parameters" do + allow(File).to receive(:exist?).and_return(true) + expect(deploy_helper).to receive(:patch_after_rubygems_update).with(target_dir, "2.7.0") + deploy_helper.update_rubygems + end + end + end end # rubocop:enable Metrics/BlockLength diff --git a/spec/options_manager_spec.rb b/spec/options_manager_spec.rb index 06376655..9716e9c0 100644 --- a/spec/options_manager_spec.rb +++ b/spec/options_manager_spec.rb @@ -379,7 +379,58 @@ end describe "#press_announce" do - context 'when options["cwd"] is set' do + context 'when mode is "application" and options["cwd"] is set' do + let(:options) do + { "cwd" => "/some/path", "entry-point" => "main.rb", "log-level" => "info", + "root" => "test_root", "mode" => "application" } + end + let(:options_manager) { Tebako::OptionsManager.new(options) } + let(:root) { File.join(Dir.pwd, options["root"]) } + let(:pckg) { File.join(Dir.pwd, "main") } + let(:prefix) { File.expand_path("~/.tebako") } + + it "returns the correct announcement" do + options_manager.cfg_options + expected_announce = <<~ANN + Running tebako press at #{prefix} + Mode: 'application' + Ruby version: '#{Tebako::RubyVersion::DEFAULT_RUBY_VERSION}' + Project root: '#{root}' + Application entry point: '#{options["entry-point"]}' + Package file name: '#{pckg}.tebako' + Package working directory: '#{options["cwd"]}' + ANN + expect(options_manager.press_announce(false)).to eq(expected_announce) + end + end + + context 'when mode is "both" and options["cwd"] is not set' do + let(:options) do + { "entry-point" => "main.rb", "log-level" => "info", "root" => "test_root", "mode" => "both" } + end + let(:options_manager) { Tebako::OptionsManager.new(options) } + let(:root) { File.join(Dir.pwd, options["root"]) } + let(:pckg) { File.join(Dir.pwd, "main") } + let(:prefix) { File.expand_path("~/.tebako") } + + it "returns the correct announcement with default cwd" do + options_manager.cfg_options + expected_announce = <<~ANN + Running tebako press at #{prefix} + Mode: 'both' + Ruby version: '#{Tebako::RubyVersion::DEFAULT_RUBY_VERSION}' + Project root: '#{root}' + Application entry point: '#{options["entry-point"]}' + Runtime file name: '#{pckg}' + Package file name: '#{pckg}.tebako' + Loging level: '#{options["log-level"]}' + Package working directory: '' + ANN + expect(options_manager.press_announce(false)).to eq(expected_announce) + end + end + + context 'when mode is "bundle" and options["cwd"] is set' do let(:options) do { "cwd" => "/some/path", "entry-point" => "main.rb", "log-level" => "info", "root" => "test_root" } end @@ -392,6 +443,7 @@ options_manager.cfg_options expected_announce = <<~ANN Running tebako press at #{prefix} + Mode: 'bundle' Ruby version: '#{Tebako::RubyVersion::DEFAULT_RUBY_VERSION}' Project root: '#{root}' Application entry point: '#{options["entry-point"]}' @@ -399,12 +451,14 @@ Loging level: '#{options["log-level"]}' Package working directory: '#{options["cwd"]}' ANN - expect(options_manager.press_announce).to eq(expected_announce) + expect(options_manager.press_announce(false)).to eq(expected_announce) end end - context 'when options["cwd"] is not set' do - let(:options) { { "entry-point" => "main.rb", "log-level" => "info", "root" => "test_root" } } + context 'when mode is "bundle" and options["cwd"] is not set' do + let(:options) do + { "entry-point" => "main.rb", "log-level" => "info", "root" => "test_root" } + end let(:options_manager) { Tebako::OptionsManager.new(options) } let(:root) { File.join(Dir.pwd, options["root"]) } let(:pckg) { File.join(Dir.pwd, "main") } @@ -414,6 +468,7 @@ options_manager.cfg_options expected_announce = <<~ANN Running tebako press at #{prefix} + Mode: 'bundle' Ruby version: '#{Tebako::RubyVersion::DEFAULT_RUBY_VERSION}' Project root: '#{root}' Application entry point: '#{options["entry-point"]}' @@ -421,7 +476,29 @@ Loging level: '#{options["log-level"]}' Package working directory: '' ANN - expect(options_manager.press_announce).to eq(expected_announce) + expect(options_manager.press_announce(false)).to eq(expected_announce) + end + end + + context 'when mode is "runtime"' do + let(:options) do + { "entry-point" => "main.rb", "log-level" => "info", "root" => "test_root", "mode" => "runtime" } + end + let(:options_manager) { Tebako::OptionsManager.new(options) } + let(:root) { File.join(Dir.pwd, options["root"]) } + let(:pckg) { File.join(Dir.pwd, "main") } + let(:prefix) { File.expand_path("~/.tebako") } + + it "returns the correct announcement with default cwd" do + options_manager.cfg_options + expected_announce = <<~ANN + Running tebako press at #{prefix} + Mode: 'runtime' + Ruby version: '#{Tebako::RubyVersion::DEFAULT_RUBY_VERSION}' + Runtime file name: '#{pckg}' + Loging level: '#{options["log-level"]}' + ANN + expect(options_manager.press_announce(false)).to eq(expected_announce) end end end diff --git a/spec/packager_lite_spec.rb b/spec/packager_lite_spec.rb index 4b20832a..0e49aa09 100644 --- a/spec/packager_lite_spec.rb +++ b/spec/packager_lite_spec.rb @@ -33,8 +33,9 @@ RSpec.describe Tebako::PackagerLite do let(:options_manager) do double("OptionsManager", stash_dir: "/tmp/stash", data_src_dir: "/tmp/src", data_pre_dir: "/tmp/pre", - data_bin_dir: "/tmp/bin", deps_bin_dir: "/tmp/deps_bin", - package: "test_package", rv: "3.0.0", root: "/", cwd: "/app") + data_bin_dir: "/tmp/bin", deps_bin_dir: "/tmp/deps_bin", mode: "both", + package: "test_package", rv: "3.2.5", ruby_ver: "3.2.5", root: "/", cwd: "/app", + ruby_src_dir: "/tmp/ruby_src") end let(:scenario_manager) { double("ScenarioManager", fs_entrance: "/entry") } @@ -44,6 +45,7 @@ allow(Tebako::Packager).to receive(:init) allow(Tebako::Packager).to receive(:deploy) allow(Tebako::Packager).to receive(:mkdwarfs) + allow(FileUtils).to receive(:rm_f) end describe "#initialize" do @@ -67,14 +69,44 @@ it "calls Packager methods to create the package" do packager_lite = described_class.new(options_manager, scenario_manager) allow(packager_lite).to receive(:codegen).and_return("codegen_result") + allow(scenario_manager).to receive(:msys?).and_return(true) + allow(Tebako::Packager).to receive(:create_def) + allow(Tebako::Packager).to receive(:create_implib) packager_lite.create_package - expect(Tebako::Packager).to have_received(:init).with("/tmp/stash", "/tmp/src", "/tmp/pre", "/tmp/bin") - expect(Tebako::Packager).to have_received(:deploy).with("/tmp/src", "/tmp/pre", "3.0.0", "/", "/entry", "/app") + expect(FileUtils).to have_received(:rm_f).with("test_package.tebako") expect(Tebako::Packager).to have_received(:mkdwarfs).with("/tmp/deps_bin", "test_package.tebako", "/tmp/src", "codegen_result") end end + describe "#deploy" do + context "when msys? is true" do + it "calls create_implib and Packager methods to deploy the package" do + allow(scenario_manager).to receive(:msys?).and_return(true) + packager_lite = described_class.new(options_manager, scenario_manager) + allow(packager_lite).to receive(:create_implib) + allow(scenario_manager).to receive(:msys?).and_return(true) + packager_lite.deploy + expect(packager_lite).to have_received(:create_implib) + expect(Tebako::Packager).to have_received(:init).with("/tmp/stash", "/tmp/src", "/tmp/pre", "/tmp/bin") + expect(Tebako::Packager).to have_received(:deploy).with("/tmp/src", "/tmp/pre", "3.2.5", "/", "/entry", "/app") + end + end + + context "when msys? is false" do + it "does not call create_implib but calls Packager methods to deploy the package" do + allow(scenario_manager).to receive(:msys?).and_return(false) + packager_lite = described_class.new(options_manager, scenario_manager) + allow(packager_lite).to receive(:create_implib) + allow(scenario_manager).to receive(:msys?).and_return(false) + packager_lite.deploy + expect(packager_lite).not_to have_received(:create_implib) + expect(Tebako::Packager).to have_received(:init).with("/tmp/stash", "/tmp/src", "/tmp/pre", "/tmp/bin") + expect(Tebako::Packager).to have_received(:deploy).with("/tmp/src", "/tmp/pre", "3.2.5", "/", "/entry", "/app") + end + end + end + describe "#name" do it "returns the correct package name" do packager_lite = described_class.new(options_manager, scenario_manager) @@ -82,4 +114,5 @@ end end end + # rubocop:enable Metrics/BlockLength diff --git a/spec/packager_spec.rb b/spec/packager_spec.rb new file mode 100644 index 00000000..c7dee552 --- /dev/null +++ b/spec/packager_spec.rb @@ -0,0 +1,355 @@ +# frozen_string_literal: true + +# Copyright (c) 2024 [Ribose Inc](https://www.ribose.com). +# All rights reserved. +# This file is a part of tebako +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +require "fileutils" +require_relative "../lib/tebako/packager" + +# rubocop:disable Metrics/BlockLength +RSpec.describe Tebako::Packager do + describe "#create_implib" do + let(:src_dir) { "/path/to/src" } + let(:package_src_dir) { "/path/to/package/src" } + let(:app_name) { "my_app" } + let(:ruby_ver) { Tebako::RubyVersion.new("3.2.5") } + + before do + allow(Tebako::Packager).to receive(:create_def) + allow(Tebako::BuildHelpers).to receive(:run_with_capture) + end + + it "calls create_def with the correct parameters" do + expect(Tebako::Packager).to receive(:create_def).with(src_dir, app_name) + Tebako::Packager.create_implib(src_dir, package_src_dir, app_name, ruby_ver) + end + + it "runs dlltool with the correct parameters" do + params = ["dlltool", "-d", + Tebako::Packager.send(:def_fname, src_dir, app_name), "-D", + Tebako::Packager.send(:out_fname, app_name), "--output-lib", + Tebako::Packager.send(:lib_fname, package_src_dir, ruby_ver)] + expect(Tebako::BuildHelpers).to receive(:run_with_capture).with(params) + Tebako::Packager.create_implib(src_dir, package_src_dir, app_name, ruby_ver) + end + end + + describe "#deploy" do + let(:target_dir) { "/path/to/target" } + let(:pre_dir) { "/path/to/pre" } + let(:ruby_ver) { "2.7.2" } + let(:fs_root) { "/path/to/fs_root" } + let(:fs_entrance) { "/path/to/fs_entrance" } + let(:cwd) { "/path/to/cwd" } + let(:deploy_helper) { instance_double(Tebako::DeployHelper) } + + before do + allow(Tebako::DeployHelper).to receive(:new).and_return(deploy_helper) + allow(deploy_helper).to receive(:configure) + allow(deploy_helper).to receive(:deploy) + allow(Tebako::Stripper).to receive(:strip) + end + + it "creates a new DeployHelper with the correct parameters" do + expect(Tebako::DeployHelper).to receive(:new) + .with(fs_root, fs_entrance, target_dir, pre_dir) + .and_return(deploy_helper) + Tebako::Packager.deploy(target_dir, pre_dir, ruby_ver, fs_root, fs_entrance, cwd) + end + + it "configures the DeployHelper with the correct parameters" do + expect(deploy_helper).to receive(:configure).with(ruby_ver, cwd) + Tebako::Packager.deploy(target_dir, pre_dir, ruby_ver, fs_root, fs_entrance, cwd) + end + + it "calls deploy on the DeployHelper" do + expect(deploy_helper).to receive(:deploy) + Tebako::Packager.deploy(target_dir, pre_dir, ruby_ver, fs_root, fs_entrance, cwd) + end + + it "calls strip on the Tebako::Stripper" do + expect(Tebako::Stripper).to receive(:strip).with(deploy_helper, target_dir) + Tebako::Packager.deploy(target_dir, pre_dir, ruby_ver, fs_root, fs_entrance, cwd) + end + end + + describe "#finalize" do + let(:os_type) { "linux" } + let(:src_dir) { "/path/to/src" } + let(:app_name) { "my_app" } + let(:ruby_ver) { "2.7.2" } + let(:patchelf) { "/usr/bin/patchelf" } + let(:ruby_builder) { instance_double(Tebako::RubyBuilder) } + + before do + allow(Tebako::RubyBuilder).to receive(:new).and_return(ruby_builder) + allow(ruby_builder).to receive(:final_build) + allow(Tebako::Packager::PatchHelpers).to receive(:exe_suffix).and_return("") + allow(Tebako::Packager).to receive(:patchelf) + allow(Tebako::Packager).to receive(:strip_or_copy) + end + + it "creates a new RubyBuilder with the correct parameters" do + expect(Tebako::RubyBuilder).to receive(:new).with(ruby_ver, src_dir).and_return(ruby_builder) + Tebako::Packager.finalize(os_type, src_dir, app_name, ruby_ver, patchelf) + end + + it "calls final_build on the RubyBuilder" do + expect(ruby_builder).to receive(:final_build) + Tebako::Packager.finalize(os_type, src_dir, app_name, ruby_ver, patchelf) + end + + it "calls patchelf with the correct parameters" do + src_name = File.join(src_dir, "ruby") + expect(Tebako::Packager).to receive(:patchelf).with(src_name, patchelf) + Tebako::Packager.finalize(os_type, src_dir, app_name, ruby_ver, patchelf) + end + + it "calls strip_or_copy with the correct parameters" do + src_name = File.join(src_dir, "ruby") + package_name = app_name.to_s + expect(Tebako::Packager).to receive(:strip_or_copy).with(os_type, src_name, package_name) + Tebako::Packager.finalize(os_type, src_dir, app_name, ruby_ver, patchelf) + end + end + + describe "#init" do + let(:stash_dir) { "/path/to/stash" } + let(:src_dir) { "/path/to/src" } + let(:pre_dir) { "/path/to/pre" } + let(:bin_dir) { "/path/to/bin" } + + before do + allow(Tebako::Packager::PatchHelpers).to receive(:recreate) + allow(FileUtils).to receive(:cp_r) + end + + it "recreates the stash directory" do + expect(Tebako::Packager::PatchHelpers).to receive(:recreate).with([src_dir, pre_dir, bin_dir]) + described_class.init(stash_dir, src_dir, pre_dir, bin_dir) + end + + it "copies the source directory to the stash directory" do + expect(FileUtils).to receive(:cp_r).with("#{stash_dir}/.", src_dir) + described_class.init(stash_dir, src_dir, pre_dir, bin_dir) + end + end + + describe "#mkdwarfs" do + let(:deps_bin_dir) { "/path/to/deps/bin" } + let(:data_bin_file) { "/path/to/output.dwarfs" } + let(:data_src_dir) { "/path/to/src" } + let(:descriptor) { "/path/to/descriptor" } + + before do + allow(Tebako::BuildHelpers).to receive(:run_with_capture_v) + end + + context "when descriptor is not provided" do + it "runs mkdwarfs with the correct parameters" do + params = [File.join(deps_bin_dir, "mkdwarfs"), "-o", data_bin_file, "-i", data_src_dir, "--no-progress"] + expect(Tebako::BuildHelpers).to receive(:run_with_capture_v).with(params) + described_class.mkdwarfs(deps_bin_dir, data_bin_file, data_src_dir) + end + end + + context "when descriptor is provided" do + it "runs mkdwarfs with the correct parameters including the descriptor" do + params = [File.join(deps_bin_dir, "mkdwarfs"), "-o", data_bin_file, "-i", data_src_dir, "--no-progress", + "--header", descriptor] + expect(Tebako::BuildHelpers).to receive(:run_with_capture_v).with(params) + described_class.mkdwarfs(deps_bin_dir, data_bin_file, data_src_dir, descriptor) + end + end + end + + describe "#pass1" do + let(:ostype) { "linux-gnu" } + let(:ruby_source_dir) { "/path/to/ruby_source" } + let(:mount_point) { "/__tebako_memfs__" } + let(:src_dir) { "/path/to/src" } + let(:ruby_ver) { "2.7.2" } + let(:patch_map) { { "file1" => "patch1", "file2" => "patch2" } } + + before do + allow(Tebako::Packager::PatchHelpers).to receive(:recreate) + allow(Tebako::Packager::Pass1).to receive(:get_patch_map).and_return(patch_map) + allow(Tebako::Packager).to receive(:do_patch) + allow(Tebako::Packager::PatchHelpers).to receive(:restore_and_save_files) + end + + it "recreates the src directory" do + expect(Tebako::Packager::PatchHelpers).to receive(:recreate).with(src_dir) + described_class.pass1(ostype, ruby_source_dir, mount_point, src_dir, ruby_ver) + end + + it "calls do_patch with the correct parameters" do + expect(Tebako::Packager).to receive(:do_patch).with(patch_map, ruby_source_dir) + described_class.pass1(ostype, ruby_source_dir, mount_point, src_dir, ruby_ver) + end + + it "restores and saves files for FILES_TO_RESTORE" do + expect(Tebako::Packager::PatchHelpers).to receive(:restore_and_save_files) + .with(Tebako::Packager::FILES_TO_RESTORE, ruby_source_dir) + described_class.pass1(ostype, ruby_source_dir, mount_point, src_dir, ruby_ver) + end + + context "when ostype is linux-musl" do + let(:ostype) { "linux-musl" } + + it "restores and saves files for FILES_TO_RESTORE_MUSL" do + expect(Tebako::Packager::PatchHelpers).to receive(:restore_and_save_files) + .with(Tebako::Packager::FILES_TO_RESTORE_MUSL, ruby_source_dir) + described_class.pass1(ostype, ruby_source_dir, mount_point, src_dir, ruby_ver) + end + end + + context "when ostype is msys" do + let(:ostype) { "msys" } + + it "restores and saves files for FILES_TO_RESTORE_MSYS" do + expect(Tebako::Packager::PatchHelpers).to receive(:restore_and_save_files) + .with(Tebako::Packager::FILES_TO_RESTORE_MSYS, ruby_source_dir) + described_class.pass1(ostype, ruby_source_dir, mount_point, src_dir, ruby_ver) + end + end + end + + describe "#pass1a" do + let(:ruby_source_dir) { "/path/to/ruby_source" } + let(:patch_map) { { "file1" => "patch1", "file2" => "patch2" } } + + before do + allow(Tebako::Packager::Pass1A).to receive(:get_patch_map).and_return(patch_map) + allow(Tebako::Packager).to receive(:do_patch) + end + + it "calls do_patch with the correct parameters" do + expect(Tebako::Packager).to receive(:do_patch).with(patch_map, ruby_source_dir) + described_class.pass1a(ruby_source_dir) + end + end + + describe "#pass2" do + let(:ostype) { "linux-gnu" } + let(:ruby_source_dir) { "/path/to/ruby_source" } + let(:deps_lib_dir) { "/path/to/deps/lib" } + let(:ruby_ver) { "2.7.2" } + let(:patch_map) { { "file1" => "patch1", "file2" => "patch2" } } + + before do + allow(Tebako::Packager::Pass2).to receive(:get_patch_map).and_return(patch_map) + allow(Tebako::Packager).to receive(:do_patch) + end + + it "calls do_patch with the correct parameters" do + expect(Tebako::Packager).to receive(:do_patch).with(patch_map, ruby_source_dir) + described_class.pass2(ostype, ruby_source_dir, deps_lib_dir, ruby_ver) + end + end + + describe "#stash" do + let(:stash_dir) { "/path/to/stash" } + let(:src_dir) { "/path/to/src" } + + before do + allow(Tebako::Packager::PatchHelpers).to receive(:recreate) + allow(FileUtils).to receive(:cp_r) + end + + it "recreates the source directory" do + expect(Tebako::Packager::PatchHelpers).to receive(:recreate).with(src_dir) + described_class.stash(stash_dir, src_dir) + end + + it "copies the stash directory to the source directory" do + expect(FileUtils).to receive(:cp_r).with("#{stash_dir}/.", src_dir) + described_class.stash(stash_dir, src_dir) + end + end + + describe "#do_patch" do + let(:patch_map) { { "file1.txt" => "mapping1", "file2.txt" => "mapping2" } } + let(:root) { "/path/to/root" } + + it "calls PatchHelpers.patch_file for each file in the patch_map" do + patch_map.each do |fname, mapping| + expect(Tebako::Packager::PatchHelpers).to receive(:patch_file).with("#{root}/#{fname}", mapping) + end + + Tebako::Packager.send(:do_patch, patch_map, root) + end + end + + describe "#patchelf" do + let(:src_name) { "binary" } + let(:patchelf) { "/usr/bin/patchelf" } + + context "when patchelf is nil" do + it "does not run patchelf" do + expect(Tebako::BuildHelpers).not_to receive(:run_with_capture) + Tebako::Packager.send(:patchelf, src_name, nil) + end + end + + context "when patchelf is provided" do + it "runs patchelf with the correct parameters" do + params = [patchelf, "--remove-needed-version", "libpthread.so.0", "GLIBC_PRIVATE", src_name] + expect(Tebako::BuildHelpers).to receive(:run_with_capture).with(params) + Tebako::Packager.send(:patchelf, src_name, patchelf) + end + end + end + + describe "#strip_or_copy" do + let(:os_type) { "linux" } + let(:src_name) { "binary" } + let(:package_name) { "package" } + + context "when running on MSys" do + before do + allow(Tebako::Packager::PatchHelpers).to receive(:msys?).with(os_type).and_return(true) + end + + it "copies the file" do + expect(FileUtils).to receive(:cp).with(src_name, package_name) + Tebako::Packager.send(:strip_or_copy, os_type, src_name, package_name) + end + end + + context "when not running on MSys" do + before do + allow(Tebako::Packager::PatchHelpers).to receive(:msys?).with(os_type).and_return(false) + end + + it "strips the file" do + expect(Tebako::Stripper).to receive(:strip_file).with(src_name, package_name) + Tebako::Packager.send(:strip_or_copy, os_type, src_name, package_name) + end + end + end +end + +# rubocop:enable Metrics/BlockLength diff --git a/spec/stripper_spec.rb b/spec/stripper_spec.rb new file mode 100644 index 00000000..0fb0eda2 --- /dev/null +++ b/spec/stripper_spec.rb @@ -0,0 +1,175 @@ +# frozen_string_literal: true + +# Copyright (c) 2024 [Ribose Inc](https://www.ribose.com). +# All rights reserved. +# This file is a part of tebako +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +require "spec_helper" +require "tebako/stripper" +require "fileutils" +require "open3" + +# rubocop:disable Metrics/BlockLength + +RSpec.describe Tebako::Stripper do + describe ".strip" do + let(:scm) { double("scm") } + let(:src_dir) { "/path/to/src" } + + before do + allow(described_class).to receive(:strip_bs) + allow(described_class).to receive(:strip_fi) + allow(described_class).to receive(:strip_li) + end + + it "calls strip_bs with the correct parameters" do + expect(described_class).to receive(:strip_bs).with(src_dir) + described_class.strip(scm, src_dir) + end + + it "calls strip_fi with the correct parameters" do + expect(described_class).to receive(:strip_fi).with(scm, src_dir) + described_class.strip(scm, src_dir) + end + + it "calls strip_li with the correct parameters" do + expect(described_class).to receive(:strip_li).with(scm, src_dir) + described_class.strip(scm, src_dir) + end + end + + describe ".strip_file" do + let(:file_in) { "/path/to/file_in" } + let(:file_out) { "/path/to/file_out" } + + context "when file_out is not provided" do + it "runs strip with the correct parameters" do + params = ["strip", "-S", file_in] + expect(Open3).to receive(:capture2e).with(*params).and_return(["", + instance_double(Process::Status, exitstatus: 0)]) + described_class.strip_file(file_in) + end + end + + context "when file_out is provided" do + it "runs strip with the correct parameters" do + params = ["strip", "-S", file_in, "-o", file_out] + expect(Open3).to receive(:capture2e).with(*params).and_return(["", + instance_double(Process::Status, exitstatus: 0)]) + described_class.strip_file(file_in, file_out) + end + end + + context "when strip command fails" do + it "prints a warning message" do + params = ["strip", "-S", file_in] + expect(Open3).to receive(:capture2e).with(*params).and_return(["error message", + instance_double(Process::Status, exitstatus: 1)]) + expect { described_class.strip_file(file_in) }.to output(/Warning: could not strip/).to_stdout + end + end + end + + describe ".get_files" do + let(:scm) { double("scm", exe_suffix: ".exe") } + + it "returns the correct list of files" do + expected_files = Tebako::Stripper::BIN_FILES.flat_map do |f| + [f, "#{f}#{Tebako::Stripper::CMD_SUFFIX}", "#{f}#{Tebako::Stripper::BAT_SUFFIX}"] + end + expected_files += ["ruby.exe", "rubyw.exe"] + + expect(described_class.send(:get_files, scm)).to eq(expected_files) + end + end + + describe ".strip_bs" do + let(:src_dir) { "/path/to/src" } + + it "removes the share directory" do + expect(FileUtils).to receive(:rm_rf) + .with([File.join(src_dir, "share"), File.join(src_dir, "include"), File.join(src_dir, "lib", "pkgconfig")]) + described_class.send(:strip_bs, src_dir) + end + end + + describe ".strip_fi" do + let(:scm) { double("scm", exe_suffix: ".exe") } + let(:src_dir) { "/path/to/src" } + let(:files) do + Tebako::Stripper::BIN_FILES.flat_map { |f| + ["#{src_dir}/bin/#{f}", "#{src_dir}/bin/#{f}.cmd", + "#{src_dir}/bin/#{f}.bat"] + } + ["#{src_dir}/bin/ruby.exe", "#{src_dir}/bin/rubyw.exe"] + end + + it "removes the correct files" do + expect(FileUtils).to receive(:rm).with(files, force: true) + described_class.send(:strip_fi, scm, src_dir) + end + end + + describe ".strip_li" do + let(:scm) { double("scm", msys?: false, macos?: false) } + let(:src_dir) { "/path/to/src" } + let(:file) { "/path/to/src/file.so" } + + before do + allow(Find).to receive(:find).and_yield(file) + allow(File).to receive(:directory?).and_return(false) + allow(File).to receive(:extname).and_return(".so") + end + + it "strips the correct files" do + expect(described_class).to receive(:strip_file).with(file) + described_class.send(:strip_li, scm, src_dir) + end + + it "removes files with DELETE_EXTENSIONS" do + allow(File).to receive(:extname).and_return(".o") + expect(FileUtils).to receive(:rm).with(file) + described_class.send(:strip_li, scm, src_dir) + end + end + + describe ".strip_extensions" do + let(:scm) { double("scm", msys?: false, macos?: false) } + + it "returns the correct extensions for non-msys and non-macos" do + expect(described_class.send(:strip_extensions, scm)).to eq(["so"]) + end + + it "returns the correct extensions for msys" do + allow(scm).to receive(:msys?).and_return(true) + expect(described_class.send(:strip_extensions, scm)).to eq(%w[so dll]) + end + + it "returns the correct extensions for macos" do + allow(scm).to receive(:macos?).and_return(true) + expect(described_class.send(:strip_extensions, scm)).to eq(%w[so dylib bundle]) + end + end +end + +# rubocop:enable Metrics/BlockLength diff --git a/tests/scripts/functional-tests-app.sh b/tests/scripts/functional-tests-app.sh new file mode 100755 index 00000000..b73cc49f --- /dev/null +++ b/tests/scripts/functional-tests-app.sh @@ -0,0 +1,275 @@ +#! /bin/bash +# +# Copyright (c) 2021-2024, [Ribose Inc](https://www.ribose.com). +# All rights reserved. +# This file is a part of tebako +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +# ...................................................................... +# Helper functions +press_runner() { +# Runs 'tabako press' +# Parameters: +# $1 -- project root +# $2 -- entry point +# $3 -- tebako package name + if [ "${VERBOSE}" == "yes" ]; then + "$DIR_BIN"/tebako press -D -R "$RUBY_VER" --root="$1" --entry-point="$2" --output="$3" --mode application 2>&1 | tee tebako_test.log + assertEquals 0 "${PIPESTATUS[0]}" + result="$( cat tebako_test.log )" + else + result=$( "$DIR_BIN"/tebako press -D -R "$RUBY_VER" --root="$1" --entry-point="$2" --output="$3" --mode application 2>&1 ) + assertEquals 0 $? + fi + +# Check the first and the last messages expected from CMake script + assertContains "$result" "Running tebako press" + assertContains "$result" "Created tebako package at" +} + +package_runner() { +# Runs a package built by tebako +# Parameters: +# $1 -- runtime name +# $2 -- application name +# $3 -- expected output + if [ "${VERBOSE}" == "yes" ]; then + "$1" --tebako-run "$2" | tee tebako_test.log + assertEquals 0 "${PIPESTATUS[0]}" + result="$( cat tebako_test.log )" + else + result=$( "$1" --tebako-run "$2" ) + assertEquals 0 $? + fi + + assertContains "$result" "$3" +} + +press_runner_with_error() { +# Runs 'tabako press' expecting failure +# Parameters: +# $1 -- project root +# $2 -- entry point +# $3 -- tebako package name +# $4 -- expected error code +# $5 -- expected error message + if [ "${VERBOSE}" == "yes" ]; then + "$DIR_BIN"/tebako press -D -R "$RUBY_VER" --root="$1" --entry-point="$2" --output="$3" --mode application 2>&1 | tee tebako_test.log + assertEquals "$4" "${PIPESTATUS[0]}" + result="$( cat tebako_test.log )" + else + result=$( "$DIR_BIN"/tebako press -D -R "$RUBY_VER" --root="$1" --entry-point="$2" --output="$3" --mode application 2>&1 ) + assertEquals "$4" "${PIPESTATUS[0]}" + fi + + assertContains "$result" "$5" +} + +# ...................................................................... +# Tests +# AU. Build runtime (--mode runtime) +# 01. Simple Ruby script, absolute path to root, relative path to entry point +# 02. Simple Ruby script, absolute path to root, relative path to entry point, entry point does not exist [Expected error at build step] +# 03. Simple Ruby script, absolute path to root, absolute path to entry point +# 04. Simple Ruby script, relative path to root, relative path to entry point +# 05. Simple Ruby script, absolute path to root absolute path to entry point, entry point not within root [Expected error at configure step] +# 09. Ruby gem (xxx.gem, no gemspec, no gemfile) +# 10. Ruby gem (xxx.gem, no gemspec, no gemfile), entry point does not exist [Expected error at build step] +# 11. Ruby gem (no gemfile, with gemspec) +# 12. Ruby gem (no gemfile, with gemspec), multiple gemspecs --- moved to RSpec tests [Expected error at configure step] +# 13. Ruby gem (no gemfile, with gemspec), gemspec error [Expected error at build step] +# 14. Ruby gem (no gemfile, with gemspec), project root does not exist [Expected error at build step] +# 15. Ruby gem (with gemspec, with gemfile) +# 16. Ruby gem (with gemspec, with gemfile), gemfile with error [Expected error at build step] +# 17. Ruby gem (with gemspec, with gemfile), entry point does not exist [Expected error at build step] +# 18. Ruby project (no gemspec, with gemfile) +# 19. Ruby project (no gemspec, with gemfile, with native extension) +# 20. Net/http Ruby script [sits here and not on tests-2 in order to allow cross test MacOS x86_64 --> MacOS arm64] + + +# ...................................................................... +# AU. Build runtime (--mode runtime) +test_AU_runtime() { + echo "==> Build tebako runtime" + result=$( "$DIR_BIN"/tebako press -D -R "$RUBY_VER" --root=tests/test-01 --entry=tebako-test-run.rb --output=tebako-runtime --mode runtime 2>&1 ) + + assertEquals 0 "${PIPESTATUS[0]}" + assertContains "$result" "Running tebako press script" + assertContains "$result" "Created tebako package at" +} + +# ...................................................................... +# 01. Simple Ruby script, absolute path to root, relative path to entry point +test_tebako_press_01() { + echo "==> simple Ruby script, absolute path to root, relative path to entry point" + press_runner "${DIR_TESTS}/test-01" "tebako-test-run.rb" "test-01-package" + package_runner "./tebako-runtime" "test-01-package.tebako" "Hello! This is test-01 talking from inside DwarFS" +} + +# ...................................................................... +# 02. Simple Ruby script, absolute path to root, relative path to entry point, entry point does not exist +test_tebako_press_02() { + echo "==> simple Ruby script, absolute path to root, relative path to entry point, entry point does not exist" + press_runner_with_error "${DIR_TESTS}/test-01" \ + "test-does-not-exist.rb" \ + "test-02-package" \ + 106 "Tebako script failed" +} + +# ...................................................................... +# 03. Simple Ruby script, absolute path to root, absolute path to entry point +test_tebako_press_03() { + echo "==> simple Ruby script, absolute path to root, absolute path to entry point" + press_runner "${DIR_TESTS}/test-01" "${DIR_TESTS}/test-01/tebako-test-run.rb" "test-03-package" + package_runner "./tebako-runtime" "test-03-package.tebako" "Hello! This is test-01 talking from inside DwarFS" +} + +# ...................................................................... +# 04. Simple Ruby script, relative path to root, relative path to entry point +test_tebako_press_04() { + echo "==> simple Ruby script, relative path to root, relative path to entry point" + pushd "${DIR_ROOT}" > /dev/null || fail "pushd ${DIR_ROOT} failed" + press_runner "tests/test-01" "tebako-test-run.rb" "test-04-package" + package_runner "${DIR_ROOT}/tebako-runtime" "test-04-package.tebako" "Hello! This is test-01 talking from inside DwarFS" + popd > /dev/null || fail "popd failed" +} + +# ...................................................................... +# 05. Simple Ruby script, absolute path to root absolute path to entry point, entry point not within root +test_tebako_press_05() { + echo "==> simple Ruby script, absolute path to root absolute path to entry point, not within root" + press_runner_with_error "${DIR_TESTS}/test-01" \ + "${DIR_TESTS}/test-00/test.rb" "test-05-package" \ + 114 "Tebako script failed: Entry point is not within the project root" +} + +# ...................................................................... +# 09. Ruby gem (xxx.gem, no gemspec, no gemfile) +test_tebako_press_09() { + echo "==> Ruby gem (xxx.gem, no gemspec, no gemfile)" + press_runner "${DIR_TESTS}/test-09" "tebako-test-run.rb" "test-09-package" + package_runner "./tebako-runtime" "test-09-package.tebako" "| a1 | b1 |" +} + +# ...................................................................... +# 10. Ruby gem (xxx.gem, no gemspec, no gemfile), entry point does not exist +test_tebako_press_10() { + echo "==> Ruby gem (xxx.gem, no gemspec, no gemfile), entry point does not exist" + press_runner_with_error "${DIR_TESTS}/test-09" \ + "test-does-not-exist.rb" \ + "test-10-package" \ + 106 "Tebako script failed" +} + +# ...................................................................... +# 11. Ruby gem (no gemfile, with gemspec) +test_tebako_press_11() { + echo "==> Ruby gem (no gemfile, with gemspec)" + press_runner "${DIR_TESTS}/test-11" "tebako-test-run.rb" "test-11-package" + package_runner "./tebako-runtime" "test-11-package.tebako" "| a1 | b1 |" +} + +# ...................................................................... +# 13. Ruby gem (no gemfile, with gemspec), gemspec error +test_tebako_press_13() { + echo "==> Ruby gem (no gemfile, with gemspec), gemspec error" + press_runner_with_error "${DIR_TESTS}/test-13" \ + "tebako-test-run.rb" \ + "test-13-package" \ + 255 "Tebako script failed" +} + +# ...................................................................... +# 14. Ruby gem (no gemfile, with gemspec), project root does not exist +test_tebako_press_14() { + echo "==> Ruby gem (no gemfile, with gemspec), project root does not exist" + press_runner_with_error "${DIR_TESTS}/test-14" \ + "test-does-not-exist.rb" \ + "test-14-package" \ + 107 "Tebako script failed: Project root does not exist or is not accessible" +} + +# ...................................................................... +# 15. Ruby gem (with gemspec, with gemfile) +test_tebako_press_15() { + echo "==> Ruby gem (with gemspec, with gemfile)" + press_runner "${DIR_TESTS}/test-15" "tebako-test-run.rb" "test-15-package" + package_runner "./tebako-runtime" "test-15-package.tebako" "| a1 | b1 |" +} + +# ...................................................................... +# 16. Ruby gem (with gemspec, with gemfile), gemfile with error +test_tebako_press_16() { + echo "==> Ruby gem (with gemspec, with gemfile), gemfile with error" + press_runner_with_error "${DIR_TESTS}/test-16" \ + "tebako-test-run.rb" \ + "test-16-package" \ + 255 "Tebako script failed" +} + +# ...................................................................... +# 17. Ruby gem (with gemspec, with gemfile), entry point dows not exist +test_tebako_press_17() { + echo "==> Ruby gem (with gemspec, with gemfile), entry point does not exist" + press_runner_with_error "${DIR_TESTS}/test-15" \ + "test-does-not-exist.rb" \ + "test-17-package" \ + 106 "Tebako script failed" +} + +# ...................................................................... +# 18. Ruby project (no gemspec, with gemfile) +test_tebako_press_18() { + echo "==> Ruby project (no gemspec, with gemfile)" + press_runner "${DIR_TESTS}/test-18" "tebako-test-run.rb" "test-18-package" + package_runner "./tebako-runtime" "test-18-package.tebako" "| a1 | b1 |" +} + +# ...................................................................... +# 19. Ruby project (no gemspec, with gemfile, with native extension) +test_tebako_press_19() { + echo "==> Ruby project (no gemspec, with gemfile, with native extension)" + press_runner "${DIR_TESTS}/test-19" "tebako-test-run.rb" "test-19-package" + package_runner "./tebako-runtime" "test-19-package.tebako" "Hello, World via libc puts using FFI on tebako package" +} + +# ...................................................................... +# 20. Net/http Ruby script +test_tebako_press_20() { + echo "==> Net/http Ruby script" + press_runner "${DIR_TESTS}/test-20" "tebako-test-run.rb" "test-20-package" + package_runner "./tebako-runtime" "test-20-package.tebako" "Response: 302 Found" +} + +# ...................................................................... +# main + +DIR0=$( dirname "$0" ) +DIR_ROOT=$( cd "$DIR0"/../.. && pwd ) +DIR_BIN=$( cd "$DIR_ROOT"/exe && pwd ) +DIR_TESTS=$( cd "$DIR_ROOT"/tests && pwd ) +RUBY_VER=${RUBY_VER:-3.2.5} + +echo "Running tebako tests for Ruby $RUBY_VER" +# shellcheck source=/dev/null +. "$DIR_TESTS/shunit2/shunit2" diff --git a/tests/scripts/functional-tests.sh b/tests/scripts/functional-tests.sh index d1284d1d..2a51007e 100755 --- a/tests/scripts/functional-tests.sh +++ b/tests/scripts/functional-tests.sh @@ -81,7 +81,6 @@ press_runner_with_error() { assertEquals "$4" "${PIPESTATUS[0]}" fi - assertContains "$result" "Running tebako press at" assertContains "$result" "$5" } @@ -289,7 +288,7 @@ test_tebako_press_19() { } # ...................................................................... -# 20. 20. Net/http Ruby script +# 20. Net/http Ruby script test_tebako_press_20() { echo "==> Net/http Ruby script" press_runner "${DIR_TESTS}/test-20" "tebako-test-run.rb" "test-20-package"