gitlab.com/gitlab-org/labkit@v1.21.0/monitoring/profiler_test.go (about)

     1  // +build continuous_profiler_stackdriver
     2  
     3  package monitoring
     4  
     5  import (
     6  	"bytes"
     7  	"fmt"
     8  	"os"
     9  	"testing"
    10  
    11  	"cloud.google.com/go/profiler"
    12  	"github.com/stretchr/testify/require"
    13  	"gitlab.com/gitlab-org/labkit/log"
    14  	"google.golang.org/api/option"
    15  )
    16  
    17  func TestInitProfiler(t *testing.T) {
    18  	tests := []struct {
    19  		name            string
    20  		envParams       string
    21  		writeEnvVar     bool
    22  		opts            profilerOpts
    23  		expectedLog     string
    24  		profErr         error
    25  		expectedConfig  profiler.Config
    26  		expectedOptions []option.ClientOption
    27  	}{
    28  		{
    29  			name:           "complete params",
    30  			opts:           profilerOpts{},
    31  			envParams:      "stackdriver?service=gitaly&service_version=1.0.1&project_id=test-123",
    32  			writeEnvVar:    true,
    33  			expectedLog:    `^time=.*level=info msg="profiler enabled" driver=stackdriver projectId=test-123 service=gitaly serviceVersion=1.0.1`,
    34  			expectedConfig: profiler.Config{Service: "gitaly", ServiceVersion: "1.0.1", ProjectID: "test-123", MutexProfiling: true},
    35  		},
    36  		{
    37  			name:           "complete env params and service version given",
    38  			opts:           profilerOpts{ServiceVersion: "9.0.0"},
    39  			envParams:      "stackdriver?service=gitaly&service_version=1.0.1&project_id=test-123",
    40  			writeEnvVar:    true,
    41  			expectedLog:    `^time=.*level=info msg="profiler enabled" driver=stackdriver projectId=test-123 service=gitaly serviceVersion=9.0.0`,
    42  			expectedConfig: profiler.Config{Service: "gitaly", ServiceVersion: "9.0.0", ProjectID: "test-123", MutexProfiling: true},
    43  		},
    44  		{
    45  			name:           "incomplete env params and service version given through args",
    46  			opts:           profilerOpts{ServiceVersion: "9.0.0"},
    47  			envParams:      "stackdriver?service=gitaly",
    48  			expectedLog:    `^time=.*level=info msg="profiler enabled" driver=stackdriver projectId= service=gitaly serviceVersion=9.0.0`,
    49  			expectedConfig: profiler.Config{MutexProfiling: true},
    50  		},
    51  		{
    52  			name:           "debug logging",
    53  			opts:           profilerOpts{ServiceVersion: "9.0.0"},
    54  			envParams:      "stackdriver?service=gitaly&debug_logging=true",
    55  			writeEnvVar:    true,
    56  			expectedLog:    `^time=.*level=info msg="profiler enabled" driver=stackdriver projectId= service=gitaly serviceVersion=9.0.0`,
    57  			expectedConfig: profiler.Config{Service: "gitaly", ServiceVersion: "9.0.0", MutexProfiling: true, DebugLogging: true},
    58  		},
    59  		{
    60  			name:        "unknown driver",
    61  			envParams:   "true?service=gitaly",
    62  			writeEnvVar: true,
    63  			opts:        profilerOpts{},
    64  			expectedLog: `^time=.*level=warning msg="unknown driver" driver=true`,
    65  		},
    66  		{
    67  			name:        "wrong env content format",
    68  			envParams:   ":foo?service=gitaly",
    69  			writeEnvVar: true,
    70  			opts:        profilerOpts{},
    71  			expectedLog: `^time=.*level=warning msg="unable to parse env var content"`,
    72  		},
    73  		{
    74  			name:        "empty logs when no env var is set",
    75  			writeEnvVar: false,
    76  			opts:        profilerOpts{},
    77  		},
    78  		{
    79  			name:           "fails to start profiler",
    80  			envParams:      "stackdriver?service=gitaly&service_version=1.0.1&project_id=test-123",
    81  			writeEnvVar:    true,
    82  			opts:           profilerOpts{},
    83  			expectedLog:    `^time=.*level=warning msg="unable to initialize stackdriver profiler" error="fail to start"`,
    84  			profErr:        fmt.Errorf("fail to start"),
    85  			expectedConfig: profiler.Config{Service: "gitaly", ServiceVersion: "1.0.1", ProjectID: "test-123", MutexProfiling: true},
    86  		},
    87  		{
    88  			name:            "with credentials file",
    89  			envParams:       "stackdriver",
    90  			writeEnvVar:     true,
    91  			opts:            profilerOpts{CredentialsFile: "/path/to/credentials.json"},
    92  			expectedOptions: []option.ClientOption{option.WithCredentialsFile("/path/to/credentials.json")},
    93  			expectedConfig:  profiler.Config{MutexProfiling: true},
    94  		},
    95  	}
    96  	for _, test := range tests {
    97  		t.Run(test.name, func(t *testing.T) {
    98  			clearGcpEnvVars(t)
    99  
   100  			preStubStart := profStart
   101  			defer func() { profStart = preStubStart }()
   102  
   103  			var actualConfig profiler.Config
   104  			var actualOptions []option.ClientOption
   105  			profStart = func(cfg profiler.Config, options ...option.ClientOption) error {
   106  				actualConfig = cfg
   107  				actualOptions = options
   108  				return test.profErr
   109  			}
   110  
   111  			if test.writeEnvVar {
   112  				err := os.Setenv(profilerEnvKey, test.envParams)
   113  				require.NoError(t, err)
   114  			}
   115  
   116  			logOutput := captureLogOutput(t, initProfiler, test.opts)
   117  
   118  			if test.writeEnvVar {
   119  				require.Regexp(t, test.expectedLog, logOutput)
   120  				require.Equal(t, test.expectedConfig, actualConfig)
   121  				require.Equal(t, test.expectedOptions, actualOptions)
   122  			} else {
   123  				require.Empty(t, logOutput)
   124  			}
   125  		})
   126  	}
   127  }
   128  
   129  func TestInitProfilerWithNoProfilerEnvKeySet(t *testing.T) {
   130  	t.Run("no GITLAB_CONTINUOUS_PROFILING env var set", func(t *testing.T) {
   131  		clearGcpEnvVars(t)
   132  
   133  		logOutput := captureLogOutput(t, initProfiler, profilerOpts{})
   134  
   135  		require.Empty(t, logOutput)
   136  	})
   137  }
   138  
   139  func captureLogOutput(t *testing.T, init func(opts profilerOpts), opts profilerOpts) string {
   140  	t.Helper()
   141  
   142  	buf := &bytes.Buffer{}
   143  	closer, err := log.Initialize(log.WithWriter(buf))
   144  	require.NoError(t, err)
   145  	defer closer.Close()
   146  
   147  	init(opts)
   148  
   149  	return buf.String()
   150  }
   151  
   152  func clearGcpEnvVars(t *testing.T) {
   153  	t.Helper()
   154  
   155  	for _, env := range []string{profilerEnvKey, "GAE_SERVICE", "GAE_VERSION", "GOOGLE_CLOUD_PROJECT"} {
   156  		err := os.Unsetenv(env)
   157  
   158  		require.NoError(t, err)
   159  	}
   160  }