Skip to content

Commit 4e0236c

Browse files
Template PR for server unit test cases using GoMock and Mockgen (#824)
* Template PR for server unit test cases * Fixed lint errors * review fixes * included mock for setAtomicWithRetries
1 parent 827e881 commit 4e0236c

File tree

6 files changed

+228
-8
lines changed

6 files changed

+228
-8
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ require (
2727
github.com/francoispqt/gojay v1.2.13 // indirect
2828
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
2929
github.com/go-sql-driver/mysql v1.8.1 // indirect
30+
github.com/golang/mock v1.6.0
3031
github.com/golang/protobuf v1.5.4 // indirect
3132
github.com/google/go-querystring v1.1.0 // indirect
3233
github.com/google/uuid v1.6.0 // indirect

go.sum

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,12 +251,14 @@ github.com/wiggin77/srslog v1.0.1 h1:gA2XjSMy3DrRdX9UqLuDtuVAAshb8bE1NhX1YK0Qe+8
251251
github.com/wiggin77/srslog v1.0.1/go.mod h1:fehkyYDq1QfuYn60TDPu9YdY2bB85VUW2mvN1WynEls=
252252
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g=
253253
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM=
254+
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
254255
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
255256
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
256257
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
257258
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
258259
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
259260
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
261+
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
260262
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
261263
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
262264
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
@@ -265,6 +267,7 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL
265267
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
266268
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
267269
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
270+
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
268271
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
269272
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
270273
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -274,7 +277,9 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r
274277
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
275278
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
276279
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
280+
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
277281
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
282+
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
278283
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
279284
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
280285
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
@@ -289,6 +294,8 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
289294
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
290295
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
291296
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
297+
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
298+
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
292299
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
293300
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
294301
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -298,6 +305,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
298305
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
299306
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
300307
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
308+
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
309+
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
301310
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
302311
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
303312
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -324,7 +333,12 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
324333
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
325334
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
326335
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
336+
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
337+
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
338+
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
339+
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
327340
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
341+
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
328342
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
329343
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
330344
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=

server/mocks/mock_KvStore.go

Lines changed: 111 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/plugin/command.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ func (p *Plugin) getMutedUsernames(userInfo *GitHubUserInfo) []string {
155155
return mutedUsers
156156
}
157157

158-
func (p *Plugin) handleMuteList(args *model.CommandArgs, userInfo *GitHubUserInfo) string {
158+
func (p *Plugin) handleMuteList(_ *model.CommandArgs, userInfo *GitHubUserInfo) string {
159159
mutedUsernames := p.getMutedUsernames(userInfo)
160160
var mutedUsers string
161161
for _, user := range mutedUsernames {
@@ -176,7 +176,7 @@ func contains(s []string, e string) bool {
176176
return false
177177
}
178178

179-
func (p *Plugin) handleMuteAdd(args *model.CommandArgs, username string, userInfo *GitHubUserInfo) string {
179+
func (p *Plugin) handleMuteAdd(_ *model.CommandArgs, username string, userInfo *GitHubUserInfo) string {
180180
mutedUsernames := p.getMutedUsernames(userInfo)
181181
if contains(mutedUsernames, username) {
182182
return username + " is already muted"
@@ -202,7 +202,7 @@ func (p *Plugin) handleMuteAdd(args *model.CommandArgs, username string, userInf
202202
return fmt.Sprintf("`%v`", username) + " is now muted. You'll no longer receive notifications for comments in your PRs and issues."
203203
}
204204

205-
func (p *Plugin) handleUnmute(args *model.CommandArgs, username string, userInfo *GitHubUserInfo) string {
205+
func (p *Plugin) handleUnmute(_ *model.CommandArgs, username string, userInfo *GitHubUserInfo) string {
206206
mutedUsernames := p.getMutedUsernames(userInfo)
207207
userToMute := []string{username}
208208
newMutedList := arrayDifference(mutedUsernames, userToMute)
@@ -215,7 +215,7 @@ func (p *Plugin) handleUnmute(args *model.CommandArgs, username string, userInfo
215215
return fmt.Sprintf("`%v`", username) + " is no longer muted"
216216
}
217217

218-
func (p *Plugin) handleUnmuteAll(args *model.CommandArgs, userInfo *GitHubUserInfo) string {
218+
func (p *Plugin) handleUnmuteAll(_ *model.CommandArgs, userInfo *GitHubUserInfo) string {
219219
_, err := p.store.Set(userInfo.UserID+"-muted-users", []byte(""))
220220
if err != nil {
221221
return "Error occurred unmuting users"
@@ -297,7 +297,7 @@ func (p *Plugin) handleSubscriptions(c *plugin.Context, args *model.CommandArgs,
297297
}
298298
}
299299

300-
func (p *Plugin) handleSubscriptionsList(_ *plugin.Context, args *model.CommandArgs, parameters []string, _ *GitHubUserInfo) string {
300+
func (p *Plugin) handleSubscriptionsList(_ *plugin.Context, args *model.CommandArgs, _ []string, _ *GitHubUserInfo) string {
301301
txt := ""
302302
subs, err := p.GetSubscriptionsByChannel(args.ChannelId)
303303
if err != nil {
@@ -713,7 +713,7 @@ func (p *Plugin) handleIssue(_ *plugin.Context, args *model.CommandArgs, paramet
713713
}
714714
}
715715

716-
func (p *Plugin) handleSetup(c *plugin.Context, args *model.CommandArgs, parameters []string) string {
716+
func (p *Plugin) handleSetup(_ *plugin.Context, args *model.CommandArgs, parameters []string) string {
717717
userID := args.UserId
718718
isSysAdmin, err := p.isAuthorizedSysAdmin(userID)
719719
if err != nil {

server/plugin/command_test.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,41 @@ import (
44
"fmt"
55
"testing"
66

7+
"github.com/golang/mock/gomock"
8+
"github.com/mattermost/mattermost/server/public/model"
9+
"github.com/mattermost/mattermost/server/public/plugin"
10+
"github.com/mattermost/mattermost/server/public/plugin/plugintest"
11+
"github.com/mattermost/mattermost/server/public/pluginapi"
712
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/mock"
14+
"github.com/stretchr/testify/require"
15+
"golang.org/x/oauth2"
16+
17+
"github.com/mattermost/mattermost-plugin-github/server/mocks"
818
)
919

20+
// Function to get the plugin object for test cases.
21+
func getPluginTest(api *plugintest.API, mockKvStore *mocks.MockKvStore) *Plugin {
22+
p := NewPlugin()
23+
p.setConfiguration(
24+
&Configuration{
25+
GitHubOrg: "mockOrg",
26+
GitHubOAuthClientID: "mockID",
27+
GitHubOAuthClientSecret: "mockSecret",
28+
EncryptionKey: "mockKey123456789",
29+
})
30+
p.initializeAPI()
31+
32+
p.store = mockKvStore
33+
34+
p.BotUserID = "mockBotID"
35+
36+
p.SetAPI(api)
37+
p.client = pluginapi.NewClient(api, p.Driver)
38+
39+
return p
40+
}
41+
1042
func TestValidateFeatures(t *testing.T) {
1143
type output struct {
1244
valid bool
@@ -239,3 +271,65 @@ func TestCheckConflictingFeatures(t *testing.T) {
239271
})
240272
}
241273
}
274+
275+
func TestExecuteCommand(t *testing.T) {
276+
tests := map[string]struct {
277+
commandArgs *model.CommandArgs
278+
expectedMsg string
279+
SetupMockStore func(*mocks.MockKvStore)
280+
}{
281+
"about command": {
282+
commandArgs: &model.CommandArgs{Command: "/github about"},
283+
expectedMsg: "GitHub version",
284+
SetupMockStore: func(mks *mocks.MockKvStore) {},
285+
},
286+
287+
"help command": {
288+
commandArgs: &model.CommandArgs{Command: "/github help", ChannelId: "test-channelID", RootId: "test-rootID", UserId: "test-userID"},
289+
expectedMsg: "###### Mattermost GitHub Plugin - Slash Command Help\n",
290+
SetupMockStore: func(mks *mocks.MockKvStore) {
291+
mks.EXPECT().Get(gomock.Any(), gomock.Any()).DoAndReturn(func(key string, value interface{}) error {
292+
// Cast the value to the appropriate type and updated it
293+
if userInfoPtr, ok := value.(**GitHubUserInfo); ok {
294+
*userInfoPtr = &GitHubUserInfo{
295+
// Mock user info data
296+
Token: &oauth2.Token{
297+
AccessToken: "ycbODW-BWbNBGfF7ac4T5RL5ruNm5BChCXgbkY1bWHqMt80JTkLsicQwo8de3tqfqlfMaglpgjqGOmSHeGp0dA==",
298+
},
299+
}
300+
}
301+
return nil // no error, so return nil
302+
})
303+
},
304+
},
305+
}
306+
for name, tt := range tests {
307+
t.Run(name, func(t *testing.T) {
308+
isSendEphemeralPostCalled := false
309+
310+
// Controller for the mocks generated using mockgen
311+
mockCtrl := gomock.NewController(t)
312+
defer mockCtrl.Finish()
313+
314+
mockKvStore := mocks.NewMockKvStore(mockCtrl)
315+
316+
tt.SetupMockStore(mockKvStore)
317+
318+
currentTestAPI := &plugintest.API{}
319+
currentTestAPI.On("SendEphemeralPost", mock.AnythingOfType("string"), mock.AnythingOfType("*model.Post")).Run(func(args mock.Arguments) {
320+
isSendEphemeralPostCalled = true
321+
322+
post := args.Get(1).(*model.Post)
323+
// Checking the contents of the post
324+
assert.Contains(t, post.Message, tt.expectedMsg)
325+
}).Once().Return(&model.Post{})
326+
327+
p := getPluginTest(currentTestAPI, mockKvStore)
328+
329+
_, err := p.ExecuteCommand(&plugin.Context{}, tt.commandArgs)
330+
require.Nil(t, err)
331+
332+
assert.Equal(t, true, isSendEphemeralPostCalled)
333+
})
334+
}
335+
}

server/plugin/plugin.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ var (
6363
testOAuthServerURL = ""
6464
)
6565

66-
type kvStore interface {
66+
type KvStore interface {
6767
Set(key string, value any, options ...pluginapi.KVSetOption) (bool, error)
6868
ListKeys(page int, count int, options ...pluginapi.ListKeysOption) ([]string, error)
6969
Get(key string, o any) error
@@ -75,7 +75,7 @@ type Plugin struct {
7575
plugin.MattermostPlugin
7676
client *pluginapi.Client
7777

78-
store kvStore
78+
store KvStore
7979

8080
// configurationLock synchronizes access to the configuration.
8181
configurationLock sync.RWMutex

0 commit comments

Comments
 (0)