github.phpd.cn/cilium/cilium@v1.6.12/pkg/idpool/idpool_test.go (about)

     1  // Copyright 2018 Authors of Cilium
     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  
    15  // +build !privileged_tests
    16  
    17  package idpool
    18  
    19  import (
    20  	"sort"
    21  	"sync"
    22  	"testing"
    23  
    24  	"github.com/cilium/cilium/pkg/checker"
    25  
    26  	. "gopkg.in/check.v1"
    27  )
    28  
    29  func Test(t *testing.T) {
    30  	TestingT(t)
    31  }
    32  
    33  type IDPoolTestSuite struct{}
    34  
    35  var _ = Suite(&IDPoolTestSuite{})
    36  
    37  func (s *IDPoolTestSuite) TestLeaseAvailableID(c *C) {
    38  	minID, maxID := 1, 5
    39  	p := NewIDPool(ID(minID), ID(maxID))
    40  
    41  	leaseAllIDs(p, minID, maxID, c)
    42  }
    43  
    44  func (s *IDPoolTestSuite) TestInsertIDs(c *C) {
    45  	minID, maxID := 2, 6
    46  	p := NewIDPool(ID(minID), ID(maxID))
    47  
    48  	// Insert IDs beyond minID, maxID range.
    49  	for i := minID - 1; i <= maxID+1; i++ {
    50  		c.Assert(p.Insert(ID(i)), Equals, i < minID || i > maxID)
    51  		c.Assert(p.Insert(ID(i)), Equals, false)
    52  	}
    53  
    54  	leaseAllIDs(p, minID-1, maxID+1, c)
    55  }
    56  
    57  func (s *IDPoolTestSuite) TestInsertRemoveIDs(c *C) {
    58  	minID, maxID := 1, 5
    59  	p := NewIDPool(ID(minID), ID(maxID))
    60  
    61  	// Remove all IDs.
    62  	for i := minID; i <= maxID; i++ {
    63  		c.Assert(p.Remove(ID(i)), Equals, true)
    64  		c.Assert(p.Remove(ID(i)), Equals, false)
    65  	}
    66  	// We should be out of IDs.
    67  	id := p.LeaseAvailableID()
    68  	c.Assert(id, Equals, NoID)
    69  
    70  	// Re-insert all IDs.
    71  	for i := minID; i <= maxID; i++ {
    72  		c.Assert(p.Insert(ID(i)), Equals, true)
    73  		c.Assert(p.Insert(ID(i)), Equals, false)
    74  	}
    75  
    76  	// Remove odd-numbered IDs.
    77  	for i := minID; i <= maxID; i++ {
    78  		if i%2 != 0 {
    79  			c.Assert(p.Remove(ID(i)), Equals, true)
    80  		}
    81  	}
    82  
    83  	// Only even-numbered IDs should be left.
    84  	evenIDs := make([]int, 0)
    85  	actualIDs := make([]int, 0)
    86  	for i := minID; i <= maxID; i++ {
    87  		if i%2 == 0 {
    88  			id := p.LeaseAvailableID()
    89  			c.Assert(id, Not(Equals), NoID)
    90  			actualIDs = append(actualIDs, int(id))
    91  			evenIDs = append(evenIDs, i)
    92  		}
    93  	}
    94  	// We should be out of IDs.
    95  	id = p.LeaseAvailableID()
    96  	c.Assert(id, Equals, NoID)
    97  
    98  	sort.Ints(actualIDs)
    99  	c.Assert(actualIDs, checker.DeepEquals, evenIDs)
   100  }
   101  
   102  func (s *IDPoolTestSuite) TestReleaseID(c *C) {
   103  	minID, maxID := 1, 5
   104  	p := NewIDPool(ID(minID), ID(maxID))
   105  
   106  	// Lease all ids and release them.
   107  	for i := minID; i <= maxID; i++ {
   108  		id := p.LeaseAvailableID()
   109  		c.Assert(id, Not(Equals), NoID)
   110  	}
   111  	// We should be out of IDs.
   112  	id := p.LeaseAvailableID()
   113  	c.Assert(id, Equals, NoID)
   114  
   115  	for i := minID; i <= maxID; i++ {
   116  		c.Assert(p.Release(ID(i)), Equals, true)
   117  		c.Assert(p.Release(ID(i)), Equals, false)
   118  	}
   119  
   120  	// Lease all ids. This time, remove them before
   121  	// releasing them.
   122  	leaseAllIDs(p, minID, maxID, c)
   123  	for i := minID; i <= maxID; i++ {
   124  		c.Assert(p.Remove(ID(i)), Equals, false)
   125  	}
   126  	// Release should not have any effect.
   127  	for i := minID; i <= maxID; i++ {
   128  		c.Assert(p.Release(ID(i)), Equals, false)
   129  	}
   130  }
   131  
   132  func (s *IDPoolTestSuite) TestOperationsOnAvailableIDs(c *C) {
   133  	minID, maxID := 1, 5
   134  
   135  	// Leasing available IDs should move its state to leased.
   136  	p0 := NewIDPool(ID(minID), ID(maxID))
   137  	leaseAllIDs(p0, minID, maxID, c)
   138  	// Check all IDs are in leased state.
   139  	for i := minID; i <= maxID; i++ {
   140  		c.Assert(p0.Release(ID(i)), Equals, true)
   141  	}
   142  	leaseAllIDs(p0, minID, maxID, c)
   143  
   144  	// Releasing available IDs should not have any effect.
   145  	p1 := NewIDPool(ID(minID), ID(maxID))
   146  	for i := minID; i <= maxID; i++ {
   147  		c.Assert(p1.Release(ID(i)), Equals, false)
   148  	}
   149  	leaseAllIDs(p1, minID, maxID, c)
   150  
   151  	// Using available IDs should not have any effect.
   152  	p2 := NewIDPool(ID(minID), ID(maxID))
   153  	for i := minID; i <= maxID; i++ {
   154  		c.Assert(p2.Use(ID(i)), Equals, false)
   155  	}
   156  	leaseAllIDs(p2, minID, maxID, c)
   157  
   158  	// Inserting available IDs should not have any effect.
   159  	p3 := NewIDPool(ID(minID), ID(maxID))
   160  	for i := minID; i <= maxID; i++ {
   161  		c.Assert(p3.Insert(ID(i)), Equals, false)
   162  	}
   163  	leaseAllIDs(p3, minID, maxID, c)
   164  
   165  	// Removing available IDs should make them unavailable.
   166  	p4 := NewIDPool(ID(minID), ID(maxID))
   167  	for i := minID; i <= maxID; i++ {
   168  		c.Assert(p4.Remove(ID(i)), Equals, true)
   169  	}
   170  	leaseAllIDs(p4, minID, minID-1, c)
   171  	for i := minID; i <= maxID; i++ {
   172  		c.Assert(p4.Release(ID(i)), Equals, false)
   173  	}
   174  }
   175  
   176  func (s *IDPoolTestSuite) TestOperationsOnLeasedIDs(c *C) {
   177  	minID, maxID := 1, 5
   178  	var poolWithAllIDsLeased = func() *IDPool {
   179  		p := NewIDPool(ID(minID), ID(maxID))
   180  		leaseAllIDs(p, minID, maxID, c)
   181  		return p
   182  	}
   183  
   184  	// Releasing leased IDs should make it available again.
   185  	p0 := poolWithAllIDsLeased()
   186  	for i := minID; i <= maxID; i++ {
   187  		c.Assert(p0.Release(ID(i)), Equals, true)
   188  	}
   189  	leaseAllIDs(p0, minID, maxID, c)
   190  
   191  	// Using leased IDs should make it unavailable again.
   192  	p1 := poolWithAllIDsLeased()
   193  	for i := minID; i <= maxID; i++ {
   194  		c.Assert(p1.Use(ID(i)), Equals, true)
   195  		// It should no longer be leased.
   196  		c.Assert(p1.Use(ID(i)), Equals, false)
   197  	}
   198  	leaseAllIDs(p1, minID, minID-1, c)
   199  
   200  	// Inserting leased IDs should not have any effect.
   201  	p2 := poolWithAllIDsLeased()
   202  	for i := minID; i <= maxID; i++ {
   203  		c.Assert(p2.Insert(ID(i)), Equals, false)
   204  	}
   205  	// The IDs should still be leased.
   206  	for i := minID; i <= maxID; i++ {
   207  		c.Assert(p2.Release(ID(i)), Equals, true)
   208  	}
   209  	leaseAllIDs(p2, minID, maxID, c)
   210  
   211  	// Removing leased IDs should make them unavailable.
   212  	p3 := poolWithAllIDsLeased()
   213  	for i := minID; i <= maxID; i++ {
   214  		c.Assert(p3.Remove(ID(i)), Equals, false)
   215  	}
   216  	// The IDs should not be leased anymore.
   217  	for i := minID; i <= maxID; i++ {
   218  		c.Assert(p3.Use(ID(i)), Equals, false)
   219  	}
   220  	// They should be unavailable.
   221  	leaseAllIDs(p3, minID, minID-1, c)
   222  }
   223  
   224  func (s *IDPoolTestSuite) TestOperationsOnUnavailableIDs(c *C) {
   225  	minID, maxID := 1, 5
   226  	var poolWithAllIDsUnavailable = func() *IDPool {
   227  		p := NewIDPool(ID(minID), ID(maxID))
   228  		for i := minID; i <= maxID; i++ {
   229  			c.Assert(p.Remove(ID(i)), Equals, true)
   230  		}
   231  		return p
   232  	}
   233  
   234  	// Releasing unavailable IDs should not have any effect.
   235  	p1 := poolWithAllIDsUnavailable()
   236  	for i := minID; i <= maxID; i++ {
   237  		c.Assert(p1.Release(ID(i)), Equals, false)
   238  	}
   239  	leaseAllIDs(p1, minID, minID-1, c)
   240  
   241  	// Using unavailable IDs should not have any effect.
   242  	p2 := poolWithAllIDsUnavailable()
   243  	for i := minID; i <= maxID; i++ {
   244  		c.Assert(p2.Use(ID(i)), Equals, false)
   245  	}
   246  	leaseAllIDs(p2, minID, minID-1, c)
   247  
   248  	// Inserting unavailable IDs should make them available.
   249  	p3 := poolWithAllIDsUnavailable()
   250  	for i := minID; i <= maxID; i++ {
   251  		c.Assert(p3.Insert(ID(i)), Equals, true)
   252  	}
   253  	// They should not be leased.
   254  	for i := minID; i <= maxID; i++ {
   255  		c.Assert(p3.Use(ID(i)), Equals, false)
   256  		c.Assert(p3.Release(ID(i)), Equals, false)
   257  	}
   258  	leaseAllIDs(p3, minID, maxID, c)
   259  
   260  	// Removing unavailable IDs should not have any effect.
   261  	p4 := poolWithAllIDsUnavailable()
   262  	for i := minID; i <= maxID; i++ {
   263  		c.Assert(p4.Remove(ID(i)), Equals, false)
   264  	}
   265  	leaseAllIDs(p4, minID, minID-1, c)
   266  }
   267  
   268  func leaseAllIDs(p *IDPool, minID int, maxID int, c *C) {
   269  	expected := make([]int, 0)
   270  	actual := make([]int, 0)
   271  	for i := minID; i <= maxID; i++ {
   272  		id := p.LeaseAvailableID()
   273  		c.Assert(id, Not(Equals), NoID)
   274  		actual = append(actual, int(id))
   275  		expected = append(expected, i)
   276  	}
   277  	// We should be out of IDs.
   278  	id := p.LeaseAvailableID()
   279  	c.Assert(id, Equals, NoID)
   280  
   281  	// Unique ids must have been leased.
   282  	sort.Ints(actual)
   283  	c.Assert(actual, checker.DeepEquals, expected)
   284  }
   285  
   286  func (s *IDPoolTestSuite) BenchmarkRemoveIDs(c *C) {
   287  	minID, maxID := 1, c.N
   288  	p := NewIDPool(ID(minID), ID(maxID))
   289  
   290  	c.ResetTimer()
   291  	for i := minID; i <= maxID; i++ {
   292  		c.Assert(p.Remove(ID(i)), Equals, true)
   293  	}
   294  }
   295  
   296  func (s *IDPoolTestSuite) BenchmarkLeaseIDs(c *C) {
   297  	minID, maxID := 1, c.N
   298  	p := NewIDPool(ID(minID), ID(maxID))
   299  
   300  	c.ResetTimer()
   301  	for i := 1; i <= c.N; i++ {
   302  		id := p.LeaseAvailableID()
   303  		c.Assert(p.Release(ID(id)), Equals, true)
   304  	}
   305  }
   306  
   307  func (s *IDPoolTestSuite) BenchmarkUseAndRelease(c *C) {
   308  	minID, maxID := 1, c.N
   309  	p := NewIDPool(ID(minID), ID(maxID))
   310  
   311  	c.ResetTimer()
   312  	for i := 1; i <= c.N; i++ {
   313  		id := p.LeaseAvailableID()
   314  		c.Assert(p.Use(ID(id)), Equals, true)
   315  	}
   316  
   317  	for i := 1; i <= c.N; i++ {
   318  		c.Assert(p.Insert(ID(i)), Equals, true)
   319  	}
   320  }
   321  
   322  func (s *IDPoolTestSuite) TestAllocateID(c *C) {
   323  	minID, maxID := 1, 6000
   324  	p := NewIDPool(ID(minID), ID(maxID))
   325  
   326  	allocated := make(chan ID, 100)
   327  	var allocators sync.WaitGroup
   328  
   329  	for i := 0; i < 256; i++ {
   330  		allocators.Add(1)
   331  		go func() {
   332  			for i := 1; i <= maxID; i++ {
   333  				id := p.AllocateID()
   334  				c.Assert(id, Not(Equals), NoID)
   335  				allocated <- id
   336  			}
   337  			allocators.Done()
   338  		}()
   339  	}
   340  
   341  	go func() {
   342  		allocators.Wait()
   343  		close(allocated)
   344  	}()
   345  
   346  	for id := range allocated {
   347  		c.Assert(p.Insert(id), Equals, true)
   348  	}
   349  }