github.com/mattermost/mattermost-server/v5@v5.39.3/store/storetest/remote_cluster_store.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package storetest
     5  
     6  import (
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/mattermost/mattermost-server/v5/model"
    11  	"github.com/mattermost/mattermost-server/v5/store"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  func TestRemoteClusterStore(t *testing.T, ss store.Store) {
    18  	t.Run("RemoteClusterGetAllInChannel", func(t *testing.T) { testRemoteClusterGetAllInChannel(t, ss) })
    19  	t.Run("RemoteClusterGetAllNotInChannel", func(t *testing.T) { testRemoteClusterGetAllNotInChannel(t, ss) })
    20  	t.Run("RemoteClusterSave", func(t *testing.T) { testRemoteClusterSave(t, ss) })
    21  	t.Run("RemoteClusterDelete", func(t *testing.T) { testRemoteClusterDelete(t, ss) })
    22  	t.Run("RemoteClusterGet", func(t *testing.T) { testRemoteClusterGet(t, ss) })
    23  	t.Run("RemoteClusterGetAll", func(t *testing.T) { testRemoteClusterGetAll(t, ss) })
    24  	t.Run("RemoteClusterGetByTopic", func(t *testing.T) { testRemoteClusterGetByTopic(t, ss) })
    25  	t.Run("RemoteClusterUpdateTopics", func(t *testing.T) { testRemoteClusterUpdateTopics(t, ss) })
    26  }
    27  
    28  func testRemoteClusterSave(t *testing.T, ss store.Store) {
    29  
    30  	t.Run("Save", func(t *testing.T) {
    31  		rc := &model.RemoteCluster{
    32  			Name:      "some_remote",
    33  			SiteURL:   "somewhere.com",
    34  			CreatorId: model.NewId(),
    35  		}
    36  
    37  		rcSaved, err := ss.RemoteCluster().Save(rc)
    38  		require.NoError(t, err)
    39  		require.Equal(t, rc.Name, rcSaved.Name)
    40  		require.Equal(t, rc.SiteURL, rcSaved.SiteURL)
    41  		require.Greater(t, rc.CreateAt, int64(0))
    42  		require.Equal(t, rc.LastPingAt, int64(0))
    43  	})
    44  
    45  	t.Run("Save missing display name", func(t *testing.T) {
    46  		rc := &model.RemoteCluster{
    47  			SiteURL:   "somewhere.com",
    48  			CreatorId: model.NewId(),
    49  		}
    50  		_, err := ss.RemoteCluster().Save(rc)
    51  		require.Error(t, err)
    52  	})
    53  
    54  	t.Run("Save missing creator id", func(t *testing.T) {
    55  		rc := &model.RemoteCluster{
    56  			Name:    "some_remote_2",
    57  			SiteURL: "somewhere.com",
    58  		}
    59  		_, err := ss.RemoteCluster().Save(rc)
    60  		require.Error(t, err)
    61  	})
    62  }
    63  
    64  func testRemoteClusterDelete(t *testing.T, ss store.Store) {
    65  	t.Run("Delete", func(t *testing.T) {
    66  		rc := &model.RemoteCluster{
    67  			Name:      "shortlived_remote",
    68  			SiteURL:   "nowhere.com",
    69  			CreatorId: model.NewId(),
    70  		}
    71  		rcSaved, err := ss.RemoteCluster().Save(rc)
    72  		require.NoError(t, err)
    73  
    74  		deleted, err := ss.RemoteCluster().Delete(rcSaved.RemoteId)
    75  		require.NoError(t, err)
    76  		require.True(t, deleted)
    77  	})
    78  
    79  	t.Run("Delete nonexistent", func(t *testing.T) {
    80  		deleted, err := ss.RemoteCluster().Delete(model.NewId())
    81  		require.NoError(t, err)
    82  		require.False(t, deleted)
    83  	})
    84  }
    85  
    86  func testRemoteClusterGet(t *testing.T, ss store.Store) {
    87  	t.Run("Get", func(t *testing.T) {
    88  		rc := &model.RemoteCluster{
    89  			Name:      "shortlived_remote_2",
    90  			SiteURL:   "nowhere.com",
    91  			CreatorId: model.NewId(),
    92  		}
    93  		rcSaved, err := ss.RemoteCluster().Save(rc)
    94  		require.NoError(t, err)
    95  
    96  		rcGet, err := ss.RemoteCluster().Get(rcSaved.RemoteId)
    97  		require.NoError(t, err)
    98  		require.Equal(t, rcSaved.RemoteId, rcGet.RemoteId)
    99  	})
   100  
   101  	t.Run("Get not found", func(t *testing.T) {
   102  		_, err := ss.RemoteCluster().Get(model.NewId())
   103  		require.Error(t, err)
   104  	})
   105  }
   106  
   107  func testRemoteClusterGetAll(t *testing.T, ss store.Store) {
   108  	require.NoError(t, clearRemoteClusters(ss))
   109  
   110  	userId := model.NewId()
   111  	now := model.GetMillis()
   112  	pingLongAgo := model.GetMillis() - (model.RemoteOfflineAfterMillis * 3)
   113  
   114  	data := []*model.RemoteCluster{
   115  		{Name: "offline_remote", CreatorId: userId, SiteURL: "somewhere.com", LastPingAt: pingLongAgo, Topics: " shared incident "},
   116  		{Name: "some_online_remote", CreatorId: userId, SiteURL: "nowhere.com", LastPingAt: now, Topics: " shared incident "},
   117  		{Name: "another_online_remote", CreatorId: model.NewId(), SiteURL: "underwhere.com", LastPingAt: now, Topics: ""},
   118  		{Name: "another_offline_remote", CreatorId: model.NewId(), SiteURL: "knowhere.com", LastPingAt: pingLongAgo, Topics: " shared "},
   119  		{Name: "brand_new_offline_remote", CreatorId: userId, SiteURL: "", LastPingAt: 0, Topics: " bogus shared stuff "},
   120  	}
   121  
   122  	idsAll := make([]string, 0)
   123  	idsOnline := make([]string, 0)
   124  	idsOffline := make([]string, 0)
   125  	idsShareTopic := make([]string, 0)
   126  
   127  	for _, item := range data {
   128  		online := item.LastPingAt == now
   129  		saved, err := ss.RemoteCluster().Save(item)
   130  		require.NoError(t, err)
   131  		idsAll = append(idsAll, saved.RemoteId)
   132  		if online {
   133  			idsOnline = append(idsOnline, saved.RemoteId)
   134  		} else {
   135  			idsOffline = append(idsOffline, saved.RemoteId)
   136  		}
   137  		if strings.Contains(saved.Topics, " shared ") {
   138  			idsShareTopic = append(idsShareTopic, saved.RemoteId)
   139  		}
   140  	}
   141  
   142  	t.Run("GetAll", func(t *testing.T) {
   143  		filter := model.RemoteClusterQueryFilter{}
   144  		remotes, err := ss.RemoteCluster().GetAll(filter)
   145  		require.NoError(t, err)
   146  		// make sure all the test data remotes were returned.
   147  		ids := getIds(remotes)
   148  		assert.ElementsMatch(t, ids, idsAll)
   149  	})
   150  
   151  	t.Run("GetAll online only", func(t *testing.T) {
   152  		filter := model.RemoteClusterQueryFilter{
   153  			ExcludeOffline: true,
   154  		}
   155  		remotes, err := ss.RemoteCluster().GetAll(filter)
   156  		require.NoError(t, err)
   157  		// make sure all the online remotes were returned.
   158  		ids := getIds(remotes)
   159  		assert.ElementsMatch(t, ids, idsOnline)
   160  	})
   161  
   162  	t.Run("GetAll by topic", func(t *testing.T) {
   163  		filter := model.RemoteClusterQueryFilter{
   164  			Topic: "shared",
   165  		}
   166  		remotes, err := ss.RemoteCluster().GetAll(filter)
   167  		require.NoError(t, err)
   168  		// make sure only correct topic returned
   169  		ids := getIds(remotes)
   170  		assert.ElementsMatch(t, ids, idsShareTopic)
   171  	})
   172  
   173  	t.Run("GetAll online by topic", func(t *testing.T) {
   174  		filter := model.RemoteClusterQueryFilter{
   175  			ExcludeOffline: true,
   176  			Topic:          "shared",
   177  		}
   178  		remotes, err := ss.RemoteCluster().GetAll(filter)
   179  		require.NoError(t, err)
   180  		// make sure only online remotes were returned.
   181  		ids := getIds(remotes)
   182  		assert.Subset(t, idsOnline, ids)
   183  		// make sure correct topic returned
   184  		assert.Subset(t, idsShareTopic, ids)
   185  		assert.Len(t, ids, 1)
   186  	})
   187  
   188  	t.Run("GetAll by Creator", func(t *testing.T) {
   189  		filter := model.RemoteClusterQueryFilter{
   190  			CreatorId: userId,
   191  		}
   192  		remotes, err := ss.RemoteCluster().GetAll(filter)
   193  		require.NoError(t, err)
   194  		// make sure only correct creator returned
   195  		assert.Len(t, remotes, 3)
   196  		for _, rc := range remotes {
   197  			assert.Equal(t, userId, rc.CreatorId)
   198  		}
   199  	})
   200  
   201  	t.Run("GetAll by Confirmed", func(t *testing.T) {
   202  		filter := model.RemoteClusterQueryFilter{
   203  			OnlyConfirmed: true,
   204  		}
   205  		remotes, err := ss.RemoteCluster().GetAll(filter)
   206  		require.NoError(t, err)
   207  		// make sure only confirmed returned
   208  		assert.Len(t, remotes, 4)
   209  		for _, rc := range remotes {
   210  			assert.NotEmpty(t, rc.SiteURL)
   211  		}
   212  	})
   213  }
   214  
   215  func testRemoteClusterGetAllInChannel(t *testing.T, ss store.Store) {
   216  	require.NoError(t, clearRemoteClusters(ss))
   217  	now := model.GetMillis()
   218  
   219  	userId := model.NewId()
   220  
   221  	channel1, err := createTestChannel(ss, "channel_1")
   222  	require.NoError(t, err)
   223  
   224  	channel2, err := createTestChannel(ss, "channel_2")
   225  	require.NoError(t, err)
   226  
   227  	channel3, err := createTestChannel(ss, "channel_3")
   228  	require.NoError(t, err)
   229  
   230  	// Create shared channels
   231  	scData := []*model.SharedChannel{
   232  		{ChannelId: channel1.Id, TeamId: model.NewId(), Home: true, ShareName: "test_chan_1", CreatorId: model.NewId()},
   233  		{ChannelId: channel2.Id, TeamId: model.NewId(), Home: true, ShareName: "test_chan_2", CreatorId: model.NewId()},
   234  		{ChannelId: channel3.Id, TeamId: model.NewId(), Home: true, ShareName: "test_chan_3", CreatorId: model.NewId()},
   235  	}
   236  	for _, item := range scData {
   237  		_, err := ss.SharedChannel().Save(item)
   238  		require.NoError(t, err)
   239  	}
   240  
   241  	// Create some remote clusters
   242  	rcData := []*model.RemoteCluster{
   243  		{Name: "AAAA_Inc", CreatorId: userId, SiteURL: "aaaa.com", RemoteId: model.NewId(), LastPingAt: now},
   244  		{Name: "BBBB_Inc", CreatorId: userId, SiteURL: "bbbb.com", RemoteId: model.NewId(), LastPingAt: 0},
   245  		{Name: "CCCC_Inc", CreatorId: userId, SiteURL: "cccc.com", RemoteId: model.NewId(), LastPingAt: now},
   246  		{Name: "DDDD_Inc", CreatorId: userId, SiteURL: "dddd.com", RemoteId: model.NewId(), LastPingAt: now},
   247  		{Name: "EEEE_Inc", CreatorId: userId, SiteURL: "eeee.com", RemoteId: model.NewId(), LastPingAt: 0},
   248  	}
   249  	for _, item := range rcData {
   250  		_, err := ss.RemoteCluster().Save(item)
   251  		require.NoError(t, err)
   252  	}
   253  
   254  	// Create some shared channel remotes
   255  	scrData := []*model.SharedChannelRemote{
   256  		{ChannelId: channel1.Id, RemoteId: rcData[0].RemoteId, CreatorId: model.NewId()},
   257  		{ChannelId: channel1.Id, RemoteId: rcData[1].RemoteId, CreatorId: model.NewId()},
   258  		{ChannelId: channel2.Id, RemoteId: rcData[2].RemoteId, CreatorId: model.NewId()},
   259  		{ChannelId: channel2.Id, RemoteId: rcData[3].RemoteId, CreatorId: model.NewId()},
   260  		{ChannelId: channel2.Id, RemoteId: rcData[4].RemoteId, CreatorId: model.NewId()},
   261  	}
   262  	for _, item := range scrData {
   263  		_, err := ss.SharedChannel().SaveRemote(item)
   264  		require.NoError(t, err)
   265  	}
   266  
   267  	t.Run("Channel 1", func(t *testing.T) {
   268  		filter := model.RemoteClusterQueryFilter{
   269  			InChannel: channel1.Id,
   270  		}
   271  		list, err := ss.RemoteCluster().GetAll(filter)
   272  		require.NoError(t, err)
   273  		require.Len(t, list, 2, "channel 1 should have 2 remote clusters")
   274  		ids := getIds(list)
   275  		require.ElementsMatch(t, []string{rcData[0].RemoteId, rcData[1].RemoteId}, ids)
   276  	})
   277  
   278  	t.Run("Channel 1 online only", func(t *testing.T) {
   279  		filter := model.RemoteClusterQueryFilter{
   280  			ExcludeOffline: true,
   281  			InChannel:      channel1.Id,
   282  		}
   283  		list, err := ss.RemoteCluster().GetAll(filter)
   284  		require.NoError(t, err)
   285  		require.Len(t, list, 1, "channel 1 should have 1 online remote clusters")
   286  		ids := getIds(list)
   287  		require.ElementsMatch(t, []string{rcData[0].RemoteId}, ids)
   288  	})
   289  
   290  	t.Run("Channel 2", func(t *testing.T) {
   291  		filter := model.RemoteClusterQueryFilter{
   292  			InChannel: channel2.Id,
   293  		}
   294  		list, err := ss.RemoteCluster().GetAll(filter)
   295  		require.NoError(t, err)
   296  		require.Len(t, list, 3, "channel 2 should have 3 remote clusters")
   297  		ids := getIds(list)
   298  		require.ElementsMatch(t, []string{rcData[2].RemoteId, rcData[3].RemoteId, rcData[4].RemoteId}, ids)
   299  	})
   300  
   301  	t.Run("Channel 2 online only", func(t *testing.T) {
   302  		filter := model.RemoteClusterQueryFilter{
   303  			ExcludeOffline: true,
   304  			InChannel:      channel2.Id,
   305  		}
   306  		list, err := ss.RemoteCluster().GetAll(filter)
   307  		require.NoError(t, err)
   308  		require.Len(t, list, 2, "channel 2 should have 2 online remote clusters")
   309  		ids := getIds(list)
   310  		require.ElementsMatch(t, []string{rcData[2].RemoteId, rcData[3].RemoteId}, ids)
   311  	})
   312  
   313  	t.Run("Channel 3", func(t *testing.T) {
   314  		filter := model.RemoteClusterQueryFilter{
   315  			InChannel: channel3.Id,
   316  		}
   317  		list, err := ss.RemoteCluster().GetAll(filter)
   318  		require.NoError(t, err)
   319  		require.Empty(t, list, "channel 3 should have 0 remote clusters")
   320  	})
   321  }
   322  
   323  func testRemoteClusterGetAllNotInChannel(t *testing.T, ss store.Store) {
   324  	require.NoError(t, clearRemoteClusters(ss))
   325  
   326  	userId := model.NewId()
   327  
   328  	channel1, err := createTestChannel(ss, "channel_1")
   329  	require.NoError(t, err)
   330  
   331  	channel2, err := createTestChannel(ss, "channel_2")
   332  	require.NoError(t, err)
   333  
   334  	channel3, err := createTestChannel(ss, "channel_3")
   335  	require.NoError(t, err)
   336  
   337  	// Create shared channels
   338  	scData := []*model.SharedChannel{
   339  		{ChannelId: channel1.Id, TeamId: model.NewId(), Home: true, ShareName: "test_chan_1", CreatorId: model.NewId()},
   340  		{ChannelId: channel2.Id, TeamId: model.NewId(), Home: true, ShareName: "test_chan_2", CreatorId: model.NewId()},
   341  		{ChannelId: channel3.Id, TeamId: model.NewId(), Home: true, ShareName: "test_chan_3", CreatorId: model.NewId()},
   342  	}
   343  	for _, item := range scData {
   344  		_, err := ss.SharedChannel().Save(item)
   345  		require.NoError(t, err)
   346  	}
   347  
   348  	// Create some remote clusters
   349  	rcData := []*model.RemoteCluster{
   350  		{Name: "AAAA_Inc", CreatorId: userId, SiteURL: "aaaa.com", RemoteId: model.NewId()},
   351  		{Name: "BBBB_Inc", CreatorId: userId, SiteURL: "bbbb.com", RemoteId: model.NewId()},
   352  		{Name: "CCCC_Inc", CreatorId: userId, SiteURL: "cccc.com", RemoteId: model.NewId()},
   353  		{Name: "DDDD_Inc", CreatorId: userId, SiteURL: "dddd.com", RemoteId: model.NewId()},
   354  		{Name: "EEEE_Inc", CreatorId: userId, SiteURL: "eeee.com", RemoteId: model.NewId()},
   355  	}
   356  	for _, item := range rcData {
   357  		_, err := ss.RemoteCluster().Save(item)
   358  		require.NoError(t, err)
   359  	}
   360  
   361  	// Create some shared channel remotes
   362  	scrData := []*model.SharedChannelRemote{
   363  		{ChannelId: channel1.Id, RemoteId: rcData[0].RemoteId, CreatorId: model.NewId()},
   364  		{ChannelId: channel1.Id, RemoteId: rcData[1].RemoteId, CreatorId: model.NewId()},
   365  		{ChannelId: channel2.Id, RemoteId: rcData[2].RemoteId, CreatorId: model.NewId()},
   366  		{ChannelId: channel2.Id, RemoteId: rcData[3].RemoteId, CreatorId: model.NewId()},
   367  		{ChannelId: channel3.Id, RemoteId: rcData[4].RemoteId, CreatorId: model.NewId()},
   368  	}
   369  	for _, item := range scrData {
   370  		_, err := ss.SharedChannel().SaveRemote(item)
   371  		require.NoError(t, err)
   372  	}
   373  
   374  	t.Run("Channel 1", func(t *testing.T) {
   375  		filter := model.RemoteClusterQueryFilter{
   376  			NotInChannel: channel1.Id,
   377  		}
   378  		list, err := ss.RemoteCluster().GetAll(filter)
   379  		require.NoError(t, err)
   380  		require.Len(t, list, 3, "channel 1 should have 3 remote clusters that are not already members")
   381  		ids := getIds(list)
   382  		require.ElementsMatch(t, []string{rcData[2].RemoteId, rcData[3].RemoteId, rcData[4].RemoteId}, ids)
   383  	})
   384  
   385  	t.Run("Channel 2", func(t *testing.T) {
   386  		filter := model.RemoteClusterQueryFilter{
   387  			NotInChannel: channel2.Id,
   388  		}
   389  		list, err := ss.RemoteCluster().GetAll(filter)
   390  		require.NoError(t, err)
   391  		require.Len(t, list, 3, "channel 2 should have 3 remote clusters that are not already members")
   392  		ids := getIds(list)
   393  		require.ElementsMatch(t, []string{rcData[0].RemoteId, rcData[1].RemoteId, rcData[4].RemoteId}, ids)
   394  	})
   395  
   396  	t.Run("Channel 3", func(t *testing.T) {
   397  		filter := model.RemoteClusterQueryFilter{
   398  			NotInChannel: channel3.Id,
   399  		}
   400  		list, err := ss.RemoteCluster().GetAll(filter)
   401  		require.NoError(t, err)
   402  		require.Len(t, list, 4, "channel 3 should have 4 remote clusters that are not already members")
   403  		ids := getIds(list)
   404  		require.ElementsMatch(t, []string{rcData[0].RemoteId, rcData[1].RemoteId, rcData[2].RemoteId, rcData[3].RemoteId}, ids)
   405  	})
   406  
   407  	t.Run("Channel with no share remotes", func(t *testing.T) {
   408  		filter := model.RemoteClusterQueryFilter{
   409  			NotInChannel: model.NewId(),
   410  		}
   411  		list, err := ss.RemoteCluster().GetAll(filter)
   412  		require.NoError(t, err)
   413  		require.Len(t, list, 5, "should have 5 remote clusters that are not already members")
   414  		ids := getIds(list)
   415  		require.ElementsMatch(t, []string{rcData[0].RemoteId, rcData[1].RemoteId, rcData[2].RemoteId, rcData[3].RemoteId,
   416  			rcData[4].RemoteId}, ids)
   417  	})
   418  }
   419  
   420  func getIds(remotes []*model.RemoteCluster) []string {
   421  	ids := make([]string, 0, len(remotes))
   422  	for _, r := range remotes {
   423  		ids = append(ids, r.RemoteId)
   424  	}
   425  	return ids
   426  }
   427  
   428  func testRemoteClusterGetByTopic(t *testing.T, ss store.Store) {
   429  	require.NoError(t, clearRemoteClusters(ss))
   430  
   431  	rcData := []*model.RemoteCluster{
   432  		{Name: "AAAA_Inc", CreatorId: model.NewId(), SiteURL: "aaaa.com", RemoteId: model.NewId(), Topics: ""},
   433  		{Name: "BBBB_Inc", CreatorId: model.NewId(), SiteURL: "bbbb.com", RemoteId: model.NewId(), Topics: " share "},
   434  		{Name: "CCCC_Inc", CreatorId: model.NewId(), SiteURL: "cccc.com", RemoteId: model.NewId(), Topics: " incident share "},
   435  		{Name: "DDDD_Inc", CreatorId: model.NewId(), SiteURL: "dddd.com", RemoteId: model.NewId(), Topics: " bogus "},
   436  		{Name: "EEEE_Inc", CreatorId: model.NewId(), SiteURL: "eeee.com", RemoteId: model.NewId(), Topics: " logs share incident "},
   437  		{Name: "FFFF_Inc", CreatorId: model.NewId(), SiteURL: "ffff.com", RemoteId: model.NewId(), Topics: " bogus incident "},
   438  		{Name: "GGGG_Inc", CreatorId: model.NewId(), SiteURL: "gggg.com", RemoteId: model.NewId(), Topics: "*"},
   439  	}
   440  	for _, item := range rcData {
   441  		_, err := ss.RemoteCluster().Save(item)
   442  		require.NoError(t, err)
   443  	}
   444  
   445  	testData := []struct {
   446  		topic         string
   447  		expectedCount int
   448  		expectError   bool
   449  	}{
   450  		{topic: "", expectedCount: 7, expectError: false},
   451  		{topic: " ", expectedCount: 0, expectError: true},
   452  		{topic: "share", expectedCount: 4},
   453  		{topic: " share ", expectedCount: 4},
   454  		{topic: "bogus", expectedCount: 3},
   455  		{topic: "non-existent", expectedCount: 1},
   456  		{topic: "*", expectedCount: 0, expectError: true}, // can't query with wildcard
   457  	}
   458  
   459  	for _, tt := range testData {
   460  		filter := model.RemoteClusterQueryFilter{
   461  			Topic: tt.topic,
   462  		}
   463  		list, err := ss.RemoteCluster().GetAll(filter)
   464  		if tt.expectError {
   465  			assert.Errorf(t, err, "expected error for topic=%s", tt.topic)
   466  		} else {
   467  			assert.NoErrorf(t, err, "expected no error for topic=%s", tt.topic)
   468  		}
   469  		assert.Lenf(t, list, tt.expectedCount, "topic=%s", tt.topic)
   470  	}
   471  }
   472  
   473  func testRemoteClusterUpdateTopics(t *testing.T, ss store.Store) {
   474  	remoteId := model.NewId()
   475  	rc := &model.RemoteCluster{
   476  		DisplayName: "Blap Inc",
   477  		Name:        "blap",
   478  		SiteURL:     "blap.com",
   479  		RemoteId:    remoteId,
   480  		Topics:      "",
   481  		CreatorId:   model.NewId(),
   482  	}
   483  
   484  	_, err := ss.RemoteCluster().Save(rc)
   485  	require.NoError(t, err)
   486  
   487  	testData := []struct {
   488  		topics   string
   489  		expected string
   490  	}{
   491  		{topics: "", expected: ""},
   492  		{topics: " ", expected: ""},
   493  		{topics: "share", expected: " share "},
   494  		{topics: " share ", expected: " share "},
   495  		{topics: "share incident", expected: " share incident "},
   496  		{topics: "  share    incident   ", expected: " share incident "},
   497  	}
   498  
   499  	for _, tt := range testData {
   500  		_, err = ss.RemoteCluster().UpdateTopics(remoteId, tt.topics)
   501  		require.NoError(t, err)
   502  
   503  		rcUpdated, err := ss.RemoteCluster().Get(remoteId)
   504  		require.NoError(t, err)
   505  
   506  		require.Equal(t, tt.expected, rcUpdated.Topics)
   507  	}
   508  }
   509  
   510  func clearRemoteClusters(ss store.Store) error {
   511  	list, err := ss.RemoteCluster().GetAll(model.RemoteClusterQueryFilter{})
   512  	if err != nil {
   513  		return err
   514  	}
   515  
   516  	for _, rc := range list {
   517  		if _, err := ss.RemoteCluster().Delete(rc.RemoteId); err != nil {
   518  			return err
   519  		}
   520  	}
   521  	return nil
   522  }