github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/storage/bucket/s3/config_test.go (about)

     1  package s3
     2  
     3  import (
     4  	"encoding/base64"
     5  	"net/http"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/grafana/dskit/flagext"
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  	"gopkg.in/yaml.v2"
    13  
    14  	bucket_http "github.com/grafana/loki/pkg/storage/bucket/http"
    15  )
    16  
    17  // defaultConfig should match the default flag values defined in RegisterFlagsWithPrefix.
    18  var defaultConfig = Config{
    19  	SignatureVersion: SignatureVersionV4,
    20  	HTTP: HTTPConfig{
    21  		Config: bucket_http.Config{
    22  			IdleConnTimeout:       90 * time.Second,
    23  			ResponseHeaderTimeout: 2 * time.Minute,
    24  			InsecureSkipVerify:    false,
    25  			TLSHandshakeTimeout:   10 * time.Second,
    26  			ExpectContinueTimeout: 1 * time.Second,
    27  			MaxIdleConns:          100,
    28  			MaxIdleConnsPerHost:   100,
    29  			MaxConnsPerHost:       0,
    30  		},
    31  	},
    32  }
    33  
    34  func TestConfig(t *testing.T) {
    35  	t.Parallel()
    36  
    37  	tests := map[string]struct {
    38  		config         string
    39  		expectedConfig Config
    40  		expectedErr    error
    41  	}{
    42  		"default config": {
    43  			config:         "",
    44  			expectedConfig: defaultConfig,
    45  			expectedErr:    nil,
    46  		},
    47  		"custom config": {
    48  			config: `
    49  endpoint: test-endpoint
    50  region: test-region
    51  bucket_name: test-bucket-name
    52  secret_access_key: test-secret-access-key
    53  access_key_id: test-access-key-id
    54  insecure: true
    55  signature_version: test-signature-version
    56  sse:
    57    type: test-type
    58    kms_key_id: test-kms-key-id
    59    kms_encryption_context: test-kms-encryption-context
    60  http:
    61    idle_conn_timeout: 2s
    62    response_header_timeout: 3s
    63    insecure_skip_verify: true
    64    tls_handshake_timeout: 4s
    65    expect_continue_timeout: 5s
    66    max_idle_connections: 6
    67    max_idle_connections_per_host: 7
    68    max_connections_per_host: 8
    69  `,
    70  			expectedConfig: Config{
    71  				Endpoint:         "test-endpoint",
    72  				Region:           "test-region",
    73  				BucketName:       "test-bucket-name",
    74  				SecretAccessKey:  flagext.SecretWithValue("test-secret-access-key"),
    75  				AccessKeyID:      "test-access-key-id",
    76  				Insecure:         true,
    77  				SignatureVersion: "test-signature-version",
    78  				SSE: SSEConfig{
    79  					Type:                 "test-type",
    80  					KMSKeyID:             "test-kms-key-id",
    81  					KMSEncryptionContext: "test-kms-encryption-context",
    82  				},
    83  				HTTP: HTTPConfig{
    84  					Config: bucket_http.Config{
    85  						IdleConnTimeout:       2 * time.Second,
    86  						ResponseHeaderTimeout: 3 * time.Second,
    87  						InsecureSkipVerify:    true,
    88  						TLSHandshakeTimeout:   4 * time.Second,
    89  						ExpectContinueTimeout: 5 * time.Second,
    90  						MaxIdleConns:          6,
    91  						MaxIdleConnsPerHost:   7,
    92  						MaxConnsPerHost:       8,
    93  					},
    94  				},
    95  			},
    96  			expectedErr: nil,
    97  		},
    98  		"invalid type": {
    99  			config:         `insecure: foo`,
   100  			expectedConfig: defaultConfig,
   101  			expectedErr:    &yaml.TypeError{Errors: []string{"line 1: cannot unmarshal !!str `foo` into bool"}},
   102  		},
   103  	}
   104  
   105  	for testName, testData := range tests {
   106  		testData := testData
   107  
   108  		t.Run(testName, func(t *testing.T) {
   109  			cfg := Config{}
   110  			flagext.DefaultValues(&cfg)
   111  
   112  			err := yaml.Unmarshal([]byte(testData.config), &cfg)
   113  			require.Equal(t, testData.expectedErr, err)
   114  			require.Equal(t, testData.expectedConfig, cfg)
   115  		})
   116  	}
   117  }
   118  
   119  func TestSSEConfig_Validate(t *testing.T) {
   120  	tests := map[string]struct {
   121  		setup    func() *SSEConfig
   122  		expected error
   123  	}{
   124  		"should pass with default config": {
   125  			setup: func() *SSEConfig {
   126  				cfg := &SSEConfig{}
   127  				flagext.DefaultValues(cfg)
   128  
   129  				return cfg
   130  			},
   131  		},
   132  		"should fail on invalid SSE type": {
   133  			setup: func() *SSEConfig {
   134  				return &SSEConfig{
   135  					Type: "unknown",
   136  				}
   137  			},
   138  			expected: errUnsupportedSSEType,
   139  		},
   140  		"should fail on invalid SSE KMS encryption context": {
   141  			setup: func() *SSEConfig {
   142  				return &SSEConfig{
   143  					Type:                 SSEKMS,
   144  					KMSEncryptionContext: "!{}!",
   145  				}
   146  			},
   147  			expected: errInvalidSSEContext,
   148  		},
   149  		"should pass on valid SSE KMS encryption context": {
   150  			setup: func() *SSEConfig {
   151  				return &SSEConfig{
   152  					Type:                 SSEKMS,
   153  					KMSEncryptionContext: `{"department": "10103.0"}`,
   154  				}
   155  			},
   156  		},
   157  	}
   158  
   159  	for testName, testData := range tests {
   160  		t.Run(testName, func(t *testing.T) {
   161  			assert.Equal(t, testData.expected, testData.setup().Validate())
   162  		})
   163  	}
   164  }
   165  
   166  func TestSSEConfig_BuildMinioConfig(t *testing.T) {
   167  	tests := map[string]struct {
   168  		cfg             *SSEConfig
   169  		expectedType    string
   170  		expectedKeyID   string
   171  		expectedContext string
   172  	}{
   173  		"SSE KMS without encryption context": {
   174  			cfg: &SSEConfig{
   175  				Type:     SSEKMS,
   176  				KMSKeyID: "test-key",
   177  			},
   178  			expectedType:    "aws:kms",
   179  			expectedKeyID:   "test-key",
   180  			expectedContext: "",
   181  		},
   182  		"SSE KMS with encryption context": {
   183  			cfg: &SSEConfig{
   184  				Type:                 SSEKMS,
   185  				KMSKeyID:             "test-key",
   186  				KMSEncryptionContext: "{\"department\":\"10103.0\"}",
   187  			},
   188  			expectedType:    "aws:kms",
   189  			expectedKeyID:   "test-key",
   190  			expectedContext: "{\"department\":\"10103.0\"}",
   191  		},
   192  	}
   193  
   194  	for testName, testData := range tests {
   195  		t.Run(testName, func(t *testing.T) {
   196  			sse, err := testData.cfg.BuildMinioConfig()
   197  			require.NoError(t, err)
   198  
   199  			headers := http.Header{}
   200  			sse.Marshal(headers)
   201  
   202  			assert.Equal(t, testData.expectedType, headers.Get("x-amz-server-side-encryption"))
   203  			assert.Equal(t, testData.expectedKeyID, headers.Get("x-amz-server-side-encryption-aws-kms-key-id"))
   204  			assert.Equal(t, base64.StdEncoding.EncodeToString([]byte(testData.expectedContext)), headers.Get("x-amz-server-side-encryption-context"))
   205  		})
   206  	}
   207  }
   208  
   209  func TestParseKMSEncryptionContext(t *testing.T) {
   210  	actual, err := parseKMSEncryptionContext("")
   211  	assert.NoError(t, err)
   212  	assert.Equal(t, map[string]string(nil), actual)
   213  
   214  	expected := map[string]string{
   215  		"department": "10103.0",
   216  	}
   217  	actual, err = parseKMSEncryptionContext(`{"department": "10103.0"}`)
   218  	assert.NoError(t, err)
   219  	assert.Equal(t, expected, actual)
   220  }