def test_python_with_explicit_python3_no_write(self): """Tests generate_config_data with python version '3' in appinfo.""" self.write_file('test.py', 'test file') config = testutil.AppInfoFake(runtime='python', entrypoint='run_me_some_python!', runtime_config=dict(python_version='3')) cfg_files = self.generate_config_data(appinfo=config, deploy=True) self.assert_genfile_exists_with_contents( cfg_files, 'Dockerfile', self.DOCKERFILE_PREAMBLE + self.DOCKERFILE_VIRTUALENV_TEMPLATE.format(python_version='3.4') + self.DOCKERFILE_INSTALL_APP + 'CMD run_me_some_python!\n') self.assertEqual(set(os.listdir(self.temp_path)), {'test.py'}) self.assertEqual({f.filename for f in cfg_files}, {'Dockerfile', '.dockerignore'})
def test_use_yarn_skip_files_not_present(self): """Ensure use_yarn is True with yarn.lock present and not skipped. In particular, this test ensures use_yarn is True even if app.yaml doesn't contain a skip_files section. """ self.write_file('package.json', '{"scripts": {"start": "foo.js"}}') self.write_file('foo.js', 'fake contents') self.write_file('yarn.lock', 'fake contents') config = testutil.AppInfoFake(runtime='nodejs') configurator = self.detect(appinfo=config) self.assertEqual(configurator.data['use_yarn'], True) self.generate_configs(appinfo=config, deploy=True) self._validate_docker_files_for_yarn() self._validate_file_list_for_skip_yarn_lock()
def test_python_app_yaml_no_entrypoint(self): self.write_file('test.py', 'test file') config = testutil.AppInfoFake(runtime='python') cleaner = self.generate_configs(appinfo=config, deploy=True) self.assert_file_exists_with_contents( 'Dockerfile', self.DOCKERFILE_PREAMBLE + self.DOCKERFILE_VIRTUALENV_TEMPLATE.format( python_version='') + self.DOCKERFILE_INSTALL_APP + 'CMD my_entrypoint\n') cleaner() self.assertEqual(sorted(os.listdir(self.temp_path)), ['test.py'])
def test_java_files_with_web_inf_and_yaml_and_no_env2(self): self.write_file('WEB-INF', '') config = testutil.AppInfoFake(runtime='java', vm=True, runtime_config=dict(server='jetty9')) self.generate_configs(appinfo=config, deploy=True) dockerfile_contents = [ constants.DOCKERFILE_LEGACY_PREAMBLE, constants.DOCKERFILE_INSTALL_APP.format('.'), ] self.assert_file_exists_with_contents('Dockerfile', ''.join(dockerfile_contents)) self.assert_file_exists_with_contents( '.dockerignore', self.read_runtime_def_file('data', 'dockerignore'))
def test_java7_runtime(self): self.write_file('WEB-INF', '') config = testutil.AppInfoFake(runtime='java7', vm=True, api_version='1') self.generate_configs(appinfo=config, deploy=True) dockerfile_contents = [ constants.DOCKERFILE_LEGACY_PREAMBLE, constants.DOCKERFILE_INSTALL_APP.format('.'), ] self.assert_file_exists_with_contents('Dockerfile', ''.join(dockerfile_contents)) self.assert_file_exists_with_contents( '.dockerignore', self.read_runtime_def_file('data', 'dockerignore'))
def test_java_files_with_config_error(self): self.write_file('foo.war', '') errors = [] def ErrorFake(message): errors.append(message) config = testutil.AppInfoFake(runtime='java', env='2', runtime_config=dict(jdk='openjdk9')) with mock.patch.dict(ext_runtime._LOG_FUNCS, {'error': ErrorFake}): self.assertIsNone( self.generate_configs(appinfo=config, deploy=True)) self.assertEqual(errors, ['Unknown JDK : openjdk9.'])
def test_generate_with_array_entrypoint(self): self.write_file('index.php', 'index') appinfo = testutil.AppInfoFake( runtime_config={'document_root': 'wordpress'}, entrypoint=['/bin/bash', 'my-cmd.sh']) self.generate_configs(deploy=True, appinfo=appinfo) dockerfile = self.file_contents('Dockerfile') self.assertEqual( dockerfile, self.preamble() + textwrap.dedent('''\ ENV DOCUMENT_ROOT /app/wordpress # Allow custom CMD CMD ["/bin/bash", "my-cmd.sh"] '''))
def test_python_with_explicit_python36(self): self.write_file('test.py', 'test file') config = testutil.AppInfoFake(runtime='python', entrypoint='run_me_some_python!', runtime_config=dict(python_version='3.6')) self.generate_configs(appinfo=config, deploy=True) self.assert_file_exists_with_contents( 'Dockerfile', self.DOCKERFILE_PREAMBLE + self.DOCKERFILE_VIRTUALENV_TEMPLATE.format( python_version='3.6') + self.DOCKERFILE_INSTALL_APP + 'CMD run_me_some_python!\n') self.assertEqual(set(os.listdir(self.temp_path)), {'test.py', '.dockerignore', 'Dockerfile'})
def test_java_files_with_war_and_yaml(self): self.write_file('foo.war', '') appinfo = testutil.AppInfoFake(runtime='java', env='2', runtime_config=dict(jdk='openjdk8', server='jetty9')) self.generate_configs(appinfo=appinfo, deploy=True) dockerfile_contents = [ constants.DOCKERFILE_JETTY9_PREAMBLE, constants.DOCKERFILE_INSTALL_WAR.format('foo.war'), ] self.assert_file_exists_with_contents('Dockerfile', ''.join(dockerfile_contents)) self.assert_file_exists_with_contents( '.dockerignore', self.read_runtime_def_file('data', 'dockerignore'))
def test_generate_with_array_entrypoint_no_write(self): """Tests generate_config_data with an array entrypoint.""" self.write_file('index.php', 'index') appinfo = testutil.AppInfoFake( runtime_config={'document_root': 'wordpress'}, entrypoint=["/bin/bash", "my-cmd.sh"]) cfg_files = self.generate_config_data(deploy=True, appinfo=appinfo) self.assert_genfile_exists_with_contents( cfg_files, 'Dockerfile', self.preamble() + textwrap.dedent('''\ ENV DOCUMENT_ROOT /app/wordpress # Allow custom CMD CMD ["/bin/bash", "my-cmd.sh"] '''))
def test_java_files_with_web_inf_and_yaml_and_env2_no_write(self): """Test generate_config_data with .war, fake appinfo, env=2.""" self.write_file('WEB-INF', '') config = testutil.AppInfoFake(runtime='java', env='2', runtime_config=dict(jdk='openjdk8', server='jetty9')) cfg_files = self.generate_config_data(appinfo=config, deploy=True) dockerfile_contents = [ constants.DOCKERFILE_COMPAT_PREAMBLE, constants.DOCKERFILE_INSTALL_APP.format('.'), ] self.assert_genfile_exists_with_contents(cfg_files, 'Dockerfile', ''.join(dockerfile_contents)) self.assert_genfile_exists_with_contents( cfg_files, '.dockerignore', self.read_runtime_def_file('data', 'dockerignore'))
def test_yarn_identification_fails(self): self.write_file('foo.js', 'bogus contents') self.write_file('package.json', '{"scripts": {"start": "foo.js"}}') self.write_file('yarn.lock', 'yarn overridden') variations = [ (testutil.AppInfoFake(runtime='nodejs'), None), (None, 'nodejs'), ] for appinfo, runtime in variations: self.errors = [] with mock.patch.dict(ext_runtime._LOG_FUNCS, {'error': self.error_fake}): self.generate_configs(appinfo=appinfo, runtime=runtime) self.assertTrue(self.errors[0].startswith( 'Yarn checker: "yarn.lock" was found indicating Yarn ' 'is being used, but "yarn" could not be run.'))
def test_python_app_yaml_no_entrypoint_no_write(self): """Tests generate_config_data with fake appinfo, no entrypoint.""" self.write_file('test.py', 'test file') config = testutil.AppInfoFake(runtime='python') cfg_files = self.generate_config_data(appinfo=config, deploy=True) self.assert_genfile_exists_with_contents( cfg_files, 'Dockerfile', self.DOCKERFILE_PREAMBLE + self.DOCKERFILE_VIRTUALENV_TEMPLATE.format( python_version='') + self.DOCKERFILE_INSTALL_APP + 'CMD my_entrypoint\n') self.assertEqual(set(os.listdir(self.temp_path)), {'test.py'}) self.assertEqual({f.filename for f in cfg_files}, {'Dockerfile', '.dockerignore'})
def test_no_startup_script(self): with mock.patch.dict(ext_runtime._LOG_FUNCS, {'debug': self.debug_fake}): self.generate_configs() print self.debug self.assertTrue(self.debug[1].startswith( 'node.js checker: No npm start and no server.js')) variations = [ (testutil.AppInfoFake(runtime='nodejs'), None), (None, 'nodejs'), ] for appinfo, runtime in variations: self.errors = [] with mock.patch.dict(ext_runtime._LOG_FUNCS, {'error': self.error_fake}): self.generate_configs(appinfo=appinfo, runtime=runtime) self.assertTrue(self.errors[0].startswith( 'node.js checker: No npm start and no server.js'))
def test_no_startup_script(self): with mock.patch.dict(ext_runtime._LOG_FUNCS, {'debug': self.debug_fake}): self.generate_configs() print self.debug self.assertTrue(self.debug[1].startswith( 'node.js checker: Neither "start" in the "scripts" section ' 'of "package.json" nor the "server.js" file were found.')) variations = [(testutil.AppInfoFake(runtime='nodejs'), None), (None, 'nodejs')] for appinfo, runtime in variations: self.errors = [] with mock.patch.dict(ext_runtime._LOG_FUNCS, {'error': self.error_fake}): self.generate_configs(appinfo=appinfo, runtime=runtime) self.assertTrue(self.errors[0].startswith( 'node.js checker: Neither "start" in the "scripts" section ' 'of "package.json" nor the "server.js" file were found.'))
def test_only_skip_yarn_lock(self): """Ensure use_yarn is False with yarn.lock present but is being skipped. Further, this test ensures use_yarn is false if the value obtained from skip_files is a regex string and not a list of strings. A yarn executable is injected that passes all checks to ensure that if yarn.lock is set to be skipped, use_yarn is set to False even if yarn can be executed and reports that the yarn.lock file is valid. """ self.write_file('package.json', '{"scripts": {"start": "foo.js"}}') self.write_file('foo.js', 'fake contents') self.write_file('yarn.lock', 'fake contents') config = testutil.AppInfoFake(runtime='nodejs', skip_files='^yarn\.lock$') configurator = self.detect(appinfo=config) self.assertEqual(configurator.data['use_yarn'], False) self.generate_configs(appinfo=config, deploy=True) self._validate_docker_files_for_npm() self._validate_file_list_for_skip_yarn_lock()
def test_invalid_package_json(self): self.write_file('package.json', '') self.write_file('server.js', '') with mock.patch.dict(ext_runtime._LOG_FUNCS, {'warn': self.warn_fake}): self.generate_configs() self.assertTrue(self.warnings[0].startswith( 'node.js checker: error accessing package.json')) variations = [ (testutil.AppInfoFake(runtime='nodejs'), None), (None, 'nodejs'), ] for appinfo, runtime in variations: self.warnings = [] with mock.patch.dict(ext_runtime._LOG_FUNCS, {'warn': self.warn_fake}): self.generate_configs(appinfo=appinfo, runtime=runtime) self.assertTrue(self.warnings[0].startswith( 'node.js checker: error accessing package.json'))
def test_skip_yarn_lock_with_other_files(self): """Ensure use_yarn is False with yarn.lock present but is being skipped. Further, this test verifies that use_yarn is False even if multiple other entries are present in skip_files. A yarn executable is injected that passes all checks to ensure that if yarn.lock is set to be skipped, use_yarn is set to False even if yarn can be executed and reports that the yarn.lock file is valid. """ self.write_file('package.json', '{"scripts": {"start": "foo.js"}}') self.write_file('foo.js', 'fake contents') self.write_file('yarn.lock', 'fake contents') config = testutil.AppInfoFake( runtime='nodejs', skip_files=['^abc$', '^xyz$', '^yarn\.lock$', '^node_modules$']) configurator = self.detect(appinfo=config) self.assertEqual(configurator.data['use_yarn'], False) self.generate_configs(appinfo=config, deploy=True) self._validate_docker_files_for_npm() self._validate_file_list_for_skip_yarn_lock()
def test_generate_with_array_entrypoint(self): self.write_file('index.php', 'index') appinfo = testutil.AppInfoFake( runtime_config={'document_root': 'wordpress'}, entrypoint=["/bin/bash", "my-cmd.sh"]) cleaner = self.generate_configs(deploy=True, appinfo=appinfo) dockerfile = self.file_contents('Dockerfile') self.assertEqual( dockerfile, textwrap.dedent('''\ # Dockerfile extending the generic PHP image with application files for a # single application. FROM gcr.io/google_appengine/php:latest # The Docker image will configure the document root according to this # environment variable. ENV DOCUMENT_ROOT /app/wordpress # Allow custom CMD CMD ["/bin/bash", "my-cmd.sh"] '''))
def test_yarn_lock_not_readable(self): self.write_file('foo.js', 'bogus contents') self.write_file('package.json', '{"scripts": {"start": "foo.js"}}') self.write_file('yarn.lock', 'yarn overridden') # ensure the yarn.lock file is not readable os.chmod(self.full_path('yarn.lock'), ~stat.S_IREAD) variations = [ (testutil.AppInfoFake(runtime='nodejs'), None), (None, 'nodejs'), ] for appinfo, runtime in variations: self.errors = [] with mock.patch.dict(ext_runtime._LOG_FUNCS, {'error': self.error_fake}): self.generate_configs(appinfo=appinfo, runtime=runtime) self.assertTrue(self.errors[0].startswith( 'Yarn checker: "yarn.lock" exists, indicating Yarn ' 'should be used, but Yarn cannot run since "yarn.lock" ' 'is not readable.'))
def test_generate_with_existing_appinfo(self): self.write_file('index.rb', 'class Index; end') self.write_file('Gemfile', 'source "https://rubygems.org"') self.write_file('config.ru', 'run Index.app') appinfo = testutil.AppInfoFake( entrypoint='bundle exec ruby index.rb $PORT', runtime='ruby', vm=True) self.generate_configs(appinfo=appinfo, deploy=True) self.assertFalse(os.path.exists(self.full_path('app.yaml'))) dockerfile = self.file_contents('Dockerfile') self.assertEqual( dockerfile, DOCKERFILE_TEXT.format( ruby_version='', entrypoint='bundle exec ruby index.rb $PORT')) dockerignore = self.file_contents('.dockerignore') self.assertIn('.dockerignore\n', dockerignore) self.assertIn('Dockerfile\n', dockerignore) self.assertIn('.git\n', dockerignore) self.assertIn('.hg\n', dockerignore) self.assertIn('.svn\n', dockerignore)
def test_python_custom_runtime_field(self): """Verify that a runtime field of "custom" works.""" self.write_file('test.py', 'test file') config = testutil.AppInfoFake(runtime='custom', entrypoint='my_entrypoint') self.assertTrue(self.generate_configs(appinfo=config, deploy=True))
def test_java_custom_runtime_field(self): self.write_file('foo.jar', '') config = testutil.AppInfoFake(runtime='java', env='2') self.assertTrue(self.generate_configs(appinfo=config))
def test_go_custom_runtime_field(self): self.write_file('foo.go', 'package main\nfunc main') config = testutil.AppInfoFake(runtime="custom", env=2, api_version=1) self.assertTrue(self.generate_configs(appinfo=config, deploy=True))
def test_node_js_runtime_field(self): self.write_file('server.js', 'fake contents') config = testutil.AppInfoFake(runtime='nodejs') self.generate_configs(appinfo=config, deploy=True) self.assertTrue(os.path.exists(self.full_path('Dockerfile')))
def test_generate_with_ruby_version(self): self.write_file('index.rb', 'class Index; end') self.write_file('Gemfile', 'source "https://rubygems.org"') self.write_file('config.ru', 'run Index.app') self.write_file('.ruby-version', '2.3.1\n') appinfo = testutil.AppInfoFake( entrypoint='bundle exec ruby index.rb $PORT', runtime='ruby', vm=True) cleaner = self.generate_configs(appinfo=appinfo, deploy=True) self.assertFalse(os.path.exists(self.full_path('app.yaml'))) dockerfile = self.file_contents('Dockerfile') self.assertEqual( dockerfile, textwrap.dedent('''\ # This Dockerfile for a Ruby application was generated by gcloud. # The base Dockerfile installs: # * A number of packages needed by the Ruby runtime and by gems # commonly used in Ruby web apps (such as libsqlite3) # * A recent version of NodeJS # * A recent version of the standard Ruby runtime to use by default # * The bundler gem FROM gcr.io/google_appengine/ruby # Install 2.3.1 if not already preinstalled by the base image RUN cd /rbenv/plugins/ruby-build && \\ git pull && \\ rbenv install -s 2.3.1 && \\ rbenv global 2.3.1 && \\ gem install -q --no-rdoc --no-ri bundler --version 1.11.2 ENV RBENV_VERSION 2.3.1 # Copy the application files. COPY . /app/ # Install required gems if Gemfile.lock is present. RUN if test -f Gemfile.lock; then \\ bundle install --deployment && rbenv rehash; \\ fi # Temporary. Will be moved to base image later. ENV RACK_ENV=production \\ RAILS_ENV=production \\ RAILS_SERVE_STATIC_FILES=true # Run asset pipeline if we're in a Rails app. RUN if test -d app/assets -a -f config/application.rb; then \\ bundle exec rake assets:precompile; \\ fi # BUG: Reset entrypoint to override base image. ENTRYPOINT [] # Start application on port $PORT. CMD bundle exec ruby index.rb $PORT ''')) dockerignore = self.file_contents('.dockerignore') self.assertIn('.dockerignore\n', dockerignore) self.assertIn('Dockerfile\n', dockerignore) self.assertIn('.git\n', dockerignore) self.assertIn('.hg\n', dockerignore) self.assertIn('.svn\n', dockerignore) cleaner()
def test_node_js_custom_runtime_field(self): self.write_file('server.js', 'fake contents') config = testutil.AppInfoFake(runtime='custom') self.assertTrue(self.generate_configs(appinfo=config, deploy=True))