177 lines
5.9 KiB
Go
177 lines
5.9 KiB
Go
package loadharness
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"path/filepath"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/iamxvbaba/td/tg"
|
|
)
|
|
|
|
func TestSeedPrimaryTargetsSelectsPrimaryAndRejectsGap(t *testing.T) {
|
|
manifest := &Manifest{Sessions: []SessionRecord{
|
|
{Index: 2, AccountIndex: 0, DeviceIndex: 1, SessionFile: "extra", UserID: 10, AccessHash: 100},
|
|
{Index: 0, AccountIndex: 0, DeviceIndex: 0, SessionFile: "primary-0", UserID: 10, AccessHash: 100},
|
|
{Index: 1, AccountIndex: 1, DeviceIndex: 0, SessionFile: "primary-1", UserID: 11, AccessHash: 101},
|
|
}}
|
|
targets, err := seedPrimaryTargets(manifest, 2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if targets[0].SessionFile != "primary-0" || targets[1].SessionFile != "primary-1" {
|
|
t.Fatalf("primary targets = %+v", targets)
|
|
}
|
|
manifest.Sessions = append(manifest.Sessions, SessionRecord{
|
|
Index: 3, AccountIndex: 2, DeviceIndex: 0, SessionFile: "primary-2", UserID: 12, AccessHash: 102,
|
|
})
|
|
if targets, err := seedPrimaryTargets(manifest, 2); err != nil || len(targets) != 2 {
|
|
t.Fatalf("manifest superset targets=%d err=%v", len(targets), err)
|
|
}
|
|
manifest.Sessions = manifest.Sessions[:2]
|
|
if _, err := seedPrimaryTargets(manifest, 2); err == nil {
|
|
t.Fatal("manifest account gap passed validation")
|
|
}
|
|
}
|
|
|
|
func TestPlanRichAccountStateUsesDeterministicPrivateAndGroupPeers(t *testing.T) {
|
|
dataset, _, _ := snapshotFixture(t)
|
|
plan, err := planRichAccountState(dataset, 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if plan.PinnedPeerAccount != 1 || plan.ReadPeerAccount != 3 || plan.ReadGroupPosition != 0 || plan.DraftMarker == "" {
|
|
t.Fatalf("rich plan = %+v", plan)
|
|
}
|
|
}
|
|
|
|
func TestValidateSeededRichDialogs(t *testing.T) {
|
|
dataset, seedState, targets := snapshotFixture(t)
|
|
seedState.RichStateByAccount = make([]bool, dataset.Config.Accounts)
|
|
seedState.RichStateByAccount[0] = true
|
|
plan, err := planRichAccountState(dataset, 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
dialogs := []ClientDialogState{
|
|
{PeerType: "user", PeerID: targets[plan.PinnedPeerAccount].UserID, Pinned: true, HasDraft: true, DraftText: plan.DraftMarker},
|
|
{PeerType: "user", PeerID: targets[plan.ReadPeerAccount].UserID, TopMessage: 8, ReadInboxMaxID: 8},
|
|
{PeerType: "channel", PeerID: seedState.Groups[plan.ReadGroupPosition].ChannelID, TopMessage: 9, ReadInboxMaxID: 9},
|
|
}
|
|
if err := validateSeededRichDialogs(dataset, seedState, targets, 0, dialogs, true); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
dialogs[0].DraftText = "wrong"
|
|
if err := validateSeededRichDialogs(dataset, seedState, targets, 0, dialogs, true); err == nil {
|
|
t.Fatal("wrong draft marker passed rich-state validation")
|
|
}
|
|
}
|
|
|
|
func TestCreatedChannelFromUpdates(t *testing.T) {
|
|
channel := &tg.Channel{ID: 41, AccessHash: 42, Title: "target", Megagroup: true}
|
|
got, err := createdChannelFromUpdates(&tg.Updates{Chats: []tg.ChatClass{
|
|
&tg.Chat{ID: 1, Title: "other"}, channel,
|
|
}}, "target")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != channel {
|
|
t.Fatalf("created channel = %#v, want target", got)
|
|
}
|
|
if _, err := createdChannelFromUpdates(&tg.UpdateShort{}, "target"); err == nil {
|
|
t.Fatal("unexpected create response passed validation")
|
|
}
|
|
if _, err := createdChannelFromUpdates(&tg.UpdatesCombined{Chats: []tg.ChatClass{
|
|
&tg.Channel{ID: 41, AccessHash: 42, Title: "target"},
|
|
}}, "target"); err == nil {
|
|
t.Fatal("broadcast/non-megagroup response passed validation")
|
|
}
|
|
}
|
|
|
|
func TestDatasetHistoryTasksRotateSenders(t *testing.T) {
|
|
cfg := DefaultDatasetConfig(20)
|
|
cfg.HotGroups, cfg.MediumGroups, cfg.HeavyGroups = 0, 0, 0
|
|
cfg.SmallGroups, cfg.SmallMembers, cfg.SmallHistory = 1, 4, 9
|
|
dataset, err := PlanDataset(cfg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tasks := datasetHistoryTasks(dataset)
|
|
wantCounts := datasetHistoryTaskCounts(dataset)
|
|
gotCounts := make([]int, len(tasks))
|
|
for account := range tasks {
|
|
gotCounts[account] = len(tasks[account])
|
|
for _, task := range tasks[account] {
|
|
group := dataset.Groups[task.GroupPosition]
|
|
if got := group.MemberAccounts[task.MessageIndex%len(group.MemberAccounts)]; got != account {
|
|
t.Fatalf("message %d sender = %d, task account %d", task.MessageIndex, got, account)
|
|
}
|
|
}
|
|
}
|
|
if !reflect.DeepEqual(gotCounts, wantCounts) {
|
|
t.Fatalf("history task counts = %v, want %v", gotCounts, wantCounts)
|
|
}
|
|
}
|
|
|
|
func TestSeedJournalPersistsPendingBoundaries(t *testing.T) {
|
|
dataset, err := PlanDataset(DefaultDatasetConfig(20))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
state, err := NewDatasetSeedState(dataset)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
path := filepath.Join(t.TempDir(), "seed-state.json")
|
|
journal := &seedJournal{path: path, dataset: dataset, state: state}
|
|
if err := journal.persist(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := journal.beginCreate(0); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
loaded, err := LoadDatasetSeedState(path, dataset)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !loaded.Groups[0].CreatePending || loaded.Groups[0].ChannelID != 0 {
|
|
t.Fatalf("pending create state = %+v", loaded.Groups[0])
|
|
}
|
|
if err := journal.commitChannel(0, 101, 202); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := journal.beginInvite(0, 7); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
loaded, err = LoadDatasetSeedState(path, dataset)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if loaded.Groups[0].InviteCursor != 0 || loaded.Groups[0].InvitePendingEnd != 7 {
|
|
t.Fatalf("pending invite state = %+v", loaded.Groups[0])
|
|
}
|
|
if err := journal.commitInvite(0, 7); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
loaded, err = LoadDatasetSeedState(path, dataset)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if loaded.Groups[0].InviteCursor != 7 || loaded.Groups[0].InvitePendingEnd != 7 {
|
|
t.Fatalf("committed invite state = %+v", loaded.Groups[0])
|
|
}
|
|
}
|
|
|
|
func TestRunSeedAccountPhaseStopsAfterFailure(t *testing.T) {
|
|
want := errors.New("stop")
|
|
err := runSeedAccountPhase(context.Background(), "test", []int{0, 1, 2}, 1, nil, func(_ context.Context, account int) error {
|
|
if account == 1 {
|
|
return want
|
|
}
|
|
return nil
|
|
})
|
|
if !errors.Is(err, want) {
|
|
t.Fatalf("phase error = %v, want wrapped stop", err)
|
|
}
|
|
}
|