Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions integration/messaging/messaging_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ func TestSendInvalidToken(t *testing.T) {
}
}

func TestSendInvalidFid(t *testing.T) {
msg := &messaging.Message{Fid: "INVALID_FID"}
if _, err := client.Send(context.Background(), msg); err == nil || !messaging.IsUnregistered(err) {
t.Errorf("Send() = %v; want UnregisteredError", err)
}
}

func TestSendEach(t *testing.T) {
messages := []*messaging.Message{
{
Expand Down Expand Up @@ -229,6 +236,44 @@ func TestSendEachForMulticast(t *testing.T) {
}
}

func TestSendEachForMulticastFids(t *testing.T) {
message := &messaging.MulticastMessage{
Notification: &messaging.Notification{
Title: "title",
Body: "body",
},
Fids: []string{"INVALID_FID", "ANOTHER_INVALID_FID"},
}

br, err := client.SendEachForMulticastDryRun(context.Background(), message)
if err != nil {
t.Fatal(err)
}

if len(br.Responses) != 2 {
t.Errorf("len(Responses) = %d; want = 2", len(br.Responses))
}
if br.SuccessCount != 0 {
t.Errorf("SuccessCount = %d; want = 0", br.SuccessCount)
}
if br.FailureCount != 2 {
t.Errorf("FailureCount = %d; want = 2", br.FailureCount)
}

for i := 0; i < 2; i++ {
sr := br.Responses[i]
if sr.Success {
t.Errorf("Responses[%d]: Success = true; want = false", i)
}
if sr.MessageID != "" {
t.Errorf("Responses[%d]: MessageID = %q; want = %q", i, sr.MessageID, "")
}
if sr.Error == nil || !messaging.IsUnregistered(sr.Error) {
t.Errorf("Responses[%d]: Error = %v; want = UnregisteredError", i, sr.Error)
}
}
}

func TestSendAll(t *testing.T) {
t.Skip("Skipping integration tests for deprecated sendAll() API")
messages := []*messaging.Message{
Expand Down
16 changes: 9 additions & 7 deletions messaging/messaging.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ var (
// Message to be sent via Firebase Cloud Messaging.
//
// Message contains payload data, recipient information and platform-specific configuration
// options. A Message must specify exactly one of Token, Topic or Condition fields. Apart from
// options. A Message must specify exactly one of Fid, Token, Topic or Condition fields. Apart from
// that a Message may specify any combination of Data, Notification, Android, Webpush and APNS
// fields. See https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages for more
// details on how the backend FCM servers handle different message parameters.
Expand All @@ -69,9 +69,11 @@ type Message struct {
Webpush *WebpushConfig `json:"webpush,omitempty"`
APNS *APNSConfig `json:"apns,omitempty"`
FCMOptions *FCMOptions `json:"fcm_options,omitempty"`
Token string `json:"token,omitempty"`
Topic string `json:"-"`
Condition string `json:"condition,omitempty"`
// Deprecated: Use Fid instead.
Token string `json:"token,omitempty"`
Topic string `json:"-"`
Condition string `json:"condition,omitempty"`
Fid string `json:"fid,omitempty"`
}

// MarshalJSON marshals a Message into JSON (for internal use only).
Expand Down Expand Up @@ -958,7 +960,7 @@ func newFCMClient(hc *http.Client, conf *internal.MessagingConfig, messagingEndp

// Send sends a Message to Firebase Cloud Messaging.
//
// The Message must specify exactly one of Token, Topic and Condition fields. FCM will
// The Message must specify exactly one of Fid, Token, Topic or Condition fields. FCM will
// customize the message for each target platform based on the arguments specified in the
// Message.
func (c *fcmClient) Send(ctx context.Context, message *Message) (string, error) {
Expand Down Expand Up @@ -1054,8 +1056,8 @@ func IsRegistrationTokenNotRegistered(err error) bool {
return IsUnregistered(err)
}

// IsUnregistered checks if the given error was due to a registration token that
// became invalid.
// IsUnregistered checks if the given error was due to a registration token or
// installation ID (FID) that was unregistered or became invalid.
func IsUnregistered(err error) bool {
return hasMessagingErrorCode(err, unregistered)
}
Expand Down
83 changes: 53 additions & 30 deletions messaging/messaging_batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,31 @@ const multipartBoundary = "__END_OF_PART__"
// MulticastMessage represents a message that can be sent to multiple devices via Firebase Cloud
// Messaging (FCM).
//
// It contains payload information as well as the list of device registration tokens to which the
// message should be sent. A single MulticastMessage may contain up to 500 registration tokens.
// It contains payload information as well as the list of device registration tokens and/or
// Firebase Installation IDs (FIDs) to which the message should be sent. A single
// MulticastMessage may contain up to 500 registration tokens and FIDs combined.
type MulticastMessage struct {
// Deprecated: Use Fids instead.
Tokens []string
Data map[string]string
Notification *Notification
Android *AndroidConfig
Webpush *WebpushConfig
APNS *APNSConfig
FCMOptions *FCMOptions
Fids []string
}

func (mm *MulticastMessage) toMessages() ([]*Message, error) {
if len(mm.Tokens) == 0 {
return nil, errors.New("tokens must not be nil or empty")
if len(mm.Tokens) == 0 && len(mm.Fids) == 0 {
return nil, errors.New("either tokens or fids must be specified")
}
if len(mm.Tokens) > maxMessages {
return nil, fmt.Errorf("tokens must not contain more than %d elements", maxMessages)
total := len(mm.Tokens) + len(mm.Fids)
if total > maxMessages {
return nil, fmt.Errorf("total tokens and fids must not exceed %d elements", maxMessages)
}

var messages []*Message
messages := make([]*Message, 0, total)
for _, token := range mm.Tokens {
temp := &Message{
Token: token,
Expand All @@ -70,6 +74,18 @@ func (mm *MulticastMessage) toMessages() ([]*Message, error) {
}
messages = append(messages, temp)
}
for _, fid := range mm.Fids {
temp := &Message{
Fid: fid,
Data: mm.Data,
Notification: mm.Notification,
Android: mm.Android,
Webpush: mm.Webpush,
APNS: mm.APNS,
FCMOptions: mm.FCMOptions,
}
messages = append(messages, temp)
}

return messages, nil
}
Expand Down Expand Up @@ -117,12 +133,14 @@ func (c *fcmClient) SendEachDryRun(ctx context.Context, messages []*Message) (*B
return c.sendEachInBatch(ctx, messages, true)
}

// SendEachForMulticast sends the given multicast message to all the FCM registration tokens specified.
// SendEachForMulticast sends the given multicast message to all the specified FCM registration
// tokens and/or Firebase Installation IDs (FIDs).
//
// The tokens array in MulticastMessage may contain up to 500 tokens. SendMulticast uses the
// SendEach() function to send the given message to all the target recipients. The
// responses list obtained from the return value corresponds to the order of the input tokens. An error
// from SendEachForMulticast or a BatchResponse with all failures indicates a total failure, meaning
// The tokens and FIDs in MulticastMessage may contain up to 500 elements in total.
// SendEachForMulticast uses the SendEach() function to send the given message. The responses list
// obtained from the return value corresponds to the order of the input targets. If both tokens
// and FIDs are provided, tokens are processed first, followed by FIDs. An error from
// SendEachForMulticast or a BatchResponse with all failures indicates a total failure, meaning
// that none of the messages in the list could be sent. Partial failures or no failures are only
// indicated by a BatchResponse return value.
func (c *fcmClient) SendEachForMulticast(ctx context.Context, message *MulticastMessage) (*BatchResponse, error) {
Expand All @@ -135,16 +153,17 @@ func (c *fcmClient) SendEachForMulticast(ctx context.Context, message *Multicast
}

// SendEachForMulticastDryRun sends the given multicast message to all the specified FCM registration
// tokens in the dry run (validation only) mode.
// tokens and/or Firebase Installation IDs (FIDs) in the dry run (validation only) mode.
//
// This function does not actually deliver any messages to target devices. Instead, it performs all
// the SDK-level and backend validations on the messages, and emulates the send operation.
//
// The tokens array in MulticastMessage may contain up to 500 tokens. SendEachForMulticastDryRunn uses the
// SendEachDryRun() function to send the given message. The responses list obtained from
// the return value corresponds to the order of the input tokens. An error from SendEachForMulticastDryRun
// or a BatchResponse with all failures indicates a total failure, meaning that of the messages in the
// list could be sent. Partial failures or no failures are only
// The tokens and FIDs in MulticastMessage may contain up to 500 elements in total.
// SendEachForMulticastDryRun uses the SendEachDryRun() function to send the given message.
// The responses list obtained from the return value corresponds to the order of the input targets.
// If both tokens and FIDs are provided, tokens are processed first, followed by FIDs. An error from
// SendEachForMulticastDryRun or a BatchResponse with all failures indicates a total failure, meaning
// that none of the messages in the list could be sent. Partial failures or no failures are only
// indicated by a BatchResponse return value.
func (c *fcmClient) SendEachForMulticastDryRun(ctx context.Context, message *MulticastMessage) (*BatchResponse, error) {
messages, err := toMessages(message)
Expand Down Expand Up @@ -275,13 +294,16 @@ func (c *fcmClient) SendAllDryRun(ctx context.Context, messages []*Message) (*Ba
return c.sendBatch(ctx, messages, true)
}

// SendMulticast sends the given multicast message to all the FCM registration tokens specified.
// SendMulticast sends the given multicast message to all the specified FCM registration
// tokens and/or Firebase Installation IDs (FIDs).
//
// The tokens array in MulticastMessage may contain up to 500 tokens. SendMulticast uses the
// SendAll() function to send the given message to all the target recipients. The
// responses list obtained from the return value corresponds to the order of the input tokens. An
// error from SendMulticast indicates a total failure, meaning that the message could not be sent
// to any of the recipients. Partial failures are indicated by a BatchResponse return value.
// The tokens and FIDs in MulticastMessage may contain up to 500 elements in total.
// SendMulticast uses the SendAll() function to send the given message to all the target
// recipients. The responses list obtained from the return value corresponds to the order of
// the input targets. If both tokens and FIDs are provided, tokens are processed first,
// followed by FIDs. An error from SendMulticast indicates a total failure, meaning that the
// message could not be sent to any of the recipients. Partial failures are indicated by a
// BatchResponse return value.
//
// Deprecated: Use SendEachForMulticast instead.
func (c *fcmClient) SendMulticast(ctx context.Context, message *MulticastMessage) (*BatchResponse, error) {
Expand All @@ -294,16 +316,17 @@ func (c *fcmClient) SendMulticast(ctx context.Context, message *MulticastMessage
}

// SendMulticastDryRun sends the given multicast message to all the specified FCM registration
// tokens in the dry run (validation only) mode.
// tokens and/or Firebase Installation IDs (FIDs) in the dry run (validation only) mode.
//
// This function does not actually deliver any messages to target devices. Instead, it performs all
// the SDK-level and backend validations on the messages, and emulates the send operation.
//
// The tokens array in MulticastMessage may contain up to 500 tokens. SendMulticastDryRun uses the
// SendAllDryRun() function to send the given message. The responses list obtained from
// the return value corresponds to the order of the input tokens. An error from SendMulticastDryRun
// indicates a total failure, meaning that none of the messages were sent to FCM for validation.
// Partial failures are indicated by a BatchResponse return value.
// The tokens and FIDs in MulticastMessage may contain up to 500 elements in total.
// SendMulticastDryRun uses the SendAllDryRun() function to send the given message.
// The responses list obtained from the return value corresponds to the order of the input targets.
// If both tokens and FIDs are provided, tokens are processed first, followed by FIDs. An error
// from SendMulticastDryRun indicates a total failure, meaning that none of the messages
// were sent to FCM for validation. Partial failures are indicated by a BatchResponse return value.
//
// Deprecated: Use SendEachForMulticastDryRun instead.
func (c *fcmClient) SendMulticastDryRun(ctx context.Context, message *MulticastMessage) (*BatchResponse, error) {
Expand Down
Loading
Loading