plugin_test.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. package rangeplugin
  2. import (
  3. "fmt"
  4. "net"
  5. "testing"
  6. "github.com/insomniacslk/dhcp/dhcpv4"
  7. "github.com/stretchr/testify/assert"
  8. "github.com/stretchr/testify/mock"
  9. )
  10. // mockAllocator is a simple mock for testing
  11. type mockAllocator struct {
  12. mock.Mock
  13. }
  14. func (m *mockAllocator) Allocate(hint net.IPNet) (net.IPNet, error) {
  15. return m.Called(hint).Get(0).(net.IPNet), nil
  16. }
  17. func (m *mockAllocator) Free(ip net.IPNet) error {
  18. m.Called(ip)
  19. return nil
  20. }
  21. type mockFailingAllocator struct {
  22. mock.Mock
  23. }
  24. func (m *mockFailingAllocator) Allocate(hint net.IPNet) (net.IPNet, error) {
  25. args := m.Called(hint)
  26. return args.Get(0).(net.IPNet), args.Error(1)
  27. }
  28. func (m *mockFailingAllocator) Free(ip net.IPNet) error {
  29. args := m.Called(ip)
  30. return args.Error(0)
  31. }
  32. func TestHandler4Release(t *testing.T) {
  33. db, dbErr := testDBSetup()
  34. if dbErr != nil {
  35. t.Fatalf("Failed to set up test DB: %v", dbErr)
  36. }
  37. mockAlloc := &mockAllocator{}
  38. pl := PluginState{
  39. leasedb: db,
  40. Recordsv4: make(map[string]*Record),
  41. allocator: mockAlloc,
  42. }
  43. loadedRecords, loadErr := loadRecords(db)
  44. if loadErr != nil {
  45. t.Fatalf("Failed to load records: %v", loadErr)
  46. }
  47. pl.Recordsv4 = loadedRecords
  48. // Create a DHCP RELEASE request using existing test data
  49. hwaddr, _ := net.ParseMAC(records[1].mac)
  50. req := &dhcpv4.DHCPv4{
  51. ClientHWAddr: hwaddr,
  52. }
  53. req.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeRelease))
  54. resp := &dhcpv4.DHCPv4{}
  55. // Verify record exists before release
  56. record, exists := pl.Recordsv4[hwaddr.String()]
  57. assert.True(t, exists, "Record should exist before release")
  58. expectedIPNet := net.IPNet{IP: record.IP}
  59. mockAlloc.On("Free", expectedIPNet).Return(nil)
  60. // Call Handler4 with RELEASE message
  61. result, stop := pl.Handler4(req, resp)
  62. assert.Nil(t, result, "Should return nil response for RELEASE")
  63. assert.True(t, stop, "Should return true to stop processing")
  64. _, exists = pl.Recordsv4[hwaddr.String()]
  65. assert.False(t, exists, "Record should be removed from memory after release")
  66. parsedRecords, parseErr := loadRecords(pl.leasedb)
  67. if parseErr != nil {
  68. t.Fatalf("Failed to load records after release: %v", parseErr)
  69. }
  70. _, exists = parsedRecords[hwaddr.String()]
  71. assert.False(t, exists, "Record should be removed from storage after release")
  72. mockAlloc.AssertExpectations(t)
  73. mockAlloc.AssertNotCalled(t, "Allocate")
  74. }
  75. func TestHandler4ReleaseAllocatorError(t *testing.T) {
  76. db, parseErr := testDBSetup()
  77. if parseErr != nil {
  78. t.Fatalf("Failed to set up test DB: %v", parseErr)
  79. }
  80. mockAlloc := &mockFailingAllocator{}
  81. pl := PluginState{
  82. leasedb: db,
  83. Recordsv4: make(map[string]*Record),
  84. allocator: mockAlloc,
  85. }
  86. loadedRecords, err := loadRecords(db)
  87. if err != nil {
  88. t.Fatalf("Failed to load records: %v", err)
  89. }
  90. pl.Recordsv4 = loadedRecords
  91. hwaddr, _ := net.ParseMAC(records[1].mac)
  92. req := &dhcpv4.DHCPv4{
  93. ClientHWAddr: hwaddr,
  94. }
  95. req.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeRelease))
  96. resp := &dhcpv4.DHCPv4{}
  97. record := pl.Recordsv4[hwaddr.String()]
  98. expectedIPNet := net.IPNet{IP: record.IP}
  99. expectedError := fmt.Errorf("mock allocator free failure")
  100. mockAlloc.On("Free", expectedIPNet).Return(expectedError)
  101. // Call Handler4 - this should fail on allocator.Free()
  102. result, stop := pl.Handler4(req, resp)
  103. assert.Nil(t, result, "Should return nil on allocator failure")
  104. assert.True(t, stop, "Should stop processing on allocator failure")
  105. _, exists := pl.Recordsv4[hwaddr.String()]
  106. assert.False(t, exists, "Record should be removed from memory even on allocator failure")
  107. parsedRecords, parseErr := loadRecords(pl.leasedb)
  108. if parseErr != nil {
  109. t.Fatalf("Failed to load records after release: %v", parseErr)
  110. }
  111. _, exists = parsedRecords[hwaddr.String()]
  112. assert.False(t, exists, "Record should be removed from storage even on allocator failure")
  113. mockAlloc.AssertExpectations(t)
  114. mockAlloc.AssertNotCalled(t, "Allocate")
  115. }
  116. func TestHandler4ReleaseStorageError(t *testing.T) {
  117. db, parseErr := testDBSetup()
  118. if parseErr != nil {
  119. t.Fatalf("Failed to set up test DB: %v", parseErr)
  120. }
  121. mockAlloc := &mockAllocator{}
  122. pl := PluginState{
  123. leasedb: db,
  124. Recordsv4: make(map[string]*Record),
  125. allocator: mockAlloc,
  126. }
  127. loadedRecords, err := loadRecords(db)
  128. if err != nil {
  129. t.Fatalf("Failed to load records: %v", err)
  130. }
  131. pl.Recordsv4 = loadedRecords
  132. hwaddr, _ := net.ParseMAC(records[1].mac)
  133. req := &dhcpv4.DHCPv4{
  134. ClientHWAddr: hwaddr,
  135. }
  136. req.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeRelease))
  137. resp := &dhcpv4.DHCPv4{}
  138. // Close the database to simulate storage failure
  139. db.Close()
  140. result, stop := pl.Handler4(req, resp)
  141. assert.Nil(t, result, "Should return nil on storage failure")
  142. assert.True(t, stop, "Should stop processing on storage failure")
  143. _, exists := pl.Recordsv4[hwaddr.String()]
  144. assert.True(t, exists, "Record should still exist in memory after storage failure")
  145. mockAlloc.AssertNotCalled(t, "Free")
  146. mockAlloc.AssertNotCalled(t, "Allocate")
  147. }