github.com/uber/kraken@v0.1.4/lib/torrent/scheduler/dispatch/piecerequest/manager_test.go (about)

     1  // Copyright (c) 2016-2019 Uber Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  package piecerequest
    15  
    16  import (
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/andres-erbsen/clock"
    21  	"github.com/stretchr/testify/require"
    22  
    23  	"github.com/uber/kraken/core"
    24  	"github.com/uber/kraken/utils/bitsetutil"
    25  	"github.com/uber/kraken/utils/syncutil"
    26  )
    27  
    28  func newManager(
    29  	clk clock.Clock,
    30  	timeout time.Duration,
    31  	policy string,
    32  	pipelineLimit int) *Manager {
    33  
    34  	m, err := NewManager(clk, timeout, policy, pipelineLimit)
    35  	if err != nil {
    36  		panic(err)
    37  	}
    38  	return m
    39  }
    40  
    41  func countsFromInts(priorities ...int) syncutil.Counters {
    42  	c := syncutil.NewCounters(len(priorities))
    43  	for i, p := range priorities {
    44  		c.Set(i, p)
    45  	}
    46  
    47  	return c
    48  }
    49  
    50  func TestManagerPipelineLimit(t *testing.T) {
    51  	require := require.New(t)
    52  
    53  	m := newManager(clock.NewMock(), 5*time.Second, DefaultPolicy, 3)
    54  
    55  	peerID := core.PeerIDFixture()
    56  
    57  	pieces, err := m.ReservePieces(peerID, bitsetutil.FromBools(true, true, true, true),
    58  		countsFromInts(0, 0, 0, 0), false)
    59  	require.NoError(err)
    60  	require.Len(pieces, 3)
    61  
    62  	require.Len(m.PendingPieces(peerID), 3)
    63  }
    64  
    65  func TestManagerReserveExpiredRequest(t *testing.T) {
    66  	require := require.New(t)
    67  
    68  	clk := clock.NewMock()
    69  	timeout := 5 * time.Second
    70  
    71  	m := newManager(clk, timeout, DefaultPolicy, 1)
    72  
    73  	peerID := core.PeerIDFixture()
    74  
    75  	pieces, err := m.ReservePieces(peerID, bitsetutil.FromBools(true),
    76  		countsFromInts(0), false)
    77  	require.NoError(err)
    78  	require.Equal([]int{0}, pieces)
    79  
    80  	// Further reservations fail.
    81  	pieces, err = m.ReservePieces(peerID, bitsetutil.FromBools(true),
    82  		countsFromInts(0), false)
    83  	require.NoError(err)
    84  	require.Empty(pieces)
    85  
    86  	pieces, err = m.ReservePieces(core.PeerIDFixture(), bitsetutil.FromBools(true),
    87  		countsFromInts(0), false)
    88  	require.NoError(err)
    89  	require.Empty(pieces)
    90  
    91  	clk.Add(timeout + 1)
    92  
    93  	pieces, err = m.ReservePieces(peerID, bitsetutil.FromBools(true),
    94  		countsFromInts(0), false)
    95  	require.NoError(err)
    96  	require.Equal([]int{0}, pieces)
    97  }
    98  
    99  func TestManagerReserveUnsentRequest(t *testing.T) {
   100  	require := require.New(t)
   101  
   102  	m := newManager(clock.NewMock(), 5*time.Second, DefaultPolicy, 1)
   103  
   104  	peerID := core.PeerIDFixture()
   105  
   106  	pieces, err := m.ReservePieces(peerID, bitsetutil.FromBools(true),
   107  		countsFromInts(0), false)
   108  	require.NoError(err)
   109  	require.Equal([]int{0}, pieces)
   110  
   111  	// Further reservations fail.
   112  	pieces, err = m.ReservePieces(peerID, bitsetutil.FromBools(true),
   113  		countsFromInts(0), false)
   114  	require.NoError(err)
   115  	require.Empty(pieces)
   116  
   117  	pieces, err = m.ReservePieces(core.PeerIDFixture(), bitsetutil.FromBools(true),
   118  		countsFromInts(0), false)
   119  	require.NoError(err)
   120  	require.Empty(pieces)
   121  
   122  	m.MarkUnsent(peerID, 0)
   123  
   124  	pieces, err = m.ReservePieces(peerID, bitsetutil.FromBools(true),
   125  		countsFromInts(0), false)
   126  	require.NoError(err)
   127  	require.Equal([]int{0}, pieces)
   128  }
   129  
   130  func TestManagerReserveInvalidRequest(t *testing.T) {
   131  	require := require.New(t)
   132  
   133  	m := newManager(clock.NewMock(), 5*time.Second, DefaultPolicy, 1)
   134  
   135  	peerID := core.PeerIDFixture()
   136  
   137  	pieces, err := m.ReservePieces(peerID, bitsetutil.FromBools(true),
   138  		countsFromInts(0), false)
   139  	require.NoError(err)
   140  	require.Equal([]int{0}, pieces)
   141  
   142  	// Further reservations fail.
   143  	pieces, err = m.ReservePieces(peerID, bitsetutil.FromBools(true),
   144  		countsFromInts(0), false)
   145  	require.NoError(err)
   146  	require.Empty(pieces)
   147  
   148  	pieces, err = m.ReservePieces(core.PeerIDFixture(), bitsetutil.FromBools(true),
   149  		countsFromInts(0), false)
   150  	require.NoError(err)
   151  	require.Empty(pieces)
   152  
   153  	m.MarkInvalid(peerID, 0)
   154  
   155  	pieces, err = m.ReservePieces(peerID, bitsetutil.FromBools(true),
   156  		countsFromInts(0), false)
   157  	require.NoError(err)
   158  	require.Equal([]int{0}, pieces)
   159  }
   160  
   161  func TestManagerGetFailedRequests(t *testing.T) {
   162  	require := require.New(t)
   163  
   164  	clk := clock.NewMock()
   165  	timeout := 5 * time.Second
   166  
   167  	m := newManager(clk, timeout, RarestFirstPolicy, 1)
   168  
   169  	p0 := core.PeerIDFixture()
   170  	p1 := core.PeerIDFixture()
   171  	p2 := core.PeerIDFixture()
   172  
   173  	pieces, err := m.ReservePieces(p0, bitsetutil.FromBools(true, true, true),
   174  		countsFromInts(0, 1, 2), false)
   175  	require.NoError(err)
   176  	require.Equal([]int{0}, pieces)
   177  
   178  	pieces, err = m.ReservePieces(p1, bitsetutil.FromBools(false, true, false),
   179  		countsFromInts(0, 1, 2), false)
   180  	require.NoError(err)
   181  	require.Equal([]int{1}, pieces)
   182  
   183  	pieces, err = m.ReservePieces(p2, bitsetutil.FromBools(false, false, true),
   184  		countsFromInts(0, 1, 2), false)
   185  	require.NoError(err)
   186  	require.Equal([]int{2}, pieces)
   187  
   188  	m.MarkUnsent(p0, 0)
   189  	m.MarkInvalid(p1, 1)
   190  	clk.Add(timeout + 1) // Expires p2's request.
   191  
   192  	p3 := core.PeerIDFixture()
   193  	pieces, err = m.ReservePieces(p3, bitsetutil.FromBools(false, false, false, true),
   194  		countsFromInts(0, 0, 0, 0), false)
   195  	require.NoError(err)
   196  	require.Equal([]int{3}, pieces)
   197  
   198  	failed := m.GetFailedRequests()
   199  
   200  	require.Len(failed, 3)
   201  	require.Contains(failed, Request{Piece: 0, PeerID: p0, Status: StatusUnsent})
   202  	require.Contains(failed, Request{Piece: 1, PeerID: p1, Status: StatusInvalid})
   203  	require.Contains(failed, Request{Piece: 2, PeerID: p2, Status: StatusExpired})
   204  }
   205  
   206  func TestManagerClear(t *testing.T) {
   207  	require := require.New(t)
   208  
   209  	m := newManager(clock.NewMock(), 5*time.Second, DefaultPolicy, 1)
   210  
   211  	peerID := core.PeerIDFixture()
   212  
   213  	pieces, err := m.ReservePieces(peerID, bitsetutil.FromBools(true),
   214  		countsFromInts(0), false)
   215  	require.NoError(err)
   216  	require.Equal([]int{0}, pieces)
   217  
   218  	require.Len(m.PendingPieces(peerID), 1)
   219  
   220  	m.Clear(0)
   221  
   222  	require.Empty(m.PendingPieces(peerID))
   223  }
   224  
   225  func TestManagerClearPeer(t *testing.T) {
   226  	require := require.New(t)
   227  
   228  	m := newManager(clock.NewMock(), 5*time.Second, DefaultPolicy, 1)
   229  
   230  	p1 := core.PeerIDFixture()
   231  	p2 := core.PeerIDFixture()
   232  
   233  	pieces, err := m.ReservePieces(p1, bitsetutil.FromBools(true),
   234  		countsFromInts(0), false)
   235  	require.NoError(err)
   236  	require.Equal([]int{0}, pieces)
   237  
   238  	pieces, err = m.ReservePieces(p1, bitsetutil.FromBools(true, true),
   239  		countsFromInts(0, 1), false)
   240  	require.NoError(err)
   241  	require.Empty(pieces)
   242  
   243  	pieces, err = m.ReservePieces(p2, bitsetutil.FromBools(true, true),
   244  		countsFromInts(0, 1), false)
   245  	require.NoError(err)
   246  	require.Equal([]int{1}, pieces)
   247  
   248  	m.ClearPeer(p1)
   249  
   250  	require.Empty(m.PendingPieces(p1))
   251  	require.Equal([]int{1}, m.PendingPieces(p2))
   252  }
   253  
   254  func TestManagerReservePiecesAllowDuplicate(t *testing.T) {
   255  	require := require.New(t)
   256  
   257  	m := newManager(clock.NewMock(), 5*time.Second, DefaultPolicy, 2)
   258  
   259  	p1 := core.PeerIDFixture()
   260  	p2 := core.PeerIDFixture()
   261  
   262  	pieces, err := m.ReservePieces(p1, bitsetutil.FromBools(true),
   263  		countsFromInts(0), true)
   264  	require.NoError(err)
   265  	require.Equal([]int{0}, pieces)
   266  
   267  	// Shouldn't allow duplicates on the same peer.
   268  	pieces, err = m.ReservePieces(p1, bitsetutil.FromBools(true),
   269  		countsFromInts(0), true)
   270  	require.NoError(err)
   271  	require.Empty(pieces)
   272  
   273  	// Should allow duplicates for different peers.
   274  	pieces, err = m.ReservePieces(p2, bitsetutil.FromBools(true),
   275  		countsFromInts(0), true)
   276  	require.NoError(err)
   277  	require.Equal([]int{0}, pieces)
   278  }
   279  
   280  func TestManagerClearWhenAllowedDuplicates(t *testing.T) {
   281  	require := require.New(t)
   282  
   283  	m := newManager(clock.NewMock(), 5*time.Second, DefaultPolicy, 2)
   284  
   285  	p1 := core.PeerIDFixture()
   286  	p2 := core.PeerIDFixture()
   287  
   288  	pieces, err := m.ReservePieces(p1, bitsetutil.FromBools(true, true),
   289  		countsFromInts(0, 0), true)
   290  	require.NoError(err)
   291  	require.Equal([]int{0, 1}, pieces)
   292  
   293  	pieces, err = m.ReservePieces(p2, bitsetutil.FromBools(true, true),
   294  		countsFromInts(0, 0), true)
   295  	require.NoError(err)
   296  	require.Equal([]int{0, 1}, pieces)
   297  
   298  	m.Clear(0)
   299  
   300  	require.Equal([]int{1}, m.PendingPieces(p1))
   301  	require.Equal([]int{1}, m.PendingPieces(p2))
   302  }
   303  
   304  func TestManagerClearPeerWhenAllowedDuplicates(t *testing.T) {
   305  	require := require.New(t)
   306  
   307  	m := newManager(clock.NewMock(), 5*time.Second, DefaultPolicy, 2)
   308  
   309  	p1 := core.PeerIDFixture()
   310  	p2 := core.PeerIDFixture()
   311  
   312  	pieces, err := m.ReservePieces(p1, bitsetutil.FromBools(true, true),
   313  		countsFromInts(0, 0), true)
   314  	require.NoError(err)
   315  	require.Equal([]int{0, 1}, pieces)
   316  
   317  	pieces, err = m.ReservePieces(p2, bitsetutil.FromBools(true, true),
   318  		countsFromInts(0, 0), true)
   319  	require.NoError(err)
   320  	require.Equal([]int{0, 1}, pieces)
   321  
   322  	m.ClearPeer(p1)
   323  
   324  	require.Empty(m.PendingPieces(p1))
   325  	require.Equal([]int{0, 1}, m.PendingPieces(p2))
   326  }
   327  
   328  func TestManagerMarkStatusWhenAllowedDuplicates(t *testing.T) {
   329  	tests := []struct {
   330  		desc string
   331  		mark func(*Manager, core.PeerID, int)
   332  	}{
   333  		{
   334  			"mark unsent",
   335  			func(m *Manager, p core.PeerID, i int) { m.MarkUnsent(p, i) },
   336  		}, {
   337  			"mark invalid",
   338  			func(m *Manager, p core.PeerID, i int) { m.MarkInvalid(p, i) },
   339  		},
   340  	}
   341  	for _, test := range tests {
   342  		t.Run(test.desc, func(t *testing.T) {
   343  			require := require.New(t)
   344  
   345  			m := newManager(clock.NewMock(), 5*time.Second, DefaultPolicy, 2)
   346  
   347  			p1 := core.PeerIDFixture()
   348  			p2 := core.PeerIDFixture()
   349  
   350  			pieces, err := m.ReservePieces(p1, bitsetutil.FromBools(true, true),
   351  				countsFromInts(0, 0), true)
   352  			require.NoError(err)
   353  			require.Equal([]int{0, 1}, pieces)
   354  
   355  			pieces, err = m.ReservePieces(p2, bitsetutil.FromBools(true, true),
   356  				countsFromInts(0, 0), true)
   357  			require.NoError(err)
   358  			require.Equal([]int{0, 1}, pieces)
   359  
   360  			test.mark(m, p1, 0)
   361  
   362  			require.Equal([]int{1}, m.PendingPieces(p1))
   363  			require.Equal([]int{0, 1}, m.PendingPieces(p2))
   364  		})
   365  	}
   366  }
   367  
   368  func TestRarestFirstPolicy(t *testing.T) {
   369  	require := require.New(t)
   370  
   371  	m := newManager(clock.NewMock(), 5*time.Second, RarestFirstPolicy, 2)
   372  
   373  	p1 := core.PeerIDFixture()
   374  	p2 := core.PeerIDFixture()
   375  	p3 := core.PeerIDFixture()
   376  
   377  	pieces, err := m.ReservePieces(p1, bitsetutil.FromBools(true, true, false, true),
   378  		countsFromInts(2, 3, 1, 0), false)
   379  	require.NoError(err)
   380  	require.Equal([]int{3, 0}, pieces)
   381  
   382  	pieces, err = m.ReservePieces(p2, bitsetutil.FromBools(true, true, false, true),
   383  		countsFromInts(2, 3, 1, 0), false)
   384  	require.NoError(err)
   385  	require.Equal([]int{1}, pieces)
   386  
   387  	pieces, err = m.ReservePieces(p3, bitsetutil.FromBools(true, true, false, true),
   388  		countsFromInts(2, 3, 1, 0), false)
   389  	require.NoError(err)
   390  	require.Empty(pieces)
   391  
   392  	pieces, err = m.ReservePieces(p1, bitsetutil.FromBools(true, true, false, true),
   393  		countsFromInts(2, 3, 1, 0), false)
   394  	require.NoError(err)
   395  	require.Empty(pieces)
   396  
   397  	m.MarkUnsent(p1, 3)
   398  	pieces, err = m.ReservePieces(p2, bitsetutil.FromBools(true, true, false, true),
   399  		countsFromInts(2, 3, 1, 0), false)
   400  	require.NoError(err)
   401  	require.Equal([]int{3}, pieces)
   402  
   403  	m.MarkUnsent(p1, 0)
   404  	pieces, err = m.ReservePieces(p2, bitsetutil.FromBools(true, true, false, true),
   405  		countsFromInts(2, 3, 1, 0), false)
   406  	require.NoError(err)
   407  	require.Empty(pieces)
   408  }