feat: add chunked desktop client release uploads
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -213,9 +218,60 @@ func TestResolveDownloadURLResultUsesSignedDownloadURL(t *testing.T) {
|
||||
require.Empty(t, storage.publicURLCalls)
|
||||
}
|
||||
|
||||
func TestDesktopClientReleaseChunkedUploadCompletesOutOfOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
storage := &desktopReleaseDownloadURLStorage{
|
||||
existsByKey: map[string]bool{},
|
||||
objects: map[string][]byte{},
|
||||
}
|
||||
svc := NewDesktopClientReleaseService(nil, storage, nil).WithReleaseUploadDir(t.TempDir())
|
||||
content := bytes.Repeat([]byte("release-package-"), 1024*1024)
|
||||
sum := sha256.Sum256(content)
|
||||
wantSHA := hex.EncodeToString(sum[:])
|
||||
|
||||
initResult, err := svc.InitiateChunkedUpload(context.Background(), DesktopClientReleaseChunkedUploadInitInput{
|
||||
Platform: "darwin",
|
||||
Arch: "arm64",
|
||||
Channel: "stable",
|
||||
Version: "1.2.3",
|
||||
Kind: DesktopClientAssetKindInstaller,
|
||||
FileName: "client.dmg",
|
||||
FileSizeBytes: int64(len(content)),
|
||||
ChunkSizeBytes: 5 * 1024 * 1024,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 4, initResult.ChunkCount)
|
||||
|
||||
order := []int{2, 0, 3, 1}
|
||||
for _, index := range order {
|
||||
start := int64(index) * initResult.ChunkSizeBytes
|
||||
end := min(start+initResult.ChunkSizeBytes, int64(len(content)))
|
||||
result, err := svc.UploadChunk(context.Background(), DesktopClientReleaseChunkUploadInput{
|
||||
UploadID: initResult.UploadID,
|
||||
ChunkIndex: index,
|
||||
ContentReader: bytes.NewReader(content[start:end]),
|
||||
ContentSizeBytes: end - start,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, index, result.ChunkIndex)
|
||||
}
|
||||
|
||||
result, err := svc.CompleteChunkedUpload(context.Background(), initResult.UploadID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, wantSHA, result.SHA256)
|
||||
require.Equal(t, int64(len(content)), result.FileSizeBytes)
|
||||
require.Equal(t, "desktop-client/releases/blobs/"+wantSHA+".dmg", result.OSSObjectKey)
|
||||
require.Equal(t, content, storage.objects[result.OSSObjectKey])
|
||||
_, err = os.Stat(svc.desktopReleaseUploadSessionDir(initResult.UploadID))
|
||||
require.True(t, errors.Is(err, os.ErrNotExist))
|
||||
}
|
||||
|
||||
type desktopReleaseDownloadURLStorage struct {
|
||||
publicURLCalls []string
|
||||
downloadURLCalls []string
|
||||
existsByKey map[string]bool
|
||||
objects map[string][]byte
|
||||
}
|
||||
|
||||
func (s *desktopReleaseDownloadURLStorage) Validate() error {
|
||||
@@ -226,11 +282,30 @@ func (s *desktopReleaseDownloadURLStorage) PutBytes(context.Context, string, []b
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *desktopReleaseDownloadURLStorage) PutReader(_ context.Context, objectKey string, reader io.Reader, _ int64, _ string) error {
|
||||
if s.objects == nil {
|
||||
s.objects = map[string][]byte{}
|
||||
}
|
||||
content, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.objects[objectKey] = content
|
||||
if s.existsByKey == nil {
|
||||
s.existsByKey = map[string]bool{}
|
||||
}
|
||||
s.existsByKey[objectKey] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *desktopReleaseDownloadURLStorage) GetBytes(context.Context, string) ([]byte, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (s *desktopReleaseDownloadURLStorage) Exists(context.Context, string) (bool, error) {
|
||||
func (s *desktopReleaseDownloadURLStorage) Exists(_ context.Context, objectKey string) (bool, error) {
|
||||
if s.existsByKey != nil {
|
||||
return s.existsByKey[objectKey], nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user