-
Notifications
You must be signed in to change notification settings - Fork 297
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support HSET
in redis
#3768
Conversation
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## master #3768 +/- ##
==========================================
+ Coverage 68.94% 69.07% +0.12%
==========================================
Files 349 349
Lines 51872 51894 +22
==========================================
+ Hits 35765 35844 +79
+ Misses 13801 13745 -56
+ Partials 2306 2305 -1
☔ View full report in Codecov by Sentry. |
Co-authored-by: Akash Chetty <achetty.iitr@gmail.com>
Co-authored-by: Akash Chetty <achetty.iitr@gmail.com>
[Optional] We can remove the |
func TestKVManagerHSETInvocation(t *testing.T) { | ||
initCustomerManager() | ||
customManager := New("REDIS", Opts{}).(*CustomManagerT) | ||
someDestination := backendconfig.DestinationT{ | ||
ID: "someDestinationID1", | ||
DestinationDefinition: backendconfig.DestinationDefinitionT{ | ||
Name: "REDIS", | ||
}, | ||
} | ||
err := customManager.onNewDestination(someDestination) | ||
assert.Nil(t, err) | ||
|
||
event := json.RawMessage(`{ | ||
"message": { | ||
"key": "someKey", | ||
"value" : "someValue", | ||
"hash": "someHash" | ||
} | ||
} | ||
`) | ||
ctrl := gomock.NewController(t) | ||
mockKVStoreManager := mock_kvstoremanager.NewMockKVStoreManager(ctrl) | ||
mockKVStoreManager.EXPECT().HSet("someHash", "someKey", "someValue").Times(1) | ||
mockKVStoreManager.EXPECT().StatusCode(nil).Times(1) | ||
customManager.send(event, mockKVStoreManager, someDestination.Config) | ||
} | ||
|
||
func TestKVManagerHMSETInvocation(t *testing.T) { | ||
initCustomerManager() | ||
customManager := New("REDIS", Opts{}).(*CustomManagerT) | ||
someDestination := backendconfig.DestinationT{ | ||
ID: "someDestinationID1", | ||
DestinationDefinition: backendconfig.DestinationDefinitionT{ | ||
Name: "REDIS", | ||
}, | ||
} | ||
err := customManager.onNewDestination(someDestination) | ||
assert.Nil(t, err) | ||
|
||
event := json.RawMessage(`{ | ||
"message": { | ||
"key": "someKey", | ||
"fields" : { | ||
"field1": "value1", | ||
"field2": "value2" | ||
} | ||
} | ||
} | ||
`) | ||
ctrl := gomock.NewController(t) | ||
mockKVStoreManager := mock_kvstoremanager.NewMockKVStoreManager(ctrl) | ||
mockKVStoreManager.EXPECT().HMSet("someKey", map[string]interface{}{ | ||
"field1": "value1", | ||
"field2": "value2", | ||
}).Times(1) | ||
mockKVStoreManager.EXPECT().StatusCode(nil).Times(1) | ||
customManager.send(event, mockKVStoreManager, someDestination.Config) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Optional] Maybe we can remove duplicate code and compact these tests?
func TestKVManagerHSETInvocation(t *testing.T) { | |
initCustomerManager() | |
customManager := New("REDIS", Opts{}).(*CustomManagerT) | |
someDestination := backendconfig.DestinationT{ | |
ID: "someDestinationID1", | |
DestinationDefinition: backendconfig.DestinationDefinitionT{ | |
Name: "REDIS", | |
}, | |
} | |
err := customManager.onNewDestination(someDestination) | |
assert.Nil(t, err) | |
event := json.RawMessage(`{ | |
"message": { | |
"key": "someKey", | |
"value" : "someValue", | |
"hash": "someHash" | |
} | |
} | |
`) | |
ctrl := gomock.NewController(t) | |
mockKVStoreManager := mock_kvstoremanager.NewMockKVStoreManager(ctrl) | |
mockKVStoreManager.EXPECT().HSet("someHash", "someKey", "someValue").Times(1) | |
mockKVStoreManager.EXPECT().StatusCode(nil).Times(1) | |
customManager.send(event, mockKVStoreManager, someDestination.Config) | |
} | |
func TestKVManagerHMSETInvocation(t *testing.T) { | |
initCustomerManager() | |
customManager := New("REDIS", Opts{}).(*CustomManagerT) | |
someDestination := backendconfig.DestinationT{ | |
ID: "someDestinationID1", | |
DestinationDefinition: backendconfig.DestinationDefinitionT{ | |
Name: "REDIS", | |
}, | |
} | |
err := customManager.onNewDestination(someDestination) | |
assert.Nil(t, err) | |
event := json.RawMessage(`{ | |
"message": { | |
"key": "someKey", | |
"fields" : { | |
"field1": "value1", | |
"field2": "value2" | |
} | |
} | |
} | |
`) | |
ctrl := gomock.NewController(t) | |
mockKVStoreManager := mock_kvstoremanager.NewMockKVStoreManager(ctrl) | |
mockKVStoreManager.EXPECT().HMSet("someKey", map[string]interface{}{ | |
"field1": "value1", | |
"field2": "value2", | |
}).Times(1) | |
mockKVStoreManager.EXPECT().StatusCode(nil).Times(1) | |
customManager.send(event, mockKVStoreManager, someDestination.Config) | |
} | |
func TestKVManagerInvocation(t *testing.T) { | |
initCustomerManager() | |
customManager := New("REDIS", Opts{}).(*CustomManagerT) | |
someDestination := backendconfig.DestinationT{ | |
ID: "someDestinationID1", | |
DestinationDefinition: backendconfig.DestinationDefinitionT{ | |
Name: "REDIS", | |
}, | |
} | |
err := customManager.onNewDestination(someDestination) | |
assert.Nil(t, err) | |
ctrl := gomock.NewController(t) | |
defer ctrl.Finish() | |
t.Run("HSET", func(t *testing.T) { | |
event := json.RawMessage(`{ | |
"message": { | |
"key": "someKey", | |
"value" : "someValue", | |
"hash": "someHash" | |
} | |
} | |
`) | |
mockKVStoreManager := mock_kvstoremanager.NewMockKVStoreManager(ctrl) | |
mockKVStoreManager.EXPECT().HSet("someHash", "someKey", "someValue").Times(1) | |
mockKVStoreManager.EXPECT().StatusCode(nil).Times(1) | |
customManager.send(event, mockKVStoreManager, someDestination.Config) | |
}) | |
t.Run("HMSET", func(t *testing.T) { | |
event := json.RawMessage(`{ | |
"message": { | |
"key": "someKey", | |
"fields" : { | |
"field1": "value1", | |
"field2": "value2" | |
} | |
} | |
} | |
`) | |
mockKVStoreManager := mock_kvstoremanager.NewMockKVStoreManager(ctrl) | |
mockKVStoreManager.EXPECT().HMSet("someKey", map[string]interface{}{ | |
"field1": "value1", | |
"field2": "value2", | |
}).Times(1) | |
mockKVStoreManager.EXPECT().StatusCode(nil).Times(1) | |
customManager.send(event, mockKVStoreManager, someDestination.Config) | |
}) | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed
// - message.hash | ||
// It doesn't account for the value of the fields. | ||
func IsHSETCompatibleEvent(jsonData json.RawMessage) bool { | ||
return gjson.GetBytes(jsonData, hashPath).Exists() && gjson.GetBytes(jsonData, keyPath).Exists() && gjson.GetBytes(jsonData, valuePath).Exists() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would avoid the extensive and repeated usage of gjson.
Using a go struct
type HSetEvent struct {
Hash string `json:"<hash_path>"`
Key string `json:"<key_path>"`
Value string `json:"<value_path>"`
}
It would be safer and faster (assuming fastjson library is used)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if I understand faster (assuming fastjson library is used)
completely.
I can use fastjson's Exists but that doesn't require a go struct to unmarshal to.
Unless we somehow use fastjson while unmarshalling, using CustomUnmarshal, or I might be completely missing the point here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Description
This PR augments the capability of the
redisManager
to support HSET as one of the operations.
More on HSET here.
The
customdestinationmanager
checks the format of the incoming eventand determines the type of operation required for writing into the key-value store.
If the incoming event is in the format of
customdestinationmanager
decides to use HSET.More on why this change is required is here
Linear Ticket
https://linear.app/rudderstack/issue/PRO-633/server-add-support-for-hset
Security