mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-28 10:51:44 +01:00 
			
		
		
		
	* policy: remove allocs before appends in acls
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
* notifier: make batcher tests stable/non-flaky
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
* {db,derp,mapper}: dont allocate until append
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
---------
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
		
	
			
		
			
				
	
	
		
			266 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			266 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package notifier
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"net/netip"
 | |
| 	"sort"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/google/go-cmp/cmp"
 | |
| 	"github.com/juanfont/headscale/hscontrol/types"
 | |
| 	"github.com/juanfont/headscale/hscontrol/util"
 | |
| 	"tailscale.com/tailcfg"
 | |
| )
 | |
| 
 | |
| func TestBatcher(t *testing.T) {
 | |
| 	tests := []struct {
 | |
| 		name    string
 | |
| 		updates []types.StateUpdate
 | |
| 		want    []types.StateUpdate
 | |
| 	}{
 | |
| 		{
 | |
| 			name: "full-passthrough",
 | |
| 			updates: []types.StateUpdate{
 | |
| 				{
 | |
| 					Type: types.StateFullUpdate,
 | |
| 				},
 | |
| 			},
 | |
| 			want: []types.StateUpdate{
 | |
| 				{
 | |
| 					Type: types.StateFullUpdate,
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "derp-passthrough",
 | |
| 			updates: []types.StateUpdate{
 | |
| 				{
 | |
| 					Type: types.StateDERPUpdated,
 | |
| 				},
 | |
| 			},
 | |
| 			want: []types.StateUpdate{
 | |
| 				{
 | |
| 					Type: types.StateDERPUpdated,
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "single-node-update",
 | |
| 			updates: []types.StateUpdate{
 | |
| 				{
 | |
| 					Type: types.StatePeerChanged,
 | |
| 					ChangeNodes: []types.NodeID{
 | |
| 						2,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			want: []types.StateUpdate{
 | |
| 				{
 | |
| 					Type: types.StatePeerChanged,
 | |
| 					ChangeNodes: []types.NodeID{
 | |
| 						2,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "merge-node-update",
 | |
| 			updates: []types.StateUpdate{
 | |
| 				{
 | |
| 					Type: types.StatePeerChanged,
 | |
| 					ChangeNodes: []types.NodeID{
 | |
| 						2, 4,
 | |
| 					},
 | |
| 				},
 | |
| 				{
 | |
| 					Type: types.StatePeerChanged,
 | |
| 					ChangeNodes: []types.NodeID{
 | |
| 						2, 3,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			want: []types.StateUpdate{
 | |
| 				{
 | |
| 					Type: types.StatePeerChanged,
 | |
| 					ChangeNodes: []types.NodeID{
 | |
| 						2, 3, 4,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "single-patch-update",
 | |
| 			updates: []types.StateUpdate{
 | |
| 				{
 | |
| 					Type: types.StatePeerChangedPatch,
 | |
| 					ChangePatches: []*tailcfg.PeerChange{
 | |
| 						{
 | |
| 							NodeID:     2,
 | |
| 							DERPRegion: 5,
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			want: []types.StateUpdate{
 | |
| 				{
 | |
| 					Type: types.StatePeerChangedPatch,
 | |
| 					ChangePatches: []*tailcfg.PeerChange{
 | |
| 						{
 | |
| 							NodeID:     2,
 | |
| 							DERPRegion: 5,
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "merge-patch-to-same-node-update",
 | |
| 			updates: []types.StateUpdate{
 | |
| 				{
 | |
| 					Type: types.StatePeerChangedPatch,
 | |
| 					ChangePatches: []*tailcfg.PeerChange{
 | |
| 						{
 | |
| 							NodeID:     2,
 | |
| 							DERPRegion: 5,
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 				{
 | |
| 					Type: types.StatePeerChangedPatch,
 | |
| 					ChangePatches: []*tailcfg.PeerChange{
 | |
| 						{
 | |
| 							NodeID:     2,
 | |
| 							DERPRegion: 6,
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			want: []types.StateUpdate{
 | |
| 				{
 | |
| 					Type: types.StatePeerChangedPatch,
 | |
| 					ChangePatches: []*tailcfg.PeerChange{
 | |
| 						{
 | |
| 							NodeID:     2,
 | |
| 							DERPRegion: 6,
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "merge-patch-to-multiple-node-update",
 | |
| 			updates: []types.StateUpdate{
 | |
| 				{
 | |
| 					Type: types.StatePeerChangedPatch,
 | |
| 					ChangePatches: []*tailcfg.PeerChange{
 | |
| 						{
 | |
| 							NodeID: 3,
 | |
| 							Endpoints: []netip.AddrPort{
 | |
| 								netip.MustParseAddrPort("1.1.1.1:9090"),
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 				{
 | |
| 					Type: types.StatePeerChangedPatch,
 | |
| 					ChangePatches: []*tailcfg.PeerChange{
 | |
| 						{
 | |
| 							NodeID: 3,
 | |
| 							Endpoints: []netip.AddrPort{
 | |
| 								netip.MustParseAddrPort("1.1.1.1:9090"),
 | |
| 								netip.MustParseAddrPort("2.2.2.2:8080"),
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 				{
 | |
| 					Type: types.StatePeerChangedPatch,
 | |
| 					ChangePatches: []*tailcfg.PeerChange{
 | |
| 						{
 | |
| 							NodeID:     4,
 | |
| 							DERPRegion: 6,
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 				{
 | |
| 					Type: types.StatePeerChangedPatch,
 | |
| 					ChangePatches: []*tailcfg.PeerChange{
 | |
| 						{
 | |
| 							NodeID: 4,
 | |
| 							Cap:    tailcfg.CapabilityVersion(54),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			want: []types.StateUpdate{
 | |
| 				{
 | |
| 					Type: types.StatePeerChangedPatch,
 | |
| 					ChangePatches: []*tailcfg.PeerChange{
 | |
| 						{
 | |
| 							NodeID: 3,
 | |
| 							Endpoints: []netip.AddrPort{
 | |
| 								netip.MustParseAddrPort("1.1.1.1:9090"),
 | |
| 								netip.MustParseAddrPort("2.2.2.2:8080"),
 | |
| 							},
 | |
| 						},
 | |
| 						{
 | |
| 							NodeID:     4,
 | |
| 							DERPRegion: 6,
 | |
| 							Cap:        tailcfg.CapabilityVersion(54),
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, tt := range tests {
 | |
| 		t.Run(tt.name, func(t *testing.T) {
 | |
| 			n := NewNotifier(&types.Config{
 | |
| 				Tuning: types.Tuning{
 | |
| 					// We will call flush manually for the tests,
 | |
| 					// so do not run the worker.
 | |
| 					BatchChangeDelay: time.Hour,
 | |
| 
 | |
| 					// Since we do not load the config, we wont get the
 | |
| 					// default, so set it manually so we dont time out
 | |
| 					// and have flakes.
 | |
| 					NotifierSendTimeout: time.Second,
 | |
| 				},
 | |
| 			})
 | |
| 
 | |
| 			ch := make(chan types.StateUpdate, 30)
 | |
| 			defer close(ch)
 | |
| 			n.AddNode(1, ch)
 | |
| 			defer n.RemoveNode(1, ch)
 | |
| 
 | |
| 			for _, u := range tt.updates {
 | |
| 				n.NotifyAll(context.Background(), u)
 | |
| 			}
 | |
| 
 | |
| 			n.b.flush()
 | |
| 
 | |
| 			var got []types.StateUpdate
 | |
| 			for len(ch) > 0 {
 | |
| 				out := <-ch
 | |
| 				got = append(got, out)
 | |
| 			}
 | |
| 
 | |
| 			// Make the inner order stable for comparison.
 | |
| 			for _, u := range got {
 | |
| 				sort.Slice(u.ChangeNodes, func(i, j int) bool {
 | |
| 					return u.ChangeNodes[i] < u.ChangeNodes[j]
 | |
| 				})
 | |
| 				sort.Slice(u.ChangePatches, func(i, j int) bool {
 | |
| 					return u.ChangePatches[i].NodeID < u.ChangePatches[j].NodeID
 | |
| 				})
 | |
| 			}
 | |
| 
 | |
| 			if diff := cmp.Diff(tt.want, got, util.Comparers...); diff != "" {
 | |
| 				t.Errorf("batcher() unexpected result (-want +got):\n%s", diff)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 |