diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aae35bd0..8f7d7708 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,8 @@ name: CI +env: + NODE_VERSION: 18.x + on: push: # Prevent duplicate runs of this workflow on our own internal PRs. @@ -23,23 +26,47 @@ jobs: fetch-depth: 0 - name: Check Bundles shell: bash - run: | - echo "Checking that all bundled tools are up to date..." - dirty_workspaces=() - for input_workspace in `find src -type d -mindepth 1 -maxdepth 1 -not -name node_modules` ; do - output_workspace=$(echo $input_workspace | sed -e 's/^src/pkgs/') - input_mtime=$(git log -1 --format=%ct $input_workspace) - output_mtime=$(git log -1 --format=%ct $output_workspace) - if [[ $input_mtime -gt $output_mtime ]] ; then - echo "❌ $input_workspace has changed since $output_workspace was last generated" - dirty_workspaces+=($input_workspace) - fi - done - if [[ ${#dirty_workspaces[@]} -gt 0 ]] ; then - echo - echo '💡 Re-run `npm run bundle` on the following workspaces before committing:' - for workspace in ${dirty_workspaces[*]} ; do - echo " • $workspace" - done - exit 1 - fi + run: ./test/lint/check-bundles.sh + + integration: + name: Integration Tests + needs: [bundles] + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Install Dependencies + shell: bash + run: npm ci --verbose + - name: Build + uses: neon-actions/build@v0.3.4 + with: + working-directory: ./pkgs/cargo-messages + target: linux-x64-gnu + node-version: ${{ env.NODE_VERSION }} + use-cross: false + npm-publish: false + github-release: false + - name: Start npm Proxy + shell: bash + working-directory: ./test/integration/proxy + timeout-minutes: 3 + run: ./ci-proxy.sh + - name: Publish to npm Proxy + shell: bash + working-directory: ./test/integration/proxy + timeout-minutes: 3 + run: ./publish.sh + # Since package integrity checksums may vary depending on what versions + # are available in the proxy registry, we don't put the lockfile for this + # test in source control. This means we have to use `npm i`, not `npm ci`. + - name: Setup test-sniff-bytes Integration Test + shell: bash + working-directory: test/integration/test-sniff-bytes + run: npm i || (cat ../proxy/proxy.log && exit 1) + - name: Run test-sniff-bytes Integration Test + shell: bash + working-directory: test/integration/test-sniff-bytes + run: npm test diff --git a/Cargo.toml b/Cargo.toml index cbfa65a9..e72b51aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,3 +2,6 @@ members = [ "pkgs/cargo-messages" ] +exclude = [ + "test/integration/sniff-bytes" +] diff --git a/pkgs/package-lock.json b/pkgs/package-lock.json index bc712e4f..95a2cd9a 100644 --- a/pkgs/package-lock.json +++ b/pkgs/package-lock.json @@ -21,13 +21,6 @@ "version": "0.0.165", "license": "MIT", "dependencies": { - "@cargo-messages/android-arm-eabi": "0.0.165", - "@cargo-messages/darwin-arm64": "0.0.165", - "@cargo-messages/darwin-x64": "0.0.165", - "@cargo-messages/linux-arm-gnueabihf": "0.0.165", - "@cargo-messages/linux-x64-gnu": "0.0.165", - "@cargo-messages/win32-arm64-msvc": "0.0.165", - "@cargo-messages/win32-x64-msvc": "0.0.165", "@neon-rs/load": "^0.0.158" }, "devDependencies": { @@ -43,90 +36,6 @@ "@cargo-messages/win32-x64-msvc": "0.0.165" } }, - "cargo-messages/node_modules/@cargo-messages/android-arm-eabi": { - "version": "0.0.165", - "resolved": "https://registry.npmjs.org/@cargo-messages/android-arm-eabi/-/android-arm-eabi-0.0.165.tgz", - "integrity": "sha512-J8jnzObmdSOurNrhtN+9atKoEQHJBHmFpORJoFlus2RggPPqilAJsL4a073qlpLCnNbcAps23Ccayuj11uHlkg==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ] - }, - "cargo-messages/node_modules/@cargo-messages/darwin-arm64": { - "version": "0.0.165", - "resolved": "https://registry.npmjs.org/@cargo-messages/darwin-arm64/-/darwin-arm64-0.0.165.tgz", - "integrity": "sha512-KwP7NryO8KRGuSmoE/PaB/1M1W3iKUKZ3PQSNNfF9G/qUpqHLZH41eLSZx1FvD1q8Kvpv5ysY3Obwd8cTDDJ1A==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "cargo-messages/node_modules/@cargo-messages/darwin-x64": { - "version": "0.0.165", - "resolved": "https://registry.npmjs.org/@cargo-messages/darwin-x64/-/darwin-x64-0.0.165.tgz", - "integrity": "sha512-reudoNbbnVqUSWb5lLqdOExYRkY7tdEopgp/ut9PgkOTkAzEoc36u2G+6GLm42uIU6CFzvzUvC5Vl4bSMLQ95A==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "cargo-messages/node_modules/@cargo-messages/linux-arm-gnueabihf": { - "version": "0.0.165", - "resolved": "https://registry.npmjs.org/@cargo-messages/linux-arm-gnueabihf/-/linux-arm-gnueabihf-0.0.165.tgz", - "integrity": "sha512-GVbdZQ8rwQF7kxTGasiW5N86fJKHaHuSKBJj/9GJj8OacRwpfdSYKdkTBu3AbNQfrqUQIGbzsjiiLed1gYtiSA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "cargo-messages/node_modules/@cargo-messages/linux-x64-gnu": { - "version": "0.0.165", - "resolved": "https://registry.npmjs.org/@cargo-messages/linux-x64-gnu/-/linux-x64-gnu-0.0.165.tgz", - "integrity": "sha512-CwbNW3ijMItDaKeX2SHag9G0uCmRDcTajh+fR01I5rNA49KNf0TrK92qWmOoj1Uql5RYe9uDfoYQRHwxfantrA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "cargo-messages/node_modules/@cargo-messages/win32-arm64-msvc": { - "version": "0.0.165", - "resolved": "https://registry.npmjs.org/@cargo-messages/win32-arm64-msvc/-/win32-arm64-msvc-0.0.165.tgz", - "integrity": "sha512-YjBCi0aS+ZVig4oVfs3VEefaY2RIK6KDMdF3ma0ccRxaAsebzOr7hTGwKC9qmGKZ2+B9RfK6m5bRn7W/uIhaWw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ] - }, - "cargo-messages/node_modules/@cargo-messages/win32-x64-msvc": { - "version": "0.0.165", - "resolved": "https://registry.npmjs.org/@cargo-messages/win32-x64-msvc/-/win32-x64-msvc-0.0.165.tgz", - "integrity": "sha512-8aLHAdVWQdfFVMsQMIQHJHlFWmtLehYN/71xQo3x17NIY3eJjf+VejNLluKujRykjVx2/klc1KO2Jj1vzycifA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] - }, "cargo-messages/node_modules/@neon-rs/cli": { "version": "0.0.158", "resolved": "https://registry.npmjs.org/@neon-rs/cli/-/cli-0.0.158.tgz", @@ -249,13 +158,13 @@ "neon": "index.js" }, "optionalDependencies": { - "@cargo-messages/android-arm-eabi": "0.0.164", - "@cargo-messages/darwin-arm64": "0.0.164", - "@cargo-messages/darwin-x64": "0.0.164", - "@cargo-messages/linux-arm-gnueabihf": "0.0.164", - "@cargo-messages/linux-x64-gnu": "0.0.164", - "@cargo-messages/win32-arm64-msvc": "0.0.164", - "@cargo-messages/win32-x64-msvc": "0.0.164" + "@cargo-messages/android-arm-eabi": "0.0.165", + "@cargo-messages/darwin-arm64": "0.0.165", + "@cargo-messages/darwin-x64": "0.0.165", + "@cargo-messages/linux-arm-gnueabihf": "0.0.165", + "@cargo-messages/linux-x64-gnu": "0.0.165", + "@cargo-messages/win32-arm64-msvc": "0.0.165", + "@cargo-messages/win32-x64-msvc": "0.0.165" } }, "install": { @@ -272,9 +181,9 @@ } }, "node_modules/@cargo-messages/android-arm-eabi": { - "version": "0.0.164", - "resolved": "https://registry.npmjs.org/@cargo-messages/android-arm-eabi/-/android-arm-eabi-0.0.164.tgz", - "integrity": "sha512-9MvvRILu3lfrSyrxmcirjmtYTfM87j6TnJexMRPD8GxlTvqg0HaVr1GdwJTullPQICbJmn5UWrKplYEsevHGcg==", + "version": "0.0.165", + "resolved": "https://registry.npmjs.org/@cargo-messages/android-arm-eabi/-/android-arm-eabi-0.0.165.tgz", + "integrity": "sha512-J8jnzObmdSOurNrhtN+9atKoEQHJBHmFpORJoFlus2RggPPqilAJsL4a073qlpLCnNbcAps23Ccayuj11uHlkg==", "cpu": [ "arm" ], @@ -284,9 +193,9 @@ ] }, "node_modules/@cargo-messages/darwin-arm64": { - "version": "0.0.164", - "resolved": "https://registry.npmjs.org/@cargo-messages/darwin-arm64/-/darwin-arm64-0.0.164.tgz", - "integrity": "sha512-tMWPPsDW62fi7t31Pg2QDUEQOmPK/9ehPzV0FVEsLjsyqLDQpzogNvhYIE11t7jouE4ivUTdDca5Z7DFsSeWWg==", + "version": "0.0.165", + "resolved": "https://registry.npmjs.org/@cargo-messages/darwin-arm64/-/darwin-arm64-0.0.165.tgz", + "integrity": "sha512-KwP7NryO8KRGuSmoE/PaB/1M1W3iKUKZ3PQSNNfF9G/qUpqHLZH41eLSZx1FvD1q8Kvpv5ysY3Obwd8cTDDJ1A==", "cpu": [ "arm64" ], @@ -296,9 +205,9 @@ ] }, "node_modules/@cargo-messages/darwin-x64": { - "version": "0.0.164", - "resolved": "https://registry.npmjs.org/@cargo-messages/darwin-x64/-/darwin-x64-0.0.164.tgz", - "integrity": "sha512-rMWGGQUF+GqfJ4IZqkSqT46kjs2WROLj07nz8tJrJ5nwvtVWWDdc1761zAM+UD87pQfH+l1FlFeUAvjmD7FP8A==", + "version": "0.0.165", + "resolved": "https://registry.npmjs.org/@cargo-messages/darwin-x64/-/darwin-x64-0.0.165.tgz", + "integrity": "sha512-reudoNbbnVqUSWb5lLqdOExYRkY7tdEopgp/ut9PgkOTkAzEoc36u2G+6GLm42uIU6CFzvzUvC5Vl4bSMLQ95A==", "cpu": [ "x64" ], @@ -308,9 +217,9 @@ ] }, "node_modules/@cargo-messages/linux-arm-gnueabihf": { - "version": "0.0.164", - "resolved": "https://registry.npmjs.org/@cargo-messages/linux-arm-gnueabihf/-/linux-arm-gnueabihf-0.0.164.tgz", - "integrity": "sha512-rsEXv2fxSHs3Q/XiDb3zWU+9NMqhssaNARCusuVT+9zoG9/NPynB+jOk312kqQNVo74i+fEFLGtn+gIebow9gQ==", + "version": "0.0.165", + "resolved": "https://registry.npmjs.org/@cargo-messages/linux-arm-gnueabihf/-/linux-arm-gnueabihf-0.0.165.tgz", + "integrity": "sha512-GVbdZQ8rwQF7kxTGasiW5N86fJKHaHuSKBJj/9GJj8OacRwpfdSYKdkTBu3AbNQfrqUQIGbzsjiiLed1gYtiSA==", "cpu": [ "arm" ], @@ -320,9 +229,9 @@ ] }, "node_modules/@cargo-messages/linux-x64-gnu": { - "version": "0.0.164", - "resolved": "https://registry.npmjs.org/@cargo-messages/linux-x64-gnu/-/linux-x64-gnu-0.0.164.tgz", - "integrity": "sha512-nw2tQ8eiXnsqeH+DbaGpWECM2OKBEng6OInnaZYUzVpdNTk4mSJFcqoGIjL/Jl9h+XiCX4D3ek3pP5nWAqZ8yA==", + "version": "0.0.165", + "resolved": "https://registry.npmjs.org/@cargo-messages/linux-x64-gnu/-/linux-x64-gnu-0.0.165.tgz", + "integrity": "sha512-CwbNW3ijMItDaKeX2SHag9G0uCmRDcTajh+fR01I5rNA49KNf0TrK92qWmOoj1Uql5RYe9uDfoYQRHwxfantrA==", "cpu": [ "x64" ], @@ -332,9 +241,9 @@ ] }, "node_modules/@cargo-messages/win32-arm64-msvc": { - "version": "0.0.164", - "resolved": "https://registry.npmjs.org/@cargo-messages/win32-arm64-msvc/-/win32-arm64-msvc-0.0.164.tgz", - "integrity": "sha512-TYKZteG7d9ul1/TpiBV/TM5Y0adUr0oveheEwAqxDzyh8gP3jznX7eCrabI9ixdnqZ5BeIMPjcV4jHUJXqkq8g==", + "version": "0.0.165", + "resolved": "https://registry.npmjs.org/@cargo-messages/win32-arm64-msvc/-/win32-arm64-msvc-0.0.165.tgz", + "integrity": "sha512-YjBCi0aS+ZVig4oVfs3VEefaY2RIK6KDMdF3ma0ccRxaAsebzOr7hTGwKC9qmGKZ2+B9RfK6m5bRn7W/uIhaWw==", "cpu": [ "arm64" ], @@ -344,9 +253,9 @@ ] }, "node_modules/@cargo-messages/win32-x64-msvc": { - "version": "0.0.164", - "resolved": "https://registry.npmjs.org/@cargo-messages/win32-x64-msvc/-/win32-x64-msvc-0.0.164.tgz", - "integrity": "sha512-tZkVPWgVhWX5qLHwyh2XnizDafY9D7uCLJ0/oymPKwKJqJoTtoCTtsiNrqzGczMp4G5MjLiw69jKZJK6gBvtUQ==", + "version": "0.0.165", + "resolved": "https://registry.npmjs.org/@cargo-messages/win32-x64-msvc/-/win32-x64-msvc-0.0.165.tgz", + "integrity": "sha512-8aLHAdVWQdfFVMsQMIQHJHlFWmtLehYN/71xQo3x17NIY3eJjf+VejNLluKujRykjVx2/klc1KO2Jj1vzycifA==", "cpu": [ "x64" ], diff --git a/test/integration/proxy/.gitignore b/test/integration/proxy/.gitignore new file mode 100644 index 00000000..e1bf9c93 --- /dev/null +++ b/test/integration/proxy/.gitignore @@ -0,0 +1,4 @@ +htpasswd +storage +proxy.log +nohup.out diff --git a/test/integration/proxy/ci-proxy.sh b/test/integration/proxy/ci-proxy.sh new file mode 100755 index 00000000..1e3e22ac --- /dev/null +++ b/test/integration/proxy/ci-proxy.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# This script is used by CI to start up the npm proxy. + +CIPROXY=http://127.0.0.1:4873 + +# Boot the server in a background process. +nohup npx verdaccio --config ./config.yml --listen $CIPROXY & + +# Wait for the server to begin listening for connections +( tail -F -n10 proxy.log & ) | fgrep -q $CIPROXY + +cat proxy.log diff --git a/test/integration/proxy/config.yml b/test/integration/proxy/config.yml new file mode 100644 index 00000000..094df90f --- /dev/null +++ b/test/integration/proxy/config.yml @@ -0,0 +1,15 @@ +storage: ./storage +auth: + htpasswd: + file: ./htpasswd +packages: + '@neon-rs/*': + access: $all + publish: $all + '@sniff-bytes/*': + access: $all + publish: $all + '@neon-integration-tests/*': + access: $all + publish: $all +log: { type: file, path: proxy.log, level: info } diff --git a/test/integration/proxy/local-proxy.sh b/test/integration/proxy/local-proxy.sh new file mode 100755 index 00000000..9843926f --- /dev/null +++ b/test/integration/proxy/local-proxy.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +# This script can be used for running the integration tests in local development. +# It starts up the npm proxy and manages it with the pm2 process manager. + +cd $(dirname $0)/../../.. +ROOT_DIR=$(pwd) +PROXY_DIR=${ROOT_DIR}/test/integration/proxy +LOCAL_PROXY=http://127.0.0.1:4873 + +cd ${PROXY_DIR} + +if ! which pm2 >/dev/null ; then + echo -e 'usage: local-proxy.sh' + echo -e + echo -e 'error: The required tool `pm2` was not found. Please install it first by running:' + echo -e + echo -e ' $ npm i -g pm2' + echo -e + exit 1 +fi + +if pm2 describe neon-test-proxy >/dev/null 2>&1 ; then + echo -e 'usage: local-proxy.sh' + echo -e + echo -e 'error: There is already a pm2 app named `neon-test-proxy`. Please remove it first by running:' + echo -e + echo -e ' $ pm2 stop neon-test-proxy' + echo -e ' $ pm2 delete neon-test-proxy' + echo -e + exit 1 +fi + +rm -rf ./storage ./proxy.log + +# Boot the server in a background process. +pm2 start verdaccio --name neon-test-proxy --no-autorestart -- --config ./config.yml --listen ${LOCAL_PROXY} + +# Wait for the server to begin listening for connections +( tail -F -n10 ./proxy.log & ) | fgrep -q "${LOCAL_PROXY}" + +cat ./proxy.log + +echo +echo 'Proxy `neon-test-proxy` started. You can now control it using pm2:' +echo +echo ' # Stop the proxy server:' +echo ' $ pm2 stop neon-test-proxy' +echo +echo ' # Restart the proxy server:' +echo ' $ pm2 restart neon-test-proxy' +echo diff --git a/test/integration/proxy/publish.sh b/test/integration/proxy/publish.sh new file mode 100755 index 00000000..dff34215 --- /dev/null +++ b/test/integration/proxy/publish.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +PROXY_DIR=$(dirname $0) +cd ${PROXY_DIR}/../../.. +ROOT_DIR=$(pwd) + +PROXY_USER=ci +PROXY_PASSWORD=dummycipassword +PROXY_EMAIL=ci@neon-bindings.com +PROXY_SERVER=http://127.0.0.1:4873/ + +npx npm-cli-adduser -u ${PROXY_USER} -p ${PROXY_PASSWORD} -e ${PROXY_EMAIL} -r ${PROXY_SERVER} +(cd pkgs/load && npm publish --registry $PROXY_SERVER) +(cd pkgs/cli && npm publish --registry $PROXY_SERVER) + +cd test/integration/sniff-bytes +npm i +npm run build +mkdir -p dist +PACKAGE_TARBALL=$(npm run pack-build -- --out-dir dist | tail -1) +npm publish ./${PACKAGE_TARBALL} --registry $PROXY_SERVER +npm publish --registry $PROXY_SERVER diff --git a/test/integration/sniff-bytes/.gitignore b/test/integration/sniff-bytes/.gitignore new file mode 100644 index 00000000..f87f71e1 --- /dev/null +++ b/test/integration/sniff-bytes/.gitignore @@ -0,0 +1,6 @@ +**/node_modules +target +**/*.node +npm-debug.log* +dist +package-lock.json diff --git a/test/integration/sniff-bytes/.npmignore b/test/integration/sniff-bytes/.npmignore new file mode 100644 index 00000000..b235581f --- /dev/null +++ b/test/integration/sniff-bytes/.npmignore @@ -0,0 +1 @@ +npm diff --git a/test/integration/sniff-bytes/.npmrc b/test/integration/sniff-bytes/.npmrc new file mode 100644 index 00000000..7c4e6695 --- /dev/null +++ b/test/integration/sniff-bytes/.npmrc @@ -0,0 +1,3 @@ +@neon-integration-tests:registry = "http://127.0.0.1:4873" +@sniff-bytes:registry = "http://127.0.0.1:4873" +@neon-rs:registry = "http://127.0.0.1:4873" diff --git a/test/integration/sniff-bytes/Cargo.lock b/test/integration/sniff-bytes/Cargo.lock new file mode 100644 index 00000000..e664b6ff --- /dev/null +++ b/test/integration/sniff-bytes/Cargo.lock @@ -0,0 +1,150 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "file-format" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd991bcfc01ee8f9ed83108da842aeddfca8a9550962cbffc9579050109c2aa9" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "neon" +version = "1.0.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8687031acf51f8b065aaf906b5a694f8d6b547c5c9430b6d636ab42422bfd0cc" +dependencies = [ + "libloading", + "neon-macros", + "once_cell", + "semver", + "send_wrapper", + "smallvec", +] + +[[package]] +name = "neon-macros" +version = "1.0.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "facd664405d5140677a63d7b7c5762425dd9d4179e07d2e67da29089c50b1ddd" +dependencies = [ + "quote", + "syn", + "syn-mid", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "sniff-bytes" +version = "1.0.0" +dependencies = [ + "file-format", + "neon", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-mid" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea305d57546cc8cd04feb14b62ec84bf17f50e3f7b12560d7bfa9265f39d9ed" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/test/integration/sniff-bytes/Cargo.toml b/test/integration/sniff-bytes/Cargo.toml new file mode 100644 index 00000000..0ecf387a --- /dev/null +++ b/test/integration/sniff-bytes/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "sniff-bytes" +version = "1.0.0" +description = "Integration test: a portable npm library with a Rust implementation." +authors = ["David Herman "] +license = "MIT" +edition = "2021" +exclude = ["index.node"] + +[lib] +crate-type = ["cdylib"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +file-format = "0.18.0" + +[dependencies.neon] +version = "1.0.0-alpha.4" +default-features = false +features = ["napi-6"] diff --git a/test/integration/sniff-bytes/LICENSE b/test/integration/sniff-bytes/LICENSE new file mode 100644 index 00000000..f0f91b7f --- /dev/null +++ b/test/integration/sniff-bytes/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2023 David Herman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/test/integration/sniff-bytes/lib/index.cjs b/test/integration/sniff-bytes/lib/index.cjs new file mode 100644 index 00000000..97b58017 --- /dev/null +++ b/test/integration/sniff-bytes/lib/index.cjs @@ -0,0 +1,5 @@ +const addon = require('./load.cjs'); + +module.exports = { + sniffBytes: addon.sniffBytes +}; diff --git a/test/integration/sniff-bytes/lib/index.mjs b/test/integration/sniff-bytes/lib/index.mjs new file mode 100644 index 00000000..4ce231ce --- /dev/null +++ b/test/integration/sniff-bytes/lib/index.mjs @@ -0,0 +1 @@ +export { sniffBytes } from './index.cjs'; diff --git a/test/integration/sniff-bytes/lib/load.cjs b/test/integration/sniff-bytes/lib/load.cjs new file mode 100644 index 00000000..3d6f16c2 --- /dev/null +++ b/test/integration/sniff-bytes/lib/load.cjs @@ -0,0 +1,10 @@ +module.exports = require('@neon-rs/load').lazy({ + targets: { + 'linux-x64-gnu': () => require('@sniff-bytes/linux-x64-gnu'), + 'darwin-arm64': () => require('@sniff-bytes/darwin-arm64') + }, + exports: [ + 'sniffBytes' + ], + debug: () => require('../index.node') +}); diff --git a/test/integration/sniff-bytes/npm/darwin-arm64/package.json b/test/integration/sniff-bytes/npm/darwin-arm64/package.json new file mode 100644 index 00000000..765dc82d --- /dev/null +++ b/test/integration/sniff-bytes/npm/darwin-arm64/package.json @@ -0,0 +1,24 @@ +{ + "name": "@sniff-bytes/darwin-arm64", + "description": "Prebuilt binary package for `sniff-bytes` on `darwin-arm64`.", + "version": "0.1.11", + "os": [ + "darwin" + ], + "cpu": [ + "arm64" + ], + "main": "index.node", + "files": [ + "index.node" + ], + "license": "MIT", + "neon": { + "type": "binary", + "rust": "aarch64-apple-darwin", + "node": "darwin-arm64", + "platform": "darwin", + "arch": "arm64", + "abi": null + } +} diff --git a/test/integration/sniff-bytes/npm/linux-x64-gnu/package.json b/test/integration/sniff-bytes/npm/linux-x64-gnu/package.json new file mode 100644 index 00000000..66fd9288 --- /dev/null +++ b/test/integration/sniff-bytes/npm/linux-x64-gnu/package.json @@ -0,0 +1,24 @@ +{ + "name": "@sniff-bytes/linux-x64-gnu", + "description": "Prebuilt binary package for `sniff-bytes` on `linux-x64-gnu`.", + "version": "1.0", + "os": [ + "linux" + ], + "cpu": [ + "x64" + ], + "main": "index.node", + "files": [ + "index.node" + ], + "license": "MIT", + "neon": { + "type": "binary", + "rust": "x86_64-unknown-linux-gnu", + "node": "linux-x64-gnu", + "platform": "linux", + "arch": "x64", + "abi": "gnu" + } +} diff --git a/test/integration/sniff-bytes/package.json b/test/integration/sniff-bytes/package.json new file mode 100644 index 00000000..2458bc43 --- /dev/null +++ b/test/integration/sniff-bytes/package.json @@ -0,0 +1,57 @@ +{ + "name": "@neon-integration-tests/sniff-bytes", + "private": false, + "version": "1.0.0", + "description": "Integration test: a portable npm library with a Rust implementation.", + "type": "module", + "exports": { + ".": { + "import": { + "types": "./types/index.d.mts", + "default": "./lib/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./lib/index.cjs" + } + } + }, + "types": "./types/index.d.cts", + "main": "./lib/index.cjs", + "files": [ + "lib/index.cjs", + "lib/load.cjs", + "lib/index.mjs", + "types/index.d.cts", + "types/index.d.mts" + ], + "scripts": { + "test": "cargo test", + "debug": "cargo build --message-format=json | neon dist", + "build": "cargo build --message-format=json --release | neon dist -v -n sniff-bytes", + "cross": "cross build --message-format=json --release | neon dist -v -n sniff-bytes -m /target", + "pack-build": "neon pack-build -v", + "prepack": "neon install-builds -v" + }, + "license": "MIT", + "neon": { + "type": "source", + "org": "@sniff-bytes", + "targets": { + "linux-x64-gnu": "x86_64-unknown-linux-gnu", + "darwin-arm64": "aarch64-apple-darwin" + } + }, + "devDependencies": { + "@neon-rs/cli": "*", + "@tsconfig/node16": "^16.1.0", + "typescript": "^5.2.2" + }, + "dependencies": { + "@neon-rs/load": "*" + }, + "optionalDependencies": { + "@sniff-bytes/darwin-arm64": "1.0.0", + "@sniff-bytes/linux-x64-gnu": "1.0.0" + } +} diff --git a/test/integration/sniff-bytes/src/lib.rs b/test/integration/sniff-bytes/src/lib.rs new file mode 100644 index 00000000..986de894 --- /dev/null +++ b/test/integration/sniff-bytes/src/lib.rs @@ -0,0 +1,36 @@ +use neon::prelude::*; + +use neon::types::buffer::TypedArray; +use file_format::FileFormat; + +fn sniff_bytes(mut cx: FunctionContext) -> JsResult { + let buffer: Handle = cx.argument(0)?; + let format = { + let bytes = buffer.as_slice(&cx); + FileFormat::from_bytes(bytes) + }; + let result = cx.empty_object(); + let name = cx.string(format.name()); + result.set(&mut cx, "name", name)?; + match format.short_name() { + Some(short_name) => { + let short_name = cx.string(short_name); + result.set(&mut cx, "shortName", short_name)?; + } + None => { + let short_name = cx.null(); + result.set(&mut cx, "shortName", short_name)?; + } + } + let media_type = cx.string(format.media_type()); + result.set(&mut cx, "mediaType", media_type)?; + let ext = cx.string(format.extension()); + result.set(&mut cx, "extension", ext)?; + Ok(result) +} + +#[neon::main] +fn main(mut cx: ModuleContext) -> NeonResult<()> { + cx.export_function("sniffBytes", sniff_bytes)?; + Ok(()) +} diff --git a/test/integration/sniff-bytes/tsconfig.json b/test/integration/sniff-bytes/tsconfig.json new file mode 100644 index 00000000..e9c0bafe --- /dev/null +++ b/test/integration/sniff-bytes/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@tsconfig/node16/tsconfig.json" +} diff --git a/test/integration/sniff-bytes/types/index.d.cts b/test/integration/sniff-bytes/types/index.d.cts new file mode 100644 index 00000000..ef68e00c --- /dev/null +++ b/test/integration/sniff-bytes/types/index.d.cts @@ -0,0 +1,8 @@ +export type FileFormat = { + name: string, + shortName: string | null, + mediaType: string, + extension: string +}; + +export function sniffBytes(buffer: ArrayBuffer): FileFormat; diff --git a/test/integration/sniff-bytes/types/index.d.mts b/test/integration/sniff-bytes/types/index.d.mts new file mode 100644 index 00000000..7863f88b --- /dev/null +++ b/test/integration/sniff-bytes/types/index.d.mts @@ -0,0 +1,3 @@ +import { FileFormat, sniffBytes } from './index.d.cts'; + +export { FileFormat, sniffBytes }; diff --git a/test/integration/test-sniff-bytes/.gitignore b/test/integration/test-sniff-bytes/.gitignore new file mode 100644 index 00000000..b22f6c2b --- /dev/null +++ b/test/integration/test-sniff-bytes/.gitignore @@ -0,0 +1,4 @@ +dist +node_modules +types +package-lock.json diff --git a/test/integration/test-sniff-bytes/.npmrc b/test/integration/test-sniff-bytes/.npmrc new file mode 100644 index 00000000..7c4e6695 --- /dev/null +++ b/test/integration/test-sniff-bytes/.npmrc @@ -0,0 +1,3 @@ +@neon-integration-tests:registry = "http://127.0.0.1:4873" +@sniff-bytes:registry = "http://127.0.0.1:4873" +@neon-rs:registry = "http://127.0.0.1:4873" diff --git a/test/integration/test-sniff-bytes/LICENSE b/test/integration/test-sniff-bytes/LICENSE new file mode 100644 index 00000000..f0f91b7f --- /dev/null +++ b/test/integration/test-sniff-bytes/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2023 David Herman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/test/integration/test-sniff-bytes/fixtures/pit-droids.jpg b/test/integration/test-sniff-bytes/fixtures/pit-droids.jpg new file mode 100644 index 00000000..1cb2cb60 Binary files /dev/null and b/test/integration/test-sniff-bytes/fixtures/pit-droids.jpg differ diff --git a/test/integration/test-sniff-bytes/fixtures/squirrel.gif b/test/integration/test-sniff-bytes/fixtures/squirrel.gif new file mode 100644 index 00000000..55e93812 Binary files /dev/null and b/test/integration/test-sniff-bytes/fixtures/squirrel.gif differ diff --git a/test/integration/test-sniff-bytes/package.json b/test/integration/test-sniff-bytes/package.json new file mode 100644 index 00000000..8296c9bf --- /dev/null +++ b/test/integration/test-sniff-bytes/package.json @@ -0,0 +1,23 @@ +{ + "name": "@neon-integration-tests/test-sniff-bytes", + "version": "1.0.0", + "description": "Integration test: use a portable library that wraps a Rust implementation", + "license": "MIT", + "type": "module", + "exports": "./dist/src/index.js", + "types": "types/index.d.ts", + "scripts": { + "build": "tsc", + "test": "NODE_OPTIONS=--experimental-vm-modules jest ./dist", + "pretest": "npm run build" + }, + "devDependencies": { + "@jest/globals": "^29.6.4", + "@tsconfig/node16": "^16.1.1", + "jest": "^29.6.4", + "typescript": "^5.2.2" + }, + "dependencies": { + "@neon-integration-tests/sniff-bytes": "^1.0.0" + } +} diff --git a/test/integration/test-sniff-bytes/src/main.test.ts b/test/integration/test-sniff-bytes/src/main.test.ts new file mode 100644 index 00000000..3057452a --- /dev/null +++ b/test/integration/test-sniff-bytes/src/main.test.ts @@ -0,0 +1,26 @@ +import { readFile } from 'node:fs/promises'; +import * as path from 'node:path'; +import { describe, expect, test } from '@jest/globals'; +import { sniffBytes } from '@neon-integration-tests/sniff-bytes'; + +async function loadFixture(name: string) { + return (await readFile(path.join('.', 'fixtures', name))).buffer; +} + +describe('main', () => { + test('sniff JPEG bytes', async () => { + const jpg = await loadFixture('pit-droids.jpg'); + const metadata = sniffBytes(jpg); + expect(metadata.shortName).toBe('JPEG'); + expect(metadata.mediaType).toBe('image/jpeg'); + expect(metadata.extension).toBe('jpg'); + }); + + test('sniff GIF bytes', async () => { + const gif = await loadFixture('squirrel.gif'); + const metadata = sniffBytes(gif); + expect(metadata.shortName).toBe('GIF'); + expect(metadata.mediaType).toBe('image/gif'); + expect(metadata.extension).toBe('gif'); + }); +}); diff --git a/test/integration/test-sniff-bytes/tsconfig.json b/test/integration/test-sniff-bytes/tsconfig.json new file mode 100644 index 00000000..f0df59bd --- /dev/null +++ b/test/integration/test-sniff-bytes/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@tsconfig/node16/tsconfig.json", + "compilerOptions": { + "module": "es2022", + "moduleResolution": "bundler", + "outDir": "dist", + "declaration": true, + "declarationDir": "types", + "noImplicitAny": true, + "resolveJsonModule": true + }, + "include": ["src/**/*"] +} diff --git a/test/lint/check-bundles.sh b/test/lint/check-bundles.sh new file mode 100755 index 00000000..1e67afec --- /dev/null +++ b/test/lint/check-bundles.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# This script implements a lint that ensures that generated bundles +# in the repo haven't gone stale since the source was last modified. + +echo "Checking that all bundled tools are up to date..." + +dirty_workspaces=() + +for input_workspace in `find src -type d -mindepth 1 -maxdepth 1 -not -name node_modules` ; do + output_workspace=$(echo $input_workspace | sed -e 's/^src/pkgs/') + input_mtime=$(git log -1 --format=%ct $input_workspace) + output_mtime=$(git log -1 --format=%ct $output_workspace) + if [[ $input_mtime -gt $output_mtime ]] ; then + echo "❌ $input_workspace has changed since $output_workspace was last generated" + dirty_workspaces+=($input_workspace) + fi +done + +if [[ ${#dirty_workspaces[@]} -gt 0 ]] ; then + echo + echo '💡 Re-run `npm run bundle` on the following workspaces before committing:' + for workspace in ${dirty_workspaces[*]} ; do + echo " • $workspace" + done + exit 1 +fi