[#222] Add support for aio v1.7.0 in integration tests #239
3 changed files with 151 additions and 6 deletions
|
@ -14,10 +14,12 @@ import (
|
|||||||
"net/http"
|
||||||||
"os"
|
||||||||
"sort"
|
||||||||
"strconv"
|
||||||||
"strings"
|
||||||||
"testing"
|
||||||||
"time"
|
||||||||
|
||||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||||||
containerv2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container"
|
||||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
||||||||
|
@ -31,6 +33,8 @@ import (
|
|||||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
|
||||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||||
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
||||||||
docker "github.com/docker/docker/api/types/container"
|
||||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||||
|
@ -51,6 +55,59 @@ const (
|
|||||||
testCORSContainerName = "cors"
|
||||||||
)
|
||||||||
|
||||||||
func versionToUint(t *testing.T, v string) uint64 {
|
||||||||
parts := strings.Split(v, ".")
|
||||||||
require.Len(t, parts, 3)
|
||||||||
major, err := strconv.ParseUint(parts[0], 10, 16)
|
||||||||
|
||||||||
require.NoError(t, err)
|
||||||||
minor, err := strconv.ParseUint(parts[1], 10, 16)
|
||||||||
require.NoError(t, err)
|
||||||||
patch, err := strconv.ParseUint(parts[2], 10, 32)
|
||||||||
require.NoError(t, err)
|
||||||||
versionNumber := major<<48 | minor<<32 | patch
|
||||||||
return versionNumber
|
||||||||
}
|
||||||||
|
||||||||
func publicReadWriteRules() []chain.Rule {
|
||||||||
return []chain.Rule{
|
||||||||
{
|
||||||||
Status: chain.Allow,
|
||||||||
Actions: chain.Actions{
|
||||||||
dkirillov
commented
Can we fix formatting (run
Can we fix formatting (run `make fmt` at least)?
For example:
```diff
diff --git a/cmd/http-gw/integration_test.go b/cmd/http-gw/integration_test.go
index 8c22931..d1a61f4 100644
--- a/cmd/http-gw/integration_test.go
+++ b/cmd/http-gw/integration_test.go
@@ -72,22 +72,24 @@ func versionToUint(t *testing.T, v string) uint64 {
func publicReadWriteRules() []chain.Rule {
return []chain.Rule{
{
- Status: chain.Allow, Actions: chain.Actions{
- Inverted: false,
- Names: []string{
- native.MethodPutObject,
- native.MethodGetObject,
- native.MethodHeadObject,
- native.MethodDeleteObject,
- native.MethodSearchObject,
- native.MethodRangeObject,
- native.MethodHashObject,
- native.MethodPatchObject,
+ Status: chain.Allow,
+ Actions: chain.Actions{
+ Names: []string{
+ native.MethodPutObject,
+ native.MethodGetObject,
+ native.MethodHeadObject,
+ native.MethodDeleteObject,
+ native.MethodSearchObject,
+ native.MethodRangeObject,
+ native.MethodHashObject,
+ native.MethodPatchObject,
+ },
},
- }, Resources: chain.Resources{
- Inverted: false,
- Names: []string{native.ResourceFormatRootObjects},
- }, Any: false},
+ Resources: chain.Resources{
+ Names: []string{native.ResourceFormatRootObjects},
+ },
+ Any: false,
+ },
}
}
```
dkirillov
commented
Please align brackets Line 73 in KurlesHS/frostfs-http-gw@101d637
and Line 92 in KurlesHS/frostfs-http-gw@101d637
Please align brackets
https://git.frostfs.info/KurlesHS/frostfs-http-gw/src/commit/101d6370b8deaed19ba1ff1bed93ae34759a0ad5/cmd/http-gw/integration_test.go#L73 and https://git.frostfs.info/KurlesHS/frostfs-http-gw/src/commit/101d6370b8deaed19ba1ff1bed93ae34759a0ad5/cmd/http-gw/integration_test.go#L92
KurlesHS
commented
For some reason, gofmt is totally fine with this on my machine. =( For some reason, gofmt is totally fine with this on my machine. =(
|
||||||||
Inverted: false,
|
||||||||
Names: []string{
|
||||||||
native.MethodPutObject,
|
||||||||
native.MethodGetObject,
|
||||||||
native.MethodHeadObject,
|
||||||||
native.MethodDeleteObject,
|
||||||||
native.MethodSearchObject,
|
||||||||
native.MethodRangeObject,
|
||||||||
native.MethodHashObject,
|
||||||||
native.MethodPatchObject,
|
||||||||
},
|
||||||||
},
|
||||||||
Resources: chain.Resources{
|
||||||||
Inverted: false,
|
||||||||
Names: []string{native.ResourceFormatRootObjects},
|
||||||||
},
|
||||||||
Any: false,
|
||||||||
},
|
||||||||
}
|
||||||||
}
|
||||||||
|
||||||||
func privateRules() []chain.Rule {
|
||||||||
rule := publicReadWriteRules()
|
||||||||
// The same as public-read-write, except that only the owner is allowed to perform the listed actions
|
||||||||
rule[0].Condition = []chain.Condition{
|
||||||||
{
|
||||||||
Op: chain.CondStringEquals,
|
||||||||
dkirillov
commented
I don't know how exactly storage node determines role when bearer token is applied, but I think using public key condition is more robust I don't know how exactly storage node determines role when bearer token is applied, but I think using public key condition is more robust
cc @alexvanin
|
||||||||
Kind: chain.KindRequest,
|
||||||||
Key: native.PropertyKeyActorRole,
|
||||||||
Value: native.PropertyValueContainerRoleOwner,
|
||||||||
},
|
||||||||
}
|
||||||||
return rule
|
||||||||
}
|
||||||||
|
||||||||
func TestIntegration(t *testing.T) {
|
||||||||
rootCtx := context.Background()
|
||||||||
aioImage := "git.frostfs.info/truecloudlab/frostfs-aio:"
|
||||||||
|
@ -59,6 +116,7 @@ func TestIntegration(t *testing.T) {
|
|||||||
"1.3.0",
|
||||||||
"1.5.0",
|
||||||||
"1.6.5",
|
||||||||
"1.7.0",
|
||||||||
}
|
||||||||
key, err := keys.NewPrivateKeyFromHex("1dd37fba80fec4e6a6f13fd708d8dcb3b29def768017052f6c930fa1c5d90bbb")
|
||||||||
require.NoError(t, err)
|
||||||||
|
@ -75,10 +133,16 @@ func TestIntegration(t *testing.T) {
|
|||||||
ctx, cancel2 := context.WithCancel(rootCtx)
|
||||||||
|
||||||||
aioContainer := createDockerContainer(ctx, t, aioImage+version)
|
||||||||
if strings.HasPrefix(version, "1.6") {
|
||||||||
versionNumber := versionToUint(t, version)
|
||||||||
if versionNumber >= versionToUint(t, "1.6.0") {
|
||||||||
registerUser(t, ctx, aioContainer, file.Name())
|
||||||||
}
|
||||||||
|
||||||||
createContainer := createContainerWithACL
|
||||||||
if versionNumber >= versionToUint(t, "1.7.0") {
|
||||||||
createContainer = createContainerWithAPE
|
||||||||
}
|
||||||||
|
||||||||
// Creating CORS container
|
||||||||
clientPool := getPool(ctx, t, key)
|
||||||||
_, err = createContainer(ctx, t, clientPool, ownerID, testCORSContainerName)
|
||||||||
|
@ -469,15 +533,18 @@ func checkStatusCodes(ctx context.Context, t *testing.T, clientPool *pool.Pool,
|
|||||||
t.Run("access denied", func(t *testing.T) {
|
||||||||
basicACL := acl.Private
|
||||||||
var recs []*eacl.Record
|
||||||||
var APERules []chain.Rule
|
||||||||
if version == "1.2.7" {
|
||||||||
basicACL = acl.PublicRWExtended
|
||||||||
rec := eacl.NewRecord()
|
||||||||
rec.SetAction(eacl.ActionDeny)
|
||||||||
rec.SetOperation(eacl.OperationGet)
|
||||||||
recs = append(recs, rec)
|
||||||||
} else if versionToUint(t, version) >= versionToUint(t, "1.7.0") {
|
||||||||
APERules = privateRules()
|
||||||||
}
|
||||||||
|
||||||||
cnrID, err := createContainerBase(ctx, t, clientPool, ownerID, basicACL, "")
|
||||||||
cnrID, err := createContainerBase(ctx, t, clientPool, ownerID, basicACL, APERules, "")
|
||||||||
require.NoError(t, err)
|
||||||||
|
||||||||
key, err := keys.NewPrivateKey()
|
||||||||
|
@ -560,11 +627,77 @@ func getPool(ctx context.Context, t *testing.T, key *keys.PrivateKey) *pool.Pool
|
|||||||
return clientPool
|
||||||||
}
|
||||||||
|
||||||||
func createContainer(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, name string) (cid.ID, error) {
|
||||||||
return createContainerBase(ctx, t, clientPool, ownerID, acl.PublicRWExtended, name)
|
||||||||
func createContainerWithACL(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, name string) (cid.ID, error) {
|
||||||||
return createContainerBase(ctx, t, clientPool, ownerID, acl.PublicRWExtended, nil, name)
|
||||||||
}
|
||||||||
dkirillov marked this conversation as resolved
Outdated
dkirillov
commented
acl here must be acl here must be `0` instead of `acl.PublicRWExtended`
|
||||||||
|
||||||||
func createContainerBase(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, basicACL acl.Basic, name string) (cid.ID, error) {
|
||||||||
func createContainerWithAPE(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, name string) (cid.ID, error) {
|
||||||||
return createContainerBase(ctx, t, clientPool, ownerID, 0, publicReadWriteRules(), name)
|
||||||||
dkirillov marked this conversation as resolved
Outdated
dkirillov
commented
Maybe the better name is Maybe the better name is `waitForAPEBeApplied` or something like this?
|
||||||||
}
|
||||||||
|
||||||||
func waitForAPEBeApplied(ctx context.Context, clientPool *pool.Pool, expectedCh chain.Chain, cnrID cid.ID) error {
|
||||||||
prmListAPEChains := pool.PrmListAPEChains{
|
||||||||
Target: ape.ChainTarget{
|
||||||||
TargetType: ape.TargetTypeContainer,
|
||||||||
Name: cnrID.EncodeToString(),
|
||||||||
},
|
||||||||
dkirillov marked this conversation as resolved
Outdated
dkirillov
commented
By the way, why do need this function? Can we just get error from By the way, why do need this function?
Can we just get error from `clientPool.ListAPEChains` (we pass context there) or by using `ctx.Err()` when `case <- ctx.Done():` happens?
|
||||||||
}
|
||||||||
|
||||||||
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
||||||||
defer cancel()
|
||||||||
for {
|
||||||||
chains, err := clientPool.ListAPEChains(ctx, prmListAPEChains)
|
||||||||
if err != nil {
|
||||||||
return fmt.Errorf("list APE chains: %w", err)
|
||||||||
}
|
||||||||
for _, rawChain := range chains {
|
||||||||
var ch chain.Chain
|
||||||||
err = ch.UnmarshalBinary(rawChain.Raw)
|
||||||||
if err != nil {
|
||||||||
return fmt.Errorf("unmarshal chain: %w", err)
|
||||||||
}
|
||||||||
if bytes.Equal(ch.ID, expectedCh.ID) {
|
||||||||
// At the moment, according to the core team, there is no way through the API
|
||||||||
// to check whether the APE chain stored in the contract has been applied to the container.
|
||||||||
// So after we make sure that the APE chain is stored, we just wait for a certain period of time
|
||||||||
// (8 seconds by default, the time until the next block and cache invalidation)
|
||||||||
select {
|
||||||||
case <-ctx.Done():
|
||||||||
return ctx.Err()
|
||||||||
case <-time.After(8 * time.Second):
|
||||||||
dkirillov
commented
Maybe we should use AIO images where this cache is disables at all? cc @alexvanin Maybe we should use AIO images where this cache is disables at all?
cc @alexvanin
|
||||||||
return nil
|
||||||||
}
|
||||||||
}
|
||||||||
}
|
||||||||
select {
|
||||||||
case <-ctx.Done():
|
||||||||
return ctx.Err()
|
||||||||
case <-time.After(500 * time.Millisecond):
|
||||||||
}
|
||||||||
}
|
||||||||
}
|
||||||||
|
||||||||
func addAPEChainToContainer(ctx context.Context, t *testing.T, clientPool *pool.Pool, chainID string, rules []chain.Rule, cnrID cid.ID) {
|
||||||||
ch := chain.Chain{
|
||||||||
ID: chain.ID(chainID),
|
||||||||
Rules: rules,
|
||||||||
}
|
||||||||
data, err := ch.MarshalBinary()
|
||||||||
require.NoError(t, err)
|
||||||||
prmAddAPEChain := pool.PrmAddAPEChain{
|
||||||||
Target: ape.ChainTarget{
|
||||||||
TargetType: ape.TargetTypeContainer,
|
||||||||
Name: cnrID.EncodeToString(),
|
||||||||
},
|
||||||||
Chain: ape.Chain{Raw: data},
|
||||||||
}
|
||||||||
err = clientPool.AddAPEChain(ctx, prmAddAPEChain)
|
||||||||
require.NoError(t, err)
|
||||||||
err = waitForAPEBeApplied(ctx, clientPool, ch, cnrID)
|
||||||||
require.NoError(t, err)
|
||||||||
}
|
||||||||
|
||||||||
func createContainerBase(ctx context.Context, t *testing.T, clientPool *pool.Pool, ownerID user.ID, basicACL acl.Basic, apeRules []chain.Rule, name string) (cid.ID, error) {
|
||||||||
dkirillov marked this conversation as resolved
Outdated
dkirillov
commented
Should we check Should we check `err` here too?
|
||||||||
var policy netmap.PlacementPolicy
|
||||||||
err := policy.DecodeString("REP 1")
|
||||||||
require.NoError(t, err)
|
||||||||
|
@ -572,7 +705,9 @@ func createContainerBase(ctx context.Context, t *testing.T, clientPool *pool.Poo
|
|||||||
var cnr container.Container
|
||||||||
cnr.Init()
|
||||||||
cnr.SetPlacementPolicy(policy)
|
||||||||
cnr.SetBasicACL(basicACL)
|
||||||||
if basicACL != 0 {
|
||||||||
cnr.SetBasicACL(basicACL)
|
||||||||
}
|
||||||||
cnr.SetOwner(ownerID)
|
||||||||
|
||||||||
container.SetCreationTime(&cnr, time.Now())
|
||||||||
|
@ -601,6 +736,11 @@ func createContainerBase(ctx context.Context, t *testing.T, clientPool *pool.Poo
|
|||||||
}
|
||||||||
fmt.Println(CID.String())
|
||||||||
|
||||||||
if len(apeRules) != 0 {
|
||||||||
chainID := "http-aio-" + CID.String()[:8]
|
||||||||
addAPEChainToContainer(ctx, t, clientPool, chainID, apeRules, CID)
|
||||||||
}
|
||||||||
|
||||||||
return CID, err
|
||||||||
}
|
||||||||
|
||||||||
|
|
3
go.mod
3
go.mod
|
@ -8,6 +8,7 @@ require (
|
|||
git.frostfs.info/TrueCloudLab/frostfs-qos v0.0.0-20250128150313-cfbca7fa1dfe
|
||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20250317082814-87bb55f992dc
|
||||
git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972
|
||||
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20250425083815-09ff3bf14991
|
||||
git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02
|
||||
github.com/bluele/gcache v0.0.2
|
||||
github.com/docker/docker v27.1.1+incompatible
|
||||
|
@ -68,10 +69,12 @@ require (
|
|||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/ipfs/go-cid v0.0.7 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/minio/sha256-simd v1.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
|
|
2
go.sum
2
go.sum
|
@ -52,6 +52,8 @@ git.frostfs.info/TrueCloudLab/hrw v1.2.1 h1:ccBRK21rFvY5R1WotI6LNoPlizk7qSvdfD8l
|
|||
git.frostfs.info/TrueCloudLab/hrw v1.2.1/go.mod h1:C1Ygde2n843yTZEQ0FP69jYiuaYV0kriLvP4zm8JuvM=
|
||||
git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972 h1:/960fWeyn2AFHwQUwDsWB3sbP6lTEnFnMzLMM6tx6N8=
|
||||
git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972/go.mod h1:2hM42MBrlhvN6XToaW6OWNk5ZLcu1FhaukGgxtfpDDI=
|
||||
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20250425083815-09ff3bf14991 h1:eTefR8y2y9cg7X5kybIcXDdmABfk/3A2awdmFD3zOsA=
|
||||
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20250425083815-09ff3bf14991/go.mod h1:GZTk55RI4dKzsK6BCn5h2xxE28UHNfgoq/NJxW/LQ6A=
|
||||
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 h1:M2KR3iBj7WpY3hP10IevfIB9MURr4O9mwVfJ+SjT3HA=
|
||||
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0/go.mod h1:okpbKfVYf/BpejtfFTfhZqFP+sZ8rsHrP8Rr/jYPNRc=
|
||||
git.frostfs.info/TrueCloudLab/tzhash v1.8.0 h1:UFMnUIk0Zh17m8rjGHJMqku2hCgaXDqjqZzS4gsb4UA=
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue
What about versions like
v0.33.0-rc.6
?This function is used to convert the version numbers of aio-containers (which we test and explicitly list at the beginning of the TestIntegration function) into a numeric format. The versions follow the "MAJOR.MINOR.PATCH" format. If in the future there's a need to support versions with an additional suffix (e.g., "1.7.2-nightly1"), this function can be extended accordingly—but for now, that would be premature.