chore: refresh gramsrv public release
This commit is contained in:
parent
75cebe8dbf
commit
70b6820474
1274 changed files with 378751 additions and 59919 deletions
510
internal/admin/service_test.go
Normal file
510
internal/admin/service_test.go
Normal file
|
|
@ -0,0 +1,510 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
func TestSetSendFrozenDryRunExecuteAndIdempotency(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
repo := newMemoryCommandRepo()
|
||||
restrictions := &fakeRestrictionStore{}
|
||||
svc := NewService(Dependencies{
|
||||
Commands: repo,
|
||||
Restrictions: restrictions,
|
||||
Now: fixedNow,
|
||||
})
|
||||
|
||||
dry, err := svc.SetSendFrozen(ctx, SetSendFrozenRequest{
|
||||
CommandMeta: CommandMeta{CommandID: "dry-freeze", Actor: "ops", Reason: "test", DryRun: true},
|
||||
UserID: 1001,
|
||||
Frozen: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("dry-run freeze: %v", err)
|
||||
}
|
||||
if !dry.DryRun || dry.Status != string(domain.AdminCommandCompleted) || restrictions.setCalls != 0 {
|
||||
t.Fatalf("dry-run result=%+v setCalls=%d, want completed dry-run without mutation", dry, restrictions.setCalls)
|
||||
}
|
||||
|
||||
execReq := SetSendFrozenRequest{
|
||||
CommandMeta: CommandMeta{CommandID: "exec-freeze", Actor: "ops", Reason: "incident", DryRun: false},
|
||||
UserID: 1001,
|
||||
Frozen: true,
|
||||
}
|
||||
exec, err := svc.SetSendFrozen(ctx, execReq)
|
||||
if err != nil {
|
||||
t.Fatalf("execute freeze: %v", err)
|
||||
}
|
||||
if exec.Status != string(domain.AdminCommandCompleted) || restrictions.setCalls != 1 {
|
||||
t.Fatalf("execute result=%+v setCalls=%d", exec, restrictions.setCalls)
|
||||
}
|
||||
if err := svc.CanSendMessages(ctx, 1001); !errors.Is(err, domain.ErrUserSendRestricted) {
|
||||
t.Fatalf("CanSendMessages err=%v, want ErrUserSendRestricted", err)
|
||||
}
|
||||
|
||||
again, err := svc.SetSendFrozen(ctx, execReq)
|
||||
if err != nil {
|
||||
t.Fatalf("duplicate freeze: %v", err)
|
||||
}
|
||||
if !again.AlreadyExecuted || restrictions.setCalls != 1 {
|
||||
t.Fatalf("duplicate result=%+v setCalls=%d, want idempotent replay", again, restrictions.setCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantPremiumDryRunExecuteAndIdempotency(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
users := &fakeUsersService{users: map[int64]domain.User{
|
||||
1001: {ID: 1001, FirstName: "Alice"},
|
||||
}}
|
||||
notifier := &fakeUserNotifier{}
|
||||
svc := NewService(Dependencies{
|
||||
Commands: newMemoryCommandRepo(),
|
||||
Users: users,
|
||||
UserNotifier: notifier,
|
||||
Now: fixedNow,
|
||||
})
|
||||
|
||||
dry, err := svc.GrantPremium(ctx, GrantPremiumRequest{
|
||||
CommandMeta: CommandMeta{CommandID: "dry-premium", Actor: "ops", Reason: "test", DryRun: true},
|
||||
UserID: 1001,
|
||||
Months: 3,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("dry-run premium: %v", err)
|
||||
}
|
||||
if !dry.DryRun || users.grantCalls != 0 || len(notifier.users) != 0 {
|
||||
t.Fatalf("dry=%+v grantCalls=%d notified=%v, want no mutation", dry, users.grantCalls, notifier.users)
|
||||
}
|
||||
|
||||
req := GrantPremiumRequest{
|
||||
CommandMeta: CommandMeta{CommandID: "exec-premium", Actor: "ops", Reason: "grant"},
|
||||
UserID: 1001,
|
||||
Months: 2,
|
||||
}
|
||||
exec, err := svc.GrantPremium(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("execute premium: %v", err)
|
||||
}
|
||||
if exec.Status != string(domain.AdminCommandCompleted) || users.grantCalls != 1 || users.lastMonths != 2 || len(notifier.users) != 1 {
|
||||
t.Fatalf("exec=%+v grantCalls=%d months=%d notified=%v", exec, users.grantCalls, users.lastMonths, notifier.users)
|
||||
}
|
||||
again, err := svc.GrantPremium(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("duplicate premium: %v", err)
|
||||
}
|
||||
if !again.AlreadyExecuted || users.grantCalls != 1 || len(notifier.users) != 1 {
|
||||
t.Fatalf("again=%+v grantCalls=%d notified=%v, want idempotent replay", again, users.grantCalls, notifier.users)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetVerifiedDryRunExecuteAndIdempotency(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
users := &fakeUsersService{users: map[int64]domain.User{
|
||||
1001: {ID: 1001, FirstName: "Alice"},
|
||||
}}
|
||||
notifier := &fakeUserNotifier{}
|
||||
svc := NewService(Dependencies{
|
||||
Commands: newMemoryCommandRepo(),
|
||||
Users: users,
|
||||
UserNotifier: notifier,
|
||||
Now: fixedNow,
|
||||
})
|
||||
|
||||
dry, err := svc.SetVerified(ctx, SetVerifiedRequest{
|
||||
CommandMeta: CommandMeta{CommandID: "dry-verified", Actor: "ops", Reason: "test", DryRun: true},
|
||||
UserID: 1001,
|
||||
Verified: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("dry-run verified: %v", err)
|
||||
}
|
||||
if !dry.DryRun || users.verifiedCalls != 0 || len(notifier.users) != 0 {
|
||||
t.Fatalf("dry=%+v verifiedCalls=%d notified=%v, want no mutation", dry, users.verifiedCalls, notifier.users)
|
||||
}
|
||||
|
||||
req := SetVerifiedRequest{
|
||||
CommandMeta: CommandMeta{CommandID: "exec-verified", Actor: "ops", Reason: "official"},
|
||||
UserID: 1001,
|
||||
Verified: true,
|
||||
}
|
||||
exec, err := svc.SetVerified(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("execute verified: %v", err)
|
||||
}
|
||||
if exec.Status != string(domain.AdminCommandCompleted) || users.verifiedCalls != 1 || !users.users[1001].Verified || len(notifier.users) != 1 {
|
||||
t.Fatalf("exec=%+v verifiedCalls=%d user=%+v notified=%v", exec, users.verifiedCalls, users.users[1001], notifier.users)
|
||||
}
|
||||
again, err := svc.SetVerified(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("duplicate verified: %v", err)
|
||||
}
|
||||
if !again.AlreadyExecuted || users.verifiedCalls != 1 || len(notifier.users) != 1 {
|
||||
t.Fatalf("again=%+v verifiedCalls=%d notified=%v, want idempotent replay", again, users.verifiedCalls, notifier.users)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetChannelVerifiedDryRunExecuteAndIdempotency(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
channels := &fakeChannelsService{channels: map[int64]domain.Channel{
|
||||
2001: {ID: 2001, CreatorUserID: 1001, Title: "Ops Channel", Username: "ops", Broadcast: true},
|
||||
}}
|
||||
notifier := &fakeChannelNotifier{}
|
||||
svc := NewService(Dependencies{
|
||||
Commands: newMemoryCommandRepo(),
|
||||
Channels: channels,
|
||||
ChannelNotifier: notifier,
|
||||
Now: fixedNow,
|
||||
})
|
||||
|
||||
dry, err := svc.SetChannelVerified(ctx, SetChannelVerifiedRequest{
|
||||
CommandMeta: CommandMeta{CommandID: "dry-channel-verified", Actor: "ops", Reason: "test", DryRun: true},
|
||||
ChannelID: 2001,
|
||||
Verified: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("dry-run channel verified: %v", err)
|
||||
}
|
||||
if !dry.DryRun || channels.verifiedCalls != 0 || len(notifier.channels) != 0 {
|
||||
t.Fatalf("dry=%+v verifiedCalls=%d notified=%v, want no mutation", dry, channels.verifiedCalls, notifier.channels)
|
||||
}
|
||||
|
||||
req := SetChannelVerifiedRequest{
|
||||
CommandMeta: CommandMeta{CommandID: "exec-channel-verified", Actor: "ops", Reason: "official"},
|
||||
ChannelID: 2001,
|
||||
Verified: true,
|
||||
}
|
||||
exec, err := svc.SetChannelVerified(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("execute channel verified: %v", err)
|
||||
}
|
||||
if exec.Status != string(domain.AdminCommandCompleted) || channels.verifiedCalls != 1 || !channels.channels[2001].Verified || len(notifier.channels) != 1 {
|
||||
t.Fatalf("exec=%+v verifiedCalls=%d channel=%+v notified=%v", exec, channels.verifiedCalls, channels.channels[2001], notifier.channels)
|
||||
}
|
||||
if exec.TargetPeer.Type != domain.PeerTypeChannel || exec.TargetPeer.ID != 2001 || exec.TargetUserID != 0 {
|
||||
t.Fatalf("target user=%d peer=%+v, want channel target", exec.TargetUserID, exec.TargetPeer)
|
||||
}
|
||||
again, err := svc.SetChannelVerified(ctx, req)
|
||||
if err != nil {
|
||||
t.Fatalf("duplicate channel verified: %v", err)
|
||||
}
|
||||
if !again.AlreadyExecuted || channels.verifiedCalls != 1 || len(notifier.channels) != 1 {
|
||||
t.Fatalf("again=%+v verifiedCalls=%d notified=%v, want idempotent replay", again, channels.verifiedCalls, notifier.channels)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeletePrivateMessagesUsesMessageServiceAndIdempotency(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
repo := newMemoryCommandRepo()
|
||||
messages := &fakeMessagesService{
|
||||
byID: []domain.Message{
|
||||
{OwnerUserID: 1001, ID: 11, Peer: domain.Peer{Type: domain.PeerTypeUser, ID: 1002}},
|
||||
{OwnerUserID: 1001, ID: 12, Peer: domain.Peer{Type: domain.PeerTypeUser, ID: 1002}},
|
||||
},
|
||||
}
|
||||
svc := NewService(Dependencies{Commands: repo, Messages: messages, Now: fixedNow})
|
||||
req := DeletePrivateMessagesRequest{
|
||||
CommandMeta: CommandMeta{CommandID: "delete-1", Actor: "ops", Reason: "abuse"},
|
||||
OwnerUserID: 1001,
|
||||
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: 1002},
|
||||
IDs: []int{12, 11},
|
||||
Revoke: true,
|
||||
}
|
||||
|
||||
if _, err := svc.DeletePrivateMessages(ctx, req); err != nil {
|
||||
t.Fatalf("delete messages: %v", err)
|
||||
}
|
||||
if messages.deleteCalls != 1 || !reflect.DeepEqual(messages.lastDelete.IDs, []int{11, 12}) || !messages.lastDelete.Revoke {
|
||||
t.Fatalf("delete calls=%d req=%+v", messages.deleteCalls, messages.lastDelete)
|
||||
}
|
||||
if _, err := svc.DeletePrivateMessages(ctx, req); err != nil {
|
||||
t.Fatalf("duplicate delete messages: %v", err)
|
||||
}
|
||||
if messages.deleteCalls != 1 {
|
||||
t.Fatalf("duplicate delete calls=%d, want 1", messages.deleteCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeletePrivateMessagesRejectsMissingOnExecute(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
svc := NewService(Dependencies{Commands: newMemoryCommandRepo(), Messages: &fakeMessagesService{}, Now: fixedNow})
|
||||
_, err := svc.DeletePrivateMessages(ctx, DeletePrivateMessagesRequest{
|
||||
CommandMeta: CommandMeta{CommandID: "delete-missing", Actor: "ops", Reason: "test"},
|
||||
OwnerUserID: 1001,
|
||||
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: 1002},
|
||||
IDs: []int{99},
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("delete missing message err=nil, want error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRevokeSessionsSpecifiedClosesRevokedAuthKey(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
key := [8]byte{1, 2, 3}
|
||||
auth := &fakeAuthService{items: []domain.Authorization{
|
||||
{AuthKeyID: key, UserID: 1001, Hash: 555},
|
||||
}}
|
||||
revoker := &fakeRevoker{}
|
||||
svc := NewService(Dependencies{Commands: newMemoryCommandRepo(), Auth: auth, Revoker: revoker, Now: fixedNow})
|
||||
if _, err := svc.RevokeSessions(ctx, RevokeSessionsRequest{
|
||||
CommandMeta: CommandMeta{CommandID: "revoke-1", Actor: "ops", Reason: "lost device"},
|
||||
UserID: 1001,
|
||||
Hash: 555,
|
||||
}); err != nil {
|
||||
t.Fatalf("revoke sessions: %v", err)
|
||||
}
|
||||
if auth.resetHash != 555 || len(revoker.keys) != 1 || revoker.keys[0] != key {
|
||||
t.Fatalf("resetHash=%d revoked=%v", auth.resetHash, revoker.keys)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeletePrivateHistoryLoopsUntilOffsetClears(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
messages := &fakeMessagesService{historyOffsets: []int{1, 0}}
|
||||
svc := NewService(Dependencies{Commands: newMemoryCommandRepo(), Messages: messages, Now: fixedNow})
|
||||
res, err := svc.DeletePrivateHistory(ctx, DeletePrivateHistoryRequest{
|
||||
CommandMeta: CommandMeta{CommandID: "history-1", Actor: "ops", Reason: "clear"},
|
||||
OwnerUserID: 1001,
|
||||
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: 1002},
|
||||
MaxBatches: 5,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("delete history: %v", err)
|
||||
}
|
||||
if messages.historyCalls != 2 || res.Details["has_more"] != false {
|
||||
t.Fatalf("historyCalls=%d result=%+v", messages.historyCalls, res)
|
||||
}
|
||||
}
|
||||
|
||||
func fixedNow() time.Time {
|
||||
return time.Unix(1_700_000_000, 0).UTC()
|
||||
}
|
||||
|
||||
type memoryCommandRepo struct {
|
||||
items map[string]domain.AdminCommand
|
||||
}
|
||||
|
||||
func newMemoryCommandRepo() *memoryCommandRepo {
|
||||
return &memoryCommandRepo{items: map[string]domain.AdminCommand{}}
|
||||
}
|
||||
|
||||
func (m *memoryCommandRepo) BeginCommand(_ context.Context, cmd domain.AdminCommand) (domain.AdminCommand, bool, error) {
|
||||
if existing, ok := m.items[cmd.CommandID]; ok {
|
||||
return existing, false, nil
|
||||
}
|
||||
m.items[cmd.CommandID] = cmd
|
||||
return cmd, true, nil
|
||||
}
|
||||
|
||||
func (m *memoryCommandRepo) FinishCommand(_ context.Context, commandID string, status domain.AdminCommandStatus, resultJSON []byte, errorText string) (domain.AdminCommand, error) {
|
||||
cmd := m.items[commandID]
|
||||
cmd.Status = status
|
||||
cmd.ResultJSON = resultJSON
|
||||
cmd.Error = errorText
|
||||
m.items[commandID] = cmd
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
type fakeRestrictionStore struct {
|
||||
items map[int64]domain.AccountSendRestriction
|
||||
setCalls int
|
||||
}
|
||||
|
||||
func (f *fakeRestrictionStore) GetSendRestriction(_ context.Context, userID int64) (domain.AccountSendRestriction, bool, error) {
|
||||
if f.items == nil {
|
||||
return domain.AccountSendRestriction{}, false, nil
|
||||
}
|
||||
r, ok := f.items[userID]
|
||||
return r, ok, nil
|
||||
}
|
||||
|
||||
func (f *fakeRestrictionStore) SetSendRestriction(_ context.Context, r domain.AccountSendRestriction) (domain.AccountSendRestriction, error) {
|
||||
if f.items == nil {
|
||||
f.items = map[int64]domain.AccountSendRestriction{}
|
||||
}
|
||||
f.setCalls++
|
||||
r.UpdatedAt = fixedNow()
|
||||
f.items[r.UserID] = r
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (f *fakeRestrictionStore) IsSendFrozen(_ context.Context, userID int64) (bool, error) {
|
||||
if f.items == nil {
|
||||
return false, nil
|
||||
}
|
||||
return f.items[userID].Frozen, nil
|
||||
}
|
||||
|
||||
type fakeMessagesService struct {
|
||||
byID []domain.Message
|
||||
deleteCalls int
|
||||
lastDelete domain.DeleteMessagesRequest
|
||||
historyCalls int
|
||||
historyOffsets []int
|
||||
}
|
||||
|
||||
func (f *fakeMessagesService) GetMessages(_ context.Context, _ int64, _ []int) (domain.MessageList, error) {
|
||||
return domain.MessageList{Messages: f.byID}, nil
|
||||
}
|
||||
|
||||
func (f *fakeMessagesService) GetHistory(_ context.Context, _ int64, _ domain.MessageFilter) (domain.MessageList, error) {
|
||||
return domain.MessageList{Messages: []domain.Message{{ID: 1}}}, nil
|
||||
}
|
||||
|
||||
func (f *fakeMessagesService) DeleteMessages(_ context.Context, userID int64, req domain.DeleteMessagesRequest) (domain.DeleteMessagesResult, error) {
|
||||
f.deleteCalls++
|
||||
f.lastDelete = req
|
||||
return domain.DeleteMessagesResult{
|
||||
OwnerUserID: userID,
|
||||
Deleted: []domain.DeletedMessagesForUser{{
|
||||
UserID: userID,
|
||||
MessageIDs: req.IDs,
|
||||
Event: domain.UpdateEvent{Pts: 10, PtsCount: len(req.IDs)},
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *fakeMessagesService) DeleteHistory(_ context.Context, userID int64, _ domain.DeleteHistoryRequest) (domain.DeleteMessagesResult, error) {
|
||||
offset := 0
|
||||
if f.historyCalls < len(f.historyOffsets) {
|
||||
offset = f.historyOffsets[f.historyCalls]
|
||||
}
|
||||
f.historyCalls++
|
||||
return domain.DeleteMessagesResult{
|
||||
OwnerUserID: userID,
|
||||
Deleted: []domain.DeletedMessagesForUser{{
|
||||
UserID: userID,
|
||||
MessageIDs: []int{f.historyCalls},
|
||||
Event: domain.UpdateEvent{Pts: f.historyCalls, PtsCount: 1},
|
||||
}},
|
||||
Offset: offset,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type fakeAuthService struct {
|
||||
items []domain.Authorization
|
||||
resetHash int64
|
||||
}
|
||||
|
||||
func (f *fakeAuthService) ListAuthorizations(context.Context, int64) ([]domain.Authorization, error) {
|
||||
return f.items, nil
|
||||
}
|
||||
|
||||
func (f *fakeAuthService) ResetAuthorization(_ context.Context, _ int64, hash int64) (domain.Authorization, bool, error) {
|
||||
f.resetHash = hash
|
||||
for _, a := range f.items {
|
||||
if a.Hash == hash {
|
||||
return a, true, nil
|
||||
}
|
||||
}
|
||||
return domain.Authorization{}, false, nil
|
||||
}
|
||||
|
||||
func (f *fakeAuthService) ResetAuthorizations(_ context.Context, _ int64, keep [8]byte) ([]domain.Authorization, error) {
|
||||
out := make([]domain.Authorization, 0)
|
||||
for _, a := range f.items {
|
||||
if a.AuthKeyID != keep {
|
||||
out = append(out, a)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
type fakeRevoker struct {
|
||||
keys [][8]byte
|
||||
}
|
||||
|
||||
func (f *fakeRevoker) RevokeAuthorizationAuthKey(_ context.Context, key [8]byte, _ int64) error {
|
||||
f.keys = append(f.keys, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
type fakeUsersService struct {
|
||||
users map[int64]domain.User
|
||||
grantCalls int
|
||||
lastMonths int
|
||||
verifiedCalls int
|
||||
}
|
||||
|
||||
func (f *fakeUsersService) AdminUser(_ context.Context, userID int64) (domain.User, bool, error) {
|
||||
u, ok := f.users[userID]
|
||||
return u, ok, nil
|
||||
}
|
||||
|
||||
func (f *fakeUsersService) GrantPremium(_ context.Context, userID int64, months int) (domain.User, error) {
|
||||
f.grantCalls++
|
||||
f.lastMonths = months
|
||||
u, ok := f.users[userID]
|
||||
if !ok {
|
||||
return domain.User{}, domain.ErrUserNotFound
|
||||
}
|
||||
if u.Bot {
|
||||
return domain.User{}, domain.ErrPremiumBotUnsupported
|
||||
}
|
||||
if months <= 0 {
|
||||
u.PremiumUntil = 0
|
||||
} else {
|
||||
u.PremiumUntil = int(fixedNow().AddDate(0, months, 0).Unix())
|
||||
}
|
||||
f.users[userID] = u
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func (f *fakeUsersService) SetVerified(_ context.Context, userID int64, verified bool) (domain.User, error) {
|
||||
f.verifiedCalls++
|
||||
u, ok := f.users[userID]
|
||||
if !ok {
|
||||
return domain.User{}, domain.ErrUserNotFound
|
||||
}
|
||||
u.Verified = verified
|
||||
f.users[userID] = u
|
||||
return u, nil
|
||||
}
|
||||
|
||||
type fakeUserNotifier struct {
|
||||
users []int64
|
||||
}
|
||||
|
||||
func (f *fakeUserNotifier) NotifyUserChanged(_ context.Context, u domain.User) error {
|
||||
f.users = append(f.users, u.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
type fakeChannelsService struct {
|
||||
channels map[int64]domain.Channel
|
||||
verifiedCalls int
|
||||
}
|
||||
|
||||
func (f *fakeChannelsService) GetChannelByID(_ context.Context, channelID int64) (domain.Channel, error) {
|
||||
ch, ok := f.channels[channelID]
|
||||
if !ok {
|
||||
return domain.Channel{}, domain.ErrChannelInvalid
|
||||
}
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
func (f *fakeChannelsService) SetVerified(_ context.Context, channelID int64, verified bool) (domain.Channel, error) {
|
||||
f.verifiedCalls++
|
||||
ch, ok := f.channels[channelID]
|
||||
if !ok {
|
||||
return domain.Channel{}, domain.ErrChannelInvalid
|
||||
}
|
||||
ch.Verified = verified
|
||||
f.channels[channelID] = ch
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
type fakeChannelNotifier struct {
|
||||
channels []int64
|
||||
}
|
||||
|
||||
func (f *fakeChannelNotifier) NotifyChannelChanged(_ context.Context, ch domain.Channel) error {
|
||||
f.channels = append(f.channels, ch.ID)
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue