mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-30 03:21:29 +02:00
The user half reused nothing: SaveUserLastLogin already exists and is the same call the dashboard and device login paths make, so the parallel RefreshUserLastLogin is gone and the proxy uses the established one. Reaching it no longer widens shared interfaces. The proxy service already receives the store, narrowed to ProxyTokenChecker; that interface now carries the two writes the proxy makes, so users.Manager, peers.Manager and Peer are untouched and the exclusion predicate moved into the proxy package next to its only caller. RefreshPeerLastSeen stays on the store because nothing there fits: SavePeerStatus rewrites the connected flag and session token from a caller snapshot, which would race the sync stream that owns them.
81 lines
2.8 KiB
Go
81 lines
2.8 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"net/netip"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
|
"github.com/netbirdio/netbird/management/server/types"
|
|
)
|
|
|
|
const activityAccountID = "activityAccountId"
|
|
|
|
func newActivityTestStore(t *testing.T) Store {
|
|
t.Helper()
|
|
|
|
store, cleanUp, err := NewTestStoreFromSQL(context.Background(), "", t.TempDir())
|
|
require.NoError(t, err)
|
|
t.Cleanup(cleanUp)
|
|
|
|
require.NoError(t, store.SaveAccount(context.Background(), &types.Account{
|
|
Id: activityAccountID,
|
|
Domain: "activity.example.com",
|
|
CreatedAt: time.Now().UTC(),
|
|
}))
|
|
|
|
return store
|
|
}
|
|
|
|
func TestRefreshPeerLastSeen(t *testing.T) {
|
|
ctx := context.Background()
|
|
store := newActivityTestStore(t)
|
|
stored := time.Now().UTC().Add(-3 * time.Hour)
|
|
require.NoError(t, store.AddPeerToAccount(ctx, activityPeer(stored)))
|
|
|
|
require.NoError(t, store.RefreshPeerLastSeen(ctx, activityAccountID, "activityPeer"))
|
|
|
|
peer, err := store.GetPeerByID(ctx, LockingStrengthNone, activityAccountID, "activityPeer")
|
|
require.NoError(t, err)
|
|
assert.WithinDuration(t, time.Now().UTC(), peer.Status.LastSeen.UTC(), time.Minute, "last seen should be stamped at write time")
|
|
assert.True(t, peer.Status.LastSeen.After(stored), "last seen must move forward")
|
|
}
|
|
|
|
// TestRefreshPeerLastSeenLeavesSessionStateAlone pins the column boundary: the
|
|
// connected flag and the session token belong to the sync stream that owns the
|
|
// peer's session, and a blind write here would corrupt its fencing. This is why
|
|
// SavePeerStatus is not reused for an activity bump.
|
|
func TestRefreshPeerLastSeenLeavesSessionStateAlone(t *testing.T) {
|
|
ctx := context.Background()
|
|
store := newActivityTestStore(t)
|
|
|
|
stored := activityPeer(time.Date(2026, 3, 1, 9, 0, 0, 0, time.UTC))
|
|
stored.Status.Connected = true
|
|
stored.Status.SessionStartedAt = 1234567890
|
|
require.NoError(t, store.AddPeerToAccount(ctx, stored))
|
|
|
|
require.NoError(t, store.RefreshPeerLastSeen(ctx, activityAccountID, "activityPeer"))
|
|
|
|
peer, err := store.GetPeerByID(ctx, LockingStrengthNone, activityAccountID, "activityPeer")
|
|
require.NoError(t, err)
|
|
assert.WithinDuration(t, time.Now().UTC(), peer.Status.LastSeen.UTC(), time.Minute, "last seen should move forward")
|
|
assert.True(t, peer.Status.Connected, "connected flag must survive an activity write")
|
|
assert.Equal(t, int64(1234567890), peer.Status.SessionStartedAt, "session token must survive an activity write")
|
|
}
|
|
|
|
func activityPeer(lastSeen time.Time) *nbpeer.Peer {
|
|
return &nbpeer.Peer{
|
|
ID: "activityPeer",
|
|
AccountID: activityAccountID,
|
|
Key: "activityPeerKey",
|
|
IP: netip.MustParseAddr("100.64.0.9"),
|
|
Name: "activity-peer",
|
|
DNSLabel: "activity-peer",
|
|
Status: &nbpeer.PeerStatus{LastSeen: lastSeen},
|
|
}
|
|
}
|