From bbfc058d05d69a8f31a2789fe27a8c5256d353da Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Sun, 10 Apr 2016 11:36:49 +0800 Subject: [PATCH 1/2] support multiple notification request. Signed-off-by: Bo-Yi Wu --- Makefile | 3 + gorush/log.go | 2 +- gorush/notification.go | 45 +++++++---- gorush/notification_test.go | 149 +++++++++++++++++++++++++++++++++--- 4 files changed, 172 insertions(+), 27 deletions(-) diff --git a/Makefile b/Makefile index 0f62656..0d11ab2 100644 --- a/Makefile +++ b/Makefile @@ -17,5 +17,8 @@ docker_build: clean tar -zxvf bin.tar.gz -rm -rf bin.tar.gz build.tar.gz +test: + cd gopush && go test -v -covermode=count -coverprofile=coverage.out + clean: rm -rf build.tar.gz bin.tar.gz bin/* diff --git a/gorush/log.go b/gorush/log.go index 749d5ce..ce9e6f4 100644 --- a/gorush/log.go +++ b/gorush/log.go @@ -174,7 +174,7 @@ func typeForPlatForm(platform int) string { } } -func LogPush(status, token string, req RequestPushNotification, errPush error) { +func LogPush(status, token string, req PushNotification, errPush error) { var plat, platColor, output string platColor = colorForPlatForm(req.Platform) diff --git a/gorush/notification.go b/gorush/notification.go index e84d5e6..dcb0e71 100644 --- a/gorush/notification.go +++ b/gorush/notification.go @@ -41,7 +41,11 @@ type Alert struct { TitleLocKey string `json:"title-loc-key,omitempty"` } -type RequestPushNotification struct { +type RequestPush struct { + Notifications []PushNotification `json:"notifications"` +} + +type PushNotification struct { // Common Tokens []string `json:"tokens" binding:"required"` Platform int `json:"platform" binding:"required"` @@ -114,26 +118,33 @@ func InitAPNSClient() error { return nil } -func pushNotification(notification RequestPushNotification) bool { - switch notification.Platform { - case PlatFormIos: - if !PushConf.Ios.Enabled { - return false +func SendNotification(req RequestPush) int { + var count int + for _, notification := range req.Notifications { + switch notification.Platform { + case PlatFormIos: + if !PushConf.Ios.Enabled { + continue + } + + count += 1 + go PushToIOS(notification) + case PlatFormAndroid: + if !PushConf.Android.Enabled { + continue + } + + count += 1 + go PushToAndroid(notification) } - go PushToIOS(notification) - case PlatFormAndroid: - if !PushConf.Android.Enabled { - return false - } - go PushToAndroid(notification) } - return true + return count } // The iOS Notification Payload // ref: https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html -func GetIOSNotification(req RequestPushNotification) *apns.Notification { +func GetIOSNotification(req PushNotification) *apns.Notification { notification := &apns.Notification{} if len(req.ApnsID) > 0 { @@ -225,7 +236,7 @@ func GetIOSNotification(req RequestPushNotification) *apns.Notification { return notification } -func PushToIOS(req RequestPushNotification) bool { +func PushToIOS(req PushNotification) bool { notification := GetIOSNotification(req) @@ -260,7 +271,7 @@ func PushToIOS(req RequestPushNotification) bool { // HTTP Connection Server Reference for Android // https://developers.google.com/cloud-messaging/http-server-ref -func GetAndroidNotification(req RequestPushNotification) gcm.HttpMessage { +func GetAndroidNotification(req PushNotification) gcm.HttpMessage { notification := gcm.HttpMessage{} notification.RegistrationIds = req.Tokens @@ -311,7 +322,7 @@ func GetAndroidNotification(req RequestPushNotification) gcm.HttpMessage { return notification } -func PushToAndroid(req RequestPushNotification) bool { +func PushToAndroid(req PushNotification) bool { var apiKey string notification := GetAndroidNotification(req) diff --git a/gorush/notification_test.go b/gorush/notification_test.go index c4c45b0..6444ab3 100644 --- a/gorush/notification_test.go +++ b/gorush/notification_test.go @@ -5,6 +5,7 @@ import ( "github.com/buger/jsonparser" "github.com/google/go-gcm" "github.com/stretchr/testify/assert" + "github.com/sideshow/apns2" "log" "os" "testing" @@ -64,7 +65,7 @@ func TestIOSNotificationStructure(t *testing.T) { test := "test" message := "Welcome notification Server" - req := RequestPushNotification{ + req := PushNotification{ ApnsID: test, Topic: test, Expiration: time.Now().Unix(), @@ -126,7 +127,7 @@ func TestIOSAlertNotificationStructure(t *testing.T) { var dat map[string]interface{} test := "test" - req := RequestPushNotification{ + req := PushNotification{ Alert: Alert{ Action: test, ActionLocKey: test, @@ -178,7 +179,7 @@ func TestIOSAlertNotificationStructure(t *testing.T) { func TestAndroidNotificationStructure(t *testing.T) { test := "test" - req := RequestPushNotification{ + req := PushNotification{ Tokens: []string{"a", "b"}, Message: "Welcome", To: test, @@ -219,7 +220,7 @@ func TestPushToIOS(t *testing.T) { PushConf.Ios.PemKeyPath = "../certificate/certificate-valid.pem" InitAPNSClient() - req := RequestPushNotification{ + req := PushNotification{ Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"}, Platform: 1, Message: "Welcome", @@ -235,7 +236,7 @@ func TestPushToAndroidWrongAPIKey(t *testing.T) { PushConf.Android.Enabled = true PushConf.Android.ApiKey = os.Getenv("ANDROID_API_KEY") + "a" - req := RequestPushNotification{ + req := PushNotification{ Tokens: []string{"aaaaaa", "bbbbb"}, Platform: 2, Message: "Welcome", @@ -251,7 +252,7 @@ func TestPushToAndroidWrongToken(t *testing.T) { PushConf.Android.Enabled = true PushConf.Android.ApiKey = os.Getenv("ANDROID_API_KEY") - req := RequestPushNotification{ + req := PushNotification{ Tokens: []string{"aaaaaa", "bbbbb"}, Platform: 2, Message: "Welcome", @@ -271,7 +272,7 @@ func TestPushToAndroidRightTokenForJSONLog(t *testing.T) { android_token := os.Getenv("ANDROID_TEST_TOKEN") - req := RequestPushNotification{ + req := PushNotification{ Tokens: []string{android_token, "bbbbb"}, Platform: 2, Message: "Welcome", @@ -289,7 +290,7 @@ func TestPushToAndroidRightTokenForStringLog(t *testing.T) { android_token := os.Getenv("ANDROID_TEST_TOKEN") - req := RequestPushNotification{ + req := PushNotification{ Tokens: []string{android_token, "bbbbb"}, Platform: 2, Message: "Welcome", @@ -307,7 +308,7 @@ func TestOverwriteAndroidApiKey(t *testing.T) { android_token := os.Getenv("ANDROID_TEST_TOKEN") - req := RequestPushNotification{ + req := PushNotification{ Tokens: []string{android_token, "bbbbb"}, Platform: 2, Message: "Welcome", @@ -318,3 +319,133 @@ func TestOverwriteAndroidApiKey(t *testing.T) { success := PushToAndroid(req) assert.False(t, success) } + +func TestSenMultipleNotifications(t *testing.T) { + PushConf = BuildDefaultPushConf() + + PushConf.Ios.Enabled = true + PushConf.Ios.PemKeyPath = "../certificate/certificate-valid.pem" + InitAPNSClient() + + PushConf.Android.Enabled = true + PushConf.Android.ApiKey = os.Getenv("ANDROID_API_KEY") + + android_token := os.Getenv("ANDROID_TEST_TOKEN") + + req := RequestPush{ + Notifications: []PushNotification{ + //ios + PushNotification{ + Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"}, + Platform: 1, + Message: "Welcome", + }, + // android + PushNotification{ + Tokens: []string{android_token, "bbbbb"}, + Platform: 2, + Message: "Welcome", + }, + }, + } + + count := SendNotification(req) + assert.Equal(t, 2, count) +} + +func TestDisabledAndroidNotifications(t *testing.T) { + PushConf = BuildDefaultPushConf() + + PushConf.Ios.Enabled = true + PushConf.Ios.PemKeyPath = "../certificate/certificate-valid.pem" + InitAPNSClient() + + PushConf.Android.Enabled = false + PushConf.Android.ApiKey = os.Getenv("ANDROID_API_KEY") + + android_token := os.Getenv("ANDROID_TEST_TOKEN") + + req := RequestPush{ + Notifications: []PushNotification{ + //ios + PushNotification{ + Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"}, + Platform: 1, + Message: "Welcome", + }, + // android + PushNotification{ + Tokens: []string{android_token, "bbbbb"}, + Platform: 2, + Message: "Welcome", + }, + }, + } + + count := SendNotification(req) + assert.Equal(t, 1, count) +} + +func TestDisabledIosNotifications(t *testing.T) { + PushConf = BuildDefaultPushConf() + + PushConf.Ios.Enabled = false + PushConf.Ios.PemKeyPath = "../certificate/certificate-valid.pem" + InitAPNSClient() + + PushConf.Android.Enabled = true + PushConf.Android.ApiKey = os.Getenv("ANDROID_API_KEY") + + android_token := os.Getenv("ANDROID_TEST_TOKEN") + + req := RequestPush{ + Notifications: []PushNotification{ + //ios + PushNotification{ + Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"}, + Platform: 1, + Message: "Welcome", + }, + // android + PushNotification{ + Tokens: []string{android_token, "bbbbb"}, + Platform: 2, + Message: "Welcome", + }, + }, + } + + count := SendNotification(req) + assert.Equal(t, 1, count) +} + +func TestMissingIosCertificate(t *testing.T) { + PushConf = BuildDefaultPushConf() + + PushConf.Ios.Enabled = true + PushConf.Ios.PemKeyPath = "test" + err := InitAPNSClient() + + assert.Error(t, err) +} + +func TestAPNSClientDevHost(t *testing.T) { + PushConf = BuildDefaultPushConf() + + PushConf.Ios.Enabled = true + PushConf.Ios.PemKeyPath = "../certificate/certificate-valid.pem" + InitAPNSClient() + + assert.Equal(t, apns2.HostDevelopment, ApnsClient.Host) +} + +func TestAPNSClientProdHost(t *testing.T) { + PushConf = BuildDefaultPushConf() + + PushConf.Ios.Enabled = true + PushConf.Ios.Production = true + PushConf.Ios.PemKeyPath = "../certificate/certificate-valid.pem" + InitAPNSClient() + + assert.Equal(t, apns2.HostProduction, ApnsClient.Host) +} From c61aeeec7f106b3fd268a814ef7685294f597015 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Sun, 10 Apr 2016 12:02:44 +0800 Subject: [PATCH 2/2] fix server testing. Signed-off-by: Bo-Yi Wu --- gorush/notification.go | 2 +- gorush/notification_test.go | 2 +- gorush/server.go | 11 ++- gorush/server_test.go | 145 ++++++------------------------------ 4 files changed, 34 insertions(+), 126 deletions(-) diff --git a/gorush/notification.go b/gorush/notification.go index dcb0e71..07e0267 100644 --- a/gorush/notification.go +++ b/gorush/notification.go @@ -42,7 +42,7 @@ type Alert struct { } type RequestPush struct { - Notifications []PushNotification `json:"notifications"` + Notifications []PushNotification `json:"notifications" binding:"required"` } type PushNotification struct { diff --git a/gorush/notification_test.go b/gorush/notification_test.go index 6444ab3..cea931b 100644 --- a/gorush/notification_test.go +++ b/gorush/notification_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "github.com/buger/jsonparser" "github.com/google/go-gcm" - "github.com/stretchr/testify/assert" "github.com/sideshow/apns2" + "github.com/stretchr/testify/assert" "log" "os" "testing" diff --git a/gorush/server.go b/gorush/server.go index d1359a4..206c2fa 100644 --- a/gorush/server.go +++ b/gorush/server.go @@ -21,15 +21,20 @@ func rootHandler(c *gin.Context) { } func pushHandler(c *gin.Context) { - var form RequestPushNotification + var form RequestPush if err := c.BindJSON(&form); err != nil { - AbortWithError(c, http.StatusBadRequest, "Bad input request, please refer to README guide.") + AbortWithError(c, http.StatusBadRequest, "Missing nitifications field.") + return + } + + if len(form.Notifications) == 0 { + AbortWithError(c, http.StatusBadRequest, "Notification field is empty.") return } // process notification. - pushNotification(form) + go SendNotification(form) c.JSON(http.StatusOK, gin.H{ "text": "Welcome to notification server.", diff --git a/gorush/server_test.go b/gorush/server_test.go index b108dda..9bfcda4 100644 --- a/gorush/server_test.go +++ b/gorush/server_test.go @@ -92,15 +92,28 @@ func TestAPIStatusHandler(t *testing.T) { }) } -func TestMissingParameterPushHandler(t *testing.T) { +func TestMissingNotificationsParameter(t *testing.T) { initTest() r := gofight.New() - // missing some parameter. + // missing notifications parameter. + r.POST("/api/push"). + Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) { + + assert.Equal(t, http.StatusBadRequest, r.Code) + }) +} + +func TestEmptyNotifications(t *testing.T) { + initTest() + + r := gofight.New() + + // notifications is empty. r.POST("/api/push"). SetJSON(gofight.D{ - "platform": 1, + "notifications": []PushNotification{}, }). Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) { @@ -108,99 +121,7 @@ func TestMissingParameterPushHandler(t *testing.T) { }) } -func TestDisabledIosPushHandler(t *testing.T) { - initTest() - - PushConf.Ios.Enabled = false - InitAPNSClient() - - r := gofight.New() - - r.POST("/api/push"). - SetJSON(gofight.D{ - "tokens": []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"}, - "platform": 1, - "message": "Welcome", - }). - Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) { - - assert.Equal(t, http.StatusOK, r.Code) - }) -} - -func TestMissingIosCertificate(t *testing.T) { - initTest() - - PushConf.Ios.Enabled = true - PushConf.Ios.PemKeyPath = "test" - err := InitAPNSClient() - - assert.Error(t, err) -} - -func TestIosPushDevelopment(t *testing.T) { - initTest() - - PushConf.Ios.Enabled = true - PushConf.Ios.PemKeyPath = "../certificate/certificate-valid.pem" - InitAPNSClient() - - r := gofight.New() - - r.POST("/api/push"). - SetJSON(gofight.D{ - "tokens": []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"}, - "platform": 1, - "message": "Welcome", - }). - Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) { - - assert.Equal(t, http.StatusOK, r.Code) - }) -} - -func TestIosPushProduction(t *testing.T) { - initTest() - - PushConf.Ios.Enabled = true - PushConf.Ios.Production = true - PushConf.Ios.PemKeyPath = "../certificate/certificate-valid.pem" - InitAPNSClient() - - r := gofight.New() - - r.POST("/api/push"). - SetJSON(gofight.D{ - "tokens": []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"}, - "platform": 1, - "message": "Welcome", - }). - Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) { - - assert.Equal(t, http.StatusOK, r.Code) - }) -} - -func TestDisabledAndroidPushHandler(t *testing.T) { - initTest() - - PushConf.Android.Enabled = false - - r := gofight.New() - - r.POST("/api/push"). - SetJSON(gofight.D{ - "tokens": []string{"aaaaaa", "bbbbb"}, - "platform": 2, - "message": "Welcome", - }). - Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) { - - assert.Equal(t, http.StatusOK, r.Code) - }) -} - -func TestHalfSuccessAndroidPushHandler(t *testing.T) { +func TestSuccessPushHandler(t *testing.T) { initTest() PushConf.Android.Enabled = true @@ -212,31 +133,13 @@ func TestHalfSuccessAndroidPushHandler(t *testing.T) { r.POST("/api/push"). SetJSON(gofight.D{ - "tokens": []string{android_token, "bbbbb"}, - "platform": 2, - "message": "Welcome", - }). - Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) { - - assert.Equal(t, http.StatusOK, r.Code) - }) -} - -func TestAllSuccessAndroidPushHandler(t *testing.T) { - initTest() - - PushConf.Android.Enabled = true - PushConf.Android.ApiKey = os.Getenv("ANDROID_API_KEY") - - android_token := os.Getenv("ANDROID_TEST_TOKEN") - - r := gofight.New() - - r.POST("/api/push"). - SetJSON(gofight.D{ - "tokens": []string{android_token, android_token}, - "platform": 2, - "message": "Welcome", + "notifications": []gofight.D{ + gofight.D{ + "tokens": []string{android_token, "bbbbb"}, + "platform": 2, + "message": "Welcome", + }, + }, }). Run(GetMainEngine(), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {