github.com/uriddle/docker@v0.0.0-20210926094723-4072e6aeb013/distribution/xfer/upload_test.go (about)

     1  package xfer
     2  
     3  import (
     4  	"errors"
     5  	"sync/atomic"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/docker/distribution/digest"
    10  	"github.com/docker/docker/layer"
    11  	"github.com/docker/docker/pkg/progress"
    12  	"golang.org/x/net/context"
    13  )
    14  
    15  const maxUploadConcurrency = 3
    16  
    17  type mockUploadDescriptor struct {
    18  	currentUploads  *int32
    19  	diffID          layer.DiffID
    20  	simulateRetries int
    21  }
    22  
    23  // Key returns the key used to deduplicate downloads.
    24  func (u *mockUploadDescriptor) Key() string {
    25  	return u.diffID.String()
    26  }
    27  
    28  // ID returns the ID for display purposes.
    29  func (u *mockUploadDescriptor) ID() string {
    30  	return u.diffID.String()
    31  }
    32  
    33  // DiffID should return the DiffID for this layer.
    34  func (u *mockUploadDescriptor) DiffID() layer.DiffID {
    35  	return u.diffID
    36  }
    37  
    38  // Upload is called to perform the upload.
    39  func (u *mockUploadDescriptor) Upload(ctx context.Context, progressOutput progress.Output) error {
    40  	if u.currentUploads != nil {
    41  		defer atomic.AddInt32(u.currentUploads, -1)
    42  
    43  		if atomic.AddInt32(u.currentUploads, 1) > maxUploadConcurrency {
    44  			return errors.New("concurrency limit exceeded")
    45  		}
    46  	}
    47  
    48  	// Sleep a bit to simulate a time-consuming upload.
    49  	for i := int64(0); i <= 10; i++ {
    50  		select {
    51  		case <-ctx.Done():
    52  			return ctx.Err()
    53  		case <-time.After(10 * time.Millisecond):
    54  			progressOutput.WriteProgress(progress.Progress{ID: u.ID(), Current: i, Total: 10})
    55  		}
    56  	}
    57  
    58  	if u.simulateRetries != 0 {
    59  		u.simulateRetries--
    60  		return errors.New("simulating retry")
    61  	}
    62  
    63  	return nil
    64  }
    65  
    66  func uploadDescriptors(currentUploads *int32) []UploadDescriptor {
    67  	return []UploadDescriptor{
    68  		&mockUploadDescriptor{currentUploads, layer.DiffID("sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf"), 0},
    69  		&mockUploadDescriptor{currentUploads, layer.DiffID("sha256:1515325234325236634634608943609283523908626098235490238423902343"), 0},
    70  		&mockUploadDescriptor{currentUploads, layer.DiffID("sha256:6929356290463485374960346430698374523437683470934634534953453453"), 0},
    71  		&mockUploadDescriptor{currentUploads, layer.DiffID("sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf"), 0},
    72  		&mockUploadDescriptor{currentUploads, layer.DiffID("sha256:8159352387436803946235346346368745389534789534897538734598734987"), 1},
    73  		&mockUploadDescriptor{currentUploads, layer.DiffID("sha256:4637863963478346897346987346987346789346789364879364897364987346"), 0},
    74  	}
    75  }
    76  
    77  var expectedDigests = map[layer.DiffID]digest.Digest{
    78  	layer.DiffID("sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf"): digest.Digest("sha256:c5095d6cf7ee42b7b064371dcc1dc3fb4af197f04d01a60009d484bd432724fc"),
    79  	layer.DiffID("sha256:1515325234325236634634608943609283523908626098235490238423902343"): digest.Digest("sha256:968cbfe2ff5269ea1729b3804767a1f57ffbc442d3bc86f47edbf7e688a4f36e"),
    80  	layer.DiffID("sha256:6929356290463485374960346430698374523437683470934634534953453453"): digest.Digest("sha256:8a5e56ab4b477a400470a7d5d4c1ca0c91235fd723ab19cc862636a06f3a735d"),
    81  	layer.DiffID("sha256:8159352387436803946235346346368745389534789534897538734598734987"): digest.Digest("sha256:5e733e5cd3688512fc240bd5c178e72671c9915947d17bb8451750d827944cb2"),
    82  	layer.DiffID("sha256:4637863963478346897346987346987346789346789364879364897364987346"): digest.Digest("sha256:ec4bb98d15e554a9f66c3ef9296cf46772c0ded3b1592bd8324d96e2f60f460c"),
    83  }
    84  
    85  func TestSuccessfulUpload(t *testing.T) {
    86  	lum := NewLayerUploadManager(maxUploadConcurrency)
    87  
    88  	progressChan := make(chan progress.Progress)
    89  	progressDone := make(chan struct{})
    90  	receivedProgress := make(map[string]int64)
    91  
    92  	go func() {
    93  		for p := range progressChan {
    94  			receivedProgress[p.ID] = p.Current
    95  		}
    96  		close(progressDone)
    97  	}()
    98  
    99  	var currentUploads int32
   100  	descriptors := uploadDescriptors(&currentUploads)
   101  
   102  	err := lum.Upload(context.Background(), descriptors, progress.ChanOutput(progressChan))
   103  	if err != nil {
   104  		t.Fatalf("upload error: %v", err)
   105  	}
   106  
   107  	close(progressChan)
   108  	<-progressDone
   109  }
   110  
   111  func TestCancelledUpload(t *testing.T) {
   112  	lum := NewLayerUploadManager(maxUploadConcurrency)
   113  
   114  	progressChan := make(chan progress.Progress)
   115  	progressDone := make(chan struct{})
   116  
   117  	go func() {
   118  		for range progressChan {
   119  		}
   120  		close(progressDone)
   121  	}()
   122  
   123  	ctx, cancel := context.WithCancel(context.Background())
   124  
   125  	go func() {
   126  		<-time.After(time.Millisecond)
   127  		cancel()
   128  	}()
   129  
   130  	descriptors := uploadDescriptors(nil)
   131  	err := lum.Upload(ctx, descriptors, progress.ChanOutput(progressChan))
   132  	if err != context.Canceled {
   133  		t.Fatal("expected upload to be cancelled")
   134  	}
   135  
   136  	close(progressChan)
   137  	<-progressDone
   138  }