move gotd fork into repo. (#111)
- update to latest telegram layer - remove some references to fields in tg.Entities that don't exist in the schema - originally added here: https://github.com/beeper/td/commit/820929062a2ba0104397bc01235ab58a9cff780e - referenced here - https://github.com/mautrix/telegramgo/commit/124f0967ed195b5a380c9bd02e170ada9710dde3 - https://github.com/mautrix/telegramgo/commit/4205047aab2e0639217148b5d125bfaab668bd8e
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
package uploader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
|
||||
"github.com/go-faster/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/syncio"
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/telegram/uploader/source"
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/testutil"
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
|
||||
)
|
||||
|
||||
type mockClient struct {
|
||||
err bool
|
||||
|
||||
// Upload state.
|
||||
buf *syncio.BufWriterAt
|
||||
parts []atomic.Int64
|
||||
|
||||
partSize int
|
||||
partSizeMux sync.Mutex
|
||||
}
|
||||
|
||||
func newMockClient(err bool) *mockClient {
|
||||
return &mockClient{
|
||||
err: err,
|
||||
buf: &syncio.BufWriterAt{},
|
||||
parts: make([]atomic.Int64, partsLimit+1),
|
||||
}
|
||||
}
|
||||
|
||||
var testErr = testutil.TestError()
|
||||
|
||||
func (m *mockClient) write(part int, data []byte) error {
|
||||
m.partSizeMux.Lock()
|
||||
if m.partSize == 0 {
|
||||
m.partSize = len(data)
|
||||
} else if m.partSize != len(data) {
|
||||
m.partSizeMux.Unlock()
|
||||
|
||||
return errors.Errorf(
|
||||
"invalid part size, expected %d, got %d",
|
||||
m.partSize, len(data),
|
||||
)
|
||||
}
|
||||
partSize := m.partSize
|
||||
m.partSizeMux.Unlock()
|
||||
|
||||
// Every part have ID which is offset in partSize from start of file.
|
||||
// But maximal ID is 3999, so part ID for big files can overflow.
|
||||
// We use parts array to count received parts by ID to compute the offset.
|
||||
rangeOffset := int(m.parts[part].Inc() - 1)
|
||||
|
||||
// If rangeOffset is zero, so offset will be zero, part ID received first time.
|
||||
// Otherwise, we count next range offset.
|
||||
offset := rangeOffset * partsLimit * partSize
|
||||
_, err := m.buf.WriteAt(data, int64(part*partSize+offset))
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *mockClient) UploadSaveFilePart(ctx context.Context, request *tg.UploadSaveFilePartRequest) (bool, error) {
|
||||
if m.err {
|
||||
return false, testErr
|
||||
}
|
||||
|
||||
if err := m.write(request.FilePart, request.Bytes); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (m *mockClient) UploadSaveBigFilePart(ctx context.Context, request *tg.UploadSaveBigFilePartRequest) (bool, error) {
|
||||
if m.err {
|
||||
return false, testErr
|
||||
}
|
||||
|
||||
if err := m.write(request.FilePart, request.Bytes); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
type mockSource struct {
|
||||
name string
|
||||
data *bytes.Reader
|
||||
}
|
||||
|
||||
func (m mockSource) Open(ctx context.Context, u *url.URL) (source.RemoteFile, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m mockSource) Read(p []byte) (n int, err error) {
|
||||
return m.data.Read(p)
|
||||
}
|
||||
|
||||
func (m mockSource) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m mockSource) Name() string {
|
||||
return m.name
|
||||
}
|
||||
|
||||
func (m mockSource) Size() int64 {
|
||||
return m.data.Size()
|
||||
}
|
||||
|
||||
func TestUploader(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
testData := make([]byte, 15*1024*1024)
|
||||
if _, err := io.ReadFull(rand.Reader, testData); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
data []byte
|
||||
err bool
|
||||
}{
|
||||
{"5b", []byte{1, 2, 3, 4, 5}, false},
|
||||
{strconv.Itoa(defaultPartSize) + "b", bytes.Repeat([]byte{1}, defaultPartSize), false},
|
||||
{strconv.Itoa(len(testData)) + "b", testData, false},
|
||||
{"Error", []byte{1, 2, 3, 4, 5}, true},
|
||||
}
|
||||
|
||||
ways := []struct {
|
||||
name string
|
||||
action func(b *Uploader, data []byte) error
|
||||
}{
|
||||
{"FromReader", func(b *Uploader, data []byte) error {
|
||||
if len(data) == len(testData) {
|
||||
b = b.WithPartSize(16384)
|
||||
}
|
||||
_, err := b.FromReader(ctx, "10.jpg", bytes.NewReader(data))
|
||||
return err
|
||||
}},
|
||||
{"FromBytes", func(b *Uploader, data []byte) error {
|
||||
if len(data) == len(testData) {
|
||||
b = b.WithPartSize(MaximumPartSize)
|
||||
}
|
||||
|
||||
_, err := b.FromBytes(ctx, "10.jpg", data)
|
||||
return err
|
||||
}},
|
||||
{"FromFS", func(b *Uploader, data []byte) error {
|
||||
if len(data) == len(testData) {
|
||||
b = b.WithPartSize(MaximumPartSize)
|
||||
}
|
||||
|
||||
_, err := b.FromFS(ctx, fstest.MapFS{
|
||||
"10.jpg": &fstest.MapFile{
|
||||
Data: data,
|
||||
},
|
||||
}, "10.jpg", "")
|
||||
return err
|
||||
}},
|
||||
{"FromURL", func(b *Uploader, data []byte) error {
|
||||
if len(data) == len(testData) {
|
||||
b = b.WithPartSize(MaximumPartSize)
|
||||
}
|
||||
b = b.WithSource(mockSource{
|
||||
name: "img.jpg",
|
||||
data: bytes.NewReader(data),
|
||||
})
|
||||
|
||||
_, err := b.FromURL(ctx, "http://example.com")
|
||||
return err
|
||||
}},
|
||||
}
|
||||
|
||||
options := []struct {
|
||||
name string
|
||||
action func(b *Uploader) *Uploader
|
||||
}{
|
||||
{"OneThread", func(b *Uploader) *Uploader {
|
||||
return b.WithThreads(1)
|
||||
}},
|
||||
{"ManyThread", func(b *Uploader) *Uploader {
|
||||
return b.WithThreads(runtime.GOMAXPROCS(0))
|
||||
}},
|
||||
}
|
||||
|
||||
for _, way := range ways {
|
||||
t.Run(way.name, func(t *testing.T) {
|
||||
for _, option := range options {
|
||||
t.Run(option.name, func(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
client := newMockClient(test.err)
|
||||
u := NewUploader(client)
|
||||
|
||||
err := way.action(option.action(u), test.data)
|
||||
if test.err {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Truef(
|
||||
t, bytes.Equal(test.data, client.buf.Bytes()),
|
||||
"expected uploaded and given equal",
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user