chore: support single queue and multiple worker (#589)

This commit is contained in:
Bo-Yi Wu
2021-07-16 12:10:34 +08:00
committed by GitHub
parent 0658f18430
commit ab8b1991ab
34 changed files with 1020 additions and 881 deletions

View File

@@ -3,14 +3,18 @@ package router
import (
"context"
"crypto/tls"
"errors"
"fmt"
"net/http"
"os"
"sync"
"github.com/appleboy/gorush/config"
"github.com/appleboy/gorush/core"
"github.com/appleboy/gorush/gorush"
"github.com/appleboy/gorush/logx"
"github.com/appleboy/gorush/metric"
"github.com/appleboy/gorush/queue"
"github.com/appleboy/gorush/status"
api "github.com/appleboy/gin-status-api"
@@ -26,14 +30,12 @@ import (
"golang.org/x/crypto/acme/autocert"
)
var isTerm bool
var (
isTerm bool
doOnce sync.Once
)
func init() {
// Support metrics
m := metric.NewMetrics(func() int {
return len(gorush.QueueNotification)
})
prometheus.MustRegister(m)
isTerm = isatty.IsTerminal(os.Stdout.Fd())
}
@@ -61,7 +63,7 @@ func versionHandler(c *gin.Context) {
})
}
func pushHandler(cfg config.ConfYaml) gin.HandlerFunc {
func pushHandler(cfg config.ConfYaml, q *queue.Queue) gin.HandlerFunc {
return func(c *gin.Context) {
var form gorush.RequestPush
var msg string
@@ -101,7 +103,7 @@ func pushHandler(cfg config.ConfYaml) gin.HandlerFunc {
}
}()
counts, logs := gorush.HandleNotification(ctx, form)
counts, logs := handleNotification(ctx, cfg, form, q)
c.JSON(http.StatusOK, gin.H{
"success": "ok",
@@ -121,21 +123,23 @@ func metricsHandler(c *gin.Context) {
promhttp.Handler().ServeHTTP(c.Writer, c.Request)
}
func appStatusHandler(c *gin.Context) {
result := status.App{}
func appStatusHandler(q *queue.Queue) gin.HandlerFunc {
return func(c *gin.Context) {
result := status.App{}
result.Version = GetVersion()
result.QueueMax = cap(gorush.QueueNotification)
result.QueueUsage = len(gorush.QueueNotification)
result.TotalCount = status.StatStorage.GetTotalCount()
result.Ios.PushSuccess = status.StatStorage.GetIosSuccess()
result.Ios.PushError = status.StatStorage.GetIosError()
result.Android.PushSuccess = status.StatStorage.GetAndroidSuccess()
result.Android.PushError = status.StatStorage.GetAndroidError()
result.Huawei.PushSuccess = status.StatStorage.GetHuaweiSuccess()
result.Huawei.PushError = status.StatStorage.GetHuaweiError()
result.Version = GetVersion()
result.QueueMax = q.Capacity()
result.QueueUsage = q.Usage()
result.TotalCount = status.StatStorage.GetTotalCount()
result.Ios.PushSuccess = status.StatStorage.GetIosSuccess()
result.Ios.PushError = status.StatStorage.GetIosError()
result.Android.PushSuccess = status.StatStorage.GetAndroidSuccess()
result.Android.PushError = status.StatStorage.GetAndroidError()
result.Huawei.PushSuccess = status.StatStorage.GetHuaweiSuccess()
result.Huawei.PushError = status.StatStorage.GetHuaweiError()
c.JSON(http.StatusOK, result)
c.JSON(http.StatusOK, result)
}
}
func sysStatsHandler() gin.HandlerFunc {
@@ -153,7 +157,7 @@ func StatMiddleware() gin.HandlerFunc {
}
}
func autoTLSServer(cfg config.ConfYaml) *http.Server {
func autoTLSServer(cfg config.ConfYaml, q *queue.Queue) *http.Server {
m := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist(cfg.Core.AutoTLS.Host),
@@ -163,11 +167,11 @@ func autoTLSServer(cfg config.ConfYaml) *http.Server {
return &http.Server{
Addr: ":https",
TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
Handler: routerEngine(cfg),
Handler: routerEngine(cfg, q),
}
}
func routerEngine(cfg config.ConfYaml) *gin.Engine {
func routerEngine(cfg config.ConfYaml, q *queue.Queue) *gin.Engine {
zerolog.SetGlobalLevel(zerolog.InfoLevel)
if cfg.Core.Mode == "debug" {
zerolog.SetGlobalLevel(zerolog.DebugLevel)
@@ -184,6 +188,14 @@ func routerEngine(cfg config.ConfYaml) *gin.Engine {
)
}
// Support metrics
doOnce.Do(func() {
m := metric.NewMetrics(func() int {
return q.Usage()
})
prometheus.MustRegister(m)
})
// set server mode
gin.SetMode(cfg.Core.Mode)
@@ -202,10 +214,10 @@ func routerEngine(cfg config.ConfYaml) *gin.Engine {
r.Use(StatMiddleware())
r.GET(cfg.API.StatGoURI, api.GinHandler)
r.GET(cfg.API.StatAppURI, appStatusHandler)
r.GET(cfg.API.StatAppURI, appStatusHandler(q))
r.GET(cfg.API.ConfigURI, configHandler(cfg))
r.GET(cfg.API.SysStatURI, sysStatsHandler())
r.POST(cfg.API.PushURI, pushHandler(cfg))
r.POST(cfg.API.PushURI, pushHandler(cfg, q))
r.GET(cfg.API.MetricURI, metricsHandler)
r.GET(cfg.API.HealthURI, heartbeatHandler)
r.HEAD(cfg.API.HealthURI, heartbeatHandler)
@@ -214,3 +226,73 @@ func routerEngine(cfg config.ConfYaml) *gin.Engine {
return r
}
// markFailedNotification adds failure logs for all tokens in push notification
func markFailedNotification(cfg config.ConfYaml, notification *gorush.PushNotification, reason string) {
logx.LogError.Error(reason)
for _, token := range notification.Tokens {
notification.AddLog(logx.GetLogPushEntry(&logx.InputLog{
ID: notification.ID,
Status: core.FailedPush,
Token: token,
Message: notification.Message,
Platform: notification.Platform,
Error: errors.New(reason),
HideToken: cfg.Log.HideToken,
Format: cfg.Log.Format,
}))
}
notification.WaitDone()
}
// HandleNotification add notification to queue list.
func handleNotification(ctx context.Context, cfg config.ConfYaml, req gorush.RequestPush, q *queue.Queue) (int, []logx.LogPushEntry) {
var count int
wg := sync.WaitGroup{}
newNotification := []*gorush.PushNotification{}
for i := range req.Notifications {
notification := &req.Notifications[i]
switch notification.Platform {
case core.PlatFormIos:
if !cfg.Ios.Enabled {
continue
}
case core.PlatFormAndroid:
if !cfg.Android.Enabled {
continue
}
case core.PlatFormHuawei:
if !cfg.Huawei.Enabled {
continue
}
}
newNotification = append(newNotification, notification)
}
log := make([]logx.LogPushEntry, 0, count)
for _, notification := range newNotification {
if cfg.Core.Sync {
notification.Wg = &wg
notification.Log = &log
notification.AddWaitCount()
}
if err := q.Enqueue(*notification); err != nil {
markFailedNotification(cfg, notification, "max capacity reached")
}
count += len(notification.Tokens)
// Count topic message
if notification.To != "" {
count++
}
}
if cfg.Core.Sync {
wg.Wait()
}
status.StatStorage.AddTotalCount(int64(count))
return count, log
}

View File

@@ -8,12 +8,13 @@ import (
"github.com/appleboy/gorush/config"
"github.com/appleboy/gorush/logx"
"github.com/appleboy/gorush/queue"
"github.com/apex/gateway"
)
// RunHTTPServer provide run http or https protocol.
func RunHTTPServer(ctx context.Context, cfg config.ConfYaml, s ...*http.Server) (err error) {
func RunHTTPServer(ctx context.Context, cfg config.ConfYaml, q *queue.Queue, s ...*http.Server) (err error) {
if !cfg.Core.Enabled {
logx.LogAccess.Debug("httpd server is disabled.")
return nil
@@ -21,5 +22,5 @@ func RunHTTPServer(ctx context.Context, cfg config.ConfYaml, s ...*http.Server)
logx.LogAccess.Info("HTTPD server is running on " + cfg.Core.Port + " port.")
return gateway.ListenAndServe(cfg.Core.Address+":"+cfg.Core.Port, routerEngine(cfg))
return gateway.ListenAndServe(cfg.Core.Address+":"+cfg.Core.Port, routerEngine(cfg, q))
}

View File

@@ -12,12 +12,13 @@ import (
"github.com/appleboy/gorush/config"
"github.com/appleboy/gorush/logx"
"github.com/appleboy/gorush/queue"
"golang.org/x/sync/errgroup"
)
// RunHTTPServer provide run http or https protocol.
func RunHTTPServer(ctx context.Context, cfg config.ConfYaml, s ...*http.Server) (err error) {
func RunHTTPServer(ctx context.Context, cfg config.ConfYaml, q *queue.Queue, s ...*http.Server) (err error) {
var server *http.Server
if !cfg.Core.Enabled {
@@ -28,7 +29,7 @@ func RunHTTPServer(ctx context.Context, cfg config.ConfYaml, s ...*http.Server)
if len(s) == 0 {
server = &http.Server{
Addr: cfg.Core.Address + ":" + cfg.Core.Port,
Handler: routerEngine(cfg),
Handler: routerEngine(cfg, q),
}
} else {
server = s[0]
@@ -36,7 +37,7 @@ func RunHTTPServer(ctx context.Context, cfg config.ConfYaml, s ...*http.Server)
logx.LogAccess.Info("HTTPD server is running on " + cfg.Core.Port + " port.")
if cfg.Core.AutoTLS.Enabled {
return startServer(ctx, autoTLSServer(cfg), cfg)
return startServer(ctx, autoTLSServer(cfg, q), cfg)
} else if cfg.Core.SSL {
config := &tls.Config{
MinVersion: tls.VersionTLS10,

View File

@@ -15,6 +15,7 @@ import (
"github.com/appleboy/gorush/core"
"github.com/appleboy/gorush/gorush"
"github.com/appleboy/gorush/logx"
"github.com/appleboy/gorush/queue"
"github.com/appleboy/gorush/status"
"github.com/appleboy/gofight/v2"
@@ -23,7 +24,10 @@ import (
"github.com/stretchr/testify/assert"
)
var goVersion = runtime.Version()
var (
goVersion = runtime.Version()
q *queue.Queue
)
func TestMain(m *testing.M) {
cfg := initTest()
@@ -40,11 +44,14 @@ func TestMain(m *testing.M) {
log.Fatal(err)
}
q = queue.NewQueue(cfg)
q.Start()
defer q.Stop()
m.Run()
}
func initTest() config.ConfYaml {
cfg, _ := config.LoadConf("")
cfg, _ := config.LoadConf()
cfg.Core.Mode = "test"
return cfg
}
@@ -88,7 +95,7 @@ func TestRunNormalServer(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
go func() {
assert.NoError(t, RunHTTPServer(ctx, cfg))
assert.NoError(t, RunHTTPServer(ctx, cfg, q))
}()
defer func() {
@@ -112,7 +119,7 @@ func TestRunTLSServer(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
go func() {
assert.NoError(t, RunHTTPServer(ctx, cfg))
assert.NoError(t, RunHTTPServer(ctx, cfg, q))
}()
defer func() {
@@ -140,7 +147,7 @@ func TestRunTLSBase64Server(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
go func() {
assert.NoError(t, RunHTTPServer(ctx, cfg))
assert.NoError(t, RunHTTPServer(ctx, cfg, q))
}()
defer func() {
@@ -159,7 +166,7 @@ func TestRunAutoTLSServer(t *testing.T) {
cfg.Core.AutoTLS.Enabled = true
ctx, cancel := context.WithCancel(context.Background())
go func() {
assert.NoError(t, RunHTTPServer(ctx, cfg))
assert.NoError(t, RunHTTPServer(ctx, cfg, q))
}()
defer func() {
@@ -179,7 +186,7 @@ func TestLoadTLSCertError(t *testing.T) {
cfg.Core.CertPath = "../config/config.yml"
cfg.Core.KeyPath = "../config/config.yml"
assert.Error(t, RunHTTPServer(context.Background(), cfg))
assert.Error(t, RunHTTPServer(context.Background(), cfg, q))
}
func TestMissingTLSCertcfgg(t *testing.T) {
@@ -192,8 +199,8 @@ func TestMissingTLSCertcfgg(t *testing.T) {
cfg.Core.CertBase64 = ""
cfg.Core.KeyBase64 = ""
err := RunHTTPServer(context.Background(), cfg)
assert.Error(t, RunHTTPServer(context.Background(), cfg))
err := RunHTTPServer(context.Background(), cfg, q)
assert.Error(t, RunHTTPServer(context.Background(), cfg, q))
assert.Equal(t, "missing https cert config", err.Error())
}
@@ -206,7 +213,7 @@ func TestRootHandler(t *testing.T) {
cfg.Log.Format = "json"
r.GET("/").
Run(routerEngine(cfg), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
data := r.Body.Bytes()
value, _ := jsonparser.GetString(data, "text")
@@ -223,7 +230,7 @@ func TestAPIStatusGoHandler(t *testing.T) {
r := gofight.New()
r.GET("/api/stat/go").
Run(routerEngine(cfg), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
data := r.Body.Bytes()
value, _ := jsonparser.GetString(data, "go_version")
@@ -242,7 +249,7 @@ func TestAPIStatusAppHandler(t *testing.T) {
SetVersion(appVersion)
r.GET("/api/stat/app").
Run(routerEngine(cfg), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
data := r.Body.Bytes()
value, _ := jsonparser.GetString(data, "version")
@@ -258,7 +265,7 @@ func TestAPIConfigHandler(t *testing.T) {
r := gofight.New()
r.GET("/api/config").
Run(routerEngine(cfg), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusCreated, r.Code)
})
}
@@ -270,7 +277,7 @@ func TestMissingNotificationsParameter(t *testing.T) {
// missing notifications parameter.
r.POST("/api/push").
Run(routerEngine(cfg), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusBadRequest, r.Code)
assert.Equal(t, "application/json; charset=utf-8", r.HeaderMap.Get("Content-Type"))
})
@@ -286,7 +293,7 @@ func TestEmptyNotifications(t *testing.T) {
SetJSON(gofight.D{
"notifications": []gorush.PushNotification{},
}).
Run(routerEngine(cfg), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusBadRequest, r.Code)
})
}
@@ -314,8 +321,8 @@ func TestMutableContent(t *testing.T) {
},
},
}).
Run(routerEngine(cfg), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
// json: cannot unmarshal number into Go struct field PushNotification.mutable_content of type bool
Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
// json: cannot unmarshal number into Go struct field gorush.PushNotification.mutable_content of type bool
assert.Equal(t, http.StatusBadRequest, r.Code)
})
}
@@ -343,7 +350,7 @@ func TestOutOfRangeMaxNotifications(t *testing.T) {
},
},
}).
Run(routerEngine(cfg), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusBadRequest, r.Code)
})
}
@@ -369,7 +376,7 @@ func TestSuccessPushHandler(t *testing.T) {
},
},
}).
Run(routerEngine(cfg), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusOK, r.Code)
})
}
@@ -380,7 +387,7 @@ func TestSysStatsHandler(t *testing.T) {
r := gofight.New()
r.GET("/sys/stats").
Run(routerEngine(cfg), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusOK, r.Code)
})
}
@@ -391,7 +398,7 @@ func TestMetricsHandler(t *testing.T) {
r := gofight.New()
r.GET("/metrics").
Run(routerEngine(cfg), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusOK, r.Code)
})
}
@@ -402,7 +409,7 @@ func TestGETHeartbeatHandler(t *testing.T) {
r := gofight.New()
r.GET("/healthz").
Run(routerEngine(cfg), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusOK, r.Code)
})
}
@@ -413,7 +420,7 @@ func TestHEADHeartbeatHandler(t *testing.T) {
r := gofight.New()
r.HEAD("/healthz").
Run(routerEngine(cfg), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusOK, r.Code)
})
}
@@ -425,7 +432,7 @@ func TestVersionHandler(t *testing.T) {
r := gofight.New()
r.GET("/version").
Run(routerEngine(cfg), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
Run(routerEngine(cfg, q), func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusOK, r.Code)
data := r.Body.Bytes()
@@ -438,8 +445,231 @@ func TestVersionHandler(t *testing.T) {
func TestDisabledHTTPServer(t *testing.T) {
cfg := initTest()
cfg.Core.Enabled = false
err := RunHTTPServer(context.Background(), cfg)
err := RunHTTPServer(context.Background(), cfg, q)
cfg.Core.Enabled = true
assert.Nil(t, err)
}
func TestSenMultipleNotifications(t *testing.T) {
ctx := context.Background()
cfg := initTest()
cfg.Ios.Enabled = true
cfg.Ios.KeyPath = "../certificate/certificate-valid.pem"
err := gorush.InitAPNSClient(cfg)
assert.Nil(t, err)
cfg.Android.Enabled = true
cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
q.Config(cfg)
androidToken := os.Getenv("ANDROID_TEST_TOKEN")
req := gorush.RequestPush{
Notifications: []gorush.PushNotification{
// ios
{
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
Platform: core.PlatFormIos,
Message: "Welcome",
},
// android
{
Tokens: []string{androidToken, "bbbbb"},
Platform: core.PlatFormAndroid,
Message: "Welcome",
},
},
}
count, logs := handleNotification(ctx, cfg, req, q)
assert.Equal(t, 3, count)
assert.Equal(t, 0, len(logs))
}
func TestDisabledAndroidNotifications(t *testing.T) {
ctx := context.Background()
cfg := initTest()
cfg.Ios.Enabled = true
cfg.Ios.KeyPath = "../certificate/certificate-valid.pem"
err := gorush.InitAPNSClient(cfg)
assert.Nil(t, err)
cfg.Android.Enabled = false
cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
q.Config(cfg)
androidToken := os.Getenv("ANDROID_TEST_TOKEN")
req := gorush.RequestPush{
Notifications: []gorush.PushNotification{
// ios
{
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
Platform: core.PlatFormIos,
Message: "Welcome",
},
// android
{
Tokens: []string{androidToken, "bbbbb"},
Platform: core.PlatFormAndroid,
Message: "Welcome",
},
},
}
count, logs := handleNotification(ctx, cfg, req, q)
assert.Equal(t, 1, count)
assert.Equal(t, 0, len(logs))
}
func TestSyncModeForNotifications(t *testing.T) {
ctx := context.Background()
cfg := initTest()
cfg.Ios.Enabled = true
cfg.Ios.KeyPath = "../certificate/certificate-valid.pem"
err := gorush.InitAPNSClient(cfg)
assert.Nil(t, err)
cfg.Android.Enabled = true
cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
// enable sync mode
cfg.Core.Sync = true
q.Config(cfg)
androidToken := os.Getenv("ANDROID_TEST_TOKEN")
req := gorush.RequestPush{
Notifications: []gorush.PushNotification{
// ios
{
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
Platform: core.PlatFormIos,
Message: "Welcome",
},
// android
{
Tokens: []string{androidToken, "bbbbb"},
Platform: core.PlatFormAndroid,
Message: "Welcome",
},
},
}
count, logs := handleNotification(ctx, cfg, req, q)
assert.Equal(t, 3, count)
assert.Equal(t, 2, len(logs))
}
func TestSyncModeForTopicNotification(t *testing.T) {
ctx := context.Background()
cfg := initTest()
cfg.Android.Enabled = true
cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
cfg.Log.HideToken = false
// enable sync mode
cfg.Core.Sync = true
q.Config(cfg)
req := gorush.RequestPush{
Notifications: []gorush.PushNotification{
// android
{
// error:InvalidParameters
// Check that the provided parameters have the right name and type.
To: "/topics/foo-bar@@@##",
Platform: core.PlatFormAndroid,
Message: "This is a Firebase Cloud Messaging Topic Message!",
},
// android
{
// success
To: "/topics/foo-bar",
Platform: core.PlatFormAndroid,
Message: "This is a Firebase Cloud Messaging Topic Message!",
},
// android
{
// success
Condition: "'dogs' in topics || 'cats' in topics",
Platform: core.PlatFormAndroid,
Message: "This is a Firebase Cloud Messaging Topic Message!",
},
},
}
count, logs := handleNotification(ctx, cfg, req, q)
assert.Equal(t, 2, count)
assert.Equal(t, 1, len(logs))
}
func TestSyncModeForDeviceGroupNotification(t *testing.T) {
ctx := context.Background()
cfg := initTest()
cfg.Android.Enabled = true
cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
cfg.Log.HideToken = false
// enable sync mode
cfg.Core.Sync = true
q.Config(cfg)
req := gorush.RequestPush{
Notifications: []gorush.PushNotification{
// android
{
To: "aUniqueKey",
Platform: core.PlatFormAndroid,
Message: "This is a Firebase Cloud Messaging Device Group Message!",
},
},
}
count, logs := handleNotification(ctx, cfg, req, q)
assert.Equal(t, 1, count)
assert.Equal(t, 1, len(logs))
}
func TestDisabledIosNotifications(t *testing.T) {
ctx := context.Background()
cfg := initTest()
cfg.Ios.Enabled = false
cfg.Ios.KeyPath = "../certificate/certificate-valid.pem"
err := gorush.InitAPNSClient(cfg)
assert.Nil(t, err)
cfg.Android.Enabled = true
cfg.Android.APIKey = os.Getenv("ANDROID_API_KEY")
q.Config(cfg)
androidToken := os.Getenv("ANDROID_TEST_TOKEN")
req := gorush.RequestPush{
Notifications: []gorush.PushNotification{
// ios
{
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"},
Platform: core.PlatFormIos,
Message: "Welcome",
},
// android
{
Tokens: []string{androidToken, androidToken + "_"},
Platform: core.PlatFormAndroid,
Message: "Welcome",
},
},
}
count, logs := handleNotification(ctx, cfg, req, q)
assert.Equal(t, 2, count)
assert.Equal(t, 0, len(logs))
}