diff options
author | Patrick Steinhardt <psteinhardt@gitlab.com> | 2022-04-26 09:29:24 +0300 |
---|---|---|
committer | Patrick Steinhardt <psteinhardt@gitlab.com> | 2022-04-26 11:14:14 +0300 |
commit | fcc3c5e76691eeed51aa9aeba37065cf31b30e01 (patch) | |
tree | 2ed7852f817fc24b641b73e33be2c3ce59d9bf93 | |
parent | 8339301f386ec041fac36d9a1098d89141672225 (diff) |
gittest: Optionally intercept Git version in intercepting factory
The intercepting Git command factory is currently always using the
intercepting script to derive the current Git version. This only works
alright because we typically don't check for the Git version in most
callsites, and thus the intercepting script's output is never used to
determine the version except for some limited cases. This is about to
change though given that we'll introduce a Git version check into the
command factory itself, which will then break all tests which use the
intercepting command factory.
Add a new option to the intercepting command factory that allows the
caller to only optionally intercept the Git version. By default, we'll
now use the real Git version so that users will continue to work.
-rw-r--r-- | internal/git/command_factory_test.go | 2 | ||||
-rw-r--r-- | internal/git/gittest/intercepting_command_factory.go | 19 | ||||
-rw-r--r-- | internal/git/gittest/intercepting_command_factory_test.go | 66 |
3 files changed, 85 insertions, 2 deletions
diff --git a/internal/git/command_factory_test.go b/internal/git/command_factory_test.go index b8ae02ad9..e9eee0a40 100644 --- a/internal/git/command_factory_test.go +++ b/internal/git/command_factory_test.go @@ -361,6 +361,7 @@ func TestExecCommandFactory_GitVersion(t *testing.T) { gitCmdFactory := gittest.NewInterceptingCommandFactory( ctx, t, testcfg.Build(t), generateVersionScript(tc.versionString), gittest.WithRealCommandFactoryOptions(git.WithSkipHooks()), + gittest.WithInterceptedVersion(), ) actualVersion, err := gitCmdFactory.GitVersion(ctx) @@ -377,6 +378,7 @@ func TestExecCommandFactory_GitVersion(t *testing.T) { gitCmdFactory := gittest.NewInterceptingCommandFactory( ctx, t, testcfg.Build(t), generateVersionScript("git version 1.2.3"), gittest.WithRealCommandFactoryOptions(git.WithSkipHooks()), + gittest.WithInterceptedVersion(), ) gitPath := gitCmdFactory.GetExecutionEnvironment(ctx).BinaryPath diff --git a/internal/git/gittest/intercepting_command_factory.go b/internal/git/gittest/intercepting_command_factory.go index 393ff38e5..ebc162487 100644 --- a/internal/git/gittest/intercepting_command_factory.go +++ b/internal/git/gittest/intercepting_command_factory.go @@ -19,10 +19,12 @@ var _ git.CommandFactory = &InterceptingCommandFactory{} type InterceptingCommandFactory struct { realCommandFactory git.CommandFactory interceptingCommandFactory git.CommandFactory + interceptVersion bool } type interceptingCommandFactoryConfig struct { - opts []git.ExecCommandFactoryOption + opts []git.ExecCommandFactoryOption + interceptVersion bool } // InterceptingCommandFactoryOption is an option that can be passed to @@ -37,6 +39,15 @@ func WithRealCommandFactoryOptions(opts ...git.ExecCommandFactoryOption) Interce } } +// WithInterceptedVersion will cause `GitVersion()` to use the intercepting Git command factory +// instead of the real Git command factory. This allows the caller to explicitly test version +// detection. +func WithInterceptedVersion() InterceptingCommandFactoryOption { + return func(cfg *interceptingCommandFactoryConfig) { + cfg.interceptVersion = true + } +} + // NewInterceptingCommandFactory creates a new command factory which intercepts Git commands. The // given configuration must point to the real Git executable. The function will be executed to // generate the script and receives as input the Git execution environment pointing to the real Git @@ -66,6 +77,7 @@ func NewInterceptingCommandFactory( return &InterceptingCommandFactory{ realCommandFactory: gitCmdFactory, interceptingCommandFactory: NewCommandFactory(tb, cfg, git.WithGitBinaryPath(scriptPath)), + interceptVersion: interceptingCommandFactoryCfg.interceptVersion, } } @@ -107,5 +119,8 @@ func (f *InterceptingCommandFactory) HooksPath(ctx context.Context) string { // GitVersion returns the Git version as returned by the intercepted command. func (f *InterceptingCommandFactory) GitVersion(ctx context.Context) (git.Version, error) { - return f.interceptingCommandFactory.GitVersion(ctx) + if f.interceptVersion { + return f.interceptingCommandFactory.GitVersion(ctx) + } + return f.realCommandFactory.GitVersion(ctx) } diff --git a/internal/git/gittest/intercepting_command_factory_test.go b/internal/git/gittest/intercepting_command_factory_test.go index f3005f86b..6b0cc136f 100644 --- a/internal/git/gittest/intercepting_command_factory_test.go +++ b/internal/git/gittest/intercepting_command_factory_test.go @@ -58,3 +58,69 @@ func TestInterceptingCommandFactory(t *testing.T) { require.Equal(t, expectedString, stdout.String()) }) } + +func TestInterceptingCommandFactory_GitVersion(t *testing.T) { + cfg, _, _ := setup(t) + ctx := testhelper.Context(t) + + generateVersionScript := func(execEnv git.ExecutionEnvironment) string { + return `#!/usr/bin/env bash + echo "git version 1.2.3" + ` + } + + // Obtain the real Git version so that we can compare that it matches what we expect. + realFactory, cleanup, err := git.NewExecCommandFactory(cfg) + require.NoError(t, err) + defer cleanup() + + realVersion, err := realFactory.GitVersion(ctx) + require.NoError(t, err) + + // Furthermore, we need to obtain the intercepted version here because we cannot construct + // `git.Version` structs ourselves. + fakeVersion, err := NewInterceptingCommandFactory(ctx, t, cfg, generateVersionScript, WithInterceptedVersion()).GitVersion(ctx) + require.NoError(t, err) + require.Equal(t, "1.2.3", fakeVersion.String()) + + for _, tc := range []struct { + desc string + opts []InterceptingCommandFactoryOption + expectedVersion git.Version + }{ + { + desc: "without version interception", + expectedVersion: realVersion, + }, + { + desc: "with version interception", + opts: []InterceptingCommandFactoryOption{ + WithInterceptedVersion(), + }, + expectedVersion: fakeVersion, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + factory := NewInterceptingCommandFactory(ctx, t, cfg, generateVersionScript, tc.opts...) + + version, err := factory.GitVersion(ctx) + require.NoError(t, err) + require.Equal(t, tc.expectedVersion, version) + + // The real command factory should always return the real Git version. + version, err = factory.realCommandFactory.GitVersion(ctx) + require.NoError(t, err) + require.Equal(t, realVersion, version) + + // On the other hand, the intercepting command factory should return + // different versions depending on whether the version is intercepted or + // not. This is required such that it correctly handles version checks in + // case it calls `GitVersion()` on itself. + // + // Right now, this doesn't work correctly though. + version, err = factory.interceptingCommandFactory.GitVersion(ctx) + require.NoError(t, err) + require.Equal(t, fakeVersion, version) + }) + } +} |