Take DBAAS multi-channel publishing Redis modules into use 45/5745/1 v0.5.5
authorTimo Tietavainen <timo.tietavainen@nokia.com>
Tue, 9 Mar 2021 14:17:31 +0000 (16:17 +0200)
committerTimo Tietavainen <timo.tietavainen@nokia.com>
Tue, 9 Mar 2021 14:17:31 +0000 (16:17 +0200)
Following SDL APIs are defined so that multiple channel-event pairs can be
given as function argument but actual SDL implementation utilized such a DBAAS
(Redis) module what expect to get only one channel-event pair. Fix the
implementation of these SDL APIs to use the correct DBAAS module what support
multiple channel-event pairs:
* SetIfAndPublish()
* SetIfNotExistsAndPublish()
* RemoveIfAndPublish()

Please note that in runtime environment DBAAS service needs to run on DBAAS
image version 0.4.0 or newer. Older images do not have multiple channel-event
pairs support as a Redis module.

Fixed also potential type conversion issue in SDL APIs RemoveIf() and
RemoveIfAndPublish() what can lead to SDL application crash.

Issue-ID: RIC-759

Signed-off-by: Timo Tietavainen <timo.tietavainen@nokia.com>
Change-Id: I74f483bb31e0c6aed10983a83d70a45272d71fa4

docs/release-notes.rst
internal/sdlgoredis/sdlgoredis.go
internal/sdlgoredis/sdlgoredis_test.go
sdl.go
sdl_test.go

index d2c1c37..1af8a8f 100644 (file)
@@ -30,6 +30,12 @@ This document provides the release notes of the sdlgo.
 Version history
 ---------------
 
+[0.5.5] - 2021-03-09
+
+* Take DBAAS multi-channel publishing Redis modules into use.
+* Fix potential type conversion crash in RemoveIf() and
+  RemoveIfAndPublish() APIs.
+
 [0.5.4] - 2020-10-07
 
 * Fix Go routine race condition when new DB notifications are subscribed.
index 72eaebe..327946e 100644 (file)
@@ -102,8 +102,14 @@ func checkIntResultAndError(result interface{}, err error) (bool, error) {
        if err != nil {
                return false, err
        }
-       if result.(int) == int(1) {
-               return true, nil
+       if n, ok := result.(int64); ok {
+               if n == 1 {
+                       return true, nil
+               }
+       } else if n, ok := result.(int); ok {
+               if n == 1 {
+                       return true, nil
+               }
        }
        return false, nil
 }
@@ -301,28 +307,53 @@ func (db *DB) SetIE(key string, oldData, newData interface{}) (bool, error) {
        return checkResultAndError(db.client.Do("SETIE", key, newData, oldData).Result())
 }
 
-func (db *DB) SetIEPub(channel, message, key string, oldData, newData interface{}) (bool, error) {
+func (db *DB) SetIEPub(channelsAndEvents []string, key string, oldData, newData interface{}) (bool, error) {
        if !db.redisModules {
-               return false, errors.New("Redis deployment not supporting command SETIEPUB")
+               return false, errors.New("Redis deployment not supporting command SETIEMPUB")
+       }
+       capacity := 4 + len(channelsAndEvents)
+       command := make([]interface{}, 0, capacity)
+       command = append(command, "SETIEMPUB")
+       command = append(command, key)
+       command = append(command, newData)
+       command = append(command, oldData)
+       for _, ce := range channelsAndEvents {
+               command = append(command, ce)
        }
-       return checkResultAndError(db.client.Do("SETIEPUB", key, newData, oldData, channel, message).Result())
+       return checkResultAndError(db.client.Do(command...).Result())
 }
 
-func (db *DB) SetNXPub(channel, message, key string, data interface{}) (bool, error) {
+func (db *DB) SetNXPub(channelsAndEvents []string, key string, data interface{}) (bool, error) {
        if !db.redisModules {
-               return false, errors.New("Redis deployment not supporting command SETNXPUB")
+               return false, errors.New("Redis deployment not supporting command SETNXMPUB")
        }
-       return checkResultAndError(db.client.Do("SETNXPUB", key, data, channel, message).Result())
+       capacity := 3 + len(channelsAndEvents)
+       command := make([]interface{}, 0, capacity)
+       command = append(command, "SETNXMPUB")
+       command = append(command, key)
+       command = append(command, data)
+       for _, ce := range channelsAndEvents {
+               command = append(command, ce)
+       }
+       return checkResultAndError(db.client.Do(command...).Result())
 }
 func (db *DB) SetNX(key string, data interface{}, expiration time.Duration) (bool, error) {
        return db.client.SetNX(key, data, expiration).Result()
 }
 
-func (db *DB) DelIEPub(channel, message, key string, data interface{}) (bool, error) {
+func (db *DB) DelIEPub(channelsAndEvents []string, key string, data interface{}) (bool, error) {
        if !db.redisModules {
-               return false, errors.New("Redis deployment not supporting command")
+               return false, errors.New("Redis deployment not supporting command DELIEMPUB")
+       }
+       capacity := 3 + len(channelsAndEvents)
+       command := make([]interface{}, 0, capacity)
+       command = append(command, "DELIEMPUB")
+       command = append(command, key)
+       command = append(command, data)
+       for _, ce := range channelsAndEvents {
+               command = append(command, ce)
        }
-       return checkIntResultAndError(db.client.Do("DELIEPUB", key, data, channel, message).Result())
+       return checkIntResultAndError(db.client.Do(command...).Result())
 }
 
 func (db *DB) DelIE(key string, data interface{}) (bool, error) {
index 4869d8f..039a208 100644 (file)
@@ -353,9 +353,9 @@ func TestSetIECommandMissing(t *testing.T) {
 
 func TestSetIEPubKeyExists(t *testing.T) {
        _, r, db := setup(true)
-       expectedMessage := []interface{}{"SETIEPUB", "key", "newdata", "olddata", "channel", "message"}
+       expectedMessage := []interface{}{"SETIEMPUB", "key", "newdata", "olddata", "channel", "message"}
        r.On("Do", expectedMessage).Return(redis.NewCmdResult("OK", nil))
-       result, err := db.SetIEPub("channel", "message", "key", "olddata", "newdata")
+       result, err := db.SetIEPub([]string{"channel", "message"}, "key", "olddata", "newdata")
        assert.True(t, result)
        assert.Nil(t, err)
        r.AssertExpectations(t)
@@ -363,9 +363,9 @@ func TestSetIEPubKeyExists(t *testing.T) {
 
 func TestSetIEPubKeyDoesntExists(t *testing.T) {
        _, r, db := setup(true)
-       expectedMessage := []interface{}{"SETIEPUB", "key", "newdata", "olddata", "channel", "message"}
+       expectedMessage := []interface{}{"SETIEMPUB", "key", "newdata", "olddata", "channel", "message"}
        r.On("Do", expectedMessage).Return(redis.NewCmdResult(nil, nil))
-       result, err := db.SetIEPub("channel", "message", "key", "olddata", "newdata")
+       result, err := db.SetIEPub([]string{"channel", "message"}, "key", "olddata", "newdata")
        assert.False(t, result)
        assert.Nil(t, err)
        r.AssertExpectations(t)
@@ -373,9 +373,9 @@ func TestSetIEPubKeyDoesntExists(t *testing.T) {
 
 func TestSetIEPubFailure(t *testing.T) {
        _, r, db := setup(true)
-       expectedMessage := []interface{}{"SETIEPUB", "key", "newdata", "olddata", "channel", "message"}
+       expectedMessage := []interface{}{"SETIEMPUB", "key", "newdata", "olddata", "channel", "message"}
        r.On("Do", expectedMessage).Return(redis.NewCmdResult(nil, errors.New("Some error")))
-       result, err := db.SetIEPub("channel", "message", "key", "olddata", "newdata")
+       result, err := db.SetIEPub([]string{"channel", "message"}, "key", "olddata", "newdata")
        assert.False(t, result)
        assert.NotNil(t, err)
        r.AssertExpectations(t)
@@ -383,9 +383,9 @@ func TestSetIEPubFailure(t *testing.T) {
 
 func TestSetIEPubCommandMissing(t *testing.T) {
        _, r, db := setup(false)
-       expectedMessage := []interface{}{"SETIEPUB", "key", "newdata", "olddata", "channel", "message"}
+       expectedMessage := []interface{}{"SETIEMPUB", "key", "newdata", "olddata", "channel", "message"}
        r.AssertNotCalled(t, "Do", expectedMessage)
-       result, err := db.SetIEPub("channel", "message", "key", "olddata", "newdata")
+       result, err := db.SetIEPub([]string{"channel", "message"}, "key", "olddata", "newdata")
        assert.False(t, result)
        assert.NotNil(t, err)
        r.AssertExpectations(t)
@@ -393,9 +393,9 @@ func TestSetIEPubCommandMissing(t *testing.T) {
 
 func TestSetNXPubKeyDoesntExist(t *testing.T) {
        _, r, db := setup(true)
-       expectedMessage := []interface{}{"SETNXPUB", "key", "data", "channel", "message"}
+       expectedMessage := []interface{}{"SETNXMPUB", "key", "data", "channel", "message"}
        r.On("Do", expectedMessage).Return(redis.NewCmdResult("OK", nil))
-       result, err := db.SetNXPub("channel", "message", "key", "data")
+       result, err := db.SetNXPub([]string{"channel", "message"}, "key", "data")
        assert.True(t, result)
        assert.Nil(t, err)
        r.AssertExpectations(t)
@@ -403,9 +403,9 @@ func TestSetNXPubKeyDoesntExist(t *testing.T) {
 
 func TestSetNXPubKeyExists(t *testing.T) {
        _, r, db := setup(true)
-       expectedMessage := []interface{}{"SETNXPUB", "key", "data", "channel", "message"}
+       expectedMessage := []interface{}{"SETNXMPUB", "key", "data", "channel", "message"}
        r.On("Do", expectedMessage).Return(redis.NewCmdResult(nil, nil))
-       result, err := db.SetNXPub("channel", "message", "key", "data")
+       result, err := db.SetNXPub([]string{"channel", "message"}, "key", "data")
        assert.False(t, result)
        assert.Nil(t, err)
        r.AssertExpectations(t)
@@ -413,9 +413,9 @@ func TestSetNXPubKeyExists(t *testing.T) {
 
 func TestSetNXPubFailure(t *testing.T) {
        _, r, db := setup(true)
-       expectedMessage := []interface{}{"SETNXPUB", "key", "data", "channel", "message"}
+       expectedMessage := []interface{}{"SETNXMPUB", "key", "data", "channel", "message"}
        r.On("Do", expectedMessage).Return(redis.NewCmdResult(nil, errors.New("Some error")))
-       result, err := db.SetNXPub("channel", "message", "key", "data")
+       result, err := db.SetNXPub([]string{"channel", "message"}, "key", "data")
        assert.False(t, result)
        assert.NotNil(t, err)
        r.AssertExpectations(t)
@@ -423,9 +423,9 @@ func TestSetNXPubFailure(t *testing.T) {
 
 func TestSetNXPubCommandMissing(t *testing.T) {
        _, r, db := setup(false)
-       expectedMessage := []interface{}{"SETNXPUB", "key", "data", "channel", "message"}
+       expectedMessage := []interface{}{"SETNXMPUB", "key", "data", "channel", "message"}
        r.AssertNotCalled(t, "Do", expectedMessage)
-       result, err := db.SetNXPub("channel", "message", "key", "data")
+       result, err := db.SetNXPub([]string{"channel", "message"}, "key", "data")
        assert.False(t, result)
        assert.NotNil(t, err)
        r.AssertExpectations(t)
@@ -467,9 +467,9 @@ func TestSetNXFailure(t *testing.T) {
 
 func TestDelIEPubKeyDoesntExist(t *testing.T) {
        _, r, db := setup(true)
-       expectedMessage := []interface{}{"DELIEPUB", "key", "data", "channel", "message"}
-       r.On("Do", expectedMessage).Return(redis.NewCmdResult(0, nil))
-       result, err := db.DelIEPub("channel", "message", "key", "data")
+       expectedMessage := []interface{}{"DELIEMPUB", "key", "data", "channel", "message"}
+       r.On("Do", expectedMessage).Return(redis.NewCmdResult(int64(0), nil))
+       result, err := db.DelIEPub([]string{"channel", "message"}, "key", "data")
        assert.False(t, result)
        assert.Nil(t, err)
        r.AssertExpectations(t)
@@ -477,9 +477,19 @@ func TestDelIEPubKeyDoesntExist(t *testing.T) {
 
 func TestDelIEPubKeyExists(t *testing.T) {
        _, r, db := setup(true)
-       expectedMessage := []interface{}{"DELIEPUB", "key", "data", "channel", "message"}
+       expectedMessage := []interface{}{"DELIEMPUB", "key", "data", "channel", "message"}
+       r.On("Do", expectedMessage).Return(redis.NewCmdResult(int64(1), nil))
+       result, err := db.DelIEPub([]string{"channel", "message"}, "key", "data")
+       assert.True(t, result)
+       assert.Nil(t, err)
+       r.AssertExpectations(t)
+}
+
+func TestDelIEPubKeyExistsIntTypeRedisValue(t *testing.T) {
+       _, r, db := setup(true)
+       expectedMessage := []interface{}{"DELIEMPUB", "key", "data", "channel", "message"}
        r.On("Do", expectedMessage).Return(redis.NewCmdResult(1, nil))
-       result, err := db.DelIEPub("channel", "message", "key", "data")
+       result, err := db.DelIEPub([]string{"channel", "message"}, "key", "data")
        assert.True(t, result)
        assert.Nil(t, err)
        r.AssertExpectations(t)
@@ -487,9 +497,9 @@ func TestDelIEPubKeyExists(t *testing.T) {
 
 func TestDelIEPubFailure(t *testing.T) {
        _, r, db := setup(true)
-       expectedMessage := []interface{}{"DELIEPUB", "key", "data", "channel", "message"}
-       r.On("Do", expectedMessage).Return(redis.NewCmdResult(0, errors.New("Some error")))
-       result, err := db.DelIEPub("channel", "message", "key", "data")
+       expectedMessage := []interface{}{"DELIEMPUB", "key", "data", "channel", "message"}
+       r.On("Do", expectedMessage).Return(redis.NewCmdResult(int64(0), errors.New("Some error")))
+       result, err := db.DelIEPub([]string{"channel", "message"}, "key", "data")
        assert.False(t, result)
        assert.NotNil(t, err)
        r.AssertExpectations(t)
@@ -497,9 +507,9 @@ func TestDelIEPubFailure(t *testing.T) {
 
 func TestDelIEPubCommandMissing(t *testing.T) {
        _, r, db := setup(false)
-       expectedMessage := []interface{}{"DELIEPUB", "key", "data", "channel", "message"}
+       expectedMessage := []interface{}{"DELIEMPUB", "key", "data", "channel", "message"}
        r.AssertNotCalled(t, "Do", expectedMessage)
-       result, err := db.DelIEPub("channel", "message", "key", "data")
+       result, err := db.DelIEPub([]string{"channel", "message"}, "key", "data")
        assert.False(t, result)
        assert.NotNil(t, err)
        r.AssertExpectations(t)
@@ -508,7 +518,7 @@ func TestDelIEPubCommandMissing(t *testing.T) {
 func TestDelIEKeyDoesntExist(t *testing.T) {
        _, r, db := setup(true)
        expectedMessage := []interface{}{"DELIE", "key", "data"}
-       r.On("Do", expectedMessage).Return(redis.NewCmdResult(0, nil))
+       r.On("Do", expectedMessage).Return(redis.NewCmdResult(int64(0), nil))
        result, err := db.DelIE("key", "data")
        assert.False(t, result)
        assert.Nil(t, err)
@@ -516,6 +526,16 @@ func TestDelIEKeyDoesntExist(t *testing.T) {
 }
 
 func TestDelIEKeyExists(t *testing.T) {
+       _, r, db := setup(true)
+       expectedMessage := []interface{}{"DELIE", "key", "data"}
+       r.On("Do", expectedMessage).Return(redis.NewCmdResult(int64(1), nil))
+       result, err := db.DelIE("key", "data")
+       assert.True(t, result)
+       assert.Nil(t, err)
+       r.AssertExpectations(t)
+}
+
+func TestDelIEKeyExistsIntTypeRedisValue(t *testing.T) {
        _, r, db := setup(true)
        expectedMessage := []interface{}{"DELIE", "key", "data"}
        r.On("Do", expectedMessage).Return(redis.NewCmdResult(1, nil))
@@ -528,7 +548,7 @@ func TestDelIEKeyExists(t *testing.T) {
 func TestDelIEFailure(t *testing.T) {
        _, r, db := setup(true)
        expectedMessage := []interface{}{"DELIE", "key", "data"}
-       r.On("Do", expectedMessage).Return(redis.NewCmdResult(0, errors.New("Some error")))
+       r.On("Do", expectedMessage).Return(redis.NewCmdResult(int64(0), errors.New("Some error")))
        result, err := db.DelIE("key", "data")
        assert.False(t, result)
        assert.NotNil(t, err)
diff --git a/sdl.go b/sdl.go
index 25194c8..b2f47bd 100644 (file)
--- a/sdl.go
+++ b/sdl.go
@@ -301,7 +301,7 @@ func (s *SdlInstance) SetIfAndPublish(channelsAndEvents []string, key string, ol
                return false, err
        }
        channelsAndEventsPrepared := s.prepareChannelsAndEvents(channelsAndEvents)
-       return s.SetIEPub(channelsAndEventsPrepared[0], channelsAndEventsPrepared[1], s.nsPrefix+key, oldData, newData)
+       return s.SetIEPub(channelsAndEventsPrepared, s.nsPrefix+key, oldData, newData)
 }
 
 //SetIf atomically replaces existing data with newData in SDL if data matches the oldData.
@@ -322,7 +322,7 @@ func (s *SdlInstance) SetIfNotExistsAndPublish(channelsAndEvents []string, key s
                return false, err
        }
        channelsAndEventsPrepared := s.prepareChannelsAndEvents(channelsAndEvents)
-       return s.SetNXPub(channelsAndEventsPrepared[0], channelsAndEventsPrepared[1], s.nsPrefix+key, data)
+       return s.SetNXPub(channelsAndEventsPrepared, s.nsPrefix+key, data)
 }
 
 //SetIfNotExists conditionally sets the value of a key. If key already exists in SDL,
@@ -381,7 +381,7 @@ func (s *SdlInstance) RemoveIfAndPublish(channelsAndEvents []string, key string,
                return false, err
        }
        channelsAndEventsPrepared := s.prepareChannelsAndEvents(channelsAndEvents)
-       return s.DelIEPub(channelsAndEventsPrepared[0], channelsAndEventsPrepared[1], s.nsPrefix+key, data)
+       return s.DelIEPub(channelsAndEventsPrepared, s.nsPrefix+key, data)
 }
 
 //RemoveIf removes data from SDL conditionally. If existing data matches given data,
@@ -615,11 +615,11 @@ type iDatabase interface {
        DelMPub(channelsAndEvents []string, keys []string) error
        Keys(key string) ([]string, error)
        SetIE(key string, oldData, newData interface{}) (bool, error)
-       SetIEPub(channel, message, key string, oldData, newData interface{}) (bool, error)
+       SetIEPub(channelsAndEvents []string, key string, oldData, newData interface{}) (bool, error)
        SetNX(key string, data interface{}, expiration time.Duration) (bool, error)
-       SetNXPub(channel, message, key string, data interface{}) (bool, error)
+       SetNXPub(channelsAndEvents []string, key string, data interface{}) (bool, error)
        DelIE(key string, data interface{}) (bool, error)
-       DelIEPub(channel, message, key string, data interface{}) (bool, error)
+       DelIEPub(channelsAndEvents []string, key string, data interface{}) (bool, error)
        SAdd(key string, data ...interface{}) error
        SRem(key string, data ...interface{}) error
        SMembers(key string) ([]string, error)
index b216e57..acacfd6 100644 (file)
@@ -85,8 +85,8 @@ func (m *mockDB) SetIE(key string, oldData, newData interface{}) (bool, error) {
        return a.Bool(0), a.Error(1)
 }
 
-func (m *mockDB) SetIEPub(channel, message, key string, oldData, newData interface{}) (bool, error) {
-       a := m.Called(channel, message, key, oldData, newData)
+func (m *mockDB) SetIEPub(channelsAndEvents []string, key string, oldData, newData interface{}) (bool, error) {
+       a := m.Called(channelsAndEvents, key, oldData, newData)
        return a.Bool(0), a.Error(1)
 }
 
@@ -95,8 +95,8 @@ func (m *mockDB) SetNX(key string, data interface{}, expiration time.Duration) (
        return a.Bool(0), a.Error(1)
 }
 
-func (m *mockDB) SetNXPub(channel, message, key string, data interface{}) (bool, error) {
-       a := m.Called(channel, message, key, data)
+func (m *mockDB) SetNXPub(channelsAndEvents []string, key string, data interface{}) (bool, error) {
+       a := m.Called(channelsAndEvents, key, data)
        return a.Bool(0), a.Error(1)
 }
 
@@ -105,8 +105,8 @@ func (m *mockDB) DelIE(key string, data interface{}) (bool, error) {
        return a.Bool(0), a.Error(1)
 }
 
-func (m *mockDB) DelIEPub(channel, message, key string, data interface{}) (bool, error) {
-       a := m.Called(channel, message, key, data)
+func (m *mockDB) DelIEPub(channelsAndEvents []string, key string, data interface{}) (bool, error) {
+       a := m.Called(channelsAndEvents, key, data)
        return a.Bool(0), a.Error(1)
 }
 
@@ -780,12 +780,11 @@ func TestSetIfFailure(t *testing.T) {
 func TestSetIfAndPublishSuccessfully(t *testing.T) {
        m, i := setup()
 
-       expectedChannel := "{namespace},channel"
-       expectedEvent := "event"
+       expectedChannelAndEvent := []string{"{namespace},channel", "event"}
        expectedKey := "{namespace},key"
        expectedOldData := interface{}("olddata")
        expectedNewData := interface{}("newdata")
-       m.On("SetIEPub", expectedChannel, expectedEvent, expectedKey, expectedOldData, expectedNewData).Return(true, nil)
+       m.On("SetIEPub", expectedChannelAndEvent, expectedKey, expectedOldData, expectedNewData).Return(true, nil)
        status, err := i.SetIfAndPublish([]string{"channel", "event"}, "key", "olddata", "newdata")
        assert.Nil(t, err)
        assert.True(t, status)
@@ -795,12 +794,11 @@ func TestSetIfAndPublishSuccessfully(t *testing.T) {
 func TestSetIfAndPublishIncorrectChannelAndEvent(t *testing.T) {
        m, i := setup()
 
-       expectedChannel := "{namespace},channel"
-       expectedEvent := "event"
+       expectedChannelAndEvent := []string{"{namespace},channel", "event"}
        expectedKey := "{namespace},key"
        expectedOldData := interface{}("olddata")
        expectedNewData := interface{}("newdata")
-       m.AssertNotCalled(t, "SetIEPub", expectedChannel, expectedEvent, expectedKey, expectedOldData, expectedNewData)
+       m.AssertNotCalled(t, "SetIEPub", expectedChannelAndEvent, expectedKey, expectedOldData, expectedNewData)
        m.AssertNotCalled(t, "SetIE", expectedKey, expectedOldData, expectedNewData)
        status, err := i.SetIfAndPublish([]string{"channel", "event1", "channel"}, "key", "olddata", "newdata")
        assert.NotNil(t, err)
@@ -810,12 +808,11 @@ func TestSetIfAndPublishIncorrectChannelAndEvent(t *testing.T) {
 func TestSetIfAndPublishNOKStatus(t *testing.T) {
        m, i := setup()
 
-       expectedChannel := "{namespace},channel"
-       expectedEvent := "event"
+       expectedChannelAndEvent := []string{"{namespace},channel", "event"}
        expectedKey := "{namespace},key"
        expectedOldData := interface{}("olddata")
        expectedNewData := interface{}("newdata")
-       m.On("SetIEPub", expectedChannel, expectedEvent, expectedKey, expectedOldData, expectedNewData).Return(false, nil)
+       m.On("SetIEPub", expectedChannelAndEvent, expectedKey, expectedOldData, expectedNewData).Return(false, nil)
        status, err := i.SetIfAndPublish([]string{"channel", "event"}, "key", "olddata", "newdata")
        assert.Nil(t, err)
        assert.False(t, status)
@@ -838,12 +835,11 @@ func TestSetIfAndPublishNoChannels(t *testing.T) {
 func TestSetIfNotExistsAndPublishSuccessfully(t *testing.T) {
        m, i := setup()
 
-       expectedChannel := "{namespace},channel"
-       expectedEvent := "event"
+       expectedChannelAndEvent := []string{"{namespace},channel", "event"}
        expectedKey := "{namespace},key"
        expectedData := interface{}("data")
 
-       m.On("SetNXPub", expectedChannel, expectedEvent, expectedKey, expectedData).Return(true, nil)
+       m.On("SetNXPub", expectedChannelAndEvent, expectedKey, expectedData).Return(true, nil)
        status, err := i.SetIfNotExistsAndPublish([]string{"channel", "event"}, "key", "data")
        assert.Nil(t, err)
        assert.True(t, status)
@@ -853,12 +849,11 @@ func TestSetIfNotExistsAndPublishSuccessfully(t *testing.T) {
 func TestSetIfNotExistsAndPublishSeveralEvents(t *testing.T) {
        m, i := setup()
 
-       expectedChannel := "{namespace},channel"
-       expectedEvent := "event1___event2"
+       expectedChannelAndEvent := []string{"{namespace},channel", "event1___event2"}
        expectedKey := "{namespace},key"
        expectedData := interface{}("data")
 
-       m.On("SetNXPub", expectedChannel, expectedEvent, expectedKey, expectedData).Return(true, nil)
+       m.On("SetNXPub", expectedChannelAndEvent, expectedKey, expectedData).Return(true, nil)
        status, err := i.SetIfNotExistsAndPublish([]string{"channel", "event1", "channel", "event2"}, "key", "data")
        assert.Nil(t, err)
        assert.True(t, status)
@@ -881,12 +876,11 @@ func TestSetIfNotExistsAndPublishNoChannels(t *testing.T) {
 func TestSetIfNotExistsAndPublishFail(t *testing.T) {
        m, i := setup()
 
-       expectedChannel := "{namespace},channel"
-       expectedEvent := "event"
+       expectedChannelAndEvent := []string{"{namespace},channel", "event"}
        expectedKey := "{namespace},key"
        expectedData := interface{}("data")
 
-       m.On("SetNXPub", expectedChannel, expectedEvent, expectedKey, expectedData).Return(false, nil)
+       m.On("SetNXPub", expectedChannelAndEvent, expectedKey, expectedData).Return(false, nil)
        status, err := i.SetIfNotExistsAndPublish([]string{"channel", "event"}, "key", "data")
        assert.Nil(t, err)
        assert.False(t, status)
@@ -896,12 +890,11 @@ func TestSetIfNotExistsAndPublishFail(t *testing.T) {
 func TestSetIfNotExistsAndPublishIncorrectChannels(t *testing.T) {
        m, i := setup()
 
-       expectedChannel := "{namespace},channel"
-       expectedEvent := "event"
+       expectedChannelAndEvent := []string{"{namespace},channel", "event"}
        expectedKey := "{namespace},key"
        expectedData := interface{}("data")
 
-       m.AssertNotCalled(t, "SetNXPub", expectedChannel, expectedEvent, expectedKey, expectedData)
+       m.AssertNotCalled(t, "SetNXPub", expectedChannelAndEvent, expectedKey, expectedData)
        m.AssertNotCalled(t, "SetNX", expectedKey, expectedData, 0)
        status, err := i.SetIfNotExistsAndPublish([]string{"channel", "event", "channel2"}, "key", "data")
        assert.NotNil(t, err)
@@ -912,12 +905,11 @@ func TestSetIfNotExistsAndPublishIncorrectChannels(t *testing.T) {
 func TestSetIfNotExistsAndPublishError(t *testing.T) {
        m, i := setup()
 
-       expectedChannel := "{namespace},channel"
-       expectedEvent := "event"
+       expectedChannelAndEvent := []string{"{namespace},channel", "event"}
        expectedKey := "{namespace},key"
        expectedData := interface{}("data")
 
-       m.On("SetNXPub", expectedChannel, expectedEvent, expectedKey, expectedData).Return(false, errors.New("Some error"))
+       m.On("SetNXPub", expectedChannelAndEvent, expectedKey, expectedData).Return(false, errors.New("Some error"))
        status, err := i.SetIfNotExistsAndPublish([]string{"channel", "event"}, "key", "data")
        assert.NotNil(t, err)
        assert.False(t, status)
@@ -963,12 +955,11 @@ func TestSetIfNotExistsFailure(t *testing.T) {
 func TestRemoveIfAndPublishSuccessfully(t *testing.T) {
        m, i := setup()
 
-       expectedChannel := "{namespace},channel"
-       expectedEvent := "event1___event2"
+       expectedChannelAndEvent := []string{"{namespace},channel", "event1___event2"}
        expectedKey := "{namespace},key"
        expectedValue := interface{}("data")
 
-       m.On("DelIEPub", expectedChannel, expectedEvent, expectedKey, expectedValue).Return(true, nil)
+       m.On("DelIEPub", expectedChannelAndEvent, expectedKey, expectedValue).Return(true, nil)
        status, err := i.RemoveIfAndPublish([]string{"channel", "event1", "channel", "event2"}, "key", "data")
        assert.Nil(t, err)
        assert.True(t, status)
@@ -978,12 +969,11 @@ func TestRemoveIfAndPublishSuccessfully(t *testing.T) {
 func TestRemoveIfAndPublishNok(t *testing.T) {
        m, i := setup()
 
-       expectedChannel := "{namespace},channel"
-       expectedEvent := "event1___event2"
+       expectedChannelAndEvent := []string{"{namespace},channel", "event1___event2"}
        expectedKey := "{namespace},key"
        expectedValue := interface{}("data")
 
-       m.On("DelIEPub", expectedChannel, expectedEvent, expectedKey, expectedValue).Return(false, nil)
+       m.On("DelIEPub", expectedChannelAndEvent, expectedKey, expectedValue).Return(false, nil)
        status, err := i.RemoveIfAndPublish([]string{"channel", "event1", "channel", "event2"}, "key", "data")
        assert.Nil(t, err)
        assert.False(t, status)
@@ -993,12 +983,11 @@ func TestRemoveIfAndPublishNok(t *testing.T) {
 func TestRemoveIfAndPublishError(t *testing.T) {
        m, i := setup()
 
-       expectedChannel := "{namespace},channel"
-       expectedEvent := "event1___event2"
+       expectedChannelAndEvent := []string{"{namespace},channel", "event1___event2"}
        expectedKey := "{namespace},key"
        expectedValue := interface{}("data")
 
-       m.On("DelIEPub", expectedChannel, expectedEvent, expectedKey, expectedValue).Return(false, errors.New("Some error"))
+       m.On("DelIEPub", expectedChannelAndEvent, expectedKey, expectedValue).Return(false, errors.New("Some error"))
        status, err := i.RemoveIfAndPublish([]string{"channel", "event1", "channel", "event2"}, "key", "data")
        assert.NotNil(t, err)
        assert.False(t, status)
@@ -1008,12 +997,11 @@ func TestRemoveIfAndPublishError(t *testing.T) {
 func TestRemoveIfAndPublishIncorrectChannel(t *testing.T) {
        m, i := setup()
 
-       expectedChannel := "{namespace},channel"
-       expectedEvent := "event"
+       expectedChannelAndEvent := []string{"{namespace},channel", "event"}
        expectedKey := "{namespace},key"
        expectedValue := interface{}("data")
 
-       m.AssertNotCalled(t, "DelIEPub", expectedChannel, expectedEvent, expectedKey, expectedValue)
+       m.AssertNotCalled(t, "DelIEPub", expectedChannelAndEvent, expectedKey, expectedValue)
        m.AssertNotCalled(t, "DelIE", expectedKey, expectedValue)
        status, err := i.RemoveIfAndPublish([]string{"channel", "event1", "channel"}, "key", "data")
        assert.NotNil(t, err)