Example #1
0
class StagerRealExecutableTest(sdk_test_base.WithLogCapture):
    """Tests the staging code using real executables."""

    _REGISTRY = runtime_registry.Registry(
        {
            runtime_registry.RegistryEntry('success', {env.FLEX}):
            staging._BundledCommand('success.sh', 'success.cmd'),
            runtime_registry.RegistryEntry('failure', {env.FLEX}):
            staging._BundledCommand('failure.sh', 'failure.cmd')
        },
        default=staging.NoopCommand())

    _SUCCESS_OUTPUT_PATTERN = (r'-+ STDOUT -+\n'
                               r'out\n'
                               r'-+ STDERR -+\n'
                               r'service-yaml path: app.yaml\n'
                               r'app-dir path: .\n'
                               r'-+')

    _FAILURE_PATTERN = (r'Staging command '
                        r'\[\S+failure.(?:sh|cmd) app.yaml . \S+\] '
                        r'failed with return code \[1\].\n\n'
                        r'-+ STDOUT -+\n'
                        r'out\n'
                        r'-+ STDERR -+\n'
                        r'service.yaml path: app.yaml\n'
                        r'app-dir path: .\n'
                        r'-+')

    def SetUp(self):
        scripts_dir = self.Resource('tests', 'unit', 'command_lib', 'app',
                                    'testdata', 'scripts')
        self.StartObjectPatch(config.Paths,
                              'sdk_root',
                              new_callable=mock.PropertyMock,
                              return_value=scripts_dir)
        self.staging_area = tempfile.mkdtemp()
        self.stager = staging.Stager(self._REGISTRY, self.staging_area)

    def testStage_Success(self):
        app_dir = self.stager.Stage('app.yaml', '.', 'success', env.FLEX)
        self.AssertFileExistsWithContents('app.yaml contents\n',
                                          os.path.join(app_dir, 'app.yaml'))
        self.AssertLogMatches(self._SUCCESS_OUTPUT_PATTERN)

    def testStage_Failure(self):
        with self.assertRaisesRegex(staging.StagingCommandFailedError,
                                    self._FAILURE_PATTERN):
            self.stager.Stage('app.yaml', '.', 'failure', env.FLEX)
Example #2
0
    def testGet_MultipleEnv(self):
        registry = runtime_registry.Registry({
            runtime_registry.RegistryEntry('intercal', {
                env.FLEX, env.STANDARD
            }):
            'intercal-value'
        })

        self.assertEqual(registry.Get('intercal', env.FLEX), 'intercal-value')
        self.assertEqual(registry.Get('intercal', env.STANDARD),
                         'intercal-value')
Example #3
0
    def testGet_Override(self):
        registry = runtime_registry.Registry(
            {
                runtime_registry.RegistryEntry(re.compile(r'.*'), {
                                                   env.FLEX, env.STANDARD
                                               }):
                'dummy'
            },
            override='my-override')

        self.assertEqual(registry.Get('anything', env.FLEX), 'my-override')
        self.assertEqual(registry.Get('anything', env.STANDARD), 'my-override')
Example #4
0
    def testGet_RegexpRuntime(self):
        default = 'default-value'
        registry = runtime_registry.Registry(
            {
                runtime_registry.RegistryEntry(re.compile('pattern[12]$'), {
                                                   env.FLEX
                                               }):
                'pattern-value'
            },
            default=default)

        self.assertEqual(registry.Get('pattern1', env.FLEX), 'pattern-value')
        self.assertEqual(registry.Get('pattern2', env.FLEX), 'pattern-value')
        self.assertEqual(registry.Get('pattern3', env.FLEX), default)
Example #5
0
PYTHON_TI_RUNTIME_EXPR = re.compile(r'python3\d*')


class Environment(enum.Enum):
    """Enum for different application environments.

  STANDARD corresponds to App Engine Standard applications.
  FLEX corresponds to any App Engine `env: flex` applications.
  MANAGED_VMS corresponds to `vm: true` applications.
  """

    STANDARD = 1
    MANAGED_VMS = 2
    FLEX = 3


def GetTiRuntimeRegistry():
    """A simple registry whose `Get()` method answers True if runtime is Ti."""
    return runtime_registry.Registry(_TI_RUNTIME_REGISTRY, default=False)


STANDARD = Environment.STANDARD
FLEX = Environment.FLEX
MANAGED_VMS = Environment.MANAGED_VMS

_TI_RUNTIME_REGISTRY = {
    runtime_registry.RegistryEntry(NODE_TI_RUNTIME_EXPR, {STANDARD}): True,
    runtime_registry.RegistryEntry(PHP_TI_RUNTIME_EXPR, {STANDARD}): True,
    runtime_registry.RegistryEntry(PYTHON_TI_RUNTIME_EXPR, {STANDARD}): True,
}
Example #6
0
_PYTHON_GCLOUDIGNORE = '\n'.join([
    gcloudignore.DEFAULT_IGNORE_FILE, '# Python pycache:', '__pycache__/',
    '# Ignored by the build system', '/setup.cfg'
])

_GO_GCLOUDIGNORE = '\n'.join([
    gcloudignore.DEFAULT_IGNORE_FILE, '# Binaries for programs and plugins',
    '*.exe', '*.exe~', '*.dll', '*.so', '*.dylib',
    '# Test binary, build with `go test -c`', '*.test',
    '# Output of the go coverage tool, specifically when used with LiteIDE',
    '*.out'
])

_GCLOUDIGNORE_REGISTRY = {
    runtime_registry.RegistryEntry(env.NODE_TI_RUNTIME_EXPR, {env.STANDARD}):
    _NODE_GCLOUDIGNORE,
    runtime_registry.RegistryEntry(env.PHP_TI_RUNTIME_EXPR, {env.STANDARD}):
    _PHP_GCLOUDIGNORE,
    runtime_registry.RegistryEntry(env.PYTHON_TI_RUNTIME_EXPR, {env.STANDARD}):
    _PYTHON_GCLOUDIGNORE,
    runtime_registry.RegistryEntry(env.GO_TI_RUNTIME_EXPR, {env.STANDARD}):
    _GO_GCLOUDIGNORE,
}


class SkipFilesError(core_exceptions.Error):
    pass


def _GetGcloudignoreRegistry():
Example #7
0
        raise StagingCommandNotFoundError(
            'The provided staging command [{}] could '
            'not be found.'.format(executable))


# Path to the go-app-stager binary
_GO_APP_STAGER_DIR = os.path.join('platform', 'google_appengine')

# Path to the jar which contains the staging command
_APPENGINE_TOOLS_JAR = os.path.join('platform', 'google_appengine', 'google',
                                    'appengine', 'tools', 'java', 'lib',
                                    'appengine-tools-api.jar')

_STAGING_REGISTRY = {
    runtime_registry.RegistryEntry(re.compile(r'(go|go1\..+)$'), {
                                       env.FLEX, env.MANAGED_VMS
                                   }):
    _BundledCommand(os.path.join(_GO_APP_STAGER_DIR, 'go-app-stager'),
                    os.path.join(_GO_APP_STAGER_DIR, 'go-app-stager.exe'),
                    component='app-engine-go'),
    runtime_registry.RegistryEntry(
        re.compile(r'(go|go1\..+|%s)$' % env.GO_TI_RUNTIME_EXPR.pattern), {
            env.STANDARD,
        }):
    _BundledCommand(os.path.join(_GO_APP_STAGER_DIR, 'go-app-stager'),
                    os.path.join(_GO_APP_STAGER_DIR, 'go-app-stager.exe'),
                    component='app-engine-go'),
    runtime_registry.RegistryEntry('java-xml', {env.STANDARD}):
    _BundledCommand(_APPENGINE_TOOLS_JAR,
                    _APPENGINE_TOOLS_JAR,
                    component='app-engine-java',
Example #8
0
        raise StagingCommandNotFoundError(
            'The provided staging command [{}] could '
            'not be found.'.format(executable))


# Path to the go-app-stager binary
_GO_APP_STAGER_DIR = os.path.join('platform', 'google_appengine')

# Path to the jar which contains the staging command
_APPENGINE_TOOLS_JAR = os.path.join('platform', 'google_appengine', 'google',
                                    'appengine', 'tools', 'java', 'lib',
                                    'appengine-tools-api.jar')

_STAGING_REGISTRY = {
    runtime_registry.RegistryEntry(re.compile(r'(go|go1\..+)$'), {
                                       env.FLEX, env.STANDARD, env.MANAGED_VMS
                                   }):
    _BundledCommand(os.path.join(_GO_APP_STAGER_DIR, 'go-app-stager'),
                    os.path.join(_GO_APP_STAGER_DIR, 'go-app-stager.exe'),
                    component='app-engine-go'),
    runtime_registry.RegistryEntry('java-xml', {env.STANDARD}):
    _BundledCommand(_APPENGINE_TOOLS_JAR,
                    _APPENGINE_TOOLS_JAR,
                    component='app-engine-java',
                    mapper=_JavaStagingMapper),
}

# _STAGING_REGISTRY_BETA extends _STAGING_REGISTRY, overriding entries if the
# same key is used.
_STAGING_REGISTRY_BETA = {}
_PHP_GCLOUDIGNORE = '\n'.join([
    gcloudignore.DEFAULT_IGNORE_FILE,
    '# PHP Composer dependencies:',
    'vendor/'
])

_PYTHON_GCLOUDIGNORE = '\n'.join([
    gcloudignore.DEFAULT_IGNORE_FILE,
    '# Python pycache:',
    '__pycache__/'
])


_GCLOUDIGNORE_REGISTRY = {
    runtime_registry.RegistryEntry(
        env.NODE_TI_RUNTIME_EXPR, {env.STANDARD}): _NODE_GCLOUDIGNORE,
    runtime_registry.RegistryEntry(
        env.PHP_TI_RUNTIME_EXPR, {env.STANDARD}): _PHP_GCLOUDIGNORE,
    runtime_registry.RegistryEntry(
        env.PYTHON_TI_RUNTIME_EXPR, {env.STANDARD}): _PYTHON_GCLOUDIGNORE,
}


class SkipFilesError(core_exceptions.Error):

  def __init__(self, error_message):
    super(SkipFilesError, self).__init__(error_message)


def _GetGcloudignoreRegistry():
  return runtime_registry.Registry(_GCLOUDIGNORE_REGISTRY, default=False)
Example #10
0
class RuntimeRegistryTest(sdk_test_base.WithLogCapture):
    _DEFAULT_REGISTRY = {
        runtime_registry.RegistryEntry('intercal', {env.FLEX}):
        'intercal-value',
        runtime_registry.RegistryEntry('x86-asm', {env.STANDARD}):
        'x86-asm-value',
    }

    def testGet_MatchFound(self):
        registry = runtime_registry.Registry(self._DEFAULT_REGISTRY)

        self.assertEqual(registry.Get('intercal', env.FLEX), 'intercal-value')

    def testGet_RightRuntimeWrongEnv(self):
        default = 'default-value'
        registry = runtime_registry.Registry(self._DEFAULT_REGISTRY,
                                             default=default)

        self.assertEqual(
            registry.Get('intercal', env.STANDARD), default,
            'A matching runtime with an incorrect environment should result in the '
            'default.')

    def testGet_DefaultFalse(self):
        registry = runtime_registry.Registry(self._DEFAULT_REGISTRY,
                                             default=False)

        self.assertFalse(
            registry.Get('intercal', env.STANDARD),
            'A matching runtime with an incorrect environment should result in the '
            'default.')

    def testGet_RegexpRuntime(self):
        default = 'default-value'
        registry = runtime_registry.Registry(
            {
                runtime_registry.RegistryEntry(re.compile('pattern[12]$'), {
                                                   env.FLEX
                                               }):
                'pattern-value'
            },
            default=default)

        self.assertEqual(registry.Get('pattern1', env.FLEX), 'pattern-value')
        self.assertEqual(registry.Get('pattern2', env.FLEX), 'pattern-value')
        self.assertEqual(registry.Get('pattern3', env.FLEX), default)

    def testGet_MultipleEnv(self):
        registry = runtime_registry.Registry({
            runtime_registry.RegistryEntry('intercal', {
                env.FLEX, env.STANDARD
            }):
            'intercal-value'
        })

        self.assertEqual(registry.Get('intercal', env.FLEX), 'intercal-value')
        self.assertEqual(registry.Get('intercal', env.STANDARD),
                         'intercal-value')

    def testGet_Override(self):
        registry = runtime_registry.Registry(
            {
                runtime_registry.RegistryEntry(re.compile(r'.*'), {
                                                   env.FLEX, env.STANDARD
                                               }):
                'dummy'
            },
            override='my-override')

        self.assertEqual(registry.Get('anything', env.FLEX), 'my-override')
        self.assertEqual(registry.Get('anything', env.STANDARD), 'my-override')

    def testGet_NoMatchFound(self):
        default = 'default-value'
        registry = runtime_registry.Registry(self._DEFAULT_REGISTRY,
                                             default=default)
        self.assertEqual(
            registry.Get('bad', env.FLEX), default,
            'A non-matching runtime should always result in the default.')

    def testGet_NoMatchFoundNoDefault(self):
        registry = runtime_registry.Registry(self._DEFAULT_REGISTRY)
        self.assertEqual(
            registry.Get('bad', env.FLEX), None,
            'A non-matching runtime should return None if no default is provided.'
        )
Example #11
0
class StagerRegistryTest(sdk_test_base.WithLogCapture):
    """Ensure that default- and beta staging registries works as intended."""

    # Use fake command strings in order to easier compare for equality
    _DEFAULT_REGISTRY = {
        runtime_registry.RegistryEntry('intercal', {env.FLEX}):
        'fake-intercal-command',
        runtime_registry.RegistryEntry('x86-asm', {env.STANDARD}):
        'fake-x86-asm-command',
    }

    _REGISTRY_BETA = {
        runtime_registry.RegistryEntry('intercal', {env.FLEX}):
        'fake-intercal-beta-command',
        runtime_registry.RegistryEntry('chicken', {env.STANDARD}):
        'fake-chicken-beta-command',
    }

    def _MockDefaultRegistries(self):
        self.StartObjectPatch(staging,
                              '_STAGING_REGISTRY',
                              new=self._DEFAULT_REGISTRY)
        self.StartObjectPatch(staging,
                              '_STAGING_REGISTRY_BETA',
                              new=self._REGISTRY_BETA)

    def SetUp(self):
        self.staging_area = '/staging-area'

    def testRegistry_DefaultMappings(self):
        """Ensures the default registry works is what it was originally set to."""
        self._MockDefaultRegistries()
        expected = {
            ('intercal', env.FLEX): 'fake-intercal-command',
            ('x86-asm', env.STANDARD): 'fake-x86-asm-command',
            ('chicken', env.STANDARD): staging.NoopCommand(),
        }
        registry = staging.GetRegistry()
        for key, value in expected.items():
            self.assertEqual(registry.Get(*key), value)

    def testRegistry_BetaMappings(self):
        """Ensures entries in beta- overrides entries in default-registry."""
        self._MockDefaultRegistries()
        expected = {
            ('intercal', env.FLEX): 'fake-intercal-beta-command',
            ('x86-asm', env.STANDARD): 'fake-x86-asm-command',
            ('chicken', env.STANDARD): 'fake-chicken-beta-command',
        }
        registry = staging.GetBetaRegistry()
        for key, value in expected.items():
            self.assertEqual(registry.Get(*key), value)

    def testRegistry_FlexGoRegexp(self):
        """Tests that the regexp for the Go staging entry does the right thing."""
        registry = staging.GetRegistry()

        def Good(runtime):
            command = registry.Get(runtime, env.FLEX)
            self.assertFalse(isinstance(command, staging.NoopCommand))

        def Bad(runtime):
            command = registry.Get(runtime, env.FLEX)
            self.assertTrue(isinstance(command, staging.NoopCommand))

        Good('go')
        Good('go1.7')
        Good('go1.8')
        Good('go1.8.9')
        Good('go1.8a')
        Good('go1.9')
        Good('go1.10')
        Good('go1.abc')
        Bad('go1')
        Bad('go2')
        Bad('go2.')
        Bad('go10')
        Bad('go1.')
        Bad('something-ends-with-go1.8')
        Bad('gs://my-bucket/go1.8')

    def testRegistry_StandardGoRegexp(self):
        """Tests that the regexp for the Go staging entry does the right thing."""
        registry = staging.GetRegistry()

        def Good(runtime):
            command = registry.Get(runtime, env.STANDARD)
            self.assertFalse(isinstance(command, staging.NoopCommand),
                             '\'%s\' should be valid' % runtime)

        def Bad(runtime):
            command = registry.Get(runtime, env.STANDARD)
            self.assertTrue(isinstance(command, staging.NoopCommand),
                            '\'%s\' should be invalid' % runtime)

        Good('go')
        Good('go1.7')
        Good('go1.8')
        Good('go1.8.9')
        Good('go1.8a')
        Good('go1.9')
        Good('go1.10')
        Good('go1.abc')
        Good('go110')
        Good('go111')
        Good('go111beta1')
        Good('go111rc2')
        Bad('go1')
        Bad('go2')
        Bad('go2.')
        Bad('go10')
        Bad('go1.')
        Bad('something-ends-with-go1.8')
        Bad('gs://my-bucket/go1.8')
Example #12
0
class StagerMockExecTest(sdk_test_base.WithLogCapture):
    """Tests the staging code by mocking executables."""

    _REGISTRY = runtime_registry.Registry(
        {
            runtime_registry.RegistryEntry('intercal', {env.FLEX}):
            staging._BundledCommand('intercal-flex', 'intercal-flex.exe'),
            runtime_registry.RegistryEntry('x86-asm', {env.STANDARD}):
            staging._BundledCommand('x86-asm-standard', 'x86-asm-standard.exe',
                                    'app-engine-x86-asm'),
            runtime_registry.RegistryEntry('german', {env.STANDARD}):
            staging._BundledCommand('german-standard',
                                    'german-standard.exe',
                                    mapper=_GermanMapper),
        },
        default=staging.NoopCommand())

    _OUTPUT_PATTERN = (r'-+ STDOUT -+\n'
                       r'out\n'
                       r'-+ STDERR -+\n'
                       r'err\n'
                       r'-+')

    _SUCCESS_MESSAGE = 'Executing staging command: [{command}]'

    _ERROR_MESSAGE = (
        'Staging command [{command}] failed with return code [{code}].')

    def SetUp(self):
        self.staging_area = '/staging-area'
        self.stager = staging.Stager(self._REGISTRY, self.staging_area)
        self.exec_mock = self.StartObjectPatch(execution_utils,
                                               'Exec',
                                               side_effect=_FakeExec())
        self.sdk_root_mock = self.StartPropertyPatch(
            config.Paths, 'sdk_root', return_value='sdk_root_dir')
        self.mkdtemp_mock = self.StartObjectPatch(tempfile,
                                                  'mkdtemp',
                                                  autospec=True,
                                                  return_value='tmp_dir')
        self.StartObjectPatch(platforms.OperatingSystem,
                              'Current',
                              return_value=platforms.OperatingSystem.LINUX)

    def testStage_StagingDir(self):
        """Ensures that the staging dir is created properly."""
        app_dir = self.stager.Stage('app.yaml', 'dir', 'intercal', env.FLEX)
        self.assertEqual(app_dir, 'tmp_dir')
        self.mkdtemp_mock.assert_called_once_with(dir='/staging-area')

    def testStage_MismatchedRuntime(self):
        self.assertIsNone(
            self.stager.Stage('app.yaml', 'dir', 'intercal', env.STANDARD))
        self.AssertOutputEquals('')
        self.AssertLogNotContains('err')  # Log will have debug messages
        self.exec_mock.assert_not_called()
        self.mkdtemp_mock.assert_not_called()

    def testStage_MismatchedEnvironment(self):
        self.assertIsNone(
            self.stager.Stage('app.yaml', 'dir', 'intercal', env.STANDARD))
        self.AssertOutputEquals('')
        self.AssertLogNotContains('err')  # Log will have debug messages
        self.exec_mock.assert_not_called()
        self.mkdtemp_mock.assert_not_called()

    def testStage_NoSdkRoot(self):
        self.sdk_root_mock.return_value = None
        with self.assertRaises(staging.NoSdkRootError):
            self.stager.Stage('app.yaml', 'dir', 'intercal', env.FLEX)
        self.exec_mock.assert_not_called()

    def testStage_StagingCommandFailed(self):
        self.exec_mock.side_effect = _FakeExec(return_code=1)
        args = [
            os.path.join('sdk_root_dir', 'intercal-flex'), 'app.yaml', 'dir',
            'tmp_dir'
        ]
        command = ' '.join(args)
        expected_pattern = (
            re.escape(self._ERROR_MESSAGE.format(command=command, code=1)) +
            '\n\n' + self._OUTPUT_PATTERN)
        with self.assertRaisesRegex(staging.StagingCommandFailedError,
                                    expected_pattern):
            self.stager.Stage('app.yaml', 'dir', 'intercal', env.FLEX)
        self.exec_mock.assert_called_once_with(args,
                                               no_exit=True,
                                               out_func=mock.ANY,
                                               err_func=mock.ANY)

    def testStage_Success(self):
        args = [
            os.path.join('sdk_root_dir', 'intercal-flex'), 'app.yaml', 'dir',
            'tmp_dir'
        ]
        self.stager.Stage('app.yaml', 'dir', 'intercal', env.FLEX)
        self.exec_mock.assert_called_once_with(args,
                                               no_exit=True,
                                               out_func=mock.ANY,
                                               err_func=mock.ANY)
        command = ' '.join(args)
        self.AssertLogMatches(
            re.escape(self._SUCCESS_MESSAGE.format(command=command)))
        self.AssertLogMatches(self._OUTPUT_PATTERN)
        self.mkdtemp_mock.assert_called_once_with(dir='/staging-area')

    def testStage_SuccessWindows(self):
        self.StartObjectPatch(platforms.OperatingSystem,
                              'Current',
                              return_value=platforms.OperatingSystem.WINDOWS)
        args = [
            os.path.join('sdk_root_dir', 'intercal-flex.exe'), 'app.yaml',
            'dir', 'tmp_dir'
        ]
        self.stager.Stage('app.yaml', 'dir', 'intercal', env.FLEX)
        self.exec_mock.assert_called_once_with(args,
                                               no_exit=True,
                                               out_func=mock.ANY,
                                               err_func=mock.ANY)
        command = ' '.join(args)
        self.AssertLogMatches(
            re.escape(self._SUCCESS_MESSAGE.format(command=command)))
        self.AssertLogMatches(self._OUTPUT_PATTERN)
        self.mkdtemp_mock.assert_called_once_with(dir='/staging-area')

    def testStage_SuccessInstalledComponent(self):
        ensure_installed_mock = self.StartObjectPatch(
            update_manager.UpdateManager, 'EnsureInstalledAndRestart')
        args = [
            os.path.join('sdk_root_dir', 'x86-asm-standard'), 'app.yaml',
            'dir', 'tmp_dir'
        ]
        self.stager.Stage('app.yaml', 'dir', 'x86-asm', env.STANDARD)
        self.exec_mock.assert_called_once_with(args,
                                               no_exit=True,
                                               out_func=mock.ANY,
                                               err_func=mock.ANY)
        command = ' '.join(args)
        self.AssertLogMatches(
            re.escape(self._SUCCESS_MESSAGE.format(command=command)))
        self.AssertLogMatches(self._OUTPUT_PATTERN)
        ensure_installed_mock.assert_called_once_with(['app-engine-x86-asm'],
                                                      msg=mock.ANY)
        self.mkdtemp_mock.assert_called_once_with(dir='/staging-area')

    def testStage_CustomMapper(self):
        """Test that a custom mapper function can be invoked."""
        args = [
            os.path.join('sdk_root_dir', 'german-standard'), '-dir', 'tmp_dir',
            '-yaml', 'app.yaml', 'dir'
        ]
        self.stager.Stage('app.yaml', 'dir', 'german', env.STANDARD)
        self.exec_mock.assert_called_once_with(args,
                                               no_exit=True,
                                               out_func=mock.ANY,
                                               err_func=mock.ANY)
        command = ' '.join(args)
        self.AssertLogMatches(
            re.escape(self._SUCCESS_MESSAGE.format(command=command)))
        self.AssertLogMatches(self._OUTPUT_PATTERN)
        self.mkdtemp_mock.assert_called_once_with(dir='/staging-area')