* H-300: wire Captain Skills into Web runtime * H-300: enforce effective model and conservative skill budget * H-300: fix CI gosec step * ci: extend golangci-lint timeout * fix lint findings across backend * fix(push): resolve delivery protocol blockers * test(repository): close SQLite test databases * test(repository): reuse SQLite schema per package * H-307: restore backend Go cache in CI * H-307: prefetch modules before cold lint * H-307: resolve govulncheck security gate * H-307: build lint with patched Go toolchain * H-307: clear remaining security scan findings --------- Co-authored-by: Rogee <rogee@ipao.vip>
2324 lines
81 KiB
Go
2324 lines
81 KiB
Go
package facebook
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/gochat/gochat/internal/channel"
|
|
"github.com/gochat/gochat/internal/model"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func init() {
|
|
// Ensure gin test mode (some sub-packages use gin)
|
|
}
|
|
|
|
// ===========================
|
|
// FacebookProvider — identity & metadata (Cov7)
|
|
// ===========================
|
|
|
|
func TestFBProvider_New_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
require.NotNil(t, p)
|
|
assert.NotNil(t, p.client)
|
|
assert.NotEmpty(t, p.graphAPIBase)
|
|
assert.NotEmpty(t, p.storagePath)
|
|
}
|
|
|
|
func TestFBProvider_Type_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
assert.Equal(t, channel.ChannelFacebook, p.Type())
|
|
}
|
|
|
|
func TestFBProvider_Name_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
assert.Equal(t, "Facebook Messenger", p.Name())
|
|
}
|
|
|
|
func TestFBProvider_Description_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
assert.NotEmpty(t, p.Description())
|
|
}
|
|
|
|
func TestFBProvider_ConfigSchema_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
schema := p.ConfigSchema()
|
|
require.NotNil(t, schema)
|
|
assert.Equal(t, "object", schema.Type)
|
|
assert.Contains(t, schema.Required, "page_id")
|
|
assert.Contains(t, schema.Required, "page_access_token")
|
|
}
|
|
|
|
func TestFBProvider_DefaultConfig_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
cfg := p.DefaultConfig()
|
|
assert.Contains(t, cfg, "page_id")
|
|
assert.Contains(t, cfg, "page_access_token")
|
|
}
|
|
|
|
func TestFBProvider_Capabilities_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
caps := p.Capabilities()
|
|
assert.True(t, caps.SupportsAttachments)
|
|
assert.True(t, caps.SupportsLocation)
|
|
assert.True(t, caps.SupportsTypingIndicator)
|
|
assert.True(t, caps.SupportsDeliveryStatus)
|
|
assert.True(t, caps.SupportsTemplates)
|
|
assert.Equal(t, 2000, caps.MaxTextLength)
|
|
}
|
|
|
|
func TestFBProvider_OAuthConfig_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
oauth := p.OAuthConfig()
|
|
require.NotNil(t, oauth)
|
|
assert.Equal(t, "facebook", oauth.Provider)
|
|
assert.Contains(t, oauth.Scopes, "pages_messaging")
|
|
assert.True(t, oauth.RequiresRefresh)
|
|
}
|
|
|
|
// ===========================
|
|
// FacebookProvider — ValidateConfig (Cov7)
|
|
// ===========================
|
|
|
|
func TestFBProvider_ValidateConfig_NoPageID_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "page_id")
|
|
}
|
|
|
|
func TestFBProvider_ValidateConfig_NoToken_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
|
|
"page_id": "12345",
|
|
})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "page_access_token")
|
|
}
|
|
|
|
func TestFBProvider_ValidateConfig_APIError_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
|
|
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
|
|
"page_id": "12345",
|
|
"page_access_token": "test_token",
|
|
})
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestFBProvider_ValidateConfig_Success_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBPageInfo{ID: "12345", Name: "Test Page"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
|
|
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
|
|
"page_id": "12345",
|
|
"page_access_token": "test_token",
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFBProvider_ValidateConfig_PageIDMismatch_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBPageInfo{ID: "99999", Name: "Other Page"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
|
|
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
|
|
"page_id": "12345",
|
|
"page_access_token": "test_token",
|
|
})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "mismatch")
|
|
}
|
|
|
|
// ===========================
|
|
// FacebookProvider — OnCreate / OnDestroy (Cov7)
|
|
// ===========================
|
|
|
|
func TestFBProvider_OnCreate_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBPageInfo{ID: "12345", Name: "Test Page"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
config := channel.ChannelConfig{
|
|
"page_id": "12345",
|
|
"page_access_token": "test_token",
|
|
}
|
|
|
|
result, err := p.OnCreate(context.Background(), inbox, config)
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
assert.Equal(t, "Test Page", result["page_name"])
|
|
}
|
|
|
|
func TestFBProvider_OnCreate_NoAppID_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBPageInfo{ID: "12345", Name: "Test Page"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
p.appID = ""
|
|
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
config := channel.ChannelConfig{
|
|
"page_id": "12345",
|
|
"page_access_token": "test_token",
|
|
}
|
|
|
|
result, err := p.OnCreate(context.Background(), inbox, config)
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
}
|
|
|
|
func TestFBProvider_OnDestroy_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}}
|
|
config := channel.ChannelConfig{
|
|
"page_id": "12345",
|
|
"page_access_token": "test_token",
|
|
"app_id": "test_app",
|
|
}
|
|
err := p.OnDestroy(context.Background(), inbox, config)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFBProvider_OnDestroy_NoAppID_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}}
|
|
config := channel.ChannelConfig{
|
|
"page_id": "12345",
|
|
"page_access_token": "test_token",
|
|
}
|
|
err := p.OnDestroy(context.Background(), inbox, config)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// ===========================
|
|
// FacebookProvider — ProcessIncoming (Cov7)
|
|
// ===========================
|
|
|
|
func TestFBProvider_ProcessIncoming_InvalidJSON_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
_, err := p.ProcessIncoming(context.Background(), inbox, []byte("invalid json"))
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestFBProvider_ProcessIncoming_NotPageObject_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"instagram","entry":[]}`
|
|
_, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "not a page event")
|
|
}
|
|
|
|
func TestFBProvider_ProcessIncoming_NoContent_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"page","entry":[{"id":"123","time":1234567890,"messaging":[]}]}`
|
|
_, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "no processable")
|
|
}
|
|
|
|
func TestFBProvider_ProcessIncoming_EchoMessage_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"page","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","text":"hello","is_echo":true}}]}]}`
|
|
_, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "no processable")
|
|
}
|
|
|
|
func TestFBProvider_ProcessIncoming_TextMessage_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"page","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","text":"hello world"}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "hello world", msg.Content)
|
|
assert.Equal(t, "m1", msg.SourceID)
|
|
}
|
|
|
|
func TestFBProvider_ProcessIncoming_Postback_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"page","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"postback":{"title":"Get Started","payload":"START"}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "START", msg.Content)
|
|
assert.Contains(t, msg.Extra, "postback_title")
|
|
}
|
|
|
|
func TestFBProvider_ProcessIncoming_Optin_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"page","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"optin":{"ref":"m_me_ref"}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "m_me_ref", msg.Content)
|
|
assert.Contains(t, msg.Extra, "optin_ref")
|
|
}
|
|
|
|
func TestFBProvider_ProcessIncoming_ImageAttachment_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"page","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","attachments":[{"type":"image","payload":{"url":"https://example.com/img.jpg"}}]}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "https://example.com/img.jpg", msg.Content)
|
|
assert.Len(t, msg.Attachments, 1)
|
|
}
|
|
|
|
func TestFBProvider_ProcessIncoming_VideoAttachment_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"page","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","attachments":[{"type":"video","payload":{"url":"https://example.com/vid.mp4"}}]}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Contains(t, msg.Content, "vid.mp4")
|
|
}
|
|
|
|
func TestFBProvider_ProcessIncoming_AudioAttachment_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"page","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","attachments":[{"type":"audio","payload":{"url":"https://example.com/audio.mp3"}}]}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Contains(t, msg.Content, "audio.mp3")
|
|
}
|
|
|
|
func TestFBProvider_ProcessIncoming_FileAttachment_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"page","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","attachments":[{"type":"file","payload":{"url":"https://example.com/doc.pdf"}}]}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Contains(t, msg.Content, "doc.pdf")
|
|
}
|
|
|
|
func TestFBProvider_ProcessIncoming_LocationAttachment_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"page","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","attachments":[{"type":"location","payload":{"url":"https://maps.example.com"}}]}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Contains(t, msg.Content, "maps.example.com")
|
|
}
|
|
|
|
func TestFBProvider_ProcessIncoming_FallbackAttachment_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"page","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","attachments":[{"type":"fallback","payload":{"name":"fallback_name"}}]}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "fallback_name", msg.Content)
|
|
}
|
|
|
|
func TestFBProvider_ProcessIncoming_UnknownAttachment_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"page","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","attachments":[{"type":"unknown_type","payload":{"url":"https://example.com/unknown"}}]}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Contains(t, msg.Content, "unknown")
|
|
}
|
|
|
|
func TestFBProvider_ProcessIncoming_TextAndAttachment_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"page","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","text":"check this out","attachments":[{"type":"image","payload":{"url":"https://example.com/img.jpg"}}]}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Contains(t, msg.Extra, "text")
|
|
}
|
|
|
|
// ===========================
|
|
// FacebookProvider — ValidateWebhookRequest (Cov7)
|
|
// ===========================
|
|
|
|
func TestFBProvider_ValidateWebhookRequest_GET_Valid_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"webhook_verify_token":"my_token"}`}
|
|
req := &channel.WebhookRequest{
|
|
Method: "GET",
|
|
QueryParams: map[string]string{"hub.mode": "subscribe", "hub.verify_token": "my_token"},
|
|
}
|
|
err := p.ValidateWebhookRequest(context.Background(), inbox, req)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFBProvider_ValidateWebhookRequest_GET_InvalidMode_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{}`}
|
|
req := &channel.WebhookRequest{
|
|
Method: "GET",
|
|
QueryParams: map[string]string{"hub.mode": "invalid", "hub.verify_token": "tok"},
|
|
}
|
|
err := p.ValidateWebhookRequest(context.Background(), inbox, req)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "hub.mode")
|
|
}
|
|
|
|
func TestFBProvider_ValidateWebhookRequest_GET_TokenMismatch_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"webhook_verify_token":"correct_token"}`}
|
|
req := &channel.WebhookRequest{
|
|
Method: "GET",
|
|
QueryParams: map[string]string{"hub.mode": "subscribe", "hub.verify_token": "wrong_token"},
|
|
}
|
|
err := p.ValidateWebhookRequest(context.Background(), inbox, req)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "mismatch")
|
|
}
|
|
|
|
func TestFBProvider_ValidateWebhookRequest_POST_NoSignature_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{}`}
|
|
req := &channel.WebhookRequest{
|
|
Method: "POST",
|
|
Headers: map[string]string{},
|
|
Body: []byte(`{}`),
|
|
}
|
|
err := p.ValidateWebhookRequest(context.Background(), inbox, req)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "X-Hub-Signature-256")
|
|
}
|
|
|
|
func TestFBProvider_ValidateWebhookRequest_POST_NoAppSecret_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
p.appSecret = ""
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{}`}
|
|
req := &channel.WebhookRequest{
|
|
Method: "POST",
|
|
Headers: map[string]string{"X-Hub-Signature-256": "sha256=abc"},
|
|
Body: []byte(`{}`),
|
|
}
|
|
err := p.ValidateWebhookRequest(context.Background(), inbox, req)
|
|
require.NoError(t, err) // skips verification when app secret not set
|
|
}
|
|
|
|
func TestFBProvider_ValidateWebhookRequest_POST_BadSignature_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
p.appSecret = "my_secret"
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{}`}
|
|
req := &channel.WebhookRequest{
|
|
Method: "POST",
|
|
Headers: map[string]string{"X-Hub-Signature-256": "sha256=bad_signature"},
|
|
Body: []byte(`{"test":true}`),
|
|
}
|
|
err := p.ValidateWebhookRequest(context.Background(), inbox, req)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "signature")
|
|
}
|
|
|
|
// ===========================
|
|
// FacebookProvider — SendMessage (Cov7)
|
|
// ===========================
|
|
|
|
func TestFBProvider_SendMessage_NoPSID_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}}
|
|
msg := &model.Message{Base: model.Base{ID: 1}, Content: "hello", ContentType: "text"}
|
|
contact := &model.Contact{Base: model.Base{ID: 1}, Identifier: ""}
|
|
_, err := p.SendMessage(context.Background(), inbox, msg, contact)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "PSID")
|
|
}
|
|
|
|
func TestFBProvider_SendMessage_NoToken_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{}`}
|
|
msg := &model.Message{Base: model.Base{ID: 1}, Content: "hello", ContentType: "text"}
|
|
contact := &model.Contact{Base: model.Base{ID: 1}, Identifier: "12345"}
|
|
_, err := p.SendMessage(context.Background(), inbox, msg, contact)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "access token")
|
|
}
|
|
|
|
func TestFBProvider_SendMessage_TextSuccess_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBSendAPIResponse{RecipientID: "12345", MessageID: "mid:123"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"page_access_token":"tok"}`}
|
|
msg := &model.Message{Base: model.Base{ID: 1}, Content: "hello", ContentType: "text"}
|
|
contact := &model.Contact{Base: model.Base{ID: 1}, Identifier: "12345"}
|
|
result, err := p.SendMessage(context.Background(), inbox, msg, contact)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "mid:123", result.ExternalID)
|
|
}
|
|
|
|
func TestFBProvider_SendMessage_AttachmentSuccess_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBSendAPIResponse{RecipientID: "12345", MessageID: "mid:456"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"page_access_token":"tok"}`}
|
|
msg := &model.Message{Base: model.Base{ID: 1}, Content: "https://example.com/img.jpg", ContentType: "image"}
|
|
contact := &model.Contact{Base: model.Base{ID: 1}, Identifier: "12345"}
|
|
result, err := p.SendMessage(context.Background(), inbox, msg, contact)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "mid:456", result.ExternalID)
|
|
}
|
|
|
|
func TestFBProvider_SendMessage_APIError_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"page_access_token":"tok"}`}
|
|
msg := &model.Message{Base: model.Base{ID: 1}, Content: "hello", ContentType: "text"}
|
|
contact := &model.Contact{Base: model.Base{ID: 1}, Identifier: "12345"}
|
|
_, err := p.SendMessage(context.Background(), inbox, msg, contact)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// ===========================
|
|
// FacebookProvider — GetContactProfile (Cov7)
|
|
// ===========================
|
|
|
|
func TestFBProvider_GetContactProfile_NoToken_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{}`}
|
|
_, err := p.GetContactProfile(context.Background(), inbox, "user123")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "access token")
|
|
}
|
|
|
|
func TestFBProvider_GetContactProfile_Success_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBUserProfile{ID: "123", Name: "John Doe", FirstName: "John", LastName: "Doe"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"page_access_token":"tok"}`}
|
|
profile, err := p.GetContactProfile(context.Background(), inbox, "123")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "John Doe", profile.Name)
|
|
}
|
|
|
|
func TestFBProvider_GetContactProfile_APIError_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"page_access_token":"tok"}`}
|
|
_, err := p.GetContactProfile(context.Background(), inbox, "123")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// ===========================
|
|
// FacebookProvider — OAuth methods (Cov7)
|
|
// ===========================
|
|
|
|
func TestFBProvider_BuildAuthURL_NoAppID_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
p.appID = ""
|
|
_, err := p.BuildAuthURL(context.Background(), 1, "https://example.com/callback")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "App ID")
|
|
}
|
|
|
|
func TestFBProvider_BuildAuthURL_Success_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
p.appID = "test_app_id"
|
|
url, err := p.BuildAuthURL(context.Background(), 1, "https://example.com/callback")
|
|
require.NoError(t, err)
|
|
assert.Contains(t, url, "test_app_id")
|
|
}
|
|
|
|
func TestFBProvider_ExchangeToken_NoConfig_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewFacebookProvider()
|
|
p.appID = ""
|
|
p.appSecret = ""
|
|
_, err := p.ExchangeToken(context.Background(), "code", "https://example.com/callback")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "not configured")
|
|
}
|
|
|
|
func TestFBProvider_ExchangeToken_Success_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBLongLivedTokenResponse{AccessToken: "long_token", TokenType: "bearer", ExpiresIn: 5184000})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
p.appID = "test_app"
|
|
p.appSecret = "test_secret"
|
|
result, err := p.ExchangeToken(context.Background(), "code", "https://example.com/callback")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "long_token", result.AccessToken)
|
|
}
|
|
|
|
func TestFBProvider_ExchangeToken_APIError_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
p.appID = "test_app"
|
|
p.appSecret = "test_secret"
|
|
_, err := p.ExchangeToken(context.Background(), "code", "https://example.com/callback")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestFBProvider_ExchangeLongLivedUserToken_Empty_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
_, err := p.ExchangeLongLivedUserToken(context.Background(), "")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "required")
|
|
}
|
|
|
|
func TestFBProvider_ExchangeLongLivedUserToken_Success_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBLongLivedTokenResponse{AccessToken: "long_token"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
p.appID = "test_app"
|
|
p.appSecret = "test_secret"
|
|
token, err := p.ExchangeLongLivedUserToken(context.Background(), "short_token")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "long_token", token)
|
|
}
|
|
|
|
func TestFBProvider_ExchangeLongLivedUserToken_EmptyResult_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBLongLivedTokenResponse{AccessToken: ""})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
p.appID = "test_app"
|
|
p.appSecret = "test_secret"
|
|
_, err := p.ExchangeLongLivedUserToken(context.Background(), "short_token")
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "empty")
|
|
}
|
|
|
|
func TestFBProvider_ListFacebookPages_EmptyToken_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewFacebookProvider()
|
|
_, err := p.ListFacebookPages(context.Background(), "")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestFBProvider_ListFacebookPages_Success_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write([]byte(`{"data":[{"id":"1","name":"Page1"}],"paging":{}}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
pages, err := p.ListFacebookPages(context.Background(), "user_token")
|
|
require.NoError(t, err)
|
|
assert.Len(t, pages, 1)
|
|
}
|
|
|
|
func TestFBProvider_ListFacebookPages_APIError_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
_, err := p.ListFacebookPages(context.Background(), "user_token")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestFBProvider_FetchInstagramBusinessAccountID_EmptyToken_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewFacebookProvider()
|
|
id, err := p.FetchInstagramBusinessAccountID(context.Background(), "")
|
|
require.NoError(t, err) // returns empty without error
|
|
assert.Empty(t, id)
|
|
}
|
|
|
|
func TestFBProvider_FetchInstagramBusinessAccountID_Success_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write([]byte(`{"id":"1","instagram_business_account":{"id":"ig_123"}}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
id, err := p.FetchInstagramBusinessAccountID(context.Background(), "page_token")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "ig_123", id)
|
|
}
|
|
|
|
func TestFBProvider_FetchInstagramBusinessAccountID_NoIGAccount_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write([]byte(`{"id":"1"}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
id, err := p.FetchInstagramBusinessAccountID(context.Background(), "page_token")
|
|
require.NoError(t, err)
|
|
assert.Empty(t, id)
|
|
}
|
|
|
|
func TestFBProvider_RefreshToken_NoToken_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewFacebookProvider()
|
|
_, err := p.RefreshToken(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, channel.ChannelConfig{})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "no current")
|
|
}
|
|
|
|
func TestFBProvider_RefreshToken_Success_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBLongLivedTokenResponse{AccessToken: "new_token", ExpiresIn: 5184000})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
result, err := p.RefreshToken(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, channel.ChannelConfig{
|
|
"page_access_token": "old_token",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "new_token", result.AccessToken)
|
|
}
|
|
|
|
func TestFBProvider_RefreshToken_APIError_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
_, err := p.RefreshToken(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, channel.ChannelConfig{
|
|
"page_access_token": "old_token",
|
|
})
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestFBProvider_CheckAuthorizationError_Nil_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
assert.False(t, p.CheckAuthorizationError(context.Background(), nil))
|
|
}
|
|
|
|
func TestFBProvider_CheckAuthorizationError_Code190_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
assert.True(t, p.CheckAuthorizationError(context.Background(), errFake("code 190")))
|
|
}
|
|
|
|
func TestFBProvider_CheckAuthorizationError_OAuthException_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
assert.True(t, p.CheckAuthorizationError(context.Background(), errFake("OAuthException")))
|
|
}
|
|
|
|
func TestFBProvider_CheckAuthorizationError_Subcode463_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
assert.True(t, p.CheckAuthorizationError(context.Background(), errFake("error_subcode 463")))
|
|
}
|
|
|
|
func TestFBProvider_CheckAuthorizationError_Subcode467_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
assert.True(t, p.CheckAuthorizationError(context.Background(), errFake("error_subcode 467")))
|
|
}
|
|
|
|
func TestFBProvider_CheckAuthorizationError_Other_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
assert.False(t, p.CheckAuthorizationError(context.Background(), errFake("some other error")))
|
|
}
|
|
|
|
func TestFBProvider_OnReauthorization_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
err := p.OnReauthorization(context.Background(), &model.Inbox{Base: model.Base{ID: 1}})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// ===========================
|
|
// FacebookProvider — Convenience methods (Cov7)
|
|
// ===========================
|
|
|
|
func TestFBProvider_CreateChannel_Success_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBPageInfo{ID: "12345", Name: "Test Page"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
ch, err := p.CreateChannel(context.Background(), 10, channel.ChannelConfig{
|
|
"page_id": "12345",
|
|
"page_access_token": "tok",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, ch)
|
|
}
|
|
|
|
func TestFBProvider_CreateChannel_APIError_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
_, err := p.CreateChannel(context.Background(), 10, channel.ChannelConfig{
|
|
"page_id": "12345",
|
|
"page_access_token": "tok",
|
|
})
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestFBProvider_CreateChannel_PageIDMismatch_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBPageInfo{ID: "99999", Name: "Other"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
_, err := p.CreateChannel(context.Background(), 10, channel.ChannelConfig{
|
|
"page_id": "12345",
|
|
"page_access_token": "tok",
|
|
})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "mismatch")
|
|
}
|
|
|
|
func TestFBProvider_UpdateChannel_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
ch, err := p.UpdateChannel(context.Background(), 1, channel.ChannelConfig{
|
|
"page_access_token": "new_tok",
|
|
"page_name": "New Name",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, ch)
|
|
}
|
|
|
|
func TestFBProvider_DeleteChannel_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
err := p.DeleteChannel(context.Background(), 1)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFBProvider_HandleWebhook_Page_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
err := p.HandleWebhook(context.Background(), map[string]interface{}{
|
|
"object": "page",
|
|
"entry": []interface{}{},
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFBProvider_HandleWebhook_NonPage_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
err := p.HandleWebhook(context.Background(), map[string]interface{}{
|
|
"object": "instagram",
|
|
"entry": []interface{}{},
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFBProvider_HandleWebhook_BadPayload_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
err := p.HandleWebhook(context.Background(), map[string]interface{}{
|
|
"object": func() {},
|
|
})
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestFBProvider_ProcessIncomingMessage_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := map[string]interface{}{
|
|
"object": "page",
|
|
"entry": []interface{}{
|
|
map[string]interface{}{
|
|
"id": "123",
|
|
"time": int64(1234567890),
|
|
"messaging": []interface{}{
|
|
map[string]interface{}{
|
|
"sender": map[string]interface{}{"id": "s1"},
|
|
"recipient": map[string]interface{}{"id": "r1"},
|
|
"timestamp": int64(1234567890),
|
|
"message": map[string]interface{}{"mid": "m1", "text": "hello"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
msg, err := p.ProcessIncomingMessage(context.Background(), inbox, payload)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "hello", msg.Content)
|
|
}
|
|
|
|
// ===========================
|
|
// FacebookProvider — Sender actions (Cov7)
|
|
// ===========================
|
|
|
|
func TestFBProvider_SendTypingOn_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write([]byte(`{"success":true}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
err := p.SendTypingOn(context.Background(), "12345", "tok")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFBProvider_SendTypingOff_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write([]byte(`{"success":true}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
err := p.SendTypingOff(context.Background(), "12345", "tok")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFBProvider_MarkSeen_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write([]byte(`{"success":true}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
err := p.MarkSeen(context.Background(), "12345", "tok")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFBProvider_SendTypingOn_APIError_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
err := p.SendTypingOn(context.Background(), "12345", "tok")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestFBProvider_TakeThreadControl_NoPSID_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"page_access_token":"tok"}`}
|
|
err := p.TakeThreadControl(context.Background(), inbox, "")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestFBProvider_TakeThreadControl_NoToken_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{}`}
|
|
err := p.TakeThreadControl(context.Background(), inbox, "12345")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestFBProvider_TakeThreadControl_Success_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"page_access_token":"tok"}`}
|
|
err := p.TakeThreadControl(context.Background(), inbox, "12345")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestFBProvider_TakeThreadControl_APIError_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"page_access_token":"tok"}`}
|
|
err := p.TakeThreadControl(context.Background(), inbox, "12345")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// ===========================
|
|
// FacebookProvider — Helper methods (Cov7)
|
|
// ===========================
|
|
|
|
func TestFBProvider_GetPageAccessTokenFromInbox_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"page_access_token":"my_token"}`}
|
|
assert.Equal(t, "my_token", p.GetPageAccessTokenFromInbox(inbox))
|
|
}
|
|
|
|
func TestFBProvider_GetPageAccessTokenFromInbox_Empty_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: ""}
|
|
assert.Empty(t, p.GetPageAccessTokenFromInbox(inbox))
|
|
}
|
|
|
|
func TestFBProvider_GetPageAccessTokenFromInbox_BadJSON_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: "bad json"}
|
|
assert.Empty(t, p.GetPageAccessTokenFromInbox(inbox))
|
|
}
|
|
|
|
func TestFBProvider_GetPageAccessTokenFromInbox_NoToken_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"other":"value"}`}
|
|
assert.Empty(t, p.GetPageAccessTokenFromInbox(inbox))
|
|
}
|
|
|
|
func TestIsNumeric_Cov7(t *testing.T) {
|
|
assert.True(t, isNumeric("12345"))
|
|
assert.False(t, isNumeric("abc"))
|
|
assert.False(t, isNumeric(""))
|
|
assert.True(t, isNumeric("0"))
|
|
}
|
|
|
|
func TestFBProvider_ExtractRecipientPSID_Numeric_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
contact := &model.Contact{Identifier: "12345"}
|
|
assert.Equal(t, "12345", p.extractRecipientPSID(contact))
|
|
}
|
|
|
|
func TestFBProvider_ExtractRecipientPSID_NonNumeric_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
contact := &model.Contact{Identifier: "abc"}
|
|
assert.Empty(t, p.extractRecipientPSID(contact))
|
|
}
|
|
|
|
func TestFBProvider_MapContentTypeToFBAttachmentType_Cov7(t *testing.T) {
|
|
p := NewFacebookProvider()
|
|
assert.Equal(t, "image", p.mapContentTypeToFBAttachmentType("image"))
|
|
assert.Equal(t, "video", p.mapContentTypeToFBAttachmentType("video"))
|
|
assert.Equal(t, "audio", p.mapContentTypeToFBAttachmentType("audio"))
|
|
assert.Equal(t, "file", p.mapContentTypeToFBAttachmentType("file"))
|
|
assert.Equal(t, "file", p.mapContentTypeToFBAttachmentType("unknown"))
|
|
}
|
|
|
|
func TestFBProvider_SetupWebhookSubscription_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write([]byte(`{"success":true}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewFacebookProvider()
|
|
p.graphAPIBase = srv.URL
|
|
err := p.setupWebhookSubscription(context.Background(), "app_id", "page_id", "token", "verify")
|
|
// May or may not error depending on the mock — just verify it doesn't panic
|
|
_ = err
|
|
}
|
|
|
|
// ===========================
|
|
// InstagramProvider — identity & metadata (Cov7)
|
|
// ===========================
|
|
|
|
func TestIGProvider_New_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
require.NotNil(t, p)
|
|
assert.NotNil(t, p.client)
|
|
assert.NotEmpty(t, p.graphAPIBase)
|
|
}
|
|
|
|
func TestIGProvider_Type_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
assert.Equal(t, channel.ChannelInstagram, p.Type())
|
|
}
|
|
|
|
func TestIGProvider_Name_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
assert.Equal(t, "Instagram DM", p.Name())
|
|
}
|
|
|
|
func TestIGProvider_Description_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
assert.NotEmpty(t, p.Description())
|
|
}
|
|
|
|
func TestIGProvider_ConfigSchema_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
schema := p.ConfigSchema()
|
|
require.NotNil(t, schema)
|
|
assert.Contains(t, schema.Required, "instagram_account_id")
|
|
assert.Contains(t, schema.Required, "page_access_token")
|
|
assert.Contains(t, schema.Required, "connected_fb_page_id")
|
|
}
|
|
|
|
func TestIGProvider_DefaultConfig_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
cfg := p.DefaultConfig()
|
|
assert.Contains(t, cfg, "instagram_account_id")
|
|
assert.Contains(t, cfg, "connected_fb_page_id")
|
|
}
|
|
|
|
func TestIGProvider_Capabilities_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
caps := p.Capabilities()
|
|
assert.True(t, caps.SupportsAttachments)
|
|
assert.True(t, caps.SupportsTypingIndicator)
|
|
assert.True(t, caps.SupportsEmojiReactions)
|
|
assert.Equal(t, 1000, caps.MaxTextLength)
|
|
}
|
|
|
|
func TestIGProvider_OAuthConfig_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
oauth := p.OAuthConfig()
|
|
require.NotNil(t, oauth)
|
|
assert.Equal(t, "facebook", oauth.Provider)
|
|
assert.Contains(t, oauth.Scopes, "instagram_manage_messages")
|
|
}
|
|
|
|
// ===========================
|
|
// InstagramProvider — ValidateConfig (Cov7)
|
|
// ===========================
|
|
|
|
func TestIGProvider_ValidateConfig_NoAccountID_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "instagram_account_id")
|
|
}
|
|
|
|
func TestIGProvider_ValidateConfig_NoToken_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
|
|
"instagram_account_id": "12345",
|
|
})
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "page_access_token")
|
|
}
|
|
|
|
func TestIGProvider_ValidateConfig_APIError_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
|
|
"instagram_account_id": "12345",
|
|
"page_access_token": "tok",
|
|
})
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ValidateConfig_Success_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, IGUserProfile{ID: "12345", Username: "testuser"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
err := p.ValidateConfig(context.Background(), channel.ChannelConfig{
|
|
"instagram_account_id": "12345",
|
|
"page_access_token": "tok",
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// ===========================
|
|
// InstagramProvider — OnCreate / OnDestroy (Cov7)
|
|
// ===========================
|
|
|
|
func TestIGProvider_OnCreate_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, IGUserProfile{ID: "12345", Username: "testuser"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
config := channel.ChannelConfig{
|
|
"instagram_account_id": "12345",
|
|
"page_access_token": "tok",
|
|
"connected_fb_page_id": "fb_page",
|
|
}
|
|
result, err := p.OnCreate(context.Background(), inbox, config)
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
}
|
|
|
|
func TestIGProvider_OnDestroy_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}}
|
|
config := channel.ChannelConfig{
|
|
"page_access_token": "tok",
|
|
"connected_fb_page_id": "fb_page",
|
|
"app_id": "app",
|
|
}
|
|
err := p.OnDestroy(context.Background(), inbox, config)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestIGProvider_OnDestroy_NoDeps_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}}
|
|
config := channel.ChannelConfig{}
|
|
err := p.OnDestroy(context.Background(), inbox, config)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// ===========================
|
|
// InstagramProvider — ProcessIncoming (Cov7)
|
|
// ===========================
|
|
|
|
func TestIGProvider_ProcessIncoming_InvalidJSON_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
_, err := p.ProcessIncoming(context.Background(), inbox, []byte("bad"))
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ProcessIncoming_NotInstagram_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"page","entry":[]}`
|
|
_, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "not an instagram")
|
|
}
|
|
|
|
func TestIGProvider_ProcessIncoming_NoContent_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"instagram","entry":[{"id":"123","time":1234567890,"messaging":[]}]}`
|
|
_, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ProcessIncoming_EchoMessage_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"instagram","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","text":"hi","is_echo":true}}]}]}`
|
|
_, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ProcessIncoming_TextMessage_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"instagram","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","text":"hello ig"}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "hello ig", msg.Content)
|
|
}
|
|
|
|
func TestIGProvider_ProcessIncoming_ReplyMessage_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"instagram","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","text":"reply","reply_to":{"mid":"orig_mid"}}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "orig_mid", msg.ReplyToID)
|
|
}
|
|
|
|
func TestIGProvider_ProcessIncoming_ImageAttachment_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"instagram","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","attachments":[{"type":"image","payload":{"url":"https://example.com/img.jpg"}}]}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Contains(t, msg.Content, "img.jpg")
|
|
}
|
|
|
|
func TestIGProvider_ProcessIncoming_ShareAttachment_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"instagram","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","attachments":[{"type":"share","payload":{"url":"https://example.com/share"}}]}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Contains(t, msg.Content, "share")
|
|
}
|
|
|
|
func TestIGProvider_ProcessIncoming_AnimatedMedia_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"instagram","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","attachments":[{"type":"animated_media","payload":{"url":"https://example.com/gif.gif"}}]}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Contains(t, msg.Content, "gif.gif")
|
|
}
|
|
|
|
func TestIGProvider_ProcessIncoming_StoryMention_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"instagram","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"message":{"mid":"m1","attachments":[{"type":"story_mention","payload":{"url":"https://example.com/story.jpg"}}]}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Contains(t, msg.Content, "story.jpg")
|
|
}
|
|
|
|
func TestIGProvider_ProcessIncoming_Postback_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"instagram","entry":[{"id":"123","time":1234567890,"messaging":[{"sender":{"id":"s1"},"recipient":{"id":"r1"},"timestamp":1234567890,"postback":{"title":"Start","payload":"START"}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "START", msg.Content)
|
|
}
|
|
|
|
func TestIGProvider_ProcessIncoming_CommentChange_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"instagram","entry":[{"id":"123","time":1234567890,"changes":[{"field":"comments","value":{"media_id":"media_1","id":"comment_1","text":"Nice post!","from":{"id":"user_1","username":"user1"}}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "Nice post!", msg.Content)
|
|
}
|
|
|
|
func TestIGProvider_ProcessIncoming_CommentReplyChange_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"instagram","entry":[{"id":"123","time":1234567890,"changes":[{"field":"comments","value":{"media_id":"media_1","id":"comment_2","text":"Reply!","from":{"id":"user_1","username":"user1"},"parent_id":"comment_1"}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "Reply!", msg.Content)
|
|
}
|
|
|
|
func TestIGProvider_ProcessIncoming_CommentDeletedChange_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := `{"object":"instagram","entry":[{"id":"123","time":1234567890,"changes":[{"field":"comments","value":{"media_id":"media_1","id":"comment_2","text":"","from":{"id":"user_1","username":"user1"},"is_deleted":true}}]}]}`
|
|
msg, err := p.ProcessIncoming(context.Background(), inbox, []byte(payload))
|
|
require.NoError(t, err)
|
|
assert.Contains(t, msg.Content, "deleted")
|
|
}
|
|
|
|
// ===========================
|
|
// InstagramProvider — ValidateWebhookRequest (Cov7)
|
|
// ===========================
|
|
|
|
func TestIGProvider_ValidateWebhookRequest_GET_Valid_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"webhook_verify_token":"my_token"}`}
|
|
req := &channel.WebhookRequest{
|
|
Method: "GET",
|
|
QueryParams: map[string]string{"hub.mode": "subscribe", "hub.verify_token": "my_token"},
|
|
}
|
|
err := p.ValidateWebhookRequest(context.Background(), inbox, req)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ValidateWebhookRequest_GET_InvalidMode_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{}`}
|
|
req := &channel.WebhookRequest{
|
|
Method: "GET",
|
|
QueryParams: map[string]string{"hub.mode": "bad"},
|
|
}
|
|
err := p.ValidateWebhookRequest(context.Background(), inbox, req)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ValidateWebhookRequest_GET_TokenMismatch_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"webhook_verify_token":"correct"}`}
|
|
req := &channel.WebhookRequest{
|
|
Method: "GET",
|
|
QueryParams: map[string]string{"hub.mode": "subscribe", "hub.verify_token": "wrong"},
|
|
}
|
|
err := p.ValidateWebhookRequest(context.Background(), inbox, req)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ValidateWebhookRequest_POST_NoSignature_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{}`}
|
|
req := &channel.WebhookRequest{
|
|
Method: "POST",
|
|
Headers: map[string]string{},
|
|
Body: []byte(`{}`),
|
|
}
|
|
err := p.ValidateWebhookRequest(context.Background(), inbox, req)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ValidateWebhookRequest_POST_NoAppSecret_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
p.appSecret = ""
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{}`}
|
|
req := &channel.WebhookRequest{
|
|
Method: "POST",
|
|
Headers: map[string]string{"X-Hub-Signature-256": "sha256=abc"},
|
|
Body: []byte(`{}`),
|
|
}
|
|
err := p.ValidateWebhookRequest(context.Background(), inbox, req)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ValidateWebhookRequest_POST_BadSig_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
p.appSecret = "secret"
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{}`}
|
|
req := &channel.WebhookRequest{
|
|
Method: "POST",
|
|
Headers: map[string]string{"X-Hub-Signature-256": "sha256=bad"},
|
|
Body: []byte(`{"test":true}`),
|
|
}
|
|
err := p.ValidateWebhookRequest(context.Background(), inbox, req)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// ===========================
|
|
// InstagramProvider — SendMessage (Cov7)
|
|
// ===========================
|
|
|
|
func TestIGProvider_SendMessage_NoIGID_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}}
|
|
msg := &model.Message{Base: model.Base{ID: 1}, Content: "hi", ContentType: "text"}
|
|
contact := &model.Contact{Base: model.Base{ID: 1}, Identifier: ""}
|
|
_, err := p.SendMessage(context.Background(), inbox, msg, contact)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_SendMessage_NoToken_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{}`}
|
|
msg := &model.Message{Base: model.Base{ID: 1}, Content: "hi", ContentType: "text"}
|
|
contact := &model.Contact{Base: model.Base{ID: 1}, Identifier: "12345"}
|
|
_, err := p.SendMessage(context.Background(), inbox, msg, contact)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_SendMessage_Success_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBSendAPIResponse{RecipientID: "12345", MessageID: "mid:123"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"page_access_token":"tok"}`}
|
|
msg := &model.Message{Base: model.Base{ID: 1}, Content: "hi", ContentType: "text"}
|
|
contact := &model.Contact{Base: model.Base{ID: 1}, Identifier: "12345"}
|
|
result, err := p.SendMessage(context.Background(), inbox, msg, contact)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "mid:123", result.ExternalID)
|
|
}
|
|
|
|
func TestIGProvider_SendMessage_Attachment_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBSendAPIResponse{RecipientID: "12345", MessageID: "mid:456"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"page_access_token":"tok"}`}
|
|
msg := &model.Message{Base: model.Base{ID: 1}, Content: "https://example.com/img.jpg", ContentType: "image"}
|
|
contact := &model.Contact{Base: model.Base{ID: 1}, Identifier: "12345"}
|
|
result, err := p.SendMessage(context.Background(), inbox, msg, contact)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "mid:456", result.ExternalID)
|
|
}
|
|
|
|
func TestIGProvider_SendMessage_APIError_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"page_access_token":"tok"}`}
|
|
msg := &model.Message{Base: model.Base{ID: 1}, Content: "hi", ContentType: "text"}
|
|
contact := &model.Contact{Base: model.Base{ID: 1}, Identifier: "12345"}
|
|
_, err := p.SendMessage(context.Background(), inbox, msg, contact)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// ===========================
|
|
// InstagramProvider — GetContactProfile (Cov7)
|
|
// ===========================
|
|
|
|
func TestIGProvider_GetContactProfile_NoToken_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{}`}
|
|
_, err := p.GetContactProfile(context.Background(), inbox, "123")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_GetContactProfile_Success_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, IGUserProfile{ID: "123", Username: "testuser"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"page_access_token":"tok"}`}
|
|
profile, err := p.GetContactProfile(context.Background(), inbox, "123")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "testuser", profile.Name)
|
|
}
|
|
|
|
func TestIGProvider_GetContactProfile_APIError_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"page_access_token":"tok"}`}
|
|
_, err := p.GetContactProfile(context.Background(), inbox, "123")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// ===========================
|
|
// InstagramProvider — OAuth methods (Cov7)
|
|
// ===========================
|
|
|
|
func TestIGProvider_BuildAuthURL_NoAppID_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
p.appID = ""
|
|
_, err := p.BuildAuthURL(context.Background(), 1, "https://example.com/callback")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_BuildAuthURL_Success_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
p.appID = "test_app"
|
|
url, err := p.BuildAuthURL(context.Background(), 1, "https://example.com/callback")
|
|
require.NoError(t, err)
|
|
assert.Contains(t, url, "test_app")
|
|
}
|
|
|
|
func TestIGProvider_ExchangeToken_NoConfig_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
p.appID = ""
|
|
p.appSecret = ""
|
|
_, err := p.ExchangeToken(context.Background(), "code", "https://example.com/callback")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ExchangeToken_Success_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBLongLivedTokenResponse{AccessToken: "long_token", ExpiresIn: 5184000})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
p.appID = "app"
|
|
p.appSecret = "secret"
|
|
result, err := p.ExchangeToken(context.Background(), "code", "https://example.com/callback")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "long_token", result.AccessToken)
|
|
}
|
|
|
|
func TestIGProvider_ExchangeToken_APIError_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
p.appID = "app"
|
|
p.appSecret = "secret"
|
|
_, err := p.ExchangeToken(context.Background(), "code", "https://example.com/callback")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_RefreshToken_NoToken_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
_, err := p.RefreshToken(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, channel.ChannelConfig{})
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_RefreshToken_Success_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, FBLongLivedTokenResponse{AccessToken: "new_token", ExpiresIn: 5184000})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
result, err := p.RefreshToken(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, channel.ChannelConfig{
|
|
"page_access_token": "old",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "new_token", result.AccessToken)
|
|
}
|
|
|
|
func TestIGProvider_RefreshToken_APIError_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
_, err := p.RefreshToken(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, channel.ChannelConfig{
|
|
"page_access_token": "old",
|
|
})
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_CheckAuthorizationError_Nil_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
assert.False(t, p.CheckAuthorizationError(context.Background(), nil))
|
|
}
|
|
|
|
func TestIGProvider_CheckAuthorizationError_Code190_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
assert.True(t, p.CheckAuthorizationError(context.Background(), errFake("code 190")))
|
|
}
|
|
|
|
func TestIGProvider_CheckAuthorizationError_Other_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
assert.False(t, p.CheckAuthorizationError(context.Background(), errFake("random error")))
|
|
}
|
|
|
|
func TestIGProvider_OnReauthorization_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
err := p.OnReauthorization(context.Background(), &model.Inbox{Base: model.Base{ID: 1}})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// ===========================
|
|
// InstagramProvider — Convenience methods (Cov7)
|
|
// ===========================
|
|
|
|
func TestIGProvider_CreateChannel_Success_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
mustEncodeTestJSON(w, IGUserProfile{ID: "12345", Username: "testuser"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
ch, err := p.CreateChannel(context.Background(), 10, channel.ChannelConfig{
|
|
"instagram_account_id": "12345",
|
|
"page_access_token": "tok",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, ch)
|
|
}
|
|
|
|
func TestIGProvider_CreateChannel_APIError_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
_, err := p.CreateChannel(context.Background(), 10, channel.ChannelConfig{
|
|
"instagram_account_id": "12345",
|
|
"page_access_token": "tok",
|
|
})
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_UpdateChannel_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
ch, err := p.UpdateChannel(context.Background(), 1, channel.ChannelConfig{
|
|
"page_access_token": "new_tok",
|
|
"instagram_account_name": "newname",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, ch)
|
|
}
|
|
|
|
func TestIGProvider_DeleteChannel_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
err := p.DeleteChannel(context.Background(), 1)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestIGProvider_HandleWebhook_Instagram_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
err := p.HandleWebhook(context.Background(), map[string]interface{}{
|
|
"object": "instagram",
|
|
"entry": []interface{}{},
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestIGProvider_HandleWebhook_NonInstagram_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
err := p.HandleWebhook(context.Background(), map[string]interface{}{
|
|
"object": "page",
|
|
"entry": []interface{}{},
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestIGProvider_HandleWebhook_BadPayload_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
err := p.HandleWebhook(context.Background(), map[string]interface{}{
|
|
"object": func() {},
|
|
})
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ProcessIncomingMessage_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 10}
|
|
payload := map[string]interface{}{
|
|
"object": "instagram",
|
|
"entry": []interface{}{
|
|
map[string]interface{}{
|
|
"id": "123",
|
|
"time": int64(1234567890),
|
|
"messaging": []interface{}{
|
|
map[string]interface{}{
|
|
"sender": map[string]interface{}{"id": "s1"},
|
|
"recipient": map[string]interface{}{"id": "r1"},
|
|
"timestamp": int64(1234567890),
|
|
"message": map[string]interface{}{"mid": "m1", "text": "ig hello"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
msg, err := p.ProcessIncomingMessage(context.Background(), inbox, payload)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "ig hello", msg.Content)
|
|
}
|
|
|
|
// ===========================
|
|
// InstagramProvider — Sender actions & helpers (Cov7)
|
|
// ===========================
|
|
|
|
func TestIGProvider_SendTypingOn_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if _, err := w.Write([]byte(`{"success":true}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
err := p.SendTypingOn(context.Background(), "12345", "tok")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestIGProvider_SendTypingOff_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if _, err := w.Write([]byte(`{"success":true}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
err := p.SendTypingOff(context.Background(), "12345", "tok")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestIGProvider_SendTypingOn_APIError_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
err := p.SendTypingOn(context.Background(), "12345", "tok")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ExtractRecipientIGID_Numeric_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
contact := &model.Contact{Identifier: "12345"}
|
|
assert.Equal(t, "12345", p.extractRecipientIGID(contact))
|
|
}
|
|
|
|
func TestIGProvider_ExtractRecipientIGID_NonNumeric_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
contact := &model.Contact{Identifier: "abc"}
|
|
assert.Empty(t, p.extractRecipientIGID(contact))
|
|
}
|
|
|
|
func TestIGProvider_GetPageAccessTokenFromInbox_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: `{"page_access_token":"my_token"}`}
|
|
assert.Equal(t, "my_token", p.GetPageAccessTokenFromInbox(inbox))
|
|
}
|
|
|
|
func TestIGProvider_GetPageAccessTokenFromInbox_Empty_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
inbox := &model.Inbox{Base: model.Base{ID: 1}, ChannelConfig: ""}
|
|
assert.Empty(t, p.GetPageAccessTokenFromInbox(inbox))
|
|
}
|
|
|
|
func TestIGProvider_MapContentTypeToIGAttachmentType_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
assert.Equal(t, "image", p.mapContentTypeToIGAttachmentType("image"))
|
|
assert.Equal(t, "video", p.mapContentTypeToIGAttachmentType("video"))
|
|
assert.Equal(t, "audio", p.mapContentTypeToIGAttachmentType("audio"))
|
|
assert.Equal(t, "file", p.mapContentTypeToIGAttachmentType("file"))
|
|
assert.Equal(t, "file", p.mapContentTypeToIGAttachmentType("unknown"))
|
|
}
|
|
|
|
// ===========================
|
|
// InstagramProvider — Comment Management API (Cov7)
|
|
// ===========================
|
|
|
|
func TestIGProvider_GetComments_NoToken_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
_, err := p.GetComments(context.Background(), "", "media_1", 10, "")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_GetComments_NoMediaID_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
_, err := p.GetComments(context.Background(), "tok", "", 10, "")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_GetComments_Success_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write([]byte(`{"data":[]}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
result, err := p.GetComments(context.Background(), "tok", "media_1", 10, "cursor1")
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
}
|
|
|
|
func TestIGProvider_GetComments_APIError_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
_, err := p.GetComments(context.Background(), "tok", "media_1", 0, "")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_GetCommentReplies_NoToken_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
_, err := p.GetCommentReplies(context.Background(), "", "comment_1", 10, "")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_GetCommentReplies_NoCommentID_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
_, err := p.GetCommentReplies(context.Background(), "tok", "", 10, "")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_GetCommentReplies_Success_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write([]byte(`{"data":[]}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
result, err := p.GetCommentReplies(context.Background(), "tok", "comment_1", 10, "")
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
}
|
|
|
|
func TestIGProvider_ReplyToComment_NoToken_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
_, err := p.ReplyToComment(context.Background(), "", "comment_1", "reply text")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ReplyToComment_NoCommentID_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
_, err := p.ReplyToComment(context.Background(), "tok", "", "reply text")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ReplyToComment_NoMessage_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
_, err := p.ReplyToComment(context.Background(), "tok", "comment_1", "")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ReplyToComment_Success_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write([]byte(`{"id":"reply_1"}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
result, err := p.ReplyToComment(context.Background(), "tok", "comment_1", "reply text")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "reply_1", result.ID)
|
|
}
|
|
|
|
func TestIGProvider_ReplyToComment_APIError_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
_, err := p.ReplyToComment(context.Background(), "tok", "comment_1", "reply text")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_HideComment_NoToken_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
_, err := p.HideComment(context.Background(), "", "comment_1", true)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_HideComment_NoCommentID_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
_, err := p.HideComment(context.Background(), "tok", "", true)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_HideComment_Success_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write([]byte(`{"success":true}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
result, err := p.HideComment(context.Background(), "tok", "comment_1", true)
|
|
require.NoError(t, err)
|
|
assert.True(t, result.Success)
|
|
}
|
|
|
|
func TestIGProvider_HideComment_APIError_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
_, err := p.HideComment(context.Background(), "tok", "comment_1", false)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_DeleteComment_NoToken_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
_, err := p.DeleteComment(context.Background(), "", "comment_1")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_DeleteComment_NoCommentID_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
p := NewInstagramProvider()
|
|
_, err := p.DeleteComment(context.Background(), "tok", "")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_DeleteComment_Success_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write([]byte(`{"success":true}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
result, err := p.DeleteComment(context.Background(), "tok", "comment_1")
|
|
require.NoError(t, err)
|
|
assert.True(t, result.Success)
|
|
}
|
|
|
|
func TestIGProvider_DeleteComment_APIError_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
_, err := p.DeleteComment(context.Background(), "tok", "comment_1")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ProcessCommentIncoming_Nil_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
_, err := p.ProcessCommentIncoming(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, nil, EventIGComment)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ProcessCommentIncoming_Comment_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
commentData := &IGCommentChangeValue{
|
|
CommentID: "c1",
|
|
MediaID: "m1",
|
|
Text: "hello",
|
|
From: IGCommentFrom{ID: "u1", Username: "user1"},
|
|
}
|
|
msg, err := p.ProcessCommentIncoming(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, commentData, EventIGComment)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "hello", msg.Content)
|
|
}
|
|
|
|
func TestIGProvider_ProcessCommentIncoming_Reply_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
commentData := &IGCommentChangeValue{
|
|
CommentID: "c2",
|
|
MediaID: "m1",
|
|
Text: "reply text",
|
|
ParentID: "c1",
|
|
From: IGCommentFrom{ID: "u1", Username: "user1"},
|
|
}
|
|
msg, err := p.ProcessCommentIncoming(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, commentData, EventIGCommentReply)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "reply text", msg.Content)
|
|
}
|
|
|
|
func TestIGProvider_ProcessCommentIncoming_Deleted_Cov7(t *testing.T) {
|
|
p := NewInstagramProvider()
|
|
commentData := &IGCommentChangeValue{
|
|
CommentID: "c3",
|
|
MediaID: "m1",
|
|
Text: "",
|
|
IsDeleted: true,
|
|
From: IGCommentFrom{ID: "u1", Username: "user1"},
|
|
}
|
|
msg, err := p.ProcessCommentIncoming(context.Background(), &model.Inbox{Base: model.Base{ID: 1}}, commentData, EventIGCommentDeleted)
|
|
require.NoError(t, err)
|
|
assert.Contains(t, msg.Content, "deleted")
|
|
}
|
|
|
|
// ===========================
|
|
// InstagramProvider — Webhook Registration (Cov7)
|
|
// ===========================
|
|
|
|
func TestIGProvider_RegisterWebhook_Success_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write([]byte(`{"success":true}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
result, err := p.RegisterWebhook(context.Background(), "tok", "page_1")
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, result)
|
|
}
|
|
|
|
func TestIGProvider_RegisterWebhook_APIError_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
_, err := p.RegisterWebhook(context.Background(), "tok", "page_1")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_RegisterWebhook_SuccessFalse_Cov7(t *testing.T) {
|
|
t.Skip("network test")
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write([]byte(`{"success":false}`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
_, err := p.RegisterWebhook(context.Background(), "tok", "page_1")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_ListWebhooks_Success_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if _, err := w.Write([]byte(`[]`)); err != nil {
|
|
panic(err)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
result, err := p.ListWebhooks(context.Background(), "tok", "page_1")
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
}
|
|
|
|
func TestIGProvider_ListWebhooks_APIError_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
_, err := p.ListWebhooks(context.Background(), "tok", "page_1")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestIGProvider_DeleteWebhook_Success_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
err := p.DeleteWebhook(context.Background(), "tok", "page_1")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestIGProvider_DeleteWebhook_APIError_Cov7(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
p := NewInstagramProvider()
|
|
p.graphAPIBase = srv.URL
|
|
err := p.DeleteWebhook(context.Background(), "tok", "page_1")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// ===========================
|
|
// Type instantiation tests (Cov7)
|
|
// ===========================
|
|
|
|
func TestFBTypes_Instantiation_Cov7(t *testing.T) {
|
|
evt := FBWebhookEvent{Object: "page"}
|
|
assert.Equal(t, "page", evt.Object)
|
|
|
|
msg := FBMessageData{Mid: "m1", Text: "hello"}
|
|
assert.Equal(t, "m1", msg.Mid)
|
|
|
|
att := FBAttachment{Type: "image", Payload: FBAttachmentPayload{URL: "http://example.com"}}
|
|
assert.Equal(t, "image", att.Type)
|
|
|
|
profile := FBUserProfile{ID: "123", Name: "Test"}
|
|
assert.Equal(t, "123", profile.ID)
|
|
|
|
pageInfo := FBPageInfo{ID: "1", Name: "Page"}
|
|
assert.Equal(t, "1", pageInfo.ID)
|
|
|
|
tokenResp := FBLongLivedTokenResponse{AccessToken: "tok"}
|
|
assert.Equal(t, "tok", tokenResp.AccessToken)
|
|
|
|
igProfile := IGUserProfile{ID: "ig1", Username: "user"}
|
|
assert.Equal(t, "ig1", igProfile.ID)
|
|
|
|
commentVal := IGCommentChangeValue{CommentID: "c1", Text: "hello"}
|
|
assert.Equal(t, "c1", commentVal.CommentID)
|
|
|
|
paging := FBGraphPaging{Next: "http://next"}
|
|
assert.Equal(t, "http://next", paging.Next)
|
|
}
|
|
|
|
func TestFBTypes_SendRequest_Cov7(t *testing.T) {
|
|
req := FBSendMessageRequest{
|
|
Recipient: FBRecipient{ID: "123"},
|
|
MessagingType: "RESP",
|
|
Message: &FBSendMessage{Text: "hello"},
|
|
}
|
|
assert.Equal(t, "123", req.Recipient.ID)
|
|
assert.Equal(t, "hello", req.Message.Text)
|
|
}
|
|
|
|
func TestFBTypes_SendAttachment_Cov7(t *testing.T) {
|
|
att := FBSendAttachment{
|
|
Type: "image",
|
|
Payload: FBSendAttachmentPayload{URL: "http://example.com/img.jpg"},
|
|
}
|
|
assert.Equal(t, "image", att.Type)
|
|
assert.Equal(t, "http://example.com/img.jpg", att.Payload.URL)
|
|
}
|
|
|
|
func TestFBTypes_SubscriptionVerify_Cov7(t *testing.T) {
|
|
verify := FBWebhookSubscriptionVerify{Mode: "subscribe", VerifyToken: "tok", Challenge: "challenge"}
|
|
assert.Equal(t, "subscribe", verify.Mode)
|
|
}
|
|
|
|
// errFake creates a simple error for testing
|
|
type fakeError7 string
|
|
|
|
func (e fakeError7) Error() string { return string(e) }
|
|
func errFake(s string) error { return fakeError7(s) }
|