Browse Source

meson: add tests (#1044)

This integrates the "main" test suite (test/test.cc) in Meson.

This allows to run the tests in the CI with the Meson-built version of
the library to ensure that nothing breaks unexpectedly.

It also simplifies life of downstream packagers, that do not have to
write a custom build script to split the library and run tests but can
instead just let Meson do that for them.
Andrea Pappacoda 4 years ago
parent
commit
e3e28c6231

+ 52 - 0
.github/workflows/test.yaml

@@ -39,3 +39,55 @@ jobs:
         cd test
         msbuild.exe test.sln /verbosity:minimal /t:Build "/p:Configuration=Release;Platform=x64"
         x64\Release\test.exe
+
+
+  meson-build:
+    runs-on: ${{ matrix.os }}
+
+    strategy:
+      matrix:
+        os: [macos-latest, ubuntu-latest, windows-latest]
+
+    steps:
+    - name: Prepare Git for checkout on Windows
+      if: matrix.os == 'windows-latest'
+      run: |
+        git config --global core.autocrlf false
+        git config --global core.eol lf
+
+    - uses: actions/checkout@v2
+
+    - name: Install dependencies on Linux
+      if: matrix.os == 'ubuntu-latest'
+      run: sudo apt-get -qq update && sudo apt-get -qq install meson libssl-dev zlib1g-dev libbrotli-dev libgtest-dev
+
+    - name: Install dependencies on MacOS
+      if: matrix.os == 'macos-latest'
+      run: brew install meson openssl brotli googletest
+
+    - name: Setup MSVC on Windows
+      if: matrix.os == 'windows-latest'
+      uses: ilammy/msvc-dev-cmd@v1
+
+    # It is necessary to remove MinGW and StrawberryPerl as they both provide
+    # GCC. This causes issues because CMake prefers to use MSVC, while Meson
+    # uses GCC, if found, causing linking errors.
+    - name: Install dependencies on Windows
+      if: matrix.os == 'windows-latest'
+      run: |
+        choco uninstall mingw strawberryperl --yes --all-versions --remove-dependencies --skip-autouninstaller --no-color
+        Remove-Item -Path C:\Strawberry -Recurse
+        choco install pkgconfiglite --yes --skip-virus-check --no-color
+        pip install meson ninja
+        Invoke-WebRequest -Uri https://github.com/google/googletest/archive/refs/heads/master.zip -OutFile googletest-master.zip
+        Expand-Archive -Path googletest-master.zip
+        cd googletest-master\googletest-master
+        cmake -S . -B build -DINSTALL_GTEST=ON -DBUILD_GMOCK=OFF -Dgtest_hide_internal_symbols=ON -DCMAKE_INSTALL_PREFIX=C:/googletest
+        cmake --build build --config=Release
+        cmake --install build --config=Release
+        cd ..\..
+
+    - name: Build and test
+      run: |
+        meson setup build -Dcpp-httplib_test=true -Dpkg_config_path=C:\googletest\lib\pkgconfig -Db_vscrt=static_from_buildtype
+        meson test --no-stdsplit --print-errorlogs -C build

+ 6 - 1
meson.build

@@ -7,6 +7,7 @@ project(
   'cpp',
   license: 'MIT',
   default_options: [
+    'cpp_std=c++11',
     'buildtype=release',
     'b_ndebug=if-release',
     'b_lto=true',
@@ -71,7 +72,7 @@ if brotli_found_all
   args += '-DCPPHTTPLIB_BROTLI_SUPPORT'
 endif
 
-cpp_httplib_dep = dependency('', required : false)
+cpp_httplib_dep = dependency('', required: false)
 
 if get_option('cpp-httplib_compile')
   httplib_ch = custom_target(
@@ -106,3 +107,7 @@ endif
 if meson.version().version_compare('>=0.54.0')
   meson.override_dependency('cpp-httplib', cpp_httplib_dep)
 endif
+
+if get_option('cpp-httplib_test')
+  subdir('test')
+endif

+ 5 - 4
meson_options.txt

@@ -2,7 +2,8 @@
 #
 # SPDX-License-Identifier: MIT
 
-option('cpp-httplib_openssl',    type: 'feature', value: 'auto', description: 'Enable OpenSSL support')
-option('cpp-httplib_zlib',       type: 'feature', value: 'auto', description: 'Enable zlib support')
-option('cpp-httplib_brotli',     type: 'feature', value: 'auto', description: 'Enable Brotli support')
-option('cpp-httplib_compile',    type: 'boolean', value: false,  description: 'Split the header into a compilable header & source file (requires Python 3)')
+option('cpp-httplib_openssl', type: 'feature', value: 'auto', description: 'Enable OpenSSL support')
+option('cpp-httplib_zlib',    type: 'feature', value: 'auto', description: 'Enable zlib support')
+option('cpp-httplib_brotli',  type: 'feature', value: 'auto', description: 'Enable Brotli support')
+option('cpp-httplib_compile', type: 'boolean', value: false,  description: 'Split the header into a compilable header & source file (requires Python 3)')
+option('cpp-httplib_test',    type: 'boolean', value: false,  description: 'Build tests')

+ 97 - 0
test/meson.build

@@ -0,0 +1,97 @@
+# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
+#
+# SPDX-License-Identifier: MIT
+
+gtest_dep = dependency('gtest', main: true)
+openssl = find_program('openssl')
+test_conf = files('test.conf')
+
+key_pem = custom_target(
+  'key_pem',
+  output: 'key.pem',
+  command: [openssl, 'genrsa', '-out', '@OUTPUT@', '2048']
+)
+
+temp_req = custom_target(
+  'temp_req',
+  input: key_pem,
+  output: 'temp_req',
+  command: [openssl, 'req', '-new', '-batch', '-config', test_conf, '-key', '@INPUT@', '-out', '@OUTPUT@']
+)
+
+cert_pem = custom_target(
+  'cert_pem',
+  input: [temp_req, key_pem],
+  output: 'cert.pem',
+  command: [openssl, 'x509', '-in', '@INPUT0@', '-days', '3650', '-req', '-signkey', '@INPUT1@', '-out', '@OUTPUT@']
+)
+
+cert2_pem = custom_target(
+  'cert2_pem',
+  input: key_pem,
+  output: 'cert2.pem',
+  command: [openssl, 'req', '-x509', '-config', test_conf, '-key', '@INPUT@', '-sha256', '-days', '3650', '-nodes', '-out', '@OUTPUT@', '-extensions', 'SAN']
+)
+
+rootca_key_pem = custom_target(
+  'rootca_key_pem',
+  output: 'rootCA.key.pem',
+  command: [openssl, 'genrsa', '-out', '@OUTPUT@', '2048']
+)
+
+rootca_cert_pem = custom_target(
+  'rootca_cert_pem',
+  input: rootca_key_pem,
+  output: 'rootCA.cert.pem',
+  command: [openssl, 'req', '-x509', '-new', '-batch', '-config', files('test.rootCA.conf'), '-key', '@INPUT@', '-days', '1024', '-out', '@OUTPUT@']
+)
+
+client_key_pem = custom_target(
+  'client_key_pem',
+  output: 'client.key.pem',
+  command: [openssl, 'genrsa', '-out', '@OUTPUT@', '2048']
+)
+
+client_temp_req = custom_target(
+  'client_temp_req',
+  input: client_key_pem,
+  output: 'client_temp_req',
+  command: [openssl, 'req', '-new', '-batch', '-config', test_conf, '-key', '@INPUT@', '-out', '@OUTPUT@']
+)
+
+client_cert_pem = custom_target(
+  'client_cert_pem',
+  input: [client_temp_req, rootca_cert_pem, rootca_key_pem],
+  output: 'client.cert.pem',
+  command: [openssl, 'x509', '-in', '@INPUT0@', '-days', '370', '-req', '-CA', '@INPUT1@', '-CAkey', '@INPUT2@', '-CAcreateserial', '-out', '@OUTPUT@']
+)
+
+# Copy test files to the build directory
+configure_file(input: 'ca-bundle.crt', output: 'ca-bundle.crt', copy: true)
+configure_file(input: 'image.jpg',     output: 'image.jpg',     copy: true)
+subdir(join_paths('www', 'dir'))
+subdir(join_paths('www2', 'dir'))
+subdir(join_paths('www3', 'dir'))
+
+test(
+  'main',
+  executable(
+    'main',
+    'test.cc',
+    dependencies: [
+      cpp_httplib_dep,
+      gtest_dep
+    ]
+  ),
+  depends: [
+    key_pem,
+    cert_pem,
+    cert2_pem,
+    rootca_key_pem,
+    rootca_cert_pem,
+    client_key_pem,
+    client_cert_pem
+  ],
+  workdir: meson.current_build_dir(),
+  timeout: 300
+)

+ 7 - 0
test/www/dir/meson.build

@@ -0,0 +1,7 @@
+# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
+#
+# SPDX-License-Identifier: MIT
+
+configure_file(input: 'index.html', output: 'index.html', copy: true)
+configure_file(input: 'test.abcde', output: 'test.abcde', copy: true)
+configure_file(input: 'test.html',  output: 'test.html',  copy: true)

+ 6 - 0
test/www2/dir/meson.build

@@ -0,0 +1,6 @@
+# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
+#
+# SPDX-License-Identifier: MIT
+
+configure_file(input: 'index.html', output: 'index.html', copy: true)
+configure_file(input: 'test.html',  output: 'test.html',  copy: true)

+ 6 - 0
test/www3/dir/meson.build

@@ -0,0 +1,6 @@
+# SPDX-FileCopyrightText: 2021 Andrea Pappacoda
+#
+# SPDX-License-Identifier: MIT
+
+configure_file(input: 'index.html', output: 'index.html', copy: true)
+configure_file(input: 'test.html',  output: 'test.html',  copy: true)