diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 25f419c4..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,47 +0,0 @@ -version: 2 -jobs: - build: - working_directory: ~/sls-py-req - machine: - image: circleci/classic - steps: - - checkout - # Build python3.6. gross. (based on my gist here: https://git.io/vxMFG ) - - run: | - sudo apt-get update - sudo apt-get install build-essential tk-dev libncurses5-dev libncursesw5-dev libreadline6-dev libdb5.3-dev libgdbm-dev libsqlite3-dev libssl-dev libbz2-dev libexpat1-dev liblzma-dev zlib1g-dev - wget https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tar.xz - tar xf Python-3.6.5.tar.xz - cd Python-3.6.5 - ./configure - make - sudo make altinstall - # other deps - - run: sudo apt -y update && sudo apt -y install python-pip python2.7 curl unzip - # upgrade python3.6 pip to latest - - run: sudo python3.6 -m pip install -U pip - # instal pipenv - - run: sudo python3.6 -m pip install pipenv pip-tools - # install poetry - - run: | - curl https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py -o get-poetry.py - python get-poetry.py --preview --yes - rm get-poetry.py - # install nodejs - - run: curl -sL https://deb.nodesource.com/setup_10.x | sudo bash - && sudo apt -y install nodejs - # install serverless & depcheck - - run: npm install -g serverless - # install deps - - run: npm i - # lint: - - run: npm run ci:lint - # test! - - run: | - export PATH="$HOME/.poetry/bin:$PATH" - export LC_ALL=C.UTF-8 - export LANG=C.UTF-8 - npm run test - - store_test_results: - path: ~/reports - - store_artifacts: - path: ~/reports diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..cb9c708b --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,25 @@ +name: Lint + +on: [push] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + node-version: [12] + steps: + - uses: actions/checkout@v2 + + - name: Set up Node ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: Install deps + run: npm install + + - name: Lint + run: npm run ci:lint diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..baf74a56 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,16 @@ +name: Publish + +on: [release] + +jobs: + publish-npm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 + with: + version: 12 + registry-url: https://registry.npmjs.org/ + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..662c731b --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,55 @@ +name: Test + +on: [push] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macOS-latest] + python-version: [3.6, 2.7] + node-version: [12] + steps: + - uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + + - name: Set up Node ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: Check python version + run: | + python --version + + - name: Install setuptools + run: python -m pip install --force setuptools wheel + + - name: Install pipenv / poetry + run: python -m pip install pipenv poetry + + - name: Install serverless + run: npm install -g serverless + + - name: Install deps + run: npm install + + - name: Test + run: npm run test + env: + LC_ALL: C.UTF-8 + LANG: C.UTF-8 + if: matrix.os != 'macOS-latest' + + - name: Test (Mac) + run: npm run test + env: + LC_ALL: en_US.UTF-8 + LANG: en_US.UTF-8 + if: matrix.os == 'macOS-latest' diff --git a/README.md b/README.md index 3196d8c8..87acbbe3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Serverless Python Requirements [![serverless](http://public.serverless.com/badges/v3.svg)](http://www.serverless.com) -[![CircleCI](https://circleci.com/gh/UnitedIncome/serverless-python-requirements.svg?style=shield)](https://circleci.com/gh/UnitedIncome/serverless-python-requirements) +![Github Actions](https://github.com/UnitedIncome/serverless-python-requirements/workflows/Test/badge.svg) [![npm](https://img.shields.io/npm/v/serverless-python-requirements.svg)](https://www.npmjs.com/package/serverless-python-requirements) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) diff --git a/lib/docker.js b/lib/docker.js index 46bbe028..1132f1de 100644 --- a/lib/docker.js +++ b/lib/docker.js @@ -73,6 +73,7 @@ function findTestFile(servicePath) { * @return {boolean} */ function tryBindPath(serverless, bindPath, testFile) { + const debug = process.env.SLS_DEBUG; const options = [ 'run', '--rm', @@ -83,13 +84,12 @@ function tryBindPath(serverless, bindPath, testFile) { `/test/${testFile}` ]; try { + if (debug) serverless.cli.log(`Trying bindPath ${bindPath} (${options})`); const ps = dockerCommand(options); - if (process.env.SLS_DEBUG) { - serverless.cli.log(`Trying bindPath ${bindPath} (${options})`); - serverless.cli.log(ps.stdout.trim()); - } + if (debug) serverless.cli.log(ps.stdout.trim()); return ps.stdout.trim() === `/test/${testFile}`; } catch (err) { + if (debug) serverless.cli.log(`Finding bindPath failed with ${err}`); return false; } } diff --git a/lib/pip.js b/lib/pip.js index ffe59797..7d1777a4 100644 --- a/lib/pip.js +++ b/lib/pip.js @@ -444,9 +444,8 @@ function copyVendors(vendorFolder, targetFolder, serverless) { function requirementsFileExists(servicePath, options, fileName) { if ( options.usePoetry && - fse.existsSync( - path.join(servicePath, 'pyproject.toml') && isPoetryProject(servicePath) - ) + fse.existsSync(path.join(servicePath, 'pyproject.toml')) && + isPoetryProject(servicePath) ) { return true; } diff --git a/lib/poetry.js b/lib/poetry.js index 108f90dd..320c1d85 100644 --- a/lib/poetry.js +++ b/lib/poetry.js @@ -62,7 +62,7 @@ function pyprojectTomlToRequirements() { fse.moveSync( sourceRequirements, path.join(this.servicePath, '.serverless', 'requirements.txt'), - { "overwrite": true } + { overwrite: true } ); } diff --git a/package.json b/package.json index 25b37eee..b5b3c394 100644 --- a/package.json +++ b/package.json @@ -44,11 +44,12 @@ "format": "prettier --write '{.,lib}/*.{js,md}'" }, "devDependencies": { - "eslint": "^6.8.0", + "eslint": "^5.16.0", "prettier": "^1", "cross-spawn": "*", - "deasync-promise": "*", - "tape": "*" + "tape": "*", + "tape-promise": "*", + "lodash": "^4.16.15" }, "dependencies": { "@iarna/toml": "^2.2.3", @@ -69,8 +70,15 @@ "eslintConfig": { "extends": "eslint:recommended", "env": { + "commonjs": true, "node": true, "es6": true + }, + "parserOptions": { + "ecmaVersion": 2018 + }, + "rules": { + "no-console": "off" } }, "prettier": { diff --git a/test.js b/test.js index c924e141..0b589b99 100644 --- a/test.js +++ b/test.js @@ -1,13 +1,12 @@ const crossSpawn = require('cross-spawn'); -const deasync = require('deasync-promise'); const glob = require('glob-all'); const JSZip = require('jszip'); const sha256File = require('sha256-file'); -const tape = require('tape'); +const tape = require('tape-promise/tape'); const { chmodSync, removeSync, - readFileSync, + readFile, copySync, writeFileSync, statSync, @@ -26,11 +25,7 @@ const mkCommand = cmd => (args, options = {}) => { args, Object.assign( { - env: Object.assign( - process.env, - { SLS_DEBUG: 't' }, - process.env.CI ? { LC_ALL: 'C.UTF-8', LANG: 'C.UTF-8' } : {} - ) + env: Object.assign({}, process.env, { SLS_DEBUG: 't' }) }, options ) @@ -55,60 +50,135 @@ const perl = mkCommand('perl'); const setup = () => { removeSync(getUserCachePath()); + process.chdir(initialWorkingDir); }; const teardown = () => { - [ - 'puck', - 'puck2', - 'puck3', - 'node_modules', - '.serverless', - '.requirements.zip', - '.requirements-cache', - 'foobar', - 'package-lock.json', - 'slimPatterns.yml', - 'serverless.yml.bak', - 'module1/foobar', - getUserCachePath(), - ...glob.sync('serverless-python-requirements-*.tgz') - ].map(path => removeSync(path)); - if (!process.cwd().endsWith('base with a space')) { - git(['checkout', 'serverless.yml']); + const cwd = process.cwd(); + if (!cwd.startsWith(initialWorkingDir)) { + throw new Error(`Somehow cd'd into ${cwd}`); + } + if (cwd != initialWorkingDir) { + [ + 'puck', + 'puck2', + 'puck3', + 'node_modules', + '.serverless', + '.requirements.zip', + '.requirements-cache', + 'foobar', + 'package-lock.json', + 'slimPatterns.yml', + 'serverless.yml.bak', + 'module1/foobar', + getUserCachePath(), + ...glob.sync('serverless-python-requirements-*.tgz') + ].map(path => removeSync(path)); + if (!cwd.endsWith('base with a space')) { + try { + git(['checkout', 'serverless.yml']); + } catch (err) { + console.error( + `At ${cwd} failed to checkout 'serverless.yml' with ${err}.` + ); + throw err; + } + } + process.chdir(initialWorkingDir); } - process.chdir(initialWorkingDir); removeSync('tests/base with a space'); }; +const testFilter = (() => { + const elems = process.argv.slice(2); // skip ['node', 'test.js'] + if (elems.length) { + return desc => + elems.some(text => desc.search(text) != -1) ? tape.test : tape.test.skip; + } else { + return () => tape.test; + } +})(); + const test = (desc, func, opts = {}) => - tape.test(desc, opts, t => { + testFilter(desc)(desc, opts, async t => { setup(); + let ended = false; try { - func(t); + await func(t); + ended = true; } catch (err) { t.fail(err); - t.end(); } finally { - teardown(); + try { + teardown(); + } catch (err) { + t.fail(err); + } + if (!ended) t.end(); } }); -const getPythonBin = (version = 3) => { - if (![2, 3].includes(version)) throw new Error('version must be 2 or 3'); - if (process.platform === 'win32') - return `c:/python${version === 2 ? '27' : '36'}-x64/python.exe`; - else return version === 2 ? 'python2.7' : 'python3.6'; +const availablePythons = (() => { + const binaries = []; + const mapping = {}; + if (process.env.USE_PYTHON) { + binaries.push( + ...process.env.USE_PYTHON.split(',').map(v => v.toString().trim()) + ); + } else { + // For running outside of CI + binaries.push('python'); + } + const exe = process.platform === 'win32' ? '.exe' : ''; + for (const bin of binaries) { + const python = `${bin}${exe}`; + const { stdout, status } = crossSpawn.sync(python, [ + '-c', + 'import sys; sys.stdout.write(".".join(map(str, sys.version_info[:2])))' + ]); + const ver = stdout && stdout.toString().trim(); + if (!status && ver) { + for (const recommend of [ver, ver.split('.')[0]]) { + if (!mapping[recommend]) { + mapping[recommend] = python; + } + } + } + } + if (!Object.entries(mapping).length) { + throw new Error('No pythons found'); + } + return mapping; +})(); + +const getPythonBin = version => { + const bin = availablePythons[String(version)]; + if (!bin) throw new Error(`No python version ${version} available`); + return bin; +}; + +const hasPython = version => { + return Boolean(availablePythons[String(version)]); +}; + +const listZipFiles = async function(filename) { + const file = await readFile(filename); + const zip = await new JSZip().loadAsync(file); + return Object.keys(zip.files); +}; + +const listZipFilesWithMetaData = async function(filename) { + const file = await readFile(filename); + const zip = await new JSZip().loadAsync(file); + return Object(zip.files); }; -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')); - const reqsZip = deasync(new JSZip().loadAsync(reqsBuffer)); +const listRequirementsZipFiles = async function(filename) { + const file = await readFile(filename); + const zip = await new JSZip().loadAsync(file); + const reqsBuffer = await zip.file('.requirements.zip').async('nodebuffer'); + const reqsZip = await new JSZip().loadAsync(reqsBuffer); return Object.keys(reqsZip.files); }; @@ -122,173 +192,214 @@ const canUseDocker = () => { return result.status === 0; }; -test('default pythonBin can package flask with default options', t => { - process.chdir('tests/base'); - 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.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); - t.end(); -}); - -test('py3.6 packages have the same hash', t => { - process.chdir('tests/base'); - const path = npm(['pack', '../..']); - npm(['i', path]); - sls(['package']); - const fileHash = sha256File('.serverless/sls-py-req-test.zip'); - sls(['package']); - t.equal( - sha256File('.serverless/sls-py-req-test.zip'), - fileHash, - 'packages have the same hash' - ); - t.end(); -}); - -test('py3.6 can package flask with default options', t => { - process.chdir('tests/base'); - const path = npm(['pack', '../..']); - npm(['i', path]); - 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.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is 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(); -}); - -test('py3.6 can package flask with nested', t => { - process.chdir('tests/base'); - const path = npm(['pack', '../..']); - npm(['i', path]); - sls([ - `--pythonBin=${getPythonBin(3)}`, - '--fileName=requirements-w-nested.txt', - '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(`boto3${sep}__init__.py`), 'boto3 is packaged'); - t.end(); -}); - -test('py3.6 can package flask with zip option', t => { - process.chdir('tests/base'); - 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('py3.6 can package flask with slim option', t => { - process.chdir('tests/base'); - const path = npm(['pack', '../..']); - npm(['i', path]); - sls([`--pythonBin=${getPythonBin(3)}`, '--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('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', - '-e', - 's/(pythonRequirements:$)/\\1\\n noDeploy: [bottle]/', - 'serverless.yml' - ]); - 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(`bottle.py`), 'bottle is NOT packaged'); - t.end(); -}); +// Skip if running on these platforms. +const brokenOn = (...platforms) => platforms.indexOf(process.platform) != -1; + +test( + 'default pythonBin can package flask with default options', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['package']); + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); + t.end(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'py3.6 packages have the same hash', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['package']); + const fileHash = sha256File('.serverless/sls-py-req-test.zip'); + sls(['package']); + t.equal( + sha256File('.serverless/sls-py-req-test.zip'), + fileHash, + 'packages have the same hash' + ); + t.end(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'py3.6 can package flask with default options', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([`--pythonBin=${getPythonBin(3)}`, 'package']); + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); + t.end(); + }, + { skip: !hasPython(3) } +); + +test( + 'py3.6 can package flask with hashes', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + `--pythonBin=${getPythonBin(3)}`, + '--fileName=requirements-w-hashes.txt', + 'package' + ]); + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.end(); + }, + { skip: !hasPython(3) || brokenOn('win32') } +); + +test( + 'py3.6 can package flask with nested', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + `--pythonBin=${getPythonBin(3)}`, + '--fileName=requirements-w-nested.txt', + 'package' + ]); + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); + t.end(); + }, + { skip: !hasPython(3) } +); + +test( + 'py3.6 can package flask with zip option', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([`--pythonBin=${getPythonBin(3)}`, '--zip=true', 'package']); + const zipfiles = await 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(); + }, + { skip: !hasPython(3) } +); + +test( + 'py3.6 can package flask with slim option', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([`--pythonBin=${getPythonBin(3)}`, '--slim=true', 'package']); + const zipfiles = await 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(); + }, + { skip: !hasPython(3) } +); + +test( + 'py3.6 can package flask with slim & slimPatterns options', + async t => { + process.chdir('tests/base'); + copySync('_slimPatterns.yml', 'slimPatterns.yml'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--slim=true', 'package']); + const zipfiles = await 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(); + }, + { skip: !hasPython(3.6) } +); + +test( + "py3.6 doesn't package bottle with noDeploy option", + async 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)}`, 'package']); + const zipfiles = await 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(); + }, + { skip: !hasPython(3) } +); test( 'py3.6 can package flask with dockerizePip option', - t => { + async 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'); + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(3.6) || brokenOn('win32') } ); test( 'py3.6 can package flask with slim & dockerizePip option', - t => { + async 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'); + const zipfiles = await 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')), @@ -301,19 +412,18 @@ test( ); t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(3.6) || brokenOn('win32') } ); test( 'py3.6 can package flask with slim & dockerizePip & slimPatterns options', - t => { + async 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'); + const zipfiles = await 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')), @@ -327,19 +437,19 @@ test( ); t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(3.6) || brokenOn('win32') } ); test( 'py3.6 can package flask with zip & dockerizePip option', - t => { + async 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( + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); + const zippedReqs = await listRequirementsZipFiles( '.serverless/sls-py-req-test.zip' ); t.true( @@ -360,19 +470,19 @@ test( ); t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(3.6) || brokenOn('win32') } ); test( 'py3.6 can package flask with zip & slim & dockerizePip option', - t => { + async 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( + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); + const zippedReqs = await listRequirementsZipFiles( '.serverless/sls-py-req-test.zip' ); t.true( @@ -393,60 +503,85 @@ test( ); 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.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is 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( - zipfiles.filter(filename => filename.endsWith('__main__.py')).length > 0, - '__main__.py files are packaged' - ); - t.end(); -}); - -test('py2.7 can package flask with zip option', t => { - process.chdir('tests/base'); - const path = npm(['pack', '../..']); - npm(['i', path]); - sls([`--pythonBin=${getPythonBin(2)}`, '--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(); -}); + { skip: !canUseDocker() || !hasPython(3.6) || brokenOn('win32') } +); + +test( + 'py2.7 can package flask with default options', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([`--pythonBin=${getPythonBin(2)}`, '--runtime=python2.7', 'package']); + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); + t.end(); + }, + { skip: !hasPython(2) } +); + +test( + 'py2.7 can package flask with slim option', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + `--pythonBin=${getPythonBin(2)}`, + '--runtime=python2.7', + '--slim=true', + 'package' + ]); + const zipfiles = await 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(); + }, + { skip: !hasPython(2) } +); + +test( + 'py2.7 can package flask with zip option', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([ + `--pythonBin=${getPythonBin(2)}`, + '--runtime=python2.7', + '--zip=true', + 'package' + ]); + const zipfiles = await 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(); + }, + { skip: !hasPython(2) } +); test( 'py2.7 can package flask with slim & dockerizePip & slimPatterns options', - t => { + async t => { process.chdir('tests/base'); copySync('_slimPatterns.yml', 'slimPatterns.yml'); @@ -454,11 +589,12 @@ test( npm(['i', path]); sls([ `--pythonBin=${getPythonBin(2)}`, + '--runtime=python2.7', '--dockerizePip=true', '--slim=true', 'package' ]); - const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + const zipfiles = await 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')), @@ -472,42 +608,47 @@ test( ); t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(2) || brokenOn('win32') } ); -test("py2.7 doesn't package bottle with noDeploy 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(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(`bottle.py`), 'bottle is NOT packaged'); - t.end(); -}); +test( + "py2.7 doesn't package bottle with noDeploy option", + async 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(2)}`, '--runtime=python2.7', 'package']); + const zipfiles = await 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(); + }, + { skip: !hasPython(2) } +); test( 'py2.7 can package flask with zip & dockerizePip option', - t => { + async t => { process.chdir('tests/base'); const path = npm(['pack', '../..']); npm(['i', path]); sls([ `--pythonBin=${getPythonBin(2)}`, + '--runtime=python2.7', '--dockerizePip=true', '--zip=true', 'package' ]); - const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); - const zippedReqs = listRequirementsZipFiles( + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); + const zippedReqs = await listRequirementsZipFiles( '.serverless/sls-py-req-test.zip' ); t.true( @@ -528,25 +669,26 @@ test( ); t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(2) || brokenOn('win32') } ); test( 'py2.7 can package flask with zip & slim & dockerizePip option', - t => { + async t => { process.chdir('tests/base'); const path = npm(['pack', '../..']); npm(['i', path]); sls([ `--pythonBin=${getPythonBin(2)}`, + '--runtime=python2.7', '--dockerizePip=true', '--zip=true', '--slim=true', 'package' ]); - const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); - const zippedReqs = listRequirementsZipFiles( + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); + const zippedReqs = await listRequirementsZipFiles( '.serverless/sls-py-req-test.zip' ); t.true( @@ -567,38 +709,44 @@ test( ); t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(2) || brokenOn('win32') } ); test( 'py2.7 can package flask with dockerizePip option', - t => { + async t => { process.chdir('tests/base'); const path = npm(['pack', '../..']); npm(['i', path]); - sls([`--pythonBin=${getPythonBin(2)}`, '--dockerizePip=true', 'package']); + sls([ + `--pythonBin=${getPythonBin(2)}`, + '--runtime=python2.7', + '--dockerizePip=true', + 'package' + ]); - const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(2) || brokenOn('win32') } ); test( 'py2.7 can package flask with slim & dockerizePip option', - t => { + async t => { process.chdir('tests/base'); const path = npm(['pack', '../..']); npm(['i', path]); sls([ `--pythonBin=${getPythonBin(2)}`, + '--runtime=python2.7', '--dockerizePip=true', '--slim=true', 'package' ]); - const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + const zipfiles = await 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')), @@ -611,12 +759,12 @@ test( ); t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(2) || brokenOn('win32') } ); test( 'py2.7 can package flask with slim & dockerizePip & slimPatterns options', - t => { + async t => { process.chdir('tests/base'); copySync('_slimPatterns.yml', 'slimPatterns.yml'); @@ -624,11 +772,12 @@ test( npm(['i', path]); sls([ `--pythonBin=${getPythonBin(2)}`, + '--runtime=python2.7', '--dockerizePip=true', '--slim=true', 'package' ]); - const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + const zipfiles = await 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')), @@ -642,249 +791,314 @@ test( ); t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(2) || brokenOn('win32') } ); -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.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); - t.false( - zipfiles.includes(`pytest${sep}__init__.py`), - 'dev-package pytest 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('non build pyproject.toml uses requirements.txt', t => { - process.chdir('tests/non_build_pyproject'); - 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.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); - t.end(); -}); - -test('non poetry pyproject.toml without requirements.txt packages handler only', t => { - process.chdir('tests/non_poetry_pyproject'); - const path = npm(['pack', '../..']); - npm(['i', path]); - sls(['package']); - const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); - t.true(zipfiles.includes(`handler.py`), 'handler is packaged'); - t.end(); -}); - -test('poetry py3.6 can package flask with default options', t => { - process.chdir('tests/poetry'); - 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.true(zipfiles.includes(`bottle.py`), 'bottle is packaged'); - t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); - t.end(); -}); - -test('poetry py3.6 can package flask with slim option', t => { - process.chdir('tests/poetry'); - 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('poetry py3.6 can package flask with slim & slimPatterns options', t => { - process.chdir('tests/poetry'); - - 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('poetry py3.6 can package flask with zip option', t => { - process.chdir('tests/poetry'); - 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("poetry py3.6 doesn't package bottle with noDeploy option", t => { - process.chdir('tests/poetry'); - 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(`boto3${sep}__init__.py`), 'boto3 is packaged'); - t.true( - zipfiles.includes(`lambda_decorators.py`), - 'lambda_decorators.py is packaged' - ); - t.end(); -}); +test( + 'pipenv py3.6 can package flask with default options', + async t => { + process.chdir('tests/pipenv'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['package']); + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); + t.false( + zipfiles.includes(`pytest${sep}__init__.py`), + 'dev-package pytest is NOT packaged' + ); + t.end(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'pipenv py3.6 can package flask with slim option', + async t => { + process.chdir('tests/pipenv'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--slim=true', 'package']); + const zipfiles = await 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(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'pipenv py3.6 can package flask with slim & slimPatterns options', + async t => { + process.chdir('tests/pipenv'); + + copySync('_slimPatterns.yml', 'slimPatterns.yml'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--slim=true', 'package']); + const zipfiles = await 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(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'pipenv py3.6 can package flask with zip option', + async t => { + process.chdir('tests/pipenv'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([`--pythonBin=${getPythonBin(3)}`, '--zip=true', 'package']); + const zipfiles = await 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(); + }, + { skip: !hasPython(3.6) } +); + +test( + "pipenv py3.6 doesn't package bottle with noDeploy option", + async 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 = await 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(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'non build pyproject.toml uses requirements.txt', + async t => { + process.chdir('tests/non_build_pyproject'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['package']); + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); + t.end(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'non poetry pyproject.toml without requirements.txt packages handler only', + async t => { + process.chdir('tests/non_poetry_pyproject'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['package']); + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`handler.py`), 'handler is packaged'); + t.end(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'poetry py3.6 can package flask with default options', + async t => { + process.chdir('tests/poetry'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['package']); + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true(zipfiles.includes(`bottle.py`), 'bottle is packaged'); + t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); + t.end(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'poetry py3.6 can package flask with slim option', + async t => { + process.chdir('tests/poetry'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--slim=true', 'package']); + const zipfiles = await 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(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'poetry py3.6 can package flask with slim & slimPatterns options', + async t => { + process.chdir('tests/poetry'); + + copySync('_slimPatterns.yml', 'slimPatterns.yml'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--slim=true', 'package']); + const zipfiles = await 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(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'poetry py3.6 can package flask with zip option', + async t => { + process.chdir('tests/poetry'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([`--pythonBin=${getPythonBin(3)}`, '--zip=true', 'package']); + const zipfiles = await 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(); + }, + { skip: !hasPython(3) } +); + +test( + "poetry py3.6 doesn't package bottle with noDeploy option", + async t => { + process.chdir('tests/poetry'); + const path = npm(['pack', '../..']); + npm(['i', path]); + perl([ + '-p', + '-i.bak', + '-e', + 's/(pythonRequirements:$)/\\1\\n noDeploy: [bottle]/', + 'serverless.yml' + ]); + sls(['package']); + const zipfiles = await 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(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'py3.6 can package flask with zip option and no explicit include', + async 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 = await 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(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'py3.6 can package lambda-decorators using vendor option', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls([`--vendor=./vendor`, 'package']); + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); + t.true( + zipfiles.includes(`lambda_decorators.py`), + 'lambda_decorators.py is packaged' + ); + t.end(); + }, + { skip: !hasPython(3.6) } +); test( "Don't nuke execute perms", - t => { + async t => { process.chdir('tests/base'); const path = npm(['pack', '../..']); const perm = '775'; @@ -901,7 +1115,7 @@ test( chmodSync(`foobar`, perm); sls(['--vendor=./vendor', 'package']); - const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); t.true( @@ -910,7 +1124,7 @@ test( ); t.true(zipfiles.includes(`foobar`), 'foobar is packaged'); - const zipfiles_with_metadata = listZipFilesWithMetaData( + const zipfiles_with_metadata = await listZipFilesWithMetaData( '.serverless/sls-py-req-test.zip' ); t.true( @@ -925,128 +1139,183 @@ test( zipfiles_with_metadata['bin/flask'].unixPermissions === flaskPerm, 'bin/flask has retained its executable file permissions' ); - + + t.end(); + }, + { skip: process.platform === 'win32' || !hasPython(3.6) } +); + +test( + 'py3.6 can package flask in a project with a space in it', + async 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 = await listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); + t.end(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'py3.6 can package flask in a project with a space in it with docker', + async 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 = await listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged'); + t.end(); + }, + { skip: !canUseDocker() || !hasPython(3.6) || brokenOn('win32') } +); + +test( + 'py3.6 supports custom file name with fileName option', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + writeFileSync('puck', 'requests'); + npm(['i', path]); + sls(['--fileName=puck', 'package']); + const zipfiles = await 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(); + }, + { skip: !hasPython(3.6) } +); + +test( + "py3.6 doesn't package bottle with zip option", + async 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 = await listZipFiles('.serverless/sls-py-req-test.zip'); + const zippedReqs = await 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(); + }, + { skip: !hasPython(3) } +); + +test( + 'py3.6 can package flask with slim, slimPatterns & slimPatternsAppendDefaults=false options', + async 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 = await 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: process.platform === 'win32' } + { skip: !hasPython(3.6) } ); -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.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is 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'); + 'py3.6 can package flask with slim & dockerizePip & slimPatterns & slimPatternsAppendDefaults=false options', + async t => { + process.chdir('tests/base'); + copySync('_slimPatterns.yml', 'slimPatterns.yml'); const path = npm(['pack', '../..']); npm(['i', path]); - sls(['--dockerizePip=true', 'package']); - const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + sls([ + '--dockerizePip=true', + '--slim=true', + '--slimPatternsAppendDefaults=false', + 'package' + ]); + + const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip'); t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); - t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 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() } + { skip: !canUseDocker() || !hasPython(3.6) || brokenOn('win32') } ); -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( - 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 slim & dockerizePip & slimPatterns & slimPatternsAppendDefaults=false options', - t => { + 'py2.7 can package flask with slim & slimPatterns & slimPatternsAppendDefaults=false options', + async 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'); + const zipfiles = await 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, @@ -1059,38 +1328,12 @@ test( ); t.end(); }, - { skip: !canUseDocker() } + { skip: !hasPython(2.7) || brokenOn('win32') } ); -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 => { + async t => { process.chdir('tests/base'); copySync('_slimPatterns.yml', 'slimPatterns.yml'); const path = npm(['pack', '../..']); @@ -1102,7 +1345,7 @@ test( '--slimPatternsAppendDefaults=false', 'package' ]); - const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + const zipfiles = await 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, @@ -1115,504 +1358,541 @@ test( ); t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(2.7) || brokenOn('win32') } ); -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( + 'pipenv py3.6 can package flask with slim & slimPatterns & slimPatternsAppendDefaults=false option', + async 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('poetry py3.6 can package flask with slim & slimPatterns & slimPatternsAppendDefaults=false option', t => { - process.chdir('tests/poetry'); - 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.false( - zipfiles_hello.includes(`fn2${sep}__init__.py`), - 'fn2 is NOT packaged in function hello' - ); - t.true( - zipfiles_hello.includes('handler.py'), - 'handler.py is packaged in function hello' - ); - t.false( - zipfiles_hello.includes(`dataclasses.py`), - 'dataclasses is NOT packaged in function hello' - ); - t.true( - zipfiles_hello.includes(`flask${sep}__init__.py`), - 'flask is packaged in function hello' - ); + sls(['--slim=true', '--slimPatternsAppendDefaults=false', 'package']); + const zipfiles = await 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: !hasPython(3.6) } +); - const zipfiles_hello2 = listZipFiles('.serverless/hello2.zip'); - t.false( - zipfiles_hello2.includes(`fn2${sep}__init__.py`), - 'fn2 is NOT packaged in function hello2' - ); - t.true( - zipfiles_hello2.includes('handler.py'), - 'handler.py is packaged in function hello2' - ); - t.false( - zipfiles_hello2.includes(`dataclasses.py`), - 'dataclasses is NOT packaged in function hello2' - ); - t.true( - zipfiles_hello2.includes(`flask${sep}__init__.py`), - 'flask is packaged in function hello2' - ); +test( + 'poetry py3.6 can package flask with slim & slimPatterns & slimPatternsAppendDefaults=false option', + async t => { + process.chdir('tests/poetry'); + copySync('_slimPatterns.yml', 'slimPatterns.yml'); + const path = npm(['pack', '../..']); + npm(['i', path]); - const zipfiles_hello3 = listZipFiles('.serverless/hello3.zip'); - t.false( - zipfiles_hello3.includes(`fn2${sep}__init__.py`), - 'fn2 is NOT packaged in function hello3' - ); - t.true( - zipfiles_hello3.includes('handler.py'), - 'handler.py is packaged in function hello3' - ); - t.false( - zipfiles_hello3.includes(`dataclasses.py`), - 'dataclasses is NOT packaged in function hello3' - ); - t.false( - zipfiles_hello3.includes(`flask${sep}__init__.py`), - 'flask is NOT packaged in function hello3' - ); + sls(['--slim=true', '--slimPatternsAppendDefaults=false', 'package']); + const zipfiles = await 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: !hasPython(3.6) } +); - const zipfiles_hello4 = listZipFiles( - '.serverless/fn2-sls-py-req-test-dev-hello4.zip' - ); - t.false( - zipfiles_hello4.includes(`fn2${sep}__init__.py`), - 'fn2 is NOT packaged in function hello4' - ); - t.true( - zipfiles_hello4.includes('fn2_handler.py'), - 'fn2_handler is packaged in the zip-root in function hello4' - ); - t.true( - zipfiles_hello4.includes(`dataclasses.py`), - 'dataclasses is packaged in function hello4' - ); - t.false( - zipfiles_hello4.includes(`flask${sep}__init__.py`), - 'flask is NOT packaged in function hello4' - ); +test( + 'py3.6 can package flask with package individually option', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--individually=true', 'package']); - t.end(); -}); + const zipfiles_hello = await listZipFiles('.serverless/hello.zip'); + t.false( + zipfiles_hello.includes(`fn2${sep}__init__.py`), + 'fn2 is NOT packaged in function hello' + ); + t.true( + zipfiles_hello.includes('handler.py'), + 'handler.py is packaged in function hello' + ); + t.false( + zipfiles_hello.includes(`dataclasses.py`), + 'dataclasses is NOT packaged in function hello' + ); + t.true( + zipfiles_hello.includes(`flask${sep}__init__.py`), + 'flask is packaged in function hello' + ); -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_hello2 = await listZipFiles('.serverless/hello2.zip'); + t.false( + zipfiles_hello2.includes(`fn2${sep}__init__.py`), + 'fn2 is NOT packaged in function hello2' + ); + t.true( + zipfiles_hello2.includes('handler.py'), + 'handler.py is packaged in function hello2' + ); + t.false( + zipfiles_hello2.includes(`dataclasses.py`), + 'dataclasses is NOT packaged in function hello2' + ); + t.true( + zipfiles_hello2.includes(`flask${sep}__init__.py`), + 'flask is packaged in function hello2' + ); - 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' - ); - t.false( - zipfiles_hello.includes(`dataclasses.py`), - 'dataclasses is NOT packaged in function hello' - ); + const zipfiles_hello3 = await listZipFiles('.serverless/hello3.zip'); + t.false( + zipfiles_hello3.includes(`fn2${sep}__init__.py`), + 'fn2 is NOT packaged in function hello3' + ); + t.true( + zipfiles_hello3.includes('handler.py'), + 'handler.py is packaged in function hello3' + ); + t.false( + zipfiles_hello3.includes(`dataclasses.py`), + 'dataclasses is NOT packaged in function hello3' + ); + t.false( + zipfiles_hello3.includes(`flask${sep}__init__.py`), + 'flask is NOT packaged in function hello3' + ); - 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' - ); - t.false( - zipfiles_hello2.includes(`dataclasses.py`), - 'dataclasses is NOT packaged in function hello2' - ); + const zipfiles_hello4 = await listZipFiles( + '.serverless/fn2-sls-py-req-test-dev-hello4.zip' + ); + t.false( + zipfiles_hello4.includes(`fn2${sep}__init__.py`), + 'fn2 is NOT packaged in function hello4' + ); + t.true( + zipfiles_hello4.includes('fn2_handler.py'), + 'fn2_handler is packaged in the zip-root in function hello4' + ); + t.true( + zipfiles_hello4.includes(`dataclasses.py`), + 'dataclasses is packaged in function hello4' + ); + t.false( + zipfiles_hello4.includes(`flask${sep}__init__.py`), + 'flask is NOT packaged in function hello4' + ); - 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(); + }, + { skip: !hasPython(3.6) } +); - const zipfiles_hello4 = listZipFiles( - '.serverless/fn2-sls-py-req-test-dev-hello4.zip' - ); - t.true( - zipfiles_hello4.includes('fn2_handler.py'), - 'fn2_handler is packaged in the zip-root in function hello4' - ); - t.true( - zipfiles_hello4.includes(`dataclasses.py`), - 'dataclasses is packaged in function hello4' - ); - t.false( - zipfiles_hello4.includes(`flask${sep}__init__.py`), - 'flask is NOT packaged in function hello4' - ); - t.deepEqual( - zipfiles_hello4.filter(filename => filename.endsWith('.pyc')), - [], - 'no pyc files packaged in function hello4' - ); +test( + 'py3.6 can package flask with package individually & slim option', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--individually=true', '--slim=true', 'package']); - t.end(); -}); + const zipfiles_hello = await 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' + ); + t.false( + zipfiles_hello.includes(`dataclasses.py`), + 'dataclasses is NOT packaged in function hello' + ); -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_hello2 = await 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' + ); + t.false( + zipfiles_hello2.includes(`dataclasses.py`), + 'dataclasses is NOT packaged in function hello2' + ); - 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' - ); - t.false( - zipfiles_hello.includes(`dataclasses.py`), - 'dataclasses is NOT packaged in function hello' - ); + const zipfiles_hello3 = await 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' + ); - 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' - ); - t.false( - zipfiles_hello2.includes(`dataclasses.py`), - 'dataclasses is NOT packaged in function hello2' - ); + const zipfiles_hello4 = await listZipFiles( + '.serverless/fn2-sls-py-req-test-dev-hello4.zip' + ); + t.true( + zipfiles_hello4.includes('fn2_handler.py'), + 'fn2_handler is packaged in the zip-root in function hello4' + ); + t.true( + zipfiles_hello4.includes(`dataclasses.py`), + 'dataclasses is packaged in function hello4' + ); + t.false( + zipfiles_hello4.includes(`flask${sep}__init__.py`), + 'flask is NOT packaged in function hello4' + ); + t.deepEqual( + zipfiles_hello4.filter(filename => filename.endsWith('.pyc')), + [], + 'no pyc files packaged in function hello4' + ); - 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.false( - zipfiles_hello3.includes(`dataclasses.py`), - 'dataclasses is NOT packaged in function hello3' - ); + t.end(); + }, + { skip: !hasPython(3.6) } +); - const zipfiles_hello4 = listZipFiles( - '.serverless/fn2-sls-py-req-test-dev-hello4.zip' - ); - t.true( - zipfiles_hello4.includes('fn2_handler.py'), - 'fn2_handler is packaged in the zip-root in function hello4' - ); - t.true( - zipfiles_hello4.includes(`dataclasses.py`), - 'dataclasses is packaged in function hello4' - ); - t.false( - zipfiles_hello4.includes(`flask${sep}__init__.py`), - 'flask is NOT packaged in function hello4' - ); +test( + 'py2.7 can package flask with package individually option', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--individually=true', '--runtime=python2.7', 'package']); + + const zipfiles_hello = await 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' + ); + t.false( + zipfiles_hello.includes(`dataclasses.py`), + 'dataclasses is NOT packaged in function hello' + ); + + const zipfiles_hello2 = await 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' + ); + t.false( + zipfiles_hello2.includes(`dataclasses.py`), + 'dataclasses is NOT packaged in function hello2' + ); + + const zipfiles_hello3 = await 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.false( + zipfiles_hello3.includes(`dataclasses.py`), + 'dataclasses is NOT packaged in function hello3' + ); - t.end(); -}); + const zipfiles_hello4 = await listZipFiles( + '.serverless/fn2-sls-py-req-test-dev-hello4.zip' + ); + t.true( + zipfiles_hello4.includes('fn2_handler.py'), + 'fn2_handler is packaged in the zip-root in function hello4' + ); + t.true( + zipfiles_hello4.includes(`dataclasses.py`), + 'dataclasses is packaged in function hello4' + ); + t.false( + zipfiles_hello4.includes(`flask${sep}__init__.py`), + 'flask is NOT packaged in function hello4' + ); + + t.end(); + }, + { skip: !hasPython(2.7) } +); -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']); +test( + 'py2.7 can package flask with package individually & slim option', + async 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' - ); - t.false( - zipfiles_hello.includes(`dataclasses.py`), - 'dataclasses is NOT packaged in function hello' - ); + const zipfiles_hello = await 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' + ); + t.false( + zipfiles_hello.includes(`dataclasses.py`), + 'dataclasses is NOT 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' - ); - t.false( - zipfiles_hello2.includes(`dataclasses.py`), - 'dataclasses is NOT packaged in function hello2' - ); + const zipfiles_hello2 = await 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' + ); + t.false( + zipfiles_hello2.includes(`dataclasses.py`), + 'dataclasses is NOT 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.false( - zipfiles_hello3.includes(`dataclasses.py`), - 'dataclasses is NOT packaged in function hello3' - ); + const zipfiles_hello3 = await 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.false( + zipfiles_hello3.includes(`dataclasses.py`), + 'dataclasses is NOT packaged in function hello3' + ); - const zipfiles_hello4 = listZipFiles( - '.serverless/fn2-sls-py-req-test-dev-hello4.zip' - ); - t.true( - zipfiles_hello4.includes('fn2_handler.py'), - 'fn2_handler is packaged in the zip-root in function hello4' - ); - t.true( - zipfiles_hello4.includes(`dataclasses.py`), - 'dataclasses is packaged in function hello4' - ); - t.false( - zipfiles_hello4.includes(`flask${sep}__init__.py`), - 'flask is NOT packaged in function hello4' - ); + const zipfiles_hello4 = await listZipFiles( + '.serverless/fn2-sls-py-req-test-dev-hello4.zip' + ); + t.true( + zipfiles_hello4.includes('fn2_handler.py'), + 'fn2_handler is packaged in the zip-root in function hello4' + ); + t.true( + zipfiles_hello4.includes(`dataclasses.py`), + 'dataclasses is packaged in function hello4' + ); + t.false( + zipfiles_hello4.includes(`flask${sep}__init__.py`), + 'flask is NOT packaged in function hello4' + ); - t.end(); -}); + t.end(); + }, + { skip: !hasPython(2.7) } +); -test('py3.6 can package only requirements of module', t => { - process.chdir('tests/individually'); - const path = npm(['pack', '../..']); - npm(['i', path]); - sls(['package']); +test( + 'py3.6 can package only requirements of module', + async 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.true( - zipfiles_hello.includes(`boto3${sep}__init__.py`), - 'boto3 is packaged in function hello1' - ); - t.false( - zipfiles_hello.includes(`flask${sep}__init__.py`), - 'flask is NOT packaged in function hello1' - ); + const zipfiles_hello = await 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.true( + zipfiles_hello.includes(`boto3${sep}__init__.py`), + 'boto3 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.false( - zipfiles_hello2.includes(`boto3${sep}__init__.py`), - 'boto3 is NOT packaged in function hello2' - ); - t.true( - zipfiles_hello2.includes(`flask${sep}__init__.py`), - 'flask is packaged in function hello2' - ); + const zipfiles_hello2 = await 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.false( + zipfiles_hello2.includes(`boto3${sep}__init__.py`), + 'boto3 is NOT packaged in function hello2' + ); + t.true( + zipfiles_hello2.includes(`flask${sep}__init__.py`), + 'flask is packaged in function hello2' + ); - t.end(); -}); + t.end(); + }, + { skip: !hasPython(3.6) } +); -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']); +test( + 'py3.6 can package lambda-decorators using vendor and invidiually option', + async 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' - ); - t.false( - zipfiles_hello.includes(`dataclasses.py`), - 'dataclasses is NOT packaged in function hello' - ); + const zipfiles_hello = await 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' + ); + t.false( + zipfiles_hello.includes(`dataclasses.py`), + 'dataclasses is NOT 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' - ); - t.false( - zipfiles_hello2.includes(`dataclasses.py`), - 'dataclasses is NOT packaged in function hello2' - ); + const zipfiles_hello2 = await 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' + ); + t.false( + zipfiles_hello2.includes(`dataclasses.py`), + 'dataclasses is NOT 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.false( - zipfiles_hello3.includes(`dataclasses.py`), - 'dataclasses is NOT packaged in function hello3' - ); + const zipfiles_hello3 = await 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.false( + zipfiles_hello3.includes(`dataclasses.py`), + 'dataclasses is NOT packaged in function hello3' + ); - const zipfiles_hello4 = listZipFiles( - '.serverless/fn2-sls-py-req-test-dev-hello4.zip' - ); - t.true( - zipfiles_hello4.includes('fn2_handler.py'), - 'fn2_handler is packaged in the zip-root in function hello4' - ); - t.true( - zipfiles_hello4.includes(`dataclasses.py`), - 'dataclasses is packaged in function hello4' - ); - t.false( - zipfiles_hello4.includes(`flask${sep}__init__.py`), - 'flask is NOT packaged in function hello4' - ); - t.end(); -}); + const zipfiles_hello4 = await listZipFiles( + '.serverless/fn2-sls-py-req-test-dev-hello4.zip' + ); + t.true( + zipfiles_hello4.includes('fn2_handler.py'), + 'fn2_handler is packaged in the zip-root in function hello4' + ); + t.true( + zipfiles_hello4.includes(`dataclasses.py`), + 'dataclasses is packaged in function hello4' + ); + t.false( + zipfiles_hello4.includes(`flask${sep}__init__.py`), + 'flask is NOT packaged in function hello4' + ); + t.end(); + }, + { skip: !hasPython(3.6) } +); test( "Don't nuke execute perms when using individually", - t => { + async t => { process.chdir('tests/individually'); const path = npm(['pack', '../..']); const perm = '775'; @@ -1622,7 +1902,9 @@ test( npm(['i', path]); sls(['package']); - const zipfiles_hello1 = listZipFilesWithMetaData('.serverless/hello1.zip'); + const zipfiles_hello1 = await listZipFilesWithMetaData( + '.serverless/hello1.zip' + ); t.true( zipfiles_hello1['module1/foobar'].unixPermissions @@ -1631,7 +1913,7 @@ test( 'foobar has retained its executable file permissions' ); - const zipfiles_hello2 = listZipFilesWithMetaData( + const zipfiles_hello2 = await listZipFilesWithMetaData( '.serverless/module2-sls-py-req-test-indiv-dev-hello2.zip' ); const flaskPerm = statSync('.serverless/module2/requirements/bin/flask') @@ -1644,12 +1926,12 @@ test( t.end(); }, - { skip: process.platform === 'win32' } + { skip: process.platform === 'win32' || !hasPython(3.6) } ); test( "Don't nuke execute perms when using individually w/docker", - t => { + async t => { process.chdir('tests/individually'); const path = npm(['pack', '../..']); const perm = '775'; @@ -1659,7 +1941,9 @@ test( npm(['i', path]); sls(['--dockerizePip=true', 'package']); - const zipfiles_hello = listZipFilesWithMetaData('.serverless/hello1.zip'); + const zipfiles_hello = await listZipFilesWithMetaData( + '.serverless/hello1.zip' + ); t.true( zipfiles_hello['module1/foobar'].unixPermissions @@ -1668,7 +1952,7 @@ test( 'foobar has retained its executable file permissions' ); - const zipfiles_hello2 = listZipFilesWithMetaData( + const zipfiles_hello2 = await listZipFilesWithMetaData( '.serverless/module2-sls-py-req-test-indiv-dev-hello2.zip' ); const flaskPerm = statSync('.serverless/module2/requirements/bin/flask') @@ -1681,37 +1965,45 @@ test( t.end(); }, - { skip: !canUseDocker() || process.platform === 'win32' } + { skip: !canUseDocker() || process.platform === 'win32' || !hasPython(3.6) } ); -test('py3.6 uses download cache by default option', t => { - process.chdir('tests/base'); - const path = npm(['pack', '../..']); - npm(['i', path]); - sls(['package']); - const cachepath = getUserCachePath(); - t.true( - pathExistsSync(`${cachepath}${sep}downloadCacheslspyc${sep}http`), - 'cache directoy exists' - ); - t.end(); -}); - -test('py3.6 uses download cache by defaul option', t => { - process.chdir('tests/base'); - const path = npm(['pack', '../..']); - npm(['i', path]); - sls(['--cacheLocation=.requirements-cache', 'package']); - t.true( - pathExistsSync(`.requirements-cache${sep}downloadCacheslspyc${sep}http`), - 'cache directoy exists' - ); - t.end(); -}); +test( + 'py3.6 uses download cache by default option', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['package']); + const cachepath = getUserCachePath(); + t.true( + pathExistsSync(`${cachepath}${sep}downloadCacheslspyc${sep}http`), + 'cache directory exists' + ); + t.end(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'py3.6 uses download cache by default', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['--cacheLocation=.requirements-cache', 'package']); + t.true( + pathExistsSync(`.requirements-cache${sep}downloadCacheslspyc${sep}http`), + 'cache directory exists' + ); + t.end(); + }, + { skip: !hasPython(3.6) } +); test( 'py3.6 uses download cache with dockerizePip option', - t => { + async t => { process.chdir('tests/base'); const path = npm(['pack', '../..']); npm(['i', path]); @@ -1719,16 +2011,16 @@ test( const cachepath = getUserCachePath(); t.true( pathExistsSync(`${cachepath}${sep}downloadCacheslspyc${sep}http`), - 'cache directoy exists' + 'cache directory exists' ); t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(3.6) || brokenOn('win32') } ); test( 'py3.6 uses download cache with dockerizePip by default option', - t => { + async t => { process.chdir('tests/base'); const path = npm(['pack', '../..']); npm(['i', path]); @@ -1739,34 +2031,38 @@ test( ]); t.true( pathExistsSync(`.requirements-cache${sep}downloadCacheslspyc${sep}http`), - 'cache directoy exists' + 'cache directory exists' ); t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(3.6) || brokenOn('win32') } ); -test('py3.6 uses static and download cache', t => { - process.chdir('tests/base'); - const path = npm(['pack', '../..']); - npm(['i', path]); - sls(['package']); - const cachepath = getUserCachePath(); - const cacheFolderHash = sha256Path('.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', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['package']); + const cachepath = getUserCachePath(); + const cacheFolderHash = sha256Path('.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: !hasPython(3.6) } +); test( 'py3.6 uses static and download cache with dockerizePip option', - t => { + async t => { process.chdir('tests/base'); const path = npm(['pack', '../..']); npm(['i', path]); @@ -1783,66 +2079,74 @@ test( ); t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(3.6) || brokenOn('win32') } ); -test('py3.6 uses static cache', t => { - process.chdir('tests/base'); - const path = npm(['pack', '../..']); - npm(['i', path]); - sls(['package']); - const cachepath = getUserCachePath(); - const cacheFolderHash = sha256Path('.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' - ); +test( + 'py3.6 uses static cache', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['package']); + const cachepath = getUserCachePath(); + const cacheFolderHash = sha256Path('.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(['package']); + // 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(['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" - ); + const zipfiles = await 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([`--cacheLocation=${cachepath}`, 'package']); - const cacheFolderHash = sha256Path('.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(); -}); + t.end(); + }, + { skip: !hasPython(3.6) } +); + +test( + 'py3.6 uses static cache with cacheLocation option', + async t => { + process.chdir('tests/base'); + const path = npm(['pack', '../..']); + npm(['i', path]); + const cachepath = '.requirements-cache'; + sls([`--cacheLocation=${cachepath}`, 'package']); + const cacheFolderHash = sha256Path('.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(); + }, + { skip: !hasPython(3.6) } +); test( 'py3.6 uses static cache with dockerizePip & slim option', - t => { + async t => { process.chdir('tests/base'); const path = npm(['pack', '../..']); npm(['i', path]); @@ -1867,7 +2171,7 @@ test( ); sls(['--dockerizePip=true', '--slim=true', 'package']); - const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + const zipfiles = await 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" @@ -1880,12 +2184,12 @@ test( t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(3.6) || brokenOn('win32') } ); test( 'py3.6 uses download cache with dockerizePip & slim option', - t => { + async t => { process.chdir('tests/base'); const path = npm(['pack', '../..']); npm(['i', path]); @@ -1896,7 +2200,7 @@ test( 'http exists in download-cache' ); - const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + const zipfiles = await 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')), @@ -1906,5 +2210,5 @@ test( t.end(); }, - { skip: !canUseDocker() } + { skip: !canUseDocker() || !hasPython(3.6) || brokenOn('win32') } ); diff --git a/tests/base/package.json b/tests/base/package.json index db241a8c..752c49c6 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-5.0.0.tgz" + "serverless-python-requirements": "file:serverless-python-requirements-5.1.0.tgz" } } diff --git a/tests/individually/package.json b/tests/individually/package.json index db241a8c..752c49c6 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-5.0.0.tgz" + "serverless-python-requirements": "file:serverless-python-requirements-5.1.0.tgz" } } diff --git a/tests/non_build_pyproject/package.json b/tests/non_build_pyproject/package.json index db241a8c..752c49c6 100644 --- a/tests/non_build_pyproject/package.json +++ b/tests/non_build_pyproject/package.json @@ -9,6 +9,6 @@ "author": "", "license": "ISC", "dependencies": { - "serverless-python-requirements": "file:serverless-python-requirements-5.0.0.tgz" + "serverless-python-requirements": "file:serverless-python-requirements-5.1.0.tgz" } } diff --git a/tests/pipenv/package.json b/tests/pipenv/package.json index db241a8c..752c49c6 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-5.0.0.tgz" + "serverless-python-requirements": "file:serverless-python-requirements-5.1.0.tgz" } } diff --git a/tests/poetry/package.json b/tests/poetry/package.json index db241a8c..752c49c6 100644 --- a/tests/poetry/package.json +++ b/tests/poetry/package.json @@ -9,6 +9,6 @@ "author": "", "license": "ISC", "dependencies": { - "serverless-python-requirements": "file:serverless-python-requirements-5.0.0.tgz" + "serverless-python-requirements": "file:serverless-python-requirements-5.1.0.tgz" } }