github.com/vmware/transport-go@v1.3.4/bus/store_test.go (about)

     1  // Copyright 2019-2020 VMware, Inc.
     2  // SPDX-License-Identifier: BSD-2-Clause
     3  
     4  package bus
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"github.com/go-stomp/stomp/v3/frame"
    10  	"github.com/stretchr/testify/assert"
    11  	"reflect"
    12  	"sync"
    13  	"sync/atomic"
    14  	"testing"
    15  )
    16  
    17  type testItem struct {
    18  	name      string
    19  	nameIndex int32
    20  }
    21  
    22  func testStore() BusStore {
    23  	store := newBusStore("testStore", newTestEventBus(), nil, nil)
    24  	store.Initialize()
    25  	return store
    26  }
    27  
    28  type mockGalacticStoreConnection struct {
    29  	messages []map[string]interface{}
    30  	topics   []string
    31  	opts     []func(fr *frame.Frame) error
    32  }
    33  
    34  func (con *mockGalacticStoreConnection) SendJSONMessage(destination string, payload []byte, opts ...func(*frame.Frame) error) error {
    35  	return con.SendMessage(destination, "application/json", payload, opts...)
    36  }
    37  
    38  func (con *mockGalacticStoreConnection) SendMessage(destination, contentType string, payload []byte, opts ...func(*frame.Frame) error) error {
    39  	var msgPayload map[string]interface{}
    40  	json.Unmarshal(payload, &msgPayload)
    41  	con.messages = append(con.messages, msgPayload)
    42  	con.topics = append(con.topics, destination)
    43  	con.opts = opts
    44  	return nil
    45  }
    46  
    47  func (con *mockGalacticStoreConnection) lastMessage() map[string]interface{} {
    48  	n := len(con.messages)
    49  	return con.messages[n-1]
    50  }
    51  
    52  func (con *mockGalacticStoreConnection) lastTopic() string {
    53  	n := len(con.topics)
    54  	return con.topics[n-1]
    55  }
    56  
    57  func testGalacticStore(itemType reflect.Type) (BusStore, *mockGalacticStoreConnection, EventBus) {
    58  
    59  	bus := newTestEventBus()
    60  	bus.GetChannelManager().CreateChannel("sync-channel")
    61  
    62  	conn := &mockGalacticStoreConnection{
    63  		messages: make([]map[string]interface{}, 0),
    64  		topics:   make([]string, 0),
    65  		opts:     make([]func(*frame.Frame) error, 0),
    66  	}
    67  
    68  	conf := &galacticStoreConfig{
    69  		syncChannelConfig: &storeSyncChannelConfig{
    70  			syncChannelName: "sync-channel",
    71  			conn:            conn,
    72  			pubPrefix:       "/pub/",
    73  		},
    74  	}
    75  
    76  	store := newBusStore("testStore", bus, itemType, conf)
    77  	return store, conn, bus
    78  }
    79  
    80  func TestBusStore_CreateStore(t *testing.T) {
    81  	store := testStore()
    82  	assert.Equal(t, store.GetName(), "testStore")
    83  	assert.False(t, store.IsGalactic())
    84  }
    85  
    86  func TestBusStore_PutAndGet(t *testing.T) {
    87  	store := testStore()
    88  	store.Put("id1", 1, "ITEM_ADDED")
    89  	store.Put("id2", "value2", "ITEM_ADDED")
    90  	store.Put("id3", nil, "ITEM_ADDED")
    91  
    92  	v, ok := store.Get("id1")
    93  	assert.Equal(t, v, 1)
    94  	assert.True(t, ok)
    95  
    96  	v, _ = store.Get("id2")
    97  	assert.Equal(t, v, "value2")
    98  
    99  	v, ok = store.Get("id3")
   100  	assert.Equal(t, v, nil)
   101  	assert.True(t, ok)
   102  
   103  	v, ok = store.Get("invalid-id")
   104  	assert.False(t, ok)
   105  	assert.Nil(t, v)
   106  }
   107  
   108  func TestBusStore_Remove(t *testing.T) {
   109  	store := testStore()
   110  	store.Put("id1", "item1", "ITEM_ADDED")
   111  
   112  	var mutationEventsCounter int32 = 0
   113  	var successfulRemovesCounter int32 = 0
   114  
   115  	wg := sync.WaitGroup{}
   116  	wg.Add(1)
   117  
   118  	stream := store.OnAllChanges("ITEM_REMOVED")
   119  	stream.Subscribe(func(change *StoreChange) {
   120  		atomic.AddInt32(&mutationEventsCounter, 1)
   121  		wg.Done()
   122  	})
   123  
   124  	for i := 0; i < 50; i++ {
   125  		wg.Add(1)
   126  		go func() {
   127  			if store.Remove("id1", "ITEM_REMOVED") {
   128  				atomic.AddInt32(&successfulRemovesCounter, 1)
   129  			}
   130  			wg.Done()
   131  		}()
   132  	}
   133  
   134  	wg.Wait()
   135  
   136  	assert.False(t, store.Remove("invalid-id", "ITEM_REMOVED"))
   137  
   138  	// Verify that only one of the Remove calls was successful (has returned true)
   139  	assert.Equal(t, successfulRemovesCounter, int32(1))
   140  	assert.Equal(t, mutationEventsCounter, int32(1))
   141  }
   142  
   143  func TestBusStore_AllValuesAndAllValuesAsMap(t *testing.T) {
   144  	store := testStore()
   145  
   146  	items := store.AllValues()
   147  	allItemsAsMap := store.AllValuesAsMap()
   148  	assert.Equal(t, len(items), 0)
   149  	assert.Equal(t, len(allItemsAsMap), 0)
   150  
   151  	store.Put("id1", testItem{name: "item1", nameIndex: 1}, "ITEM_ADDED")
   152  	store.Put("id2", testItem{name: "item2", nameIndex: 2}, "ITEM_ADDED")
   153  	store.Put("id3", testItem{name: "item3", nameIndex: 3}, "ITEM_ADDED")
   154  
   155  	items = store.AllValues()
   156  	allItemsAsMap = store.AllValuesAsMap()
   157  
   158  	assert.Equal(t, len(items), 3)
   159  	for _, item := range items {
   160  		assert.Equal(t, fmt.Sprintf("item%d", item.(testItem).nameIndex), item.(testItem).name)
   161  	}
   162  
   163  	assert.Equal(t, len(allItemsAsMap), 3)
   164  	assert.Equal(t, allItemsAsMap["id1"], testItem{name: "item1", nameIndex: 1})
   165  	assert.Equal(t, allItemsAsMap["id2"], testItem{name: "item2", nameIndex: 2})
   166  	assert.Equal(t, allItemsAsMap["id3"], testItem{name: "item3", nameIndex: 3})
   167  
   168  	allItemsAsMapWithVer, version := store.AllValuesAndVersion()
   169  	assert.Equal(t, allItemsAsMap, allItemsAsMapWithVer)
   170  	assert.Equal(t, version, int64(4))
   171  }
   172  
   173  func TestBusStore_OnChange(t *testing.T) {
   174  	store := testStore()
   175  
   176  	wg := sync.WaitGroup{}
   177  
   178  	allChangesStreams := make([]StoreStream, 0)
   179  
   180  	var allChangesCounter int32 = 0
   181  	for i := 0; i < 5; i++ {
   182  		stream := store.OnChange("id1")
   183  		allChangesStreams = append(allChangesStreams, stream)
   184  		stream.Subscribe(func(change *StoreChange) {
   185  			atomic.AddInt32(&allChangesCounter, 1)
   186  			wg.Done()
   187  		})
   188  	}
   189  
   190  	var itemUpdateCounter int32 = 0
   191  	for i := 0; i < 5; i++ {
   192  		store.OnChange("id1", "ITEM_REMOVE", "ITEM_UPDATE").Subscribe(
   193  			func(change *StoreChange) {
   194  				atomic.AddInt32(&itemUpdateCounter, 1)
   195  				wg.Done()
   196  			})
   197  	}
   198  
   199  	for i := 0; i < 200; i++ {
   200  		if i%2 == 0 {
   201  			wg.Add(10)
   202  			go func() {
   203  				store.Put("id1", "newValue", "ITEM_UPDATE")
   204  			}()
   205  		} else {
   206  			wg.Add(5)
   207  			go func() {
   208  				store.Put("id1", "newValue", "ITEM_ADD")
   209  			}()
   210  		}
   211  	}
   212  
   213  	wg.Wait()
   214  
   215  	assert.Equal(t, allChangesCounter, int32(1000))
   216  	assert.Equal(t, itemUpdateCounter, int32(500))
   217  
   218  	// Unsubscribe all changes listeners
   219  	for _, stream := range allChangesStreams {
   220  		stream.Unsubscribe()
   221  	}
   222  
   223  	wg.Add(5)
   224  	store.Put("id1", "newValue", "ITEM_REMOVE")
   225  	wg.Wait()
   226  
   227  	assert.Equal(t, allChangesCounter, int32(1000))
   228  	assert.Equal(t, itemUpdateCounter, int32(505))
   229  }
   230  
   231  func TestBusStore_OnChangeErrorHandling(t *testing.T) {
   232  	store := testStore()
   233  	stream := store.OnChange("id1")
   234  	e := stream.Unsubscribe()
   235  	assert.EqualError(t, e, "stream not subscribed")
   236  
   237  	subscribeErr := stream.Subscribe(func(change *StoreChange) {
   238  	})
   239  
   240  	assert.Nil(t, subscribeErr)
   241  	subscribeErr = stream.Subscribe(func(change *StoreChange) {
   242  	})
   243  	assert.EqualError(t, subscribeErr, "stream already subscribed")
   244  
   245  	e = stream.Subscribe(nil)
   246  	assert.EqualError(t, e, "invalid StoreChangeHandlerFunction")
   247  }
   248  
   249  func TestBusStore_OnAllChanges(t *testing.T) {
   250  	store := testStore()
   251  
   252  	wg := sync.WaitGroup{}
   253  
   254  	var allChangesCounter int32 = 0
   255  	allChangesStream := store.OnAllChanges()
   256  	allChangesStream.Subscribe(func(change *StoreChange) {
   257  		atomic.AddInt32(&allChangesCounter, 1)
   258  		wg.Done()
   259  	})
   260  
   261  	itemUpdatedStream := store.OnAllChanges("ITEM_UPDATED", "ITEM_REMOVED")
   262  	var itemUpdateCounter int32 = 0
   263  	itemUpdatedStream.Subscribe(
   264  		func(change *StoreChange) {
   265  			atomic.AddInt32(&itemUpdateCounter, 1)
   266  			wg.Done()
   267  		})
   268  
   269  	for i := 0; i < 200; i++ {
   270  		if i%2 == 0 {
   271  			wg.Add(2)
   272  			go func() {
   273  				store.Put("id1", "newValue", "ITEM_UPDATED")
   274  			}()
   275  		} else {
   276  			wg.Add(1)
   277  			go func() {
   278  				store.Put("id1", "newValue", "ITEM_ADD")
   279  			}()
   280  		}
   281  	}
   282  
   283  	wg.Wait()
   284  
   285  	assert.Equal(t, allChangesCounter, int32(200))
   286  	assert.Equal(t, itemUpdateCounter, int32(100))
   287  
   288  	allChangesStream.Unsubscribe()
   289  
   290  	wg.Add(1)
   291  	store.Put("id1", "newValue", "ITEM_REMOVED")
   292  	wg.Wait()
   293  
   294  	assert.Equal(t, allChangesCounter, int32(200))
   295  	assert.Equal(t, itemUpdateCounter, int32(101))
   296  }
   297  
   298  func TestBusStore_WhenReady(t *testing.T) {
   299  	store := newBusStore("testStore", newTestEventBus(), nil, nil)
   300  
   301  	wg := sync.WaitGroup{}
   302  	var counter int32 = 0
   303  	for i := 0; i < 100; i++ {
   304  		wg.Add(1)
   305  		store.WhenReady(func() {
   306  			atomic.AddInt32(&counter, 1)
   307  			wg.Done()
   308  		})
   309  	}
   310  
   311  	store.Initialize()
   312  
   313  	wg.Wait()
   314  	assert.Equal(t, counter, int32(100))
   315  
   316  	for i := 0; i < 100; i++ {
   317  		wg.Add(1)
   318  		store.WhenReady(func() {
   319  			atomic.AddInt32(&counter, 1)
   320  			wg.Done()
   321  		})
   322  	}
   323  
   324  	wg.Wait()
   325  	assert.Equal(t, counter, int32(200))
   326  }
   327  
   328  func TestBusStore_Populate(t *testing.T) {
   329  	store := newBusStore("testStore", newTestEventBus(), nil, nil)
   330  
   331  	wg := sync.WaitGroup{}
   332  	counter := 0
   333  
   334  	wg.Add(1)
   335  	store.WhenReady(func() {
   336  		counter++
   337  		wg.Done()
   338  	})
   339  
   340  	err := store.Populate(map[string]interface{}{
   341  		"id1": 1,
   342  		"id2": 2,
   343  		"id3": 3,
   344  		"id4": 4,
   345  	})
   346  
   347  	assert.Nil(t, err)
   348  
   349  	wg.Wait()
   350  
   351  	assert.Equal(t, counter, 1)
   352  
   353  	allValues := store.AllValuesAsMap()
   354  	assert.Equal(t, len(allValues), 4)
   355  	assert.Equal(t, allValues["id1"], 1)
   356  	assert.Equal(t, allValues["id2"], 2)
   357  	assert.Equal(t, allValues["id3"], 3)
   358  	assert.Equal(t, allValues["id4"], 4)
   359  
   360  	err = store.Populate(map[string]interface{}{
   361  		"id1": 1,
   362  	})
   363  
   364  	assert.EqualError(t, err, "store items already initialized")
   365  	assert.Equal(t, len(store.AllValues()), 4)
   366  }
   367  
   368  func TestBusStore_Reset(t *testing.T) {
   369  	store := newBusStore("testStore", newTestEventBus(), nil, nil)
   370  	wg := sync.WaitGroup{}
   371  	counter := 0
   372  
   373  	wg.Add(1)
   374  	store.WhenReady(func() {
   375  		counter++
   376  		wg.Done()
   377  	})
   378  
   379  	store.Populate(map[string]interface{}{
   380  		"id1": 1,
   381  		"id2": 2,
   382  		"id3": 3,
   383  	})
   384  	wg.Wait()
   385  
   386  	store.Reset()
   387  
   388  	assert.Equal(t, len(store.AllValues()), 0)
   389  
   390  	wg.Add(1)
   391  	store.WhenReady(func() {
   392  		counter++
   393  		wg.Done()
   394  	})
   395  
   396  	store.Initialize()
   397  	wg.Wait()
   398  	assert.Equal(t, counter, 2)
   399  }
   400  
   401  func TestBusStore_OnMutationRequest(t *testing.T) {
   402  	store := testStore()
   403  
   404  	var allMutationsCounter int32 = 0
   405  	var responseCount int32 = 0
   406  	var errorCount int32 = 0
   407  
   408  	allMutationsStream := store.OnMutationRequest()
   409  	allMutationsStream.Subscribe(func(mutationReq *MutationRequest) {
   410  		atomic.AddInt32(&allMutationsCounter, 1)
   411  		mutationReq.SuccessHandler(mutationReq.Request.(string) + "-response")
   412  	})
   413  
   414  	var updateMutationsCounter int32 = 0
   415  	updateMutationStream := store.OnMutationRequest("UPDATE_ITEM", "REMOVE_ITEM")
   416  	updateMutationStream.Subscribe(func(mutationReq *MutationRequest) {
   417  		atomic.AddInt32(&updateMutationsCounter, 1)
   418  		mutationReq.ErrorHandler(mutationReq.Request.(string) + "-error")
   419  	})
   420  
   421  	wg := sync.WaitGroup{}
   422  
   423  	for i := 0; i < 100; i++ {
   424  		req := fmt.Sprintf("req%d", i)
   425  		wg.Add(2)
   426  		go func() {
   427  			store.Mutate(req, "UPDATE_ITEM",
   428  				func(result interface{}) {
   429  					assert.Equal(t, result, req+"-response")
   430  					atomic.AddInt32(&responseCount, 1)
   431  					wg.Done()
   432  				},
   433  				func(err interface{}) {
   434  					assert.Equal(t, err, req+"-error")
   435  					atomic.AddInt32(&errorCount, 1)
   436  					wg.Done()
   437  				})
   438  		}()
   439  
   440  		wg.Add(1)
   441  		go func() {
   442  			store.Mutate(req, "MODIFY_ITEM",
   443  				func(result interface{}) {
   444  					assert.Equal(t, result, req+"-response")
   445  					atomic.AddInt32(&responseCount, 1)
   446  					wg.Done()
   447  				},
   448  				nil)
   449  		}()
   450  	}
   451  
   452  	wg.Wait()
   453  	assert.Equal(t, allMutationsCounter, int32(200))
   454  	assert.Equal(t, responseCount, int32(200))
   455  	assert.Equal(t, updateMutationsCounter, int32(100))
   456  	assert.Equal(t, errorCount, int32(100))
   457  
   458  	allMutationsStream.Unsubscribe()
   459  
   460  	wg.Add(1)
   461  	store.Mutate("req", "UPDATE_ITEM",
   462  		nil,
   463  		func(err interface{}) {
   464  			assert.Equal(t, err, "req-error")
   465  			atomic.AddInt32(&errorCount, 1)
   466  			wg.Done()
   467  		})
   468  	wg.Wait()
   469  	assert.Equal(t, allMutationsCounter, int32(200))
   470  	assert.Equal(t, responseCount, int32(200))
   471  	assert.Equal(t, updateMutationsCounter, int32(101))
   472  	assert.Equal(t, errorCount, int32(101))
   473  }
   474  
   475  func TestBusStore_OnMutationRequest_ErrorHandling(t *testing.T) {
   476  	store := testStore()
   477  
   478  	ms := store.OnMutationRequest()
   479  	err := ms.Unsubscribe()
   480  
   481  	assert.EqualError(t, err, "stream not subscribed")
   482  
   483  	err = ms.Subscribe(nil)
   484  	assert.EqualError(t, err, "invalid MutationRequestHandlerFunction")
   485  
   486  	ms.Subscribe(func(mutationReq *MutationRequest) {})
   487  
   488  	err = ms.Subscribe(func(mutationReq *MutationRequest) {})
   489  	assert.EqualError(t, err, "stream already subscribed")
   490  }
   491  
   492  func TestBusStore_InitGalacticStore(t *testing.T) {
   493  	store, conn, bus := testGalacticStore(nil)
   494  
   495  	assert.True(t, store.IsGalactic())
   496  	assert.EqualError(t, store.Populate(nil), "populate() API is not supported for galactic stores")
   497  
   498  	assert.Equal(t, len(conn.messages), 1)
   499  	assert.Equal(t, conn.lastTopic(), "/pub/sync-channel")
   500  	assert.Equal(t, conn.lastMessage()["request"], "openStore")
   501  
   502  	rq := conn.lastMessage()["payload"].(map[string]interface{})
   503  	assert.Equal(t, rq["storeId"], "testStore")
   504  
   505  	wg := sync.WaitGroup{}
   506  	wg.Add(1)
   507  
   508  	store.WhenReady(func() {
   509  		wg.Done()
   510  	})
   511  
   512  	var jsonBlob = []byte(`{
   513          "storeId": "testStore",
   514          "responseType": "storeContentResponse",
   515          "items": {
   516              "id3": "value3"
   517          },
   518          "storeVersion": 12
   519      }`)
   520  	bus.SendResponseMessage("sync-channel", jsonBlob, nil)
   521  
   522  	wg.Wait()
   523  	assert.Equal(t, len(store.AllValues()), 1)
   524  
   525  	store.Put("id1", "value1", "add")
   526  	assert.Equal(t, len(conn.messages), 2)
   527  
   528  	assert.Equal(t, conn.lastTopic(), "/pub/sync-channel")
   529  	assert.Equal(t, conn.lastMessage()["request"], "updateStore")
   530  	rq = conn.lastMessage()["payload"].(map[string]interface{})
   531  	assert.Equal(t, rq["storeId"], "testStore")
   532  	assert.Equal(t, rq["itemId"], "id1")
   533  	assert.Equal(t, rq["newItemValue"], "value1")
   534  	assert.Equal(t, rq["clientStoreVersion"], float64(12))
   535  
   536  	assert.False(t, store.Remove("id1", "removing"))
   537  	assert.Equal(t, len(conn.messages), 2)
   538  
   539  	assert.True(t, store.Remove("id3", "removing"))
   540  	assert.Equal(t, len(conn.messages), 3)
   541  
   542  	assert.Equal(t, conn.lastTopic(), "/pub/sync-channel")
   543  	assert.Equal(t, conn.lastMessage()["request"], "updateStore")
   544  	rq = conn.lastMessage()["payload"].(map[string]interface{})
   545  	assert.Equal(t, rq["storeId"], "testStore")
   546  	assert.Equal(t, rq["itemId"], "id3")
   547  	assert.Equal(t, rq["newItemValue"], nil)
   548  	assert.Equal(t, rq["clientStoreVersion"], float64(12))
   549  
   550  	store.Reset()
   551  	assert.Equal(t, len(conn.messages), 4)
   552  	assert.Equal(t, conn.lastTopic(), "/pub/sync-channel")
   553  	assert.Equal(t, conn.lastMessage()["request"], "openStore")
   554  
   555  	store.(*busStore).OnDestroy()
   556  	assert.Equal(t, len(conn.messages), 5)
   557  	assert.Equal(t, conn.lastTopic(), "/pub/sync-channel")
   558  	assert.Equal(t, conn.lastMessage()["request"], "closeStore")
   559  }
   560  
   561  func TestBusStore_GalacticStoreUpdates(t *testing.T) {
   562  	store, _, bus := testGalacticStore(reflect.TypeOf(MockStoreItem{}))
   563  
   564  	wg := sync.WaitGroup{}
   565  	wg.Add(1)
   566  
   567  	var lastStoreChange *StoreChange
   568  
   569  	store.OnAllChanges().Subscribe(func(change *StoreChange) {
   570  		lastStoreChange = change
   571  		wg.Done()
   572  	})
   573  
   574  	var jsonBlob = []byte(`{
   575          "storeId": "testStore",
   576          "responseType": "updateStoreResponse",
   577          "itemId": "id1",
   578          "newItemValue": { "from": "admin", "message": "value1"},
   579          "storeVersion": 54
   580      }`)
   581  	bus.SendResponseMessage("sync-channel", jsonBlob, nil)
   582  
   583  	bus.SendResponseMessage("sync-channel", []byte("invalid-json}"), nil)
   584  
   585  	bus.SendResponseMessage("sync-channel", []byte(`{
   586          "storeId": "testStore2",
   587          "responseType": "updateStoreResponse",
   588          "itemId": "id1",
   589          "newItemValue": "value4",
   590          "storeVersion": 55
   591      }`), nil)
   592  
   593  	wg.Wait()
   594  
   595  	assert.Equal(t, store.(*busStore).storeVersion, int64(54))
   596  	assert.NotNil(t, lastStoreChange)
   597  
   598  	assert.Equal(t, lastStoreChange.Id, "id1")
   599  	assert.Equal(t, lastStoreChange.Value, MockStoreItem{From: "admin", Message: "value1"})
   600  	assert.Equal(t, store.GetValue("id1"), MockStoreItem{From: "admin", Message: "value1"})
   601  
   602  	wg.Add(1)
   603  	jsonBlob = []byte(`{
   604          "storeId": "testStore",
   605          "responseType": "updateStoreResponse",
   606          "itemId": "id1",
   607          "storeVersion": 55
   608      }`)
   609  	bus.SendResponseMessage("sync-channel", jsonBlob, nil)
   610  
   611  	bus.SendResponseMessage("sync-channel", []byte(`{
   612          "storeId": "testStore",
   613          "responseType": "updateStoreResponse",
   614          "itemId": "id1",
   615          "newItemValue": "invalid-obj",
   616          "storeVersion": 55
   617      }`), nil)
   618  
   619  	wg.Wait()
   620  
   621  	assert.Equal(t, lastStoreChange.Id, "id1")
   622  	assert.Equal(t, lastStoreChange.Value, MockStoreItem{From: "admin", Message: "value1"})
   623  	assert.Equal(t, lastStoreChange.IsDeleteChange, true)
   624  	assert.Nil(t, store.GetValue("id1"))
   625  }
   626  
   627  func TestBusStore_GalacticStoreContent(t *testing.T) {
   628  	store, _, bus := testGalacticStore(reflect.TypeOf(MockStoreItem{}))
   629  
   630  	wg := sync.WaitGroup{}
   631  	wg.Add(1)
   632  
   633  	store.WhenReady(func() {
   634  		wg.Done()
   635  	})
   636  
   637  	var jsonBlob = []byte(`{
   638          "storeId": "testStore",
   639          "responseType": "storeContentResponse",
   640          "items": {
   641              "id1": { "from": "admin", "message": "value1"},
   642              "id2": { "from": "admin", "message": "value2"},
   643              "id3": "invalid-obj"
   644          },
   645          "storeVersion": 12
   646      }`)
   647  	bus.SendResponseMessage("sync-channel", jsonBlob, nil)
   648  
   649  	wg.Wait()
   650  
   651  	allValues, version := store.AllValuesAndVersion()
   652  	assert.Equal(t, version, int64(12))
   653  	assert.Equal(t, len(allValues), 2)
   654  	assert.Equal(t, allValues["id1"], MockStoreItem{From: "admin", Message: "value1"})
   655  	assert.Equal(t, allValues["id2"], MockStoreItem{From: "admin", Message: "value2"})
   656  }