File: profiler_test.go

package info (click to toggle)
golang-gitlab-gitlab-org-labkit 1.17.0-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,092 kB
  • sloc: sh: 210; javascript: 49; makefile: 4
file content (160 lines) | stat: -rw-r--r-- 5,323 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// +build continuous_profiler_stackdriver

package monitoring

import (
	"bytes"
	"fmt"
	"os"
	"testing"

	"cloud.google.com/go/profiler"
	"github.com/stretchr/testify/require"
	"gitlab.com/gitlab-org/labkit/log"
	"google.golang.org/api/option"
)

func TestInitProfiler(t *testing.T) {
	tests := []struct {
		name            string
		envParams       string
		writeEnvVar     bool
		opts            profilerOpts
		expectedLog     string
		profErr         error
		expectedConfig  profiler.Config
		expectedOptions []option.ClientOption
	}{
		{
			name:           "complete params",
			opts:           profilerOpts{},
			envParams:      "stackdriver?service=gitaly&service_version=1.0.1&project_id=test-123",
			writeEnvVar:    true,
			expectedLog:    `^time=.*level=info msg="profiler enabled" driver=stackdriver projectId=test-123 service=gitaly serviceVersion=1.0.1`,
			expectedConfig: profiler.Config{Service: "gitaly", ServiceVersion: "1.0.1", ProjectID: "test-123", MutexProfiling: true},
		},
		{
			name:           "complete env params and service version given",
			opts:           profilerOpts{ServiceVersion: "9.0.0"},
			envParams:      "stackdriver?service=gitaly&service_version=1.0.1&project_id=test-123",
			writeEnvVar:    true,
			expectedLog:    `^time=.*level=info msg="profiler enabled" driver=stackdriver projectId=test-123 service=gitaly serviceVersion=9.0.0`,
			expectedConfig: profiler.Config{Service: "gitaly", ServiceVersion: "9.0.0", ProjectID: "test-123", MutexProfiling: true},
		},
		{
			name:           "incomplete env params and service version given through args",
			opts:           profilerOpts{ServiceVersion: "9.0.0"},
			envParams:      "stackdriver?service=gitaly",
			expectedLog:    `^time=.*level=info msg="profiler enabled" driver=stackdriver projectId= service=gitaly serviceVersion=9.0.0`,
			expectedConfig: profiler.Config{MutexProfiling: true},
		},
		{
			name:           "debug logging",
			opts:           profilerOpts{ServiceVersion: "9.0.0"},
			envParams:      "stackdriver?service=gitaly&debug_logging=true",
			writeEnvVar:    true,
			expectedLog:    `^time=.*level=info msg="profiler enabled" driver=stackdriver projectId= service=gitaly serviceVersion=9.0.0`,
			expectedConfig: profiler.Config{Service: "gitaly", ServiceVersion: "9.0.0", MutexProfiling: true, DebugLogging: true},
		},
		{
			name:        "unknown driver",
			envParams:   "true?service=gitaly",
			writeEnvVar: true,
			opts:        profilerOpts{},
			expectedLog: `^time=.*level=warning msg="unknown driver" driver=true`,
		},
		{
			name:        "wrong env content format",
			envParams:   ":foo?service=gitaly",
			writeEnvVar: true,
			opts:        profilerOpts{},
			expectedLog: `^time=.*level=warning msg="unable to parse env var content"`,
		},
		{
			name:        "empty logs when no env var is set",
			writeEnvVar: false,
			opts:        profilerOpts{},
		},
		{
			name:           "fails to start profiler",
			envParams:      "stackdriver?service=gitaly&service_version=1.0.1&project_id=test-123",
			writeEnvVar:    true,
			opts:           profilerOpts{},
			expectedLog:    `^time=.*level=warning msg="unable to initialize stackdriver profiler" error="fail to start"`,
			profErr:        fmt.Errorf("fail to start"),
			expectedConfig: profiler.Config{Service: "gitaly", ServiceVersion: "1.0.1", ProjectID: "test-123", MutexProfiling: true},
		},
		{
			name:            "with credentials file",
			envParams:       "stackdriver",
			writeEnvVar:     true,
			opts:            profilerOpts{CredentialsFile: "/path/to/credentials.json"},
			expectedOptions: []option.ClientOption{option.WithCredentialsFile("/path/to/credentials.json")},
			expectedConfig:  profiler.Config{MutexProfiling: true},
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			clearGcpEnvVars(t)

			preStubStart := profStart
			defer func() { profStart = preStubStart }()

			var actualConfig profiler.Config
			var actualOptions []option.ClientOption
			profStart = func(cfg profiler.Config, options ...option.ClientOption) error {
				actualConfig = cfg
				actualOptions = options
				return test.profErr
			}

			if test.writeEnvVar {
				err := os.Setenv(profilerEnvKey, test.envParams)
				require.NoError(t, err)
			}

			logOutput := captureLogOutput(t, initProfiler, test.opts)

			if test.writeEnvVar {
				require.Regexp(t, test.expectedLog, logOutput)
				require.Equal(t, test.expectedConfig, actualConfig)
				require.Equal(t, test.expectedOptions, actualOptions)
			} else {
				require.Empty(t, logOutput)
			}
		})
	}
}

func TestInitProfilerWithNoProfilerEnvKeySet(t *testing.T) {
	t.Run("no GITLAB_CONTINUOUS_PROFILING env var set", func(t *testing.T) {
		clearGcpEnvVars(t)

		logOutput := captureLogOutput(t, initProfiler, profilerOpts{})

		require.Empty(t, logOutput)
	})
}

func captureLogOutput(t *testing.T, init func(opts profilerOpts), opts profilerOpts) string {
	t.Helper()

	buf := &bytes.Buffer{}
	closer, err := log.Initialize(log.WithWriter(buf))
	require.NoError(t, err)
	defer closer.Close()

	init(opts)

	return buf.String()
}

func clearGcpEnvVars(t *testing.T) {
	t.Helper()

	for _, env := range []string{profilerEnvKey, "GAE_SERVICE", "GAE_VERSION", "GOOGLE_CLOUD_PROJECT"} {
		err := os.Unsetenv(env)

		require.NoError(t, err)
	}
}