package mtproto import ( "context" "crypto/rand" "io" "testing" "time" "github.com/stretchr/testify/require" "go.uber.org/zap" "github.com/gotd/neo" "go.mau.fi/mautrix-telegram/pkg/gotd/bin" "go.mau.fi/mautrix-telegram/pkg/gotd/crypto" "go.mau.fi/mautrix-telegram/pkg/gotd/proto" "go.mau.fi/mautrix-telegram/pkg/gotd/tdsync" "go.mau.fi/mautrix-telegram/pkg/gotd/testutil" ) func TestCheckMessageID(t *testing.T) { now := testutil.Date() t.Run("Good", func(t *testing.T) { for _, good := range []proto.MessageID{ proto.NewMessageID(now, proto.MessageFromServer), proto.NewMessageID(now, proto.MessageServerResponse), proto.NewMessageID(now.Add(time.Second*29), proto.MessageFromServer), proto.NewMessageID(now.Add(-time.Second*299), proto.MessageFromServer), } { t.Run(good.String(), func(t *testing.T) { require.NoError(t, checkMessageID(now, int64(good))) }) } }) t.Run("Bad", func(t *testing.T) { for _, bad := range []proto.MessageID{ proto.NewMessageID(now, proto.MessageFromClient), proto.NewMessageID(now.Add(time.Second*31), proto.MessageFromServer), proto.NewMessageID(now.Add(-time.Second*301), proto.MessageFromServer), proto.NewMessageID(time.Time{}, proto.MessageFromServer), proto.NewMessageID(now.AddDate(-10, 0, 0), proto.MessageServerResponse), proto.NewMessageID(time.Time{}, proto.MessageFromClient), } { t.Run(bad.String(), func(t *testing.T) { require.ErrorIs(t, checkMessageID(now, int64(bad)), errRejected) }) } }) } func benchRead(payloadSize int) func(b *testing.B) { return func(b *testing.B) { a := require.New(b) logger := zap.NewNop() random := rand.Reader c := neo.NewTime(time.Now()) var key crypto.Key _, err := io.ReadFull(random, key[:]) a.NoError(err) authKey := key.WithID() payload := make([]byte, payloadSize) _, err = io.ReadFull(random, payload) a.NoError(err) msg := new(bin.Buffer) serverCipher := crypto.NewServerCipher(random) id := proto.NewMessageIDGen(c.Now).New(proto.MessageServerResponse) a.NoError(msg.Encode(&testPayload{ Data: payload, })) length := msg.Len() data := msg.Copy() a.NoError(serverCipher.Encrypt(authKey, crypto.EncryptedMessageData{ MessageID: id, SeqNo: 0, MessageDataLen: int32(length), MessageDataWithPadding: data, }, msg)) ctx, cancel := context.WithCancel(context.Background()) defer cancel() conn := Conn{ conn: &constantConn{ data: msg.Raw(), cancel: cancel, counter: b.N, }, handler: nopHandler{}, clock: c, rand: random, cipher: crypto.NewClientCipher(random), log: logger, messageIDBuf: noopBuf{}, authKey: authKey, compressThreshold: -1, } grp := tdsync.NewCancellableGroup(ctx) b.ResetTimer() b.ReportAllocs() b.SetBytes(int64(payloadSize)) grp.Go(conn.readLoop) a.ErrorIs(grp.Wait(), context.Canceled) } } func BenchmarkRead(b *testing.B) { testutil.RunPayloads(b, benchRead) }