storj/satellite/overlay/statdb_test.go
Michal Niewrzal 98f4f249b2 satellite/overlay: refactor KnownReliable to be used with repairer
Currently we are using KnownUnreliableOrOffline to get missing pieces
for segment repairer (GetMissingPieces). The issue is that now repairer
is looking at more things than just missing pieces (clumped/off
placement pieces).

KnownReliable was refactored to get data (e.g. country, lastNet) about
all reliable nodes from provided list. List is split into online and
offline. This way we will be able to use results from this method to all
checks: missing pieces, clumped pieces, out of placement pieces.

This this first part of changes to handle different kind of pieces in
segment repairer.

https://github.com/storj/storj/issues/5998

Change-Id: I6cbaf59cff9d6c4346ace75bb814ccd985c0e43e
2023-06-27 13:27:23 +02:00

250 lines
9.0 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package overlay_test
import (
"context"
"fmt"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/exp/slices"
"storj.io/common/pb"
"storj.io/common/storj"
"storj.io/common/storj/location"
"storj.io/common/testcontext"
"storj.io/storj/satellite"
"storj.io/storj/satellite/overlay"
"storj.io/storj/satellite/satellitedb/satellitedbtest"
)
func TestStatDB(t *testing.T) {
satellitedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db satellite.DB) {
testDatabase(ctx, t, db.OverlayCache())
})
}
func testDatabase(ctx context.Context, t *testing.T, cache overlay.DB) {
{ // Test KnownReliable and Reliable
for i, tt := range []struct {
nodeID storj.NodeID
unknownAuditSuspended bool
offlineSuspended bool
disqualified bool
offline bool
gracefullyexited bool
countryCode string
}{
{storj.NodeID{1}, false, false, false, false, false, "DE"}, // good
{storj.NodeID{2}, false, false, true, false, false, "DE"}, // disqualified
{storj.NodeID{3}, true, false, false, false, false, "DE"}, // unknown audit suspended
{storj.NodeID{4}, false, false, false, true, false, "DE"}, // offline
{storj.NodeID{5}, false, false, false, false, true, "DE"}, // gracefully exited
{storj.NodeID{6}, false, true, false, false, false, "DE"}, // offline suspended
{storj.NodeID{7}, false, false, false, false, false, "FR"}, // excluded country
{storj.NodeID{8}, false, false, false, false, false, ""}, // good
} {
addr := fmt.Sprintf("127.0.%d.0:8080", i)
lastNet := fmt.Sprintf("127.0.%d", i)
d := overlay.NodeCheckInInfo{
NodeID: tt.nodeID,
Address: &pb.NodeAddress{Address: addr},
LastIPPort: addr,
LastNet: lastNet,
Version: &pb.NodeVersion{Version: "v1.0.0"},
Capacity: &pb.NodeCapacity{},
IsUp: true,
CountryCode: location.ToCountryCode(tt.countryCode),
}
err := cache.UpdateCheckIn(ctx, d, time.Now().UTC(), overlay.NodeSelectionConfig{})
require.NoError(t, err)
if tt.unknownAuditSuspended {
err = cache.TestSuspendNodeUnknownAudit(ctx, tt.nodeID, time.Now())
require.NoError(t, err)
}
if tt.offlineSuspended {
err = cache.TestSuspendNodeOffline(ctx, tt.nodeID, time.Now())
require.NoError(t, err)
}
if tt.disqualified {
_, err = cache.DisqualifyNode(ctx, tt.nodeID, time.Now(), overlay.DisqualificationReasonUnknown)
require.NoError(t, err)
}
if tt.offline {
checkInInfo := getNodeInfo(tt.nodeID)
err = cache.UpdateCheckIn(ctx, checkInInfo, time.Now().Add(-2*time.Hour), overlay.NodeSelectionConfig{})
require.NoError(t, err)
}
if tt.gracefullyexited {
req := &overlay.ExitStatusRequest{
NodeID: tt.nodeID,
ExitInitiatedAt: time.Now(),
ExitLoopCompletedAt: time.Now(),
ExitFinishedAt: time.Now(),
}
_, err := cache.UpdateExitStatus(ctx, req)
require.NoError(t, err)
}
}
nodeIds := storj.NodeIDList{
storj.NodeID{1}, storj.NodeID{2},
storj.NodeID{3}, storj.NodeID{4},
storj.NodeID{5}, storj.NodeID{6},
storj.NodeID{7}, storj.NodeID{8},
storj.NodeID{9},
}
criteria := &overlay.NodeCriteria{
OnlineWindow: time.Hour,
ExcludedCountries: []string{"FR", "BE"},
}
contains := func(nodeID storj.NodeID) func(node overlay.SelectedNode) bool {
return func(node overlay.SelectedNode) bool {
return node.ID == nodeID
}
}
online, offline, err := cache.KnownReliable(ctx, nodeIds, criteria.OnlineWindow, criteria.AsOfSystemInterval)
require.NoError(t, err)
// unrealiable nodes shouldn't be in results
require.False(t, slices.ContainsFunc(append(online, offline...), contains(storj.NodeID{2}))) // disqualified
require.False(t, slices.ContainsFunc(append(online, offline...), contains(storj.NodeID{3}))) // unknown audit suspended
require.False(t, slices.ContainsFunc(append(online, offline...), contains(storj.NodeID{5}))) // gracefully exited
require.False(t, slices.ContainsFunc(append(online, offline...), contains(storj.NodeID{6}))) // offline suspended
require.False(t, slices.ContainsFunc(append(online, offline...), contains(storj.NodeID{9}))) // not in db
require.True(t, slices.ContainsFunc(offline, contains(storj.NodeID{4}))) // offline
require.Len(t, append(online, offline...), 4)
valid, err := cache.Reliable(ctx, criteria)
require.NoError(t, err)
require.NotContains(t, valid, storj.NodeID{2}) // disqualified
require.NotContains(t, valid, storj.NodeID{3}) // unknown audit suspended
require.NotContains(t, valid, storj.NodeID{4}) // offline
require.NotContains(t, valid, storj.NodeID{5}) // gracefully exited
require.NotContains(t, valid, storj.NodeID{6}) // offline suspended
require.NotContains(t, valid, storj.NodeID{7}) // excluded country
require.NotContains(t, valid, storj.NodeID{9}) // not in db
require.Len(t, valid, 2)
}
{ // TestUpdateOperator
nodeID := storj.NodeID{10}
addr := "127.0.1.0:8080"
lastNet := "127.0.1"
d := overlay.NodeCheckInInfo{
NodeID: nodeID,
Address: &pb.NodeAddress{Address: addr},
LastIPPort: addr,
LastNet: lastNet,
Version: &pb.NodeVersion{Version: "v1.0.0"},
Capacity: &pb.NodeCapacity{},
}
err := cache.UpdateCheckIn(ctx, d, time.Now().UTC(), overlay.NodeSelectionConfig{})
require.NoError(t, err)
update, err := cache.UpdateNodeInfo(ctx, nodeID, &overlay.InfoResponse{
Operator: &pb.NodeOperator{
Wallet: "0x1111111111111111111111111111111111111111",
Email: "abc123@mail.test",
WalletFeatures: []string{"wallet_features"},
},
})
require.NoError(t, err)
require.NotNil(t, update)
require.Equal(t, "0x1111111111111111111111111111111111111111", update.Operator.Wallet)
require.Equal(t, "abc123@mail.test", update.Operator.Email)
require.Equal(t, []string{"wallet_features"}, update.Operator.WalletFeatures)
found, err := cache.Get(ctx, nodeID)
require.NoError(t, err)
require.NotNil(t, found)
require.Equal(t, "0x1111111111111111111111111111111111111111", found.Operator.Wallet)
require.Equal(t, "abc123@mail.test", found.Operator.Email)
require.Equal(t, []string{"wallet_features"}, found.Operator.WalletFeatures)
updateEmail, err := cache.UpdateNodeInfo(ctx, nodeID, &overlay.InfoResponse{
Operator: &pb.NodeOperator{
Wallet: update.Operator.Wallet,
Email: "def456@mail.test",
WalletFeatures: update.Operator.WalletFeatures,
},
})
require.NoError(t, err)
assert.NotNil(t, updateEmail)
assert.Equal(t, "0x1111111111111111111111111111111111111111", updateEmail.Operator.Wallet)
assert.Equal(t, "def456@mail.test", updateEmail.Operator.Email)
assert.Equal(t, []string{"wallet_features"}, updateEmail.Operator.WalletFeatures)
updateWallet, err := cache.UpdateNodeInfo(ctx, nodeID, &overlay.InfoResponse{
Operator: &pb.NodeOperator{
Wallet: "0x2222222222222222222222222222222222222222",
Email: updateEmail.Operator.Email,
WalletFeatures: update.Operator.WalletFeatures,
},
})
require.NoError(t, err)
assert.NotNil(t, updateWallet)
assert.Equal(t, "0x2222222222222222222222222222222222222222", updateWallet.Operator.Wallet)
assert.Equal(t, "def456@mail.test", updateWallet.Operator.Email)
assert.Equal(t, []string{"wallet_features"}, updateWallet.Operator.WalletFeatures)
updateWalletFeatures, err := cache.UpdateNodeInfo(ctx, nodeID, &overlay.InfoResponse{
Operator: &pb.NodeOperator{
Wallet: updateWallet.Operator.Wallet,
Email: updateEmail.Operator.Email,
WalletFeatures: []string{"wallet_features_updated"},
},
})
require.NoError(t, err)
assert.NotNil(t, updateWalletFeatures)
assert.Equal(t, "0x2222222222222222222222222222222222222222", updateWalletFeatures.Operator.Wallet)
assert.Equal(t, "def456@mail.test", updateWalletFeatures.Operator.Email)
assert.Equal(t, []string{"wallet_features_updated"}, updateWalletFeatures.Operator.WalletFeatures)
}
{ // test UpdateCheckIn updates the reputation correctly when the node is offline/online
nodeID := storj.NodeID{1}
// get the existing node info that is stored in nodes table
_, err := cache.Get(ctx, nodeID)
require.NoError(t, err)
info := overlay.NodeCheckInInfo{
NodeID: nodeID,
Address: &pb.NodeAddress{
Address: "1.2.3.4",
},
IsUp: false,
Version: &pb.NodeVersion{
Version: "v0.0.0",
CommitHash: "",
Timestamp: time.Time{},
Release: false,
},
}
// update check-in when node is offline
err = cache.UpdateCheckIn(ctx, info, time.Now(), overlay.NodeSelectionConfig{})
require.NoError(t, err)
_, err = cache.Get(ctx, nodeID)
require.NoError(t, err)
info.IsUp = true
// update check-in when node is online
err = cache.UpdateCheckIn(ctx, info, time.Now(), overlay.NodeSelectionConfig{})
require.NoError(t, err)
_, err = cache.Get(ctx, nodeID)
require.NoError(t, err)
}
}