From 6dc1145011d30df0d4af00f844f35d73e33374fa Mon Sep 17 00:00:00 2001 From: bweigel Date: Sun, 2 Dec 2018 00:46:48 +0100 Subject: [PATCH] fix #269 - migrates tests from bats to tape --- package.json | 4 +- test.bats | 594 ----------- test.js | 1417 ++++++++++++++++++++++++-- tests/base/_slimPatterns.yml | 2 +- tests/base/package.json | 2 +- tests/base/requirements-w-hashes.txt | 89 ++ tests/base/serverless.yml | 9 +- tests/individually/package.json | 2 +- tests/individually/serverless.yml | 1 + tests/pipenv/_slimPatterns.yml | 2 +- tests/pipenv/package.json | 2 +- 11 files changed, 1443 insertions(+), 681 deletions(-) delete mode 100755 test.bats create mode 100644 tests/base/requirements-w-hashes.txt diff --git a/package.json b/package.json index c426c94f..b56b3037 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "main": "index.js", "bin": {}, "scripts": { - "test": "node test.js && bats test.bats", + "test": "node test.js", "lint": "eslint *.js lib/*.js && prettier -l index.js lib/*.js || (echo need formatting ; exit 1)", "format": "prettier --write index.js lib/*.js test.js" }, @@ -76,4 +76,4 @@ "singleQuote": true, "parser": "babylon" } -} +} \ No newline at end of file diff --git a/test.bats b/test.bats deleted file mode 100755 index 3e42ac4e..00000000 --- a/test.bats +++ /dev/null @@ -1,594 +0,0 @@ -#!/usr/bin/env bats - - -setup() { - export SLS_DEBUG=t - if ! [ -z "$CI" ]; then - export LC_ALL=C.UTF-8 - export LANG=C.UTF-8 - fi - export USR_CACHE_DIR=`node -e 'console.log(require("./lib/shared").getUserCachePath())'` - # Please note: If you update change the requirements.txt in test/base this value will - # change. Run a test which uses this variable manually step by step and list the cache - # folder to find the new hash if you do this - if [ -d "${USR_CACHE_DIR}" ] ; then - rm -Rf "${USR_CACHE_DIR}" - fi -} - -teardown() { - rm -rf puck puck2 puck3 node_modules .serverless .requirements.zip .requirements-cache \ - foobar package-lock.json serverless.yml.bak slimPatterns.yml "${USR_CACHE_DIR}" - serverless-python-requirements-*.tgz - git checkout serverless.yml - cd ../.. - if [ -d "tests/base with a space" ] ; then - rm -Rf "tests/base with a space" - fi -} - -@test "py3.6 can package flask with default options" { - cd tests/base - npm i $(npm pack ../..) - sls package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask -} - -@test "py3.6 can package flask with hashes" { - cd tests/base - npm i $(npm pack ../..) - pip-compile --output-file requirements-w-hashes.txt --generate-hashes requirements.txt - sls package --fileName requirements-w-hashes.txt - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask -} - -@test "py3.6 can package flask & bottle with zip option" { - cd tests/base - npm i $(npm pack ../..) - sls --zip=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/.requirements.zip puck/unzip_requirements.py - ! ls puck/flask - ! ls puck/bottle -} - -@test "py3.6 can package flask with slim options" { - cd tests/base - npm i $(npm pack ../..) - sls --slim=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask - test $(find puck -name "*.pyc" | wc -l) -eq 0 -} - -@test "py3.6 can package flask with slim & slimPatterns options" { - cd tests/base - cat _slimPatterns.yml > slimPatterns.yml - npm i $(npm pack ../..) - sls --slim=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask - test $(find puck -name "*.pyc" | wc -l) -eq 0 - test $(find puck -type d -name "*.egg-info*" | wc -l) -eq 0 -} - -@test "py3.6 doesn't package boto3 by default" { - cd tests/base - npm i $(npm pack ../..) - sls package - unzip .serverless/sls-py-req-test.zip -d puck - ! ls puck/boto3 -} - -@test "py3.6 doesn't package bottle with noDeploy option" { - cd tests/base - npm i $(npm pack ../..) - perl -p -i'.bak' -e 's/(pythonRequirements:$)/\1\n noDeploy: [bottle]/' serverless.yml - sls package - unzip .serverless/sls-py-req-test.zip -d puck - ! ls puck/bottle.py - ! ls puck/__pycache__/bottle.cpython-36.pyc -} - -@test "py3.6 can package flask with zip & dockerizePip option" { - cd tests/base - npm i $(npm pack ../..) - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - sls --dockerizePip=true --zip=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/.requirements.zip puck/unzip_requirements.py -} - -@test "py3.6 can package flask with zip & slim & dockerizePip option" { - cd tests/base - npm i $(npm pack ../..) - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - sls --dockerizePip=true --zip=true --slim=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/.requirements.zip puck/unzip_requirements.py -} - -@test "py3.6 can package flask with dockerizePip option" { - cd tests/base - npm i $(npm pack ../..) - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - sls --dockerizePip=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask -} - -@test "py3.6 can package flask with slim & dockerizePip option" { - cd tests/base - npm i $(npm pack ../..) - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - sls --dockerizePip=true --slim=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask - test $(find puck -name "*.pyc" | wc -l) -eq 0 -} - -@test "py3.6 can package flask with slim & dockerizePip & slimPatterns options" { - cd tests/base - cat _slimPatterns.yml > slimPatterns.yml - npm i $(npm pack ../..) - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - sls --dockerizePip=true --slim=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask - test $(find puck -name "*.pyc" | wc -l) -eq 0 - test $(find puck -type d -name "*.egg-info*" | wc -l) -eq 0 -} - -@test "py3.6 uses download cache with useDownloadCache option" { - cd tests/base - npm i $(npm pack ../..) - perl -p -i'.bak' -e 's/(pythonRequirements:$)/\1\n useDownloadCache: true/' serverless.yml - sls package - USR_CACHE_DIR=`node -e 'console.log(require("../../lib/shared").getUserCachePath())'` - ls $USR_CACHE_DIR/downloadCacheslspyc/http -} - -@test "py3.6 uses download cache with cacheLocation option" { - cd tests/base - npm i $(npm pack ../..) - perl -p -i'.bak' -e 's/(pythonRequirements:$)/\1\n useDownloadCache: true\n cacheLocation: .requirements-cache/' serverless.yml - sls package - ls .requirements-cache/downloadCacheslspyc/http -} - -@test "py3.6 uses download cache with dockerizePip option" { - cd tests/base - npm i $(npm pack ../..) - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - perl -p -i'.bak' -e 's/(pythonRequirements:$)/\1\n useDownloadCache: true/' serverless.yml - sls --dockerizePip=true package - USR_CACHE_DIR=`node -e 'console.log(require("../../lib/shared").getUserCachePath())'` - ls $USR_CACHE_DIR/downloadCacheslspyc/http -} - -@test "py3.6 uses download cache with dockerizePip + cacheLocation option" { - cd tests/base - npm i $(npm pack ../..) - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - perl -p -i'.bak' -e 's/(pythonRequirements:$)/\1\n useDownloadCache: true\n cacheLocation: .requirements-cache/' serverless.yml - sls --dockerizePip=true package - ls .requirements-cache/downloadCacheslspyc/http -} - -@test "py3.6 uses static and download cache" { - cd tests/base - npm i $(npm pack ../..) - perl -p -i'.bak' -e 's/(pythonRequirements:$)/\1\n useDownloadCache: true\n useStaticCache: true/' serverless.yml - sls package - USR_CACHE_DIR=`node -e 'console.log(require("./node_modules/serverless-python-requirements/lib/shared").getUserCachePath())'` - CACHE_FOLDER_HASH=$(md5sum <(grep -v boto3 requirements.txt|sort) | cut -d' ' -f1)_slspyc - ls $USR_CACHE_DIR/$CACHE_FOLDER_HASH/flask - ls $USR_CACHE_DIR/downloadCacheslspyc/http -} - -@test "py3.6 uses static and download cache with dockerizePip option" { - cd tests/base - npm i $(npm pack ../..) - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - perl -p -i'.bak' -e 's/(pythonRequirements:$)/\1\n useDownloadCache: true\n useStaticCache: true/' serverless.yml - sls --dockerizePip=true package - USR_CACHE_DIR=`node -e 'console.log(require("../../lib/shared").getUserCachePath())'` - CACHE_FOLDER_HASH=$(md5sum <(grep -v boto3 requirements.txt|sort) | cut -d' ' -f1)_slspyc - ls $USR_CACHE_DIR/$CACHE_FOLDER_HASH/flask - ls $USR_CACHE_DIR/downloadCacheslspyc/http -} - -@test "py3.6 uses static cache" { - cd tests/base - npm i $(npm pack ../..) - perl -p -i'.bak' -e 's/(pythonRequirements:$)/\1\n useStaticCache: true/' serverless.yml - sls package - USR_CACHE_DIR=`node -e 'console.log(require("../../lib/shared").getUserCachePath())'` - CACHE_FOLDER_HASH=$(md5sum <(grep -v boto3 requirements.txt|sort) | cut -d' ' -f1)_slspyc - ls $USR_CACHE_DIR/$CACHE_FOLDER_HASH/flask - ls $USR_CACHE_DIR/$CACHE_FOLDER_HASH/.completed_requirements -} - -@test "py3.6 uses static cache with cacheLocation option" { - cd tests/base - npm i $(npm pack ../..) - perl -p -i'.bak' -e 's/(pythonRequirements:$)/\1\n useStaticCache: true\n cacheLocation: .requirements-cache/' serverless.yml - sls package - USR_CACHE_DIR=`node -e 'console.log(require("../../lib/shared").getUserCachePath())'` - CACHE_FOLDER_HASH=$(md5sum <(grep -v boto3 requirements.txt|sort) | cut -d' ' -f1)_slspyc - ls .requirements-cache/$CACHE_FOLDER_HASH/flask - ls .requirements-cache/$CACHE_FOLDER_HASH/.completed_requirements -} - -@test "py3.6 checking that static cache actually pulls from cache (by poisoning it)" { - cd tests/base - npm i $(npm pack ../..) - perl -p -i'.bak' -e 's/(pythonRequirements:$)/\1\n useStaticCache: true/' serverless.yml - sls package - cp .serverless/sls-py-req-test.zip ./puck - USR_CACHE_DIR=`node -e 'console.log(require("../../lib/shared").getUserCachePath())'` - CACHE_FOLDER_HASH=$(md5sum <(grep -v boto3 requirements.txt|sort) | cut -d' ' -f1)_slspyc - echo "injected new file into static cache folder" > $USR_CACHE_DIR/$CACHE_FOLDER_HASH/injected_file_is_bad_form - sls package - [ `wc -c ./.serverless/sls-py-req-test.zip | awk '{ print $1 }'` -gt `wc -c ./puck | awk '{ print $1 }'` ] -} - -@test "py3.6 uses static cache with dockerizePip & slim option" { - cd tests/base - npm i $(npm pack ../..) - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - perl -p -i'.bak' -e 's/(pythonRequirements:$)/\1\n useStaticCache: true/' serverless.yml - sls --dockerizePip=true --slim=true package - CACHE_FOLDER_HASH=$(md5sum <(grep -v boto3 requirements.txt|sort) | cut -d' ' -f1)_slspyc - ls $USR_CACHE_DIR/$CACHE_FOLDER_HASH/flask - unzip .serverless/sls-py-req-test.zip -d puck - test $(find puck -name "*.pyc" | wc -l) -eq 0 -} - -@test "py3.6 uses download cache with dockerizePip & slim option" { - cd tests/base - npm i $(npm pack ../..) - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - perl -p -i'.bak' -e 's/(pythonRequirements:$)/\1\n useDownloadCache: true/' serverless.yml - sls --dockerizePip=true --slim=true package - ls $USR_CACHE_DIR/downloadCacheslspyc/http - unzip .serverless/sls-py-req-test.zip -d puck - test $(find puck -name "*.pyc" | wc -l) -eq 0 -} - -@test "py2.7 can package flask with default options" { - cd tests/base - npm i $(npm pack ../..) - sls --runtime=python2.7 package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask -} - -@test "py2.7 can package flask with slim option" { - cd tests/base - npm i $(npm pack ../..) - sls --runtime=python2.7 --slim=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask - test $(find puck -name "*.pyc" | wc -l) -eq 0 -} - -@test "py2.7 can package flask with zip option" { - cd tests/base - npm i $(npm pack ../..) - sls --runtime=python2.7 --zip=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/.requirements.zip puck/unzip_requirements.py -} - -@test "py2.7 can package flask with slim & dockerizePip & slimPatterns options" { - cd tests/base - cat _slimPatterns.yml > slimPatterns.yml - npm i $(npm pack ../..) - sls --runtime=python2.7 --slim=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask - test $(find puck -name "*.pyc" | wc -l) -eq 0 - test $(find puck -type d -name "*.egg-info*" | wc -l) -eq 0 -} - -@test "py2.7 doesn't package boto3 by default" { - cd tests/base - npm i $(npm pack ../..) - sls package - unzip .serverless/sls-py-req-test.zip -d puck - ! ls puck/boto3 -} - -@test "py2.7 doesn't package bottle with noDeploy option" { - cd tests/base - npm i $(npm pack ../..) - perl -p -i'.bak' -e 's/(pythonRequirements:$)/\1\n noDeploy: [bottle]/' serverless.yml - sls --runtime=python2.7 package - unzip .serverless/sls-py-req-test.zip -d puck - ! ls puck/bottle.py -} - -@test "py2.7 can package flask with zip & dockerizePip option" { - cd tests/base - npm i $(npm pack ../..) - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - sls --dockerizePip=true --runtime=python2.7 --zip=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/.requirements.zip puck/unzip_requirements.py -} - -@test "py2.7 can package flask with zip & slim & dockerizePip option" { - cd tests/base - npm i $(npm pack ../..) - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - sls --dockerizePip=true --runtime=python2.7 --zip=true --slim=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/.requirements.zip puck/unzip_requirements.py -} - -@test "py2.7 can package flask with dockerizePip option" { - cd tests/base - npm i $(npm pack ../..) - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - sls --dockerizePip=true --runtime=python2.7 package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask -} - -@test "py2.7 can package flask with slim & dockerizePip option" { - cd tests/base - npm i $(npm pack ../..) - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - sls --dockerizePip=true --slim=true --runtime=python2.7 package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask - test $(find puck -name "*.pyc" | wc -l) -eq 0 -} - -@test "py2.7 can package flask with slim & dockerizePip & slimPatterns options" { - cd tests/base - cat _slimPatterns.yml > slimPatterns.yml - npm i $(npm pack ../..) - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - sls --dockerizePip=true --slim=true --runtime=python2.7 package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask - test $(find puck -name "*.pyc" | wc -l) -eq 0 - test $(find puck -type d -name "*.egg-info*" | wc -l) -eq 0 -} - -@test "pipenv py3.6 can package flask with default options" { - cd tests/pipenv - npm i $(npm pack ../..) - sls package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask -} - -@test "pipenv py3.6 can package flask with slim option" { - cd tests/pipenv - npm i $(npm pack ../..) - sls --slim=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask - test $(find puck -name "*.pyc" | wc -l) -eq 0 -} - -@test "pipenv py3.6 can package flask with slim & slimPatterns option" { - cd tests/pipenv - npm i $(npm pack ../..) - cat _slimPatterns.yml > slimPatterns.yml - sls --slim=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask - test $(find puck -name "*.pyc" | wc -l) -eq 0 - test $(find puck -type d -name "*.egg-info*" | wc -l) -eq 0 -} - -@test "pipenv py3.6 can package flask with zip option" { - cd tests/pipenv - npm i $(npm pack ../..) - sls --zip=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/.requirements.zip puck/unzip_requirements.py -} - -@test "pipenv py3.6 doesn't package boto3 by default" { - cd tests/pipenv - npm i $(npm pack ../..) - sls package - unzip .serverless/sls-py-req-test.zip -d puck - ! ls puck/boto3 -} - -@test "pipenv py3.6 doesn't package bottle with noDeploy option" { - cd tests/pipenv - npm i $(npm pack ../..) - perl -p -i'.bak' -e 's/(pythonRequirements:$)/\1\n noDeploy: [bottle]/' serverless.yml - sls package - unzip .serverless/sls-py-req-test.zip -d puck - ! ls puck/bottle.py -} - -@test "py3.6 can package flask with zip option and no explicit include" { - cd tests/base - npm i $(npm pack ../..) - sed -i'.bak' -e 's/include://' -e 's/^.*handler.py//' serverless.yml - sls --zip=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/.requirements.zip puck/unzip_requirements.py -} - -@test "py3.6 can package flask with package individually option" { - cd tests/base - npm i $(npm pack ../..) - sls --individually=true package - unzip .serverless/hello.zip -d puck - unzip .serverless/hello2.zip -d puck2 - unzip .serverless/hello3.zip -d puck3 - ls puck/flask - ls puck2/flask - ! ls puck3/flask -} - -@test "py3.6 can package flask with package individually & slim option" { - cd tests/base - npm i $(npm pack ../..) - sls --individually=true --slim=true package - unzip .serverless/hello.zip -d puck - unzip .serverless/hello2.zip -d puck2 - unzip .serverless/hello3.zip -d puck3 - ls puck/flask - ls puck2/flask - ! ls puck3/flask - test $(find "puck*" -name "*.pyc" | wc -l) -eq 0 -} - -@test "py2.7 can package flask with package individually option" { - cd tests/base - npm i $(npm pack ../..) - sls --individually=true --runtime=python2.7 package - unzip .serverless/hello.zip -d puck - unzip .serverless/hello2.zip -d puck2 - unzip .serverless/hello3.zip -d puck3 - ls puck/flask - ls puck2/flask - ! ls puck3/flask -} - -@test "py2.7 can package flask with package individually & slim option" { - cd tests/base - npm i $(npm pack ../..) - sls --individually=true --slim=true --runtime=python2.7 package - unzip .serverless/hello.zip -d puck - unzip .serverless/hello2.zip -d puck2 - unzip .serverless/hello3.zip -d puck3 - ls puck/flask - ls puck2/flask - ! ls puck3/flask - test $(find puck* -name "*.pyc" | wc -l) -eq 0 -} - -@test "py3.6 can package only requirements of module" { - cd tests/individually - npm i $(npm pack ../..) - sls package - unzip .serverless/module1-sls-py-req-test-indiv-dev-hello1.zip -d puck - unzip .serverless/module2-sls-py-req-test-indiv-dev-hello2.zip -d puck2 - ls puck/handler1.py - ls puck2/handler2.py - ls puck/pyaml - ls puck2/flask - ! ls puck/handler2.py - ! ls puck2/handler1.py - ! ls puck/flask - ! ls puck2/pyaml -} - -@test "py3.6 can package lambda-decorators using vendor option" { - cd tests/base - npm i $(npm pack ../..) - sls --vendor=./vendor package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask - ls puck/lambda_decorators.py -} - -@test "py3.6 can package lambda-decorators using vendor and invidiually option" { - cd tests/base - npm i $(npm pack ../..) - sls --individually=true --vendor=./vendor package - unzip .serverless/hello.zip -d puck - unzip .serverless/hello2.zip -d puck2 - unzip .serverless/hello3.zip -d puck3 - ls puck/flask - ls puck2/flask - ! ls puck3/flask - ls puck/lambda_decorators.py - ls puck2/lambda_decorators.py - ! ls puck3/lambda_decorators.py -} - -@test "Don't nuke execute perms" { - cd tests/base - npm i $(npm pack ../..) - touch foobar - chmod +x foobar - perl -p -i'.bak' -e 's/(handler.py$)/\1\n - foobar/' serverless.yml - sls --vendor=./vendor package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask - ls puck/lambda_decorators.py - ./puck/foobar -} - -@test "Don't nuke execute perms when using individually" { - cd tests/individually - npm i $(npm pack ../..) - touch module1/foobar - chmod +x module1/foobar - perl -p -i'.bak' -e 's/(handler.py$)/\1\n - foobar/' serverless.yml - sls package - unzip .serverless/hello1.zip -d puck - ./puck/module1/foobar -} - -@test "Don't nuke execute perms when using individually w/docker" { - cd tests/individually - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - npm i $(npm pack ../..) - touch module1/foobar - chmod +x module1/foobar - perl -p -i'.bak' -e 's/(handler.py$)/\1\n - foobar/' serverless.yml - sls package --dockerizePip=true - unzip .serverless/hello1.zip -d puck - ./puck/module1/foobar -} - -@test "py3.6 can package flask in a project with a space in it" { - cp -a tests/base "tests/base with a space" - cd "tests/base with a space" - npm i $(npm pack ../..) - sls package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask -} - -@test "py3.6 can package flask in a project with a space in it with docker" { - docker &> /dev/null || skip "docker not present" - ! uname -sm|grep Linux || groups|grep docker || id -u|egrep '^0$' || skip "can't dockerize on linux if not root & not in docker group" - cp -a tests/base "tests/base with a space" - cd "tests/base with a space" - npm i $(npm pack ../..) - sls --dockerizePip=true package - unzip .serverless/sls-py-req-test.zip -d puck - ls puck/flask -} - -@test "py3.6 supports custom file name with fileName option" { - cd tests/base - npm i $(npm pack ../..) - echo "requests" > puck - sls --fileName puck package - ls .serverless/requirements/requests - ! ls .serverless/requirements/flask -} diff --git a/test.js b/test.js index 557b0c5b..b310e672 100644 --- a/test.js +++ b/test.js @@ -3,11 +3,17 @@ const deasync = require('deasync-promise'); const glob = require('glob-all'); const JSZip = require('jszip'); const tape = require('tape'); +const { + removeSync, + readFileSync, + copySync, + writeFileSync, + pathExistsSync +} = require('fs-extra'); const { quote } = require('shell-quote'); -const { removeSync, readFileSync, copySync } = require('fs-extra'); const { sep } = require('path'); -const { getUserCachePath } = require('./lib/shared'); +const { getUserCachePath, md5Path } = require('./lib/shared'); const initialWorkingDir = process.cwd(); @@ -61,10 +67,13 @@ const teardown = () => { 'package-lock.json', 'slimPatterns.yml', 'serverless.yml.bak', + 'module1/foobar', getUserCachePath(), ...glob.sync('serverless-python-requirements-*.tgz') ].map(path => removeSync(path)); - git(['checkout', 'serverless.yml']); + if (!process.cwd().endsWith('base with a space')) { + git(['checkout', 'serverless.yml']); + } process.chdir(initialWorkingDir); removeSync('tests/base with a space'); }; @@ -74,6 +83,9 @@ const test = (desc, func, opts = {}) => setup(); try { func(t); + } catch (err) { + t.fail(err); + t.end(); } finally { teardown(); } @@ -88,6 +100,8 @@ const getPythonBin = (version = 3) => { const listZipFiles = filename => Object.keys(deasync(new JSZip().loadAsync(readFileSync(filename))).files); +const listZipFilesWithMetaData = filename => + Object(deasync(new JSZip().loadAsync(readFileSync(filename))).files); const listRequirementsZipFiles = filename => { const zip = deasync(new JSZip().loadAsync(readFileSync(filename))); const reqsBuffer = deasync(zip.file('.requirements.zip').async('nodebuffer')); @@ -112,6 +126,7 @@ test('default pythonBin can package flask with default options', t => { sls(['package']); const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.false(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is NOT packaged'); t.end(); }); @@ -122,6 +137,21 @@ test('py3.6 can package flask with default options', t => { sls([`--pythonBin=${getPythonBin(3)}`, 'package']); const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.false(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is NOT packaged'); + t.end(); +}); + +test('py3.6 can package flask with hashes', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + `--pythonBin=${getPythonBin(3)}`, + '--fileName=requirements-w-hashes.txt', + 'package' + ]); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); t.end(); }); @@ -155,163 +185,701 @@ test('py3.6 can package flask with slim option', t => { [], 'no pyc files packaged' ); + t.true( + zipfiles.filter(filename => filename.endsWith('__main__.py')).length > 0, + '__main__.py files are packaged' + ); t.end(); }); /* - * News tests not in test.bats + * News tests NOT in test.bats */ -test("py3.6 doesn't package bottle with zip option", t => { +test('py3.6 can package flask with slim & slimPatterns options', t => { + process.chdir('tests/base'); + + copySync('_slimPatterns.yml', 'slimPatterns.yml'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--slim=true', 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('.pyc')), + [], + 'no pyc files packaged' + ); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('__main__.py')), + [], + '__main__.py files are NOT packaged' + ); + t.end(); +}); + +test("py3.6 doesn't package bottle with noDeploy option", t => { process.chdir('tests/base'); const path = npm(['pack', '../..']); npm(['i', path]); perl([ '-p', - "-i'.bak'", + '-i.bak', '-e', 's/(pythonRequirements:$)/\\1\\n noDeploy: [bottle]/', 'serverless.yml' ]); - sls([`--pythonBin=${getPythonBin(3)}`, '--zip=true', 'package']); + sls([`--pythonBin=${getPythonBin(3)}`, 'package']); const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); - const zippedReqs = listRequirementsZipFiles( - '.serverless/sls-py-req-test.zip' - ); - t.true( - zipfiles.includes('.requirements.zip'), - 'zipped requirements are packaged' - ); - t.true(zipfiles.includes(`unzip_requirements.py`), 'unzip util is packaged'); - t.false( - zipfiles.includes(`flask${sep}__init__.py`), - "flask isn't packaged on its own" + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.false(zipfiles.includes(`bottle.py`), 'bottle is NOT packaged'); + t.end(); +}); + +test( + 'py3.6 can package flask with dockerizePip option', + t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--dockerizePip=true', 'package']); + + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.false( + zipfiles.includes(`boto3${sep}__init__.py`), + 'boto3 is NOT packaged' + ); + t.end(); + }, + { skip: !canUseDocker() } +); + +test( + 'py3.6 can package flask with slim & dockerizePip option', + t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--dockerizePip=true', '--slim=true', 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('.pyc')), + [], + '*.pyc files are NOT packaged' + ); + t.true( + zipfiles.filter(filename => filename.endsWith('__main__.py')).length > 0, + '__main__.py files are packaged' + ); + t.end(); + }, + { skip: !canUseDocker() } +); + +test( + 'py3.6 can package flask with slim & dockerizePip & slimPatterns options', + t => { + process.chdir('tests/base'); + + copySync('_slimPatterns.yml', 'slimPatterns.yml'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--dockerizePip=true', '--slim=true', 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('.pyc')), + [], + '*.pyc files are packaged' + ); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('__main__.py')), + [], + '__main__.py files are NOT packaged' + ); + t.end(); + }, + { skip: !canUseDocker() } +); + +test( + 'py3.6 can package flask with zip & dockerizePip option', + t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--dockerizePip=true', '--zip=true', 'package']); + + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + const zippedReqs = listRequirementsZipFiles( + '.serverless/sls-py-req-test.zip' + ); + t.true( + zipfiles.includes('.requirements.zip'), + 'zipped requirements are packaged' + ); + t.true( + zipfiles.includes(`unzip_requirements.py`), + 'unzip util is packaged' + ); + t.false( + zipfiles.includes(`flask${sep}__init__.py`), + "flask isn't packaged on its own" + ); + t.true( + zippedReqs.includes(`flask/__init__.py`), + 'flask is packaged in the .requirements.zip file' + ); + t.end(); + }, + { skip: !canUseDocker() } +); + +test( + 'py3.6 can package flask with zip & slim & dockerizePip option', + t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--dockerizePip=true', '--zip=true', '--slim=true', 'package']); + + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + const zippedReqs = listRequirementsZipFiles( + '.serverless/sls-py-req-test.zip' + ); + t.true( + zipfiles.includes('.requirements.zip'), + 'zipped requirements are packaged' + ); + t.true( + zipfiles.includes(`unzip_requirements.py`), + 'unzip util is packaged' + ); + t.false( + zipfiles.includes(`flask${sep}__init__.py`), + "flask isn't packaged on its own" + ); + t.true( + zippedReqs.includes(`flask/__init__.py`), + 'flask is packaged in the .requirements.zip file' + ); + t.end(); + }, + { skip: !canUseDocker() } +); + +test('py2.7 can package flask with default options', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([`--pythonBin=${getPythonBin(2)}`, 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.false(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is NOT packaged'); + t.end(); +}); + +test('py2.7 can package flask with slim option', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([`--pythonBin=${getPythonBin(2)}`, '--slim=true', 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('.pyc')), + [], + 'no pyc files packaged' ); t.true( - zippedReqs.includes(`flask/__init__.py`), - 'flask is packaged in the .requirements.zip file' - ); - t.false( - zippedReqs.includes(`bottle.py`), - 'bottle is not packaged in the .requirements.zip file' + zipfiles.filter(filename => filename.endsWith('__main__.py')).length > 0, + '__main__.py files are packaged' ); t.end(); }); -test('py3.6 can package flask with slim, slimPatterns & slimPatternsAppendDefaults=false options', t => { +test('py2.7 can package flask with zip option', t => { process.chdir('tests/base'); - copySync('_slimPatterns.yml', 'slimPatterns.yml'); const path = npm(['pack', '../..']); npm(['i', path]); - sls(['--slim=true', '--slimPatternsAppendDefaults=false', 'package']); - + sls([`--pythonBin=${getPythonBin(2)}`, '--zip=true', 'package']); const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); - t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); t.true( - zipfiles.filter(filename => filename.endsWith('.pyc')).length >= 1, - 'pyc files are packaged' + zipfiles.includes('.requirements.zip'), + 'zipped requirements are packaged' ); - t.deepEqual( - zipfiles.filter(filename => filename.includes('.egg-info')), - [], - '.egg-info folders are not packaged' + t.true(zipfiles.includes(`unzip_requirements.py`), 'unzip util is packaged'); + t.false( + zipfiles.includes(`flask${sep}__init__.py`), + "flask isn't packaged on its own" ); t.end(); }); test( - 'py3.6 can package flask with slim & dockerizePip & slimPatterns & slimPatternsAppendDefaults=false options', + 'py2.7 can package flask with slim & dockerizePip & slimPatterns options', t => { process.chdir('tests/base'); + copySync('_slimPatterns.yml', 'slimPatterns.yml'); const path = npm(['pack', '../..']); npm(['i', path]); sls([ + `--pythonBin=${getPythonBin(2)}`, '--dockerizePip=true', '--slim=true', - '--slimPatternsAppendDefaults=false', 'package' ]); - const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); - t.true( - zipfiles.filter(filename => filename.endsWith('.pyc')).length >= 1, - 'pyc files are packaged' + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('.pyc')), + [], + '*.pyc files are packaged' ); t.deepEqual( - zipfiles.filter(filename => filename.includes('.egg-infooo')), + zipfiles.filter(filename => filename.endsWith('__main__.py')), [], - '.egg-info folders are not packaged' + '__main__.py files are NOT packaged' ); t.end(); }, { skip: !canUseDocker() } ); -test('py2.7 can package flask with slim & slimPatterns & slimPatternsAppendDefaults=false options', t => { +test("py2.7 doesn't package bottle with noDeploy option", t => { process.chdir('tests/base'); - copySync('_slimPatterns.yml', 'slimPatterns.yml'); const path = npm(['pack', '../..']); npm(['i', path]); - sls([ - '--runtime=python2.7', - '--slim=true', - '--slimPatternsAppendDefaults=false', - 'package' + perl([ + '-p', + '-i.bak', + '-e', + 's/(pythonRequirements:$)/\\1\\n noDeploy: [bottle]/', + 'serverless.yml' ]); - + sls([`--pythonBin=${getPythonBin(2)}`, 'package']); const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); - t.true( - zipfiles.filter(filename => filename.endsWith('.pyc')).length >= 1, - 'pyc files are packaged' - ); - t.deepEqual( - zipfiles.filter(filename => filename.includes('.egg-info')), - [], - '.egg-info folders are not packaged' - ); + t.false(zipfiles.includes(`bottle.py`), 'bottle is NOT packaged'); t.end(); }); test( - 'py2.7 can package flask with slim & dockerizePip & slimPatterns & slimPatternsAppendDefaults=false options', + 'py2.7 can package flask with zip & dockerizePip option', t => { process.chdir('tests/base'); - copySync('_slimPatterns.yml', 'slimPatterns.yml'); const path = npm(['pack', '../..']); npm(['i', path]); sls([ + `--pythonBin=${getPythonBin(2)}`, '--dockerizePip=true', - '--runtime=python2.7', + '--zip=true', + 'package' + ]); + + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + const zippedReqs = listRequirementsZipFiles( + '.serverless/sls-py-req-test.zip' + ); + t.true( + zipfiles.includes('.requirements.zip'), + 'zipped requirements are packaged' + ); + t.true( + zipfiles.includes(`unzip_requirements.py`), + 'unzip util is packaged' + ); + t.false( + zipfiles.includes(`flask${sep}__init__.py`), + "flask isn't packaged on its own" + ); + t.true( + zippedReqs.includes(`flask/__init__.py`), + 'flask is packaged in the .requirements.zip file' + ); + t.end(); + }, + { skip: !canUseDocker() } +); + +test( + 'py2.7 can package flask with zip & slim & dockerizePip option', + t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + `--pythonBin=${getPythonBin(2)}`, + '--dockerizePip=true', + '--zip=true', '--slim=true', - '--slimPatternsAppendDefaults=false', 'package' ]); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); - t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + const zippedReqs = listRequirementsZipFiles( + '.serverless/sls-py-req-test.zip' + ); t.true( - zipfiles.filter(filename => filename.endsWith('.pyc')).length >= 1, - 'pyc files are packaged' + zipfiles.includes('.requirements.zip'), + 'zipped requirements are packaged' ); - t.deepEqual( - zipfiles.filter(filename => filename.includes('.egg-info')), - [], - '.egg-info folders are not packaged' + t.true( + zipfiles.includes(`unzip_requirements.py`), + 'unzip util is packaged' + ); + t.false( + zipfiles.includes(`flask${sep}__init__.py`), + "flask isn't packaged on its own" + ); + t.true( + zippedReqs.includes(`flask/__init__.py`), + 'flask is packaged in the .requirements.zip file' ); t.end(); }, { skip: !canUseDocker() } ); -test('pipenv py3.6 can package flask with slim & slimPatterns & slimPatternsAppendDefaults=false option', t => { - process.chdir('tests/pipenv'); - copySync('_slimPatterns.yml', 'slimPatterns.yml'); - const path = npm(['pack', '../..']); - npm(['i', path]); +test( + 'py2.7 can package flask with dockerizePip option', + t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([`--pythonBin=${getPythonBin(2)}`, '--dockerizePip=true', 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.false( + zipfiles.includes(`boto3${sep}__init__.py`), + 'boto3 is NOT packaged' + ); + t.end(); + }, + { skip: !canUseDocker() } +); + +test( + 'py2.7 can package flask with slim & dockerizePip option', + t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + `--pythonBin=${getPythonBin(2)}`, + '--dockerizePip=true', + '--slim=true', + 'package' + ]); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('.pyc')), + [], + '*.pyc files are NOT packaged' + ); + t.true( + zipfiles.filter(filename => filename.endsWith('__main__.py')).length > 0, + '__main__.py files are packaged' + ); + t.end(); + }, + { skip: !canUseDocker() } +); + +test( + 'py2.7 can package flask with slim & dockerizePip & slimPatterns options', + t => { + process.chdir('tests/base'); + + copySync('_slimPatterns.yml', 'slimPatterns.yml'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + `--pythonBin=${getPythonBin(2)}`, + '--dockerizePip=true', + '--slim=true', + 'package' + ]); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('.pyc')), + [], + '*.pyc files are packaged' + ); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('__main__.py')), + [], + '__main__.py files are NOT packaged' + ); + t.end(); + }, + { skip: !canUseDocker() } +); + +test('pipenv py3.6 can package flask with default options', t => { + process.chdir('tests/pipenv'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.false(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is NOT packaged'); + t.end(); +}); + +test('pipenv py3.6 can package flask with slim option', t => { + process.chdir('tests/pipenv'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--slim=true', 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('.pyc')), + [], + 'no pyc files packaged' + ); + t.true( + zipfiles.filter(filename => filename.endsWith('__main__.py')).length > 0, + '__main__.py files are packaged' + ); + t.end(); +}); + +test('pipenv py3.6 can package flask with slim & slimPatterns options', t => { + process.chdir('tests/pipenv'); + + copySync('_slimPatterns.yml', 'slimPatterns.yml'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--slim=true', 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('.pyc')), + [], + 'no pyc files packaged' + ); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('__main__.py')), + [], + '__main__.py files are NOT packaged' + ); + t.end(); +}); + +test('pipenv py3.6 can package flask with zip option', t => { + process.chdir('tests/pipenv'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([`--pythonBin=${getPythonBin(3)}`, '--zip=true', 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true( + zipfiles.includes('.requirements.zip'), + 'zipped requirements are packaged' + ); + t.true(zipfiles.includes(`unzip_requirements.py`), 'unzip util is packaged'); + t.false( + zipfiles.includes(`flask${sep}__init__.py`), + "flask isn't packaged on its own" + ); + t.end(); +}); + +test("pipenv py3.6 doesn't package bottle with noDeploy option", t => { + process.chdir('tests/pipenv'); + const path = npm(['pack', '../..']); + npm(['i', path]); + perl([ + '-p', + '-i.bak', + '-e', + 's/(pythonRequirements:$)/\\1\\n noDeploy: [bottle]/', + 'serverless.yml' + ]); + sls(['package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.false(zipfiles.includes(`bottle.py`), 'bottle is NOT packaged'); + t.end(); +}); + +test('py3.6 can package flask with zip option and no explicit include', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + perl(['-p', '-i.bak', '-e', 's/include://', 'serverless.yml']); + perl(['-p', '-i.bak', '-e', 's/^.*handler.py.*$//', 'serverless.yml']); + sls(['--zip=true', 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true( + zipfiles.includes('.requirements.zip'), + 'zipped requirements are packaged' + ); + t.true(zipfiles.includes(`unzip_requirements.py`), 'unzip util is packaged'); + t.false( + zipfiles.includes(`flask${sep}__init__.py`), + "flask isn't packaged on its own" + ); + t.end(); +}); + +test('py3.6 can package lambda-decorators using vendor option', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([`--vendor=./vendor`, 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true( + zipfiles.includes(`lambda_decorators.py`), + 'lambda_decorators.py is packaged' + ); + t.false(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is NOT packaged'); + t.end(); +}); + +test( + "Don't nuke execute perms", + t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + const perm = '775'; + + npm(['i', path]); + perl([ + '-p', + '-i.bak', + '-e', + 's/(handler.py.*$)/$1\n - foobar/', + 'serverless.yml' + ]); + writeFileSync(`foobar`, '', { mode: perm }); + sls(['--vendor=./vendor', 'package']); + + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true( + zipfiles.includes(`lambda_decorators.py`), + 'lambda_decorators.py is packaged' + ); + t.true(zipfiles.includes(`foobar`), 'foobar is packaged'); + t.false( + zipfiles.includes(`boto3${sep}__init__.py`), + 'boto3 is NOT packaged' + ); + + const zipfiles_with_metadata = listZipFilesWithMetaData( + '.serverless/sls-py-req-test.zip' + ); + t.true( + zipfiles_with_metadata['foobar'].unixPermissions + .toString(8) + .slice(3, 6) === perm, + 'foobar has retained its executable file permissions' + ); + + t.end(); + }, + { skip: process.platform === 'win32' } +); + +test('py3.6 can package flask in a project with a space in it', t => { + copySync('tests/base', 'tests/base with a space'); + process.chdir('tests/base with a space'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.false(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is NOT packaged'); + t.end(); +}); + +test( + 'py3.6 can package flask in a project with a space in it with docker', + t => { + copySync('tests/base', 'tests/base with a space'); + process.chdir('tests/base with a space'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--dockerizePip=true', 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.false( + zipfiles.includes(`boto3${sep}__init__.py`), + 'boto3 is NOT packaged' + ); + t.end(); + }, + { skip: !canUseDocker() } +); + +test('py3.6 supports custom file name with fileName option', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + writeFileSync('puck', 'requests'); + npm(['i', path]); + sls(['--fileName=puck', 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true( + zipfiles.includes(`requests${sep}__init__.py`), + 'requests is packaged' + ); + t.false(zipfiles.includes(`flask${sep}__init__.py`), 'flask is NOT packaged'); + t.false(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is NOT packaged'); + t.end(); +}); + +test("py3.6 doesn't package bottle with zip option", t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + perl([ + '-p', + '-i.bak', + '-e', + 's/(pythonRequirements:$)/\\1\\n noDeploy: [bottle]/', + 'serverless.yml' + ]); + sls([`--pythonBin=${getPythonBin(3)}`, '--zip=true', 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + const zippedReqs = listRequirementsZipFiles( + '.serverless/sls-py-req-test.zip' + ); + t.true( + zipfiles.includes('.requirements.zip'), + 'zipped requirements are packaged' + ); + t.true(zipfiles.includes(`unzip_requirements.py`), 'unzip util is packaged'); + t.false( + zipfiles.includes(`flask${sep}__init__.py`), + "flask isn't packaged on its own" + ); + t.true( + zippedReqs.includes(`flask/__init__.py`), + 'flask is packaged in the .requirements.zip file' + ); + t.false( + zippedReqs.includes(`bottle.py`), + 'bottle is NOT packaged in the .requirements.zip file' + ); + t.end(); +}); + +test('py3.6 can package flask with slim, slimPatterns & slimPatternsAppendDefaults=false options', t => { + process.chdir('tests/base'); + copySync('_slimPatterns.yml', 'slimPatterns.yml'); + const path = npm(['pack', '../..']); + npm(['i', path]); sls(['--slim=true', '--slimPatternsAppendDefaults=false', 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); t.true( @@ -319,9 +887,702 @@ test('pipenv py3.6 can package flask with slim & slimPatterns & slimPatternsAppe 'pyc files are packaged' ); t.deepEqual( - zipfiles.filter(filename => filename.includes('.egg-info')), + zipfiles.filter(filename => filename.endsWith('__main__.py')), [], - '.egg-info folders are not packaged' + '__main__.py files are NOT packaged' ); t.end(); }); + +test( + 'py3.6 can package flask with slim & dockerizePip & slimPatterns & slimPatternsAppendDefaults=false options', + t => { + process.chdir('tests/base'); + copySync('_slimPatterns.yml', 'slimPatterns.yml'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + '--dockerizePip=true', + '--slim=true', + '--slimPatternsAppendDefaults=false', + 'package' + ]); + + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true( + zipfiles.filter(filename => filename.endsWith('.pyc')).length >= 1, + 'pyc files are packaged' + ); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('__main__.py')), + [], + '__main__.py files are NOT packaged' + ); + t.end(); + }, + { skip: !canUseDocker() } +); + +test('py2.7 can package flask with slim & slimPatterns & slimPatternsAppendDefaults=false options', t => { + process.chdir('tests/base'); + copySync('_slimPatterns.yml', 'slimPatterns.yml'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + '--runtime=python2.7', + '--slim=true', + '--slimPatternsAppendDefaults=false', + 'package' + ]); + + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true( + zipfiles.filter(filename => filename.endsWith('.pyc')).length >= 1, + 'pyc files are packaged' + ); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('__main__.py')), + [], + '__main__.py files are NOT packaged' + ); + t.end(); +}); + +test( + 'py2.7 can package flask with slim & dockerizePip & slimPatterns & slimPatternsAppendDefaults=false options', + t => { + process.chdir('tests/base'); + copySync('_slimPatterns.yml', 'slimPatterns.yml'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + '--dockerizePip=true', + '--runtime=python2.7', + '--slim=true', + '--slimPatternsAppendDefaults=false', + 'package' + ]); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true( + zipfiles.filter(filename => filename.endsWith('.pyc')).length >= 1, + 'pyc files are packaged' + ); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('__main__.py')), + [], + '__main__.py files are NOT packaged' + ); + t.end(); + }, + { skip: !canUseDocker() } +); + +test('pipenv py3.6 can package flask with slim & slimPatterns & slimPatternsAppendDefaults=false option', t => { + process.chdir('tests/pipenv'); + copySync('_slimPatterns.yml', 'slimPatterns.yml'); + const path = npm(['pack', '../..']); + npm(['i', path]); + + sls(['--slim=true', '--slimPatternsAppendDefaults=false', 'package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true( + zipfiles.filter(filename => filename.endsWith('.pyc')).length >= 1, + 'pyc files are packaged' + ); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('__main__.py')), + [], + '__main__.py files are NOT packaged' + ); + t.end(); +}); + +test('py3.6 can package flask with package individually option', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--individually=true', 'package']); + + const zipfiles_hello = listZipFiles('.serverless/hello.zip'); + t.true( + zipfiles_hello.includes('handler.py'), + 'handler.py is packaged in function hello' + ); + t.true( + zipfiles_hello.includes(`flask${sep}__init__.py`), + 'flask is packaged in function hello' + ); + + const zipfiles_hello2 = listZipFiles('.serverless/hello2.zip'); + t.true( + zipfiles_hello2.includes('handler.py'), + 'handler.py is packaged in function hello2' + ); + t.true( + zipfiles_hello2.includes(`flask${sep}__init__.py`), + 'flask is packaged in function hello2' + ); + + const zipfiles_hello3 = listZipFiles('.serverless/hello3.zip'); + t.true( + zipfiles_hello3.includes('handler.py'), + 'handler.py is packaged in function hello2' + ); + t.false( + zipfiles_hello3.includes(`flask${sep}__init__.py`), + 'flask is NOT packaged in function hello3' + ); + + t.end(); +}); + +test('py3.6 can package flask with package individually & slim option', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--individually=true', '--slim=true', 'package']); + + const zipfiles_hello = listZipFiles('.serverless/hello.zip'); + t.true( + zipfiles_hello.includes('handler.py'), + 'handler.py is packaged in function hello' + ); + t.deepEqual( + zipfiles_hello.filter(filename => filename.endsWith('.pyc')), + [], + 'no pyc files packaged in function hello' + ); + t.true( + zipfiles_hello.includes(`flask${sep}__init__.py`), + 'flask is packaged in function hello' + ); + + const zipfiles_hello2 = listZipFiles('.serverless/hello2.zip'); + t.true( + zipfiles_hello2.includes('handler.py'), + 'handler.py is packaged in function hello2' + ); + t.deepEqual( + zipfiles_hello2.filter(filename => filename.endsWith('.pyc')), + [], + 'no pyc files packaged in function hello2' + ); + t.true( + zipfiles_hello2.includes(`flask${sep}__init__.py`), + 'flask is packaged in function hello2' + ); + + const zipfiles_hello3 = listZipFiles('.serverless/hello3.zip'); + t.true( + zipfiles_hello3.includes('handler.py'), + 'handler.py is packaged in function hello3' + ); + t.deepEqual( + zipfiles_hello3.filter(filename => filename.endsWith('.pyc')), + [], + 'no pyc files packaged in function hello3' + ); + t.false( + zipfiles_hello3.includes(`flask${sep}__init__.py`), + 'flask is NOT packaged in function hello3' + ); + + t.end(); +}); + +test('py2.7 can package flask with package individually option', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--individually=true', '--runtime=python2.7', 'package']); + + const zipfiles_hello = listZipFiles('.serverless/hello.zip'); + t.true( + zipfiles_hello.includes('handler.py'), + 'handler.py is packaged in function hello' + ); + t.true( + zipfiles_hello.includes(`flask${sep}__init__.py`), + 'flask is packaged in function hello' + ); + + const zipfiles_hello2 = listZipFiles('.serverless/hello2.zip'); + t.true( + zipfiles_hello2.includes('handler.py'), + 'handler.py is packaged in function hello2' + ); + t.true( + zipfiles_hello2.includes(`flask${sep}__init__.py`), + 'flask is packaged in function hello2' + ); + + const zipfiles_hello3 = listZipFiles('.serverless/hello3.zip'); + t.true( + zipfiles_hello3.includes('handler.py'), + 'handler.py is packaged in function hello3' + ); + t.false( + zipfiles_hello3.includes(`flask${sep}__init__.py`), + 'flask is NOT packaged in function hello3' + ); + + t.end(); +}); + +test('py2.7 can package flask with package individually & slim option', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--individually=true', '--runtime=python2.7', '--slim=true', 'package']); + + const zipfiles_hello = listZipFiles('.serverless/hello.zip'); + t.true( + zipfiles_hello.includes('handler.py'), + 'handler.py is packaged in function hello' + ); + t.deepEqual( + zipfiles_hello.filter(filename => filename.endsWith('.pyc')), + [], + 'no pyc files packaged in function hello' + ); + t.true( + zipfiles_hello.includes(`flask${sep}__init__.py`), + 'flask is packaged in function hello' + ); + + const zipfiles_hello2 = listZipFiles('.serverless/hello2.zip'); + t.true( + zipfiles_hello2.includes('handler.py'), + 'handler.py is packaged in function hello2' + ); + t.deepEqual( + zipfiles_hello2.filter(filename => filename.endsWith('.pyc')), + [], + 'no pyc files packaged in function hello2' + ); + t.true( + zipfiles_hello2.includes(`flask${sep}__init__.py`), + 'flask is packaged in function hello2' + ); + + const zipfiles_hello3 = listZipFiles('.serverless/hello3.zip'); + t.true( + zipfiles_hello3.includes('handler.py'), + 'handler.py is packaged in function hello3' + ); + t.deepEqual( + zipfiles_hello3.filter(filename => filename.endsWith('.pyc')), + [], + 'no pyc files packaged in function hello3' + ); + t.false( + zipfiles_hello3.includes(`flask${sep}__init__.py`), + 'flask is NOT packaged in function hello3' + ); + + t.end(); +}); + +test('py3.6 can package only requirements of module', t => { + process.chdir('tests/individually'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['package']); + + const zipfiles_hello = listZipFiles( + '.serverless/module1-sls-py-req-test-indiv-dev-hello1.zip' + ); + t.true( + zipfiles_hello.includes('handler1.py'), + 'handler1.py is packaged at root level in function hello1' + ); + t.false( + zipfiles_hello.includes('handler2.py'), + 'handler2.py is NOT packaged at root level in function hello1' + ); + t.true( + zipfiles_hello.includes(`pyaml${sep}__init__.py`), + 'pyaml is packaged in function hello1' + ); + t.false( + zipfiles_hello.includes(`flask${sep}__init__.py`), + 'flask is NOT packaged in function hello1' + ); + + const zipfiles_hello2 = listZipFiles( + '.serverless/module2-sls-py-req-test-indiv-dev-hello2.zip' + ); + t.true( + zipfiles_hello2.includes('handler2.py'), + 'handler2.py is packaged at root level in function hello2' + ); + t.false( + zipfiles_hello2.includes('handler1.py'), + 'handler1.py is NOT packaged at root level in function hello2' + ); + t.false( + zipfiles_hello2.includes(`pyaml${sep}__init__.py`), + 'pyaml is NOT packaged in function hello2' + ); + t.true( + zipfiles_hello2.includes(`flask${sep}__init__.py`), + 'flask is packaged in function hello2' + ); + + t.end(); +}); + +test('py3.6 can package lambda-decorators using vendor and invidiually option', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--individually=true', '--vendor=./vendor', 'package']); + + const zipfiles_hello = listZipFiles('.serverless/hello.zip'); + t.true( + zipfiles_hello.includes('handler.py'), + 'handler.py is packaged at root level in function hello' + ); + t.true( + zipfiles_hello.includes(`flask${sep}__init__.py`), + 'flask is packaged in function hello' + ); + t.true( + zipfiles_hello.includes(`lambda_decorators.py`), + 'lambda_decorators.py is packaged in function hello' + ); + + const zipfiles_hello2 = listZipFiles('.serverless/hello2.zip'); + t.true( + zipfiles_hello2.includes('handler.py'), + 'handler.py is packaged at root level in function hello2' + ); + t.true( + zipfiles_hello2.includes(`flask${sep}__init__.py`), + 'flask is packaged in function hello2' + ); + t.true( + zipfiles_hello2.includes(`lambda_decorators.py`), + 'lambda_decorators.py is packaged in function hello2' + ); + + const zipfiles_hello3 = listZipFiles('.serverless/hello3.zip'); + t.true( + zipfiles_hello3.includes('handler.py'), + 'handler.py is packaged at root level in function hello3' + ); + t.false( + zipfiles_hello3.includes(`flask${sep}__init__.py`), + 'flask is NOT packaged in function hello3' + ); + t.false( + zipfiles_hello3.includes(`lambda_decorators.py`), + 'lambda_decorators.py is NOT packaged in function hello3' + ); + + t.end(); +}); + +test( + "Don't nuke execute perms when using individually", + t => { + process.chdir('tests/individually'); + const path = npm(['pack', '../..']); + const perm = '775'; + writeFileSync(`module1${sep}foobar`, '', { mode: perm }); + + npm(['i', path]); + sls(['package']); + + const zipfiles_hello = listZipFilesWithMetaData('.serverless/hello1.zip'); + + t.true( + zipfiles_hello['module1/foobar'].unixPermissions + .toString(8) + .slice(3, 6) === perm, + 'foobar has retained its executable file permissions' + ); + + t.end(); + }, + { skip: process.platform === 'win32' } +); + +test( + "Don't nuke execute perms when using individually w/docker", + t => { + process.chdir('tests/individually'); + const path = npm(['pack', '../..']); + const perm = '775'; + writeFileSync(`module1${sep}foobar`, '', { mode: perm }); + + npm(['i', path]); + sls(['--dockerizePip=true', 'package']); + + const zipfiles_hello = listZipFilesWithMetaData('.serverless/hello1.zip'); + + t.true( + zipfiles_hello['module1/foobar'].unixPermissions + .toString(8) + .slice(3, 6) === perm, + 'foobar has retained its executable file permissions' + ); + + t.end(); + }, + { skip: !canUseDocker() || process.platform === 'win32' } +); + +test('py3.6 uses download cache with useDownloadCache option', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--useDownloadCache=true', 'package']); + const cachepath = getUserCachePath(); + t.true( + pathExistsSync(`${cachepath}${sep}downloadCacheslspyc${sep}http`), + 'cache directoy exists' + ); + t.end(); +}); + +test('py3.6 uses download cache with cacheLocation option', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + '--useDownloadCache=true', + '--cacheLocation=.requirements-cache', + 'package' + ]); + t.true( + pathExistsSync(`.requirements-cache${sep}downloadCacheslspyc${sep}http`), + 'cache directoy exists' + ); + t.end(); +}); + +test( + 'py3.6 uses download cache with dockerizePip option', + t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--useDownloadCache=true', '--dockerizePip=true', 'package']); + const cachepath = getUserCachePath(); + t.true( + pathExistsSync(`${cachepath}${sep}downloadCacheslspyc${sep}http`), + 'cache directoy exists' + ); + t.end(); + }, + { skip: !canUseDocker() } +); + +test( + 'py3.6 uses download cache with dockerizePip + cacheLocation option', + t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + '--useDownloadCache=true', + '--dockerizePip=true', + '--cacheLocation=.requirements-cache', + 'package' + ]); + t.true( + pathExistsSync(`.requirements-cache${sep}downloadCacheslspyc${sep}http`), + 'cache directoy exists' + ); + t.end(); + }, + { skip: !canUseDocker() } +); + +test('py3.6 uses static and download cache', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--useDownloadCache=true', '--useStaticCache=true', 'package']); + const cachepath = getUserCachePath(); + const cacheFolderHash = md5Path('.serverless/requirements.txt'); + t.true( + pathExistsSync(`${cachepath}${sep}downloadCacheslspyc${sep}http`), + 'http exists in download-cache' + ); + t.true( + pathExistsSync(`${cachepath}${sep}${cacheFolderHash}_slspyc${sep}flask`), + 'flask exists in static-cache' + ); + t.end(); +}); + +test( + 'py3.6 uses static and download cache with dockerizePip option', + t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + '--useDownloadCache=true', + '--useStaticCache=true', + '--dockerizePip=true', + 'package' + ]); + const cachepath = getUserCachePath(); + const cacheFolderHash = md5Path('.serverless/requirements.txt'); + t.true( + pathExistsSync(`${cachepath}${sep}downloadCacheslspyc${sep}http`), + 'http exists in download-cache' + ); + t.true( + pathExistsSync(`${cachepath}${sep}${cacheFolderHash}_slspyc${sep}flask`), + 'flask exists in static-cache' + ); + t.end(); + }, + { skip: !canUseDocker() } +); + +test('py3.6 uses static cache', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--useStaticCache=true', 'package']); + const cachepath = getUserCachePath(); + const cacheFolderHash = md5Path('.serverless/requirements.txt'); + t.true( + pathExistsSync(`${cachepath}${sep}${cacheFolderHash}_slspyc${sep}flask`), + 'flask exists in static-cache' + ); + t.true( + pathExistsSync( + `${cachepath}${sep}${cacheFolderHash}_slspyc${sep}.completed_requirements` + ), + '.completed_requirements exists in static-cache' + ); + + // py3.6 checking that static cache actually pulls from cache (by poisoning it) + writeFileSync( + `${cachepath}${sep}${cacheFolderHash}_slspyc${sep}injected_file_is_bad_form`, + 'injected new file into static cache folder' + ); + sls(['--useStaticCache=true', 'package']); + + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true( + zipfiles.includes('injected_file_is_bad_form'), + "static cache is really used when running 'sls package' again" + ); + + t.end(); +}); + +test('py3.6 uses static cache with cacheLocation option', t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + const cachepath = '.requirements-cache'; + sls(['--useStaticCache=true', `--cacheLocation=${cachepath}`, 'package']); + const cacheFolderHash = md5Path('.serverless/requirements.txt'); + t.true( + pathExistsSync(`${cachepath}${sep}${cacheFolderHash}_slspyc${sep}flask`), + 'flask exists in static-cache' + ); + t.true( + pathExistsSync( + `${cachepath}${sep}${cacheFolderHash}_slspyc${sep}.completed_requirements` + ), + '.completed_requirements exists in static-cache' + ); + t.end(); +}); + +test( + 'py3.6 uses static cache with dockerizePip & slim option', + t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + '--useStaticCache=true', + '--dockerizePip=true', + '--slim=true', + 'package' + ]); + const cachepath = getUserCachePath(); + const cacheFolderHash = md5Path('.serverless/requirements.txt'); + t.true( + pathExistsSync(`${cachepath}${sep}${cacheFolderHash}_slspyc${sep}flask`), + 'flask exists in static-cache' + ); + t.true( + pathExistsSync( + `${cachepath}${sep}${cacheFolderHash}_slspyc${sep}.completed_requirements` + ), + '.completed_requirements exists in static-cache' + ); + + // py3.6 checking that static cache actually pulls from cache (by poisoning it) + writeFileSync( + `${cachepath}${sep}${cacheFolderHash}_slspyc${sep}injected_file_is_bad_form`, + 'injected new file into static cache folder' + ); + sls([ + '--useStaticCache=true', + '--dockerizePip=true', + '--slim=true', + 'package' + ]); + + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true( + zipfiles.includes('injected_file_is_bad_form'), + "static cache is really used when running 'sls package' again" + ); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('.pyc')), + [], + 'no pyc files are packaged' + ); + + t.end(); + }, + { skip: !canUseDocker() } +); + +test( + 'py3.6 uses download cache with dockerizePip & slim option', + t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + '--useDownloadCache=true', + '--dockerizePip=true', + '--slim=true', + 'package' + ]); + const cachepath = getUserCachePath(); + t.true( + pathExistsSync(`${cachepath}${sep}downloadCacheslspyc${sep}http`), + 'http exists in download-cache' + ); + + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.deepEqual( + zipfiles.filter(filename => filename.endsWith('.pyc')), + [], + 'no pyc files are packaged' + ); + + t.end(); + }, + { skip: !canUseDocker() } +); diff --git a/tests/base/_slimPatterns.yml b/tests/base/_slimPatterns.yml index 70f863cc..02c631b4 100644 --- a/tests/base/_slimPatterns.yml +++ b/tests/base/_slimPatterns.yml @@ -1,2 +1,2 @@ slimPatterns: - - "**/*.egg-info*" + - "**/__main__.py" diff --git a/tests/base/package.json b/tests/base/package.json index d37ade00..d13fd651 100644 --- a/tests/base/package.json +++ b/tests/base/package.json @@ -9,6 +9,6 @@ "author": "", "license": "ISC", "dependencies": { - "serverless-python-requirements": "file:serverless-python-requirements-4.2.4.tgz" + "serverless-python-requirements": "file:serverless-python-requirements-4.2.5.tgz" } } diff --git a/tests/base/requirements-w-hashes.txt b/tests/base/requirements-w-hashes.txt new file mode 100644 index 00000000..018a6fb9 --- /dev/null +++ b/tests/base/requirements-w-hashes.txt @@ -0,0 +1,89 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile --generate-hashes --output-file requirements-w-hashes.txt requirements.txt +# +boto3==1.9.50 \ + --hash=sha256:177e9dd53db5028bb43050da20cc7956287889fc172e5e6275a634e42a10beeb \ + --hash=sha256:8c63e616b91907037ab19236afbcf0057efb31411faf38b46f4590e634dc17ea +botocore==1.12.50 \ + --hash=sha256:07fae5a2b8cfb5a92c1dbee3f2feb4da7c471bcead7e18ce735babe5f39e270f \ + --hash=sha256:eeaa190f50ee05a56225ee78c64cb8bf0c3bf090ec605ca6c2f325aa3826a347 \ + # via boto3, s3transfer +bottle==0.12.13 \ + --hash=sha256:39b751aee0b167be8dffb63ca81b735bbf1dd0905b3bc42761efedee8f123355 +click==7.0 \ + --hash=sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13 \ + --hash=sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7 \ + # via flask +docutils==0.14 \ + --hash=sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6 \ + --hash=sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274 \ + --hash=sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6 \ + # via botocore +flask==1.0.2 \ + --hash=sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48 \ + --hash=sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05 +itsdangerous==1.1.0 \ + --hash=sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19 \ + --hash=sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749 \ + # via flask +jinja2==2.10 \ + --hash=sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd \ + --hash=sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4 \ + # via flask +jmespath==0.9.3 \ + --hash=sha256:6a81d4c9aa62caf061cb517b4d9ad1dd300374cd4706997aff9cd6aedd61fc64 \ + --hash=sha256:f11b4461f425740a1d908e9a3f7365c3d2e569f6ca68a2ff8bc5bcd9676edd63 \ + # via boto3, botocore +markupsafe==1.1.0 \ + --hash=sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432 \ + --hash=sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b \ + --hash=sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9 \ + --hash=sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af \ + --hash=sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834 \ + --hash=sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd \ + --hash=sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d \ + --hash=sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7 \ + --hash=sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b \ + --hash=sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3 \ + --hash=sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c \ + --hash=sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2 \ + --hash=sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7 \ + --hash=sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36 \ + --hash=sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1 \ + --hash=sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e \ + --hash=sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1 \ + --hash=sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c \ + --hash=sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856 \ + --hash=sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550 \ + --hash=sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492 \ + --hash=sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672 \ + --hash=sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401 \ + --hash=sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6 \ + --hash=sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6 \ + --hash=sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c \ + --hash=sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd \ + --hash=sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1 \ + # via jinja2 +python-dateutil==2.7.5 \ + --hash=sha256:063df5763652e21de43de7d9e00ccf239f953a832941e37be541614732cdfc93 \ + --hash=sha256:88f9287c0174266bb0d8cedd395cfba9c58e87e5ad86b2ce58859bc11be3cf02 \ + # via botocore +s3transfer==0.1.13 \ + --hash=sha256:90dc18e028989c609146e241ea153250be451e05ecc0c2832565231dacdf59c1 \ + --hash=sha256:c7a9ec356982d5e9ab2d4b46391a7d6a950e2b04c472419f5fdec70cc0ada72f \ + # via boto3 +six==1.11.0 \ + --hash=sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9 \ + --hash=sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb \ + # via python-dateutil +urllib3==1.24.1 \ + --hash=sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39 \ + --hash=sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22 \ + # via botocore +werkzeug==0.14.1 \ + --hash=sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c \ + --hash=sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b \ + # via flask diff --git a/tests/base/serverless.yml b/tests/base/serverless.yml index 23b3f793..a62dbc01 100644 --- a/tests/base/serverless.yml +++ b/tests/base/serverless.yml @@ -15,6 +15,9 @@ custom: slimPatternsAppendDefaults: ${opt:slimPatternsAppendDefaults, self:custom.defaults.slimPatternsAppendDefaults} vendor: ${opt:vendor, ''} fileName: ${opt:fileName, 'requirements.txt'} + useStaticCache: ${opt:useStaticCache, self:custom.defaults.useStaticCache} + useDownloadCache: ${opt:useDownloadCache, self:custom.defaults.useDownloadCache} + cacheLocation: ${opt:cacheLocation, ''} defaults: slim: false slimPatterns: false @@ -22,13 +25,15 @@ custom: zip: false dockerizePip: false individually: false + useStaticCache: false + useDownloadCache: false package: individually: ${opt:individually, self:custom.defaults.individually} exclude: - '**/*' - include: - - handler.py + include: + - 'handler.py' functions: hello: diff --git a/tests/individually/package.json b/tests/individually/package.json index f75ba960..d13fd651 100644 --- a/tests/individually/package.json +++ b/tests/individually/package.json @@ -9,6 +9,6 @@ "author": "", "license": "ISC", "dependencies": { - "serverless-python-requirements": "file:serverless-python-requirements-4.2.1.tgz" + "serverless-python-requirements": "file:serverless-python-requirements-4.2.5.tgz" } } diff --git a/tests/individually/serverless.yml b/tests/individually/serverless.yml index 9ae79d6e..c7cf3802 100644 --- a/tests/individually/serverless.yml +++ b/tests/individually/serverless.yml @@ -6,6 +6,7 @@ provider: package: individually: true + exclude: 'node_modules/**' custom: pythonRequirements: dockerizePip: ${opt:dockerizePip, self:custom.defaults.dockerizePip} diff --git a/tests/pipenv/_slimPatterns.yml b/tests/pipenv/_slimPatterns.yml index 70f863cc..02c631b4 100644 --- a/tests/pipenv/_slimPatterns.yml +++ b/tests/pipenv/_slimPatterns.yml @@ -1,2 +1,2 @@ slimPatterns: - - "**/*.egg-info*" + - "**/__main__.py" diff --git a/tests/pipenv/package.json b/tests/pipenv/package.json index f75ba960..d13fd651 100644 --- a/tests/pipenv/package.json +++ b/tests/pipenv/package.json @@ -9,6 +9,6 @@ "author": "", "license": "ISC", "dependencies": { - "serverless-python-requirements": "file:serverless-python-requirements-4.2.1.tgz" + "serverless-python-requirements": "file:serverless-python-requirements-4.2.5.tgz" } }