go.temporal.io/server@v1.23.0/common/persistence/client/fault_injection_test.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
     4  //
     5  // Copyright (c) 2020 Uber Technologies, Inc.
     6  //
     7  // Permission is hereby granted, free of charge, to any person obtaining a copy
     8  // of this software and associated documentation files (the "Software"), to deal
     9  // in the Software without restriction, including without limitation the rights
    10  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11  // copies of the Software, and to permit persons to whom the Software is
    12  // furnished to do so, subject to the following conditions:
    13  //
    14  // The above copyright notice and this permission notice shall be included in
    15  // all copies or substantial portions of the Software.
    16  //
    17  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23  // THE SOFTWARE.
    24  
    25  package client_test
    26  
    27  import (
    28  	"context"
    29  	"errors"
    30  	"testing"
    31  
    32  	"github.com/stretchr/testify/assert"
    33  	"github.com/stretchr/testify/require"
    34  
    35  	"go.temporal.io/server/common/config"
    36  	"go.temporal.io/server/common/persistence"
    37  	"go.temporal.io/server/common/persistence/client"
    38  )
    39  
    40  type (
    41  	testDataStoreFactory struct {
    42  		client.DataStoreFactory
    43  		err                 error
    44  		enqueueRequests     int
    45  		readRequests        int
    46  		createRequests      int
    47  		rangeDeleteRequests int
    48  	}
    49  	testQueueV2 struct {
    50  		enqueueRequests     *int
    51  		readRequests        *int
    52  		createRequests      *int
    53  		rangeDeleteRequests *int
    54  		listQueuesRequests  *int
    55  	}
    56  )
    57  
    58  func (t *testQueueV2) EnqueueMessage(
    59  	context.Context,
    60  	*persistence.InternalEnqueueMessageRequest,
    61  ) (*persistence.InternalEnqueueMessageResponse, error) {
    62  	*t.enqueueRequests++
    63  	return nil, nil
    64  }
    65  
    66  func (t *testQueueV2) ReadMessages(
    67  	context.Context,
    68  	*persistence.InternalReadMessagesRequest,
    69  ) (*persistence.InternalReadMessagesResponse, error) {
    70  	*t.readRequests++
    71  	return nil, nil
    72  }
    73  
    74  func (t *testQueueV2) CreateQueue(
    75  	context.Context,
    76  	*persistence.InternalCreateQueueRequest,
    77  ) (*persistence.InternalCreateQueueResponse, error) {
    78  	*t.createRequests++
    79  	return nil, nil
    80  }
    81  
    82  func (t *testQueueV2) RangeDeleteMessages(
    83  	context.Context,
    84  	*persistence.InternalRangeDeleteMessagesRequest,
    85  ) (*persistence.InternalRangeDeleteMessagesResponse, error) {
    86  	*t.rangeDeleteRequests++
    87  	return nil, nil
    88  }
    89  
    90  func (t *testQueueV2) ListQueues(
    91  	context.Context,
    92  	*persistence.InternalListQueuesRequest,
    93  ) (*persistence.InternalListQueuesResponse, error) {
    94  	*t.listQueuesRequests++
    95  	return nil, nil
    96  }
    97  
    98  func (t *testDataStoreFactory) NewQueueV2() (persistence.QueueV2, error) {
    99  	if t.err != nil {
   100  		return nil, t.err
   101  	}
   102  	return &testQueueV2{
   103  		enqueueRequests:     &t.enqueueRequests,
   104  		readRequests:        &t.readRequests,
   105  		createRequests:      &t.createRequests,
   106  		rangeDeleteRequests: &t.rangeDeleteRequests,
   107  	}, nil
   108  }
   109  
   110  func TestFaultInjectionDataStoreFactory_NewQueueV2_CreateErr(t *testing.T) {
   111  	// Tests that we propagate errors from the base data store factory when creating a QueueV2
   112  
   113  	t.Parallel()
   114  
   115  	errCreate := errors.New("error creating QueueV2")
   116  	dataStoreFactory := &testDataStoreFactory{
   117  		err: errCreate,
   118  	}
   119  	factory := client.NewFaultInjectionDatastoreFactory(&config.FaultInjection{
   120  		Rate:    1.0,
   121  		Targets: config.FaultInjectionTargets{},
   122  	}, dataStoreFactory)
   123  
   124  	_, err := factory.NewQueueV2()
   125  	assert.ErrorIs(t, err, errCreate)
   126  }
   127  
   128  func TestFaultInjectionDataStoreFactory_NewQueueV2_FlatErrorRate(t *testing.T) {
   129  	// Tests fault injection for QueueV2 with a flat error rate across all methods.
   130  
   131  	t.Parallel()
   132  
   133  	for _, tc := range []struct {
   134  		name      string
   135  		errorRate float64
   136  		expectErr bool
   137  	}{
   138  		{
   139  			name:      "No errors",
   140  			errorRate: 0.0,
   141  			expectErr: false,
   142  		},
   143  		{
   144  			name:      "All errors",
   145  			errorRate: 1.0,
   146  			expectErr: true,
   147  		},
   148  	} {
   149  		tc := tc
   150  		t.Run(tc.name, func(t *testing.T) {
   151  			t.Parallel()
   152  			faultInjectionConfig := &config.FaultInjection{
   153  				Rate:    tc.errorRate,
   154  				Targets: config.FaultInjectionTargets{},
   155  			}
   156  			expectErr := tc.expectErr
   157  
   158  			testFaultInjectionConfig(t, faultInjectionConfig, expectErr)
   159  		})
   160  	}
   161  }
   162  
   163  func TestFaultInjectionDataStoreFactory_NewQueueV2_MethodConfig(t *testing.T) {
   164  	// Tests fault injection for QueueV2 with a per-method error config and no flat error rate.
   165  
   166  	t.Parallel()
   167  
   168  	for _, tc := range []struct {
   169  		name      string
   170  		errorRate float64
   171  		expectErr bool
   172  	}{
   173  		{
   174  			name:      "No errors",
   175  			errorRate: 0.0,
   176  			expectErr: false,
   177  		},
   178  		{
   179  			name:      "All errors",
   180  			errorRate: 1.0,
   181  			expectErr: true,
   182  		},
   183  	} {
   184  		tc := tc
   185  		t.Run(tc.name, func(t *testing.T) {
   186  			t.Parallel()
   187  
   188  			methodConfig := config.FaultInjectionMethodConfig{
   189  				Errors: map[string]float64{
   190  					"ResourceExhausted": tc.errorRate,
   191  				},
   192  			}
   193  			faultInjectionConfig := &config.FaultInjection{
   194  				Rate: 0.0,
   195  				Targets: config.FaultInjectionTargets{
   196  					DataStores: map[config.DataStoreName]config.FaultInjectionDataStoreConfig{
   197  						config.QueueV2Name: {
   198  							Methods: map[string]config.FaultInjectionMethodConfig{
   199  								"EnqueueMessage":      methodConfig,
   200  								"ReadMessages":        methodConfig,
   201  								"CreateQueue":         methodConfig,
   202  								"RangeDeleteMessages": methodConfig,
   203  							},
   204  						},
   205  					},
   206  				},
   207  			}
   208  			expectErr := tc.expectErr
   209  
   210  			testFaultInjectionConfig(t, faultInjectionConfig, expectErr)
   211  		})
   212  	}
   213  }
   214  
   215  func testFaultInjectionConfig(t *testing.T, faultInjectionConfig *config.FaultInjection, expectErr bool) {
   216  	t.Helper()
   217  
   218  	dataStoreFactory := &testDataStoreFactory{}
   219  	factory := client.NewFaultInjectionDatastoreFactory(faultInjectionConfig, dataStoreFactory)
   220  
   221  	q, err := factory.NewQueueV2()
   222  	require.NoError(t, err)
   223  
   224  	_, err = q.EnqueueMessage(context.Background(), nil)
   225  	verifyMethod(t, expectErr, err, dataStoreFactory.enqueueRequests)
   226  
   227  	_, err = q.ReadMessages(context.Background(), nil)
   228  	verifyMethod(t, expectErr, err, dataStoreFactory.readRequests)
   229  
   230  	_, err = q.CreateQueue(context.Background(), nil)
   231  	verifyMethod(t, expectErr, err, dataStoreFactory.createRequests)
   232  
   233  	_, err = q.RangeDeleteMessages(context.Background(), nil)
   234  	verifyMethod(t, expectErr, err, dataStoreFactory.rangeDeleteRequests)
   235  
   236  	q2, err := factory.NewQueueV2()
   237  	require.NoError(t, err)
   238  	assert.Equal(t, q, q2, "NewQueueV2 should cache previous result")
   239  }
   240  
   241  func verifyMethod(t *testing.T, expectErr bool, err error, requests int) {
   242  	t.Helper()
   243  	if expectErr {
   244  		assert.Error(t, err)
   245  		assert.Zero(t, requests)
   246  	} else {
   247  		assert.NoError(t, err)
   248  		assert.Equal(t, 1, requests)
   249  	}
   250  }