From a487572a904cc149840488eefdfe121173d8bcb5 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sat, 19 Sep 2020 03:34:49 -0700 Subject: Make it possible to propagate correlation ID across processes Previously, gitlab-shell did not pass a context through the application. Correlation IDs were generated down the call stack instead of passed around from the start execution. This has several potential downsides: 1. It's easier for programming mistakes to be made in future that lead to multiple correlation IDs being generated for a single request. 2. Correlation IDs cannot be passed in from upstream requests 3. Other advantages of context passing, such as distributed tracing is not possible. This commit changes the behavior: 1. Extract the correlation ID from the environment at the start of the application. 2. If no correlation ID exists, generate a random one. 3. Pass the correlation ID to the GitLabNet API requests. This change also enables other clients of GitLabNet (e.g. Gitaly) to pass along the correlation ID in the internal API requests (https://gitlab.com/gitlab-org/gitaly/-/issues/2725). Fixes https://gitlab.com/gitlab-org/gitlab-shell/-/issues/474 --- internal/command/command_test.go | 66 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'internal/command/command_test.go') diff --git a/internal/command/command_test.go b/internal/command/command_test.go index db55e7d..9160abf 100644 --- a/internal/command/command_test.go +++ b/internal/command/command_test.go @@ -2,6 +2,7 @@ package command import ( "errors" + "os" "testing" "github.com/stretchr/testify/require" @@ -20,6 +21,7 @@ import ( "gitlab.com/gitlab-org/gitlab-shell/internal/config" "gitlab.com/gitlab-org/gitlab-shell/internal/executable" "gitlab.com/gitlab-org/gitlab-shell/internal/testhelper" + "gitlab.com/gitlab-org/labkit/correlation" ) var ( @@ -151,3 +153,67 @@ func TestFailingNew(t *testing.T) { }) } } + +func TestContextWithCorrelationID(t *testing.T) { + testCases := []struct { + name string + additionalEnv map[string]string + expectedCorrelationID string + }{ + { + name: "no CORRELATION_ID in environment", + }, + { + name: "CORRELATION_ID in environment", + additionalEnv: map[string]string{ + "CORRELATION_ID": "abc123", + }, + expectedCorrelationID: "abc123", + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + resetEnvironment := addAdditionalEnv(tc.additionalEnv) + defer resetEnvironment() + + ctx, finished := ContextWithCorrelationID() + require.NotNil(t, ctx, "ctx is nil") + require.NotNil(t, finished, "finished is nil") + correlationID := correlation.ExtractFromContext(ctx) + require.NotEmpty(t, correlationID) + + if tc.expectedCorrelationID != "" { + require.Equal(t, tc.expectedCorrelationID, correlationID) + } + defer finished() + }) + } +} + +// addAdditionalEnv will configure additional environment values +// and return a deferrable function to reset the environment to +// it's original state after the test +func addAdditionalEnv(envMap map[string]string) func() { + prevValues := map[string]string{} + unsetValues := []string{} + for k, v := range envMap { + value, exists := os.LookupEnv(k) + if exists { + prevValues[k] = value + } else { + unsetValues = append(unsetValues, k) + } + os.Setenv(k, v) + } + + return func() { + for k, v := range prevValues { + os.Setenv(k, v) + } + + for _, k := range unsetValues { + os.Unsetenv(k) + } + + } +} -- cgit v1.2.1