98921f9faa
When we do `satellite run api --placement '...'`, the placement rules are not parsed well. The problem is based on `viper.AllSettings()`, and the main logic is sg. like this (from a new unit test): ``` r := ConfigurablePlacementRule{} err := r.Set(p) require.NoError(t, err) serialized := r.String() r2 := ConfigurablePlacementRule{} err = r2.Set(serialized) require.NoError(t, err) require.Equal(t, p, r2.String()) ``` All settings evaluates the placement rules in `ConfigurablePlacementRules` and stores the string representation. The problem is that we don't have proper `String()` implementation (it prints out the structs instead of the original definition. There are two main solutions for this problem: 1. We can fix the `String()`. When we parse a placement rule, the `String()` method should print out the original definition 2. We can switch to use pure string as configuration parameter, and parse the rules only when required. I feel that 1 is error prone, we can do it (and in this patch I added a lot of `String()` implementations, but it's hard to be sure that our `String()` logic is inline with the parsing logic. Therefore I decided to make the configuration value of the placements a string (or a wrapper around string). That's the main reason why this patch seems to be big, as I updated all the usages. But the main part is in beginning of the `placement.go` (configuration parsing is not a pflag.Value implementation any more, but a separated step). And `filter.go`, (a few more String implementation for filters. https://github.com/storj/storj/issues/6248 Change-Id: I47c762d3514342b76a2e85683b1c891502a0756a
116 lines
2.9 KiB
Go
116 lines
2.9 KiB
Go
// Copyright (C) 2023 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package orders_test
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/golang/mock/gomock"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/zap/zaptest"
|
|
|
|
"storj.io/common/identity/testidentity"
|
|
"storj.io/common/pb"
|
|
"storj.io/common/signing"
|
|
"storj.io/common/storj"
|
|
"storj.io/common/testcontext"
|
|
"storj.io/common/testrand"
|
|
"storj.io/storj/satellite/metabase"
|
|
"storj.io/storj/satellite/nodeselection"
|
|
"storj.io/storj/satellite/orders"
|
|
"storj.io/storj/satellite/overlay"
|
|
)
|
|
|
|
func TestGetOrderLimits(t *testing.T) {
|
|
ctx := testcontext.New(t)
|
|
ctrl := gomock.NewController(t)
|
|
|
|
bucket := metabase.BucketLocation{ProjectID: testrand.UUID(), BucketName: "bucket1"}
|
|
|
|
pieces := metabase.Pieces{}
|
|
nodes := map[storj.NodeID]*nodeselection.SelectedNode{}
|
|
for i := 0; i < 8; i++ {
|
|
nodeID := testrand.NodeID()
|
|
nodes[nodeID] = &nodeselection.SelectedNode{
|
|
ID: nodeID,
|
|
Address: &pb.NodeAddress{
|
|
Address: fmt.Sprintf("host%d.com", i),
|
|
},
|
|
}
|
|
|
|
pieces = append(pieces, metabase.Piece{
|
|
Number: uint16(i),
|
|
StorageNode: nodeID,
|
|
})
|
|
}
|
|
testIdentity, err := testidentity.PregeneratedIdentity(0, storj.LatestIDVersion())
|
|
require.NoError(t, err)
|
|
k := signing.SignerFromFullIdentity(testIdentity)
|
|
|
|
overlayService := orders.NewMockOverlayForOrders(ctrl)
|
|
overlayService.
|
|
EXPECT().
|
|
CachedGetOnlineNodesForGet(gomock.Any(), gomock.Any()).
|
|
Return(nodes, nil).AnyTimes()
|
|
|
|
service, err := orders.NewService(zaptest.NewLogger(t), k, overlayService, orders.NewNoopDB(),
|
|
overlay.NewPlacementDefinitions().CreateFilters,
|
|
orders.Config{
|
|
EncryptionKeys: orders.EncryptionKeys{
|
|
Default: orders.EncryptionKey{
|
|
ID: orders.EncryptionKeyID{1, 2, 3, 4, 5, 6, 7, 8},
|
|
Key: testrand.Key(),
|
|
},
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
segment := metabase.Segment{
|
|
StreamID: testrand.UUID(),
|
|
CreatedAt: time.Now(),
|
|
Redundancy: storj.RedundancyScheme{
|
|
Algorithm: storj.ReedSolomon,
|
|
ShareSize: 256,
|
|
RequiredShares: 4,
|
|
RepairShares: 5,
|
|
OptimalShares: 6,
|
|
TotalShares: 10,
|
|
},
|
|
Pieces: pieces,
|
|
EncryptedKey: []byte{1, 2, 3, 4},
|
|
RootPieceID: testrand.PieceID(),
|
|
}
|
|
|
|
checkExpectedLimits := func(requested int32, received int) {
|
|
limits, _, err := service.CreateGetOrderLimits(ctx, bucket, segment, requested, 0)
|
|
require.NoError(t, err)
|
|
realLimits := 0
|
|
for _, limit := range limits {
|
|
if limit.Limit != nil {
|
|
realLimits++
|
|
}
|
|
}
|
|
require.Equal(t, received, realLimits)
|
|
}
|
|
|
|
t.Run("Do not request any specific number", func(t *testing.T) {
|
|
checkExpectedLimits(0, 6)
|
|
})
|
|
|
|
t.Run("Request less than the optimal", func(t *testing.T) {
|
|
checkExpectedLimits(2, 6)
|
|
})
|
|
|
|
t.Run("Request more than the optimal", func(t *testing.T) {
|
|
checkExpectedLimits(8, 8)
|
|
})
|
|
|
|
t.Run("Request more than the replication", func(t *testing.T) {
|
|
checkExpectedLimits(1000, 8)
|
|
})
|
|
|
|
}
|