[#352] container: Implement iterators over attributes
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
This commit is contained in:
parent
88bc9eeb26
commit
a0e4d16dbb
3 changed files with 133 additions and 7 deletions
|
@ -5,6 +5,7 @@ import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"iter"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -337,10 +338,41 @@ func (x Container) Attribute(key string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attributes returns an iterator over all Container attributes.
|
||||||
|
//
|
||||||
|
// See also [Container.SetAttribute], [Container.UserAttributes].
|
||||||
|
func (x Container) Attributes() iter.Seq2[string, string] {
|
||||||
|
return func(yield func(string, string) bool) {
|
||||||
|
attrs := x.v2.GetAttributes()
|
||||||
|
for i := range attrs {
|
||||||
|
if !yield(attrs[i].GetKey(), attrs[i].GetValue()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attributes returns an iterator over all non-system Container attributes.
|
||||||
|
//
|
||||||
|
// See also [Container.SetAttribute], [Container.Attributes].
|
||||||
|
func (x Container) UserAttributes() iter.Seq2[string, string] {
|
||||||
|
return func(yield func(string, string) bool) {
|
||||||
|
for key, value := range x.Attributes() {
|
||||||
|
if !strings.HasPrefix(key, container.SysAttributePrefix) {
|
||||||
|
if !yield(key, value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// IterateAttributes iterates over all Container attributes and passes them
|
// IterateAttributes iterates over all Container attributes and passes them
|
||||||
// into f. The handler MUST NOT be nil.
|
// into f. The handler MUST NOT be nil.
|
||||||
//
|
//
|
||||||
// See also SetAttribute, Attribute.
|
// See also SetAttribute, Attribute.
|
||||||
|
//
|
||||||
|
// Deprecated: use [Container.Attributes] instead.
|
||||||
func (x Container) IterateAttributes(f func(key, val string)) {
|
func (x Container) IterateAttributes(f func(key, val string)) {
|
||||||
attrs := x.v2.GetAttributes()
|
attrs := x.v2.GetAttributes()
|
||||||
for i := range attrs {
|
for i := range attrs {
|
||||||
|
@ -352,6 +384,8 @@ func (x Container) IterateAttributes(f func(key, val string)) {
|
||||||
// into f. The handler MUST NOT be nil.
|
// into f. The handler MUST NOT be nil.
|
||||||
//
|
//
|
||||||
// See also SetAttribute, Attribute.
|
// See also SetAttribute, Attribute.
|
||||||
|
//
|
||||||
|
// Deprecated: use [Container.UserAttributes] instead.
|
||||||
func (x Container) IterateUserAttributes(f func(key, val string)) {
|
func (x Container) IterateUserAttributes(f func(key, val string)) {
|
||||||
attrs := x.v2.GetAttributes()
|
attrs := x.v2.GetAttributes()
|
||||||
for _, attr := range attrs {
|
for _, attr := range attrs {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package container_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
"maps"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -159,9 +160,9 @@ func TestContainer_Attribute(t *testing.T) {
|
||||||
val.SetAttribute(attrKey2, attrVal2)
|
val.SetAttribute(attrKey2, attrVal2)
|
||||||
|
|
||||||
var i int
|
var i int
|
||||||
val.IterateUserAttributes(func(key, val string) {
|
for range val.UserAttributes() {
|
||||||
i++
|
i++
|
||||||
})
|
}
|
||||||
require.Equal(t, 1, i)
|
require.Equal(t, 1, i)
|
||||||
|
|
||||||
var msg v2container.Container
|
var msg v2container.Container
|
||||||
|
@ -177,11 +178,7 @@ func TestContainer_Attribute(t *testing.T) {
|
||||||
require.Equal(t, attrVal1, val2.Attribute(attrKey1))
|
require.Equal(t, attrVal1, val2.Attribute(attrKey1))
|
||||||
require.Equal(t, attrVal2, val2.Attribute(attrKey2))
|
require.Equal(t, attrVal2, val2.Attribute(attrKey2))
|
||||||
|
|
||||||
m := map[string]string{}
|
m := maps.Collect(val2.Attributes())
|
||||||
|
|
||||||
val2.IterateAttributes(func(key, val string) {
|
|
||||||
m[key] = val
|
|
||||||
})
|
|
||||||
|
|
||||||
require.GreaterOrEqual(t, len(m), 2)
|
require.GreaterOrEqual(t, len(m), 2)
|
||||||
require.Equal(t, attrVal1, m[attrKey1])
|
require.Equal(t, attrVal1, m[attrKey1])
|
||||||
|
|
95
container/iterators_test.go
Normal file
95
container/iterators_test.go
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
package container_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
containerAPI "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestContainer_Attributes(t *testing.T) {
|
||||||
|
t.Run("empty", func(t *testing.T) {
|
||||||
|
var n container.Container
|
||||||
|
t.Run("attributes", func(t *testing.T) {
|
||||||
|
for range n.Attributes() {
|
||||||
|
t.Fatalf("handler is called, but it shouldn't")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("user attributes", func(t *testing.T) {
|
||||||
|
for range n.UserAttributes() {
|
||||||
|
t.Fatalf("handler is called, but it shouldn't")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
var n container.Container
|
||||||
|
n.SetAttribute(containerAPI.SysAttributeName, "myname")
|
||||||
|
n.SetAttribute("key1", "value1")
|
||||||
|
n.SetAttribute("key2", "value2")
|
||||||
|
n.SetAttribute(containerAPI.SysAttributeZone, "test")
|
||||||
|
|
||||||
|
t.Run("break", func(t *testing.T) {
|
||||||
|
t.Run("attributes", func(t *testing.T) {
|
||||||
|
var res [][2]string
|
||||||
|
for key, value := range n.Attributes() {
|
||||||
|
if key == "key2" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
res = append(res, [2]string{key, value})
|
||||||
|
}
|
||||||
|
require.Equal(t, [][2]string{{containerAPI.SysAttributeName, "myname"}, {"key1", "value1"}}, res)
|
||||||
|
})
|
||||||
|
t.Run("user attributes", func(t *testing.T) {
|
||||||
|
var res [][2]string
|
||||||
|
for key, value := range n.UserAttributes() {
|
||||||
|
if key == "key2" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
res = append(res, [2]string{key, value})
|
||||||
|
}
|
||||||
|
require.Equal(t, [][2]string{{"key1", "value1"}}, res)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
t.Run("continue", func(t *testing.T) {
|
||||||
|
t.Run("attributes", func(t *testing.T) {
|
||||||
|
var res [][2]string
|
||||||
|
for key, value := range n.Attributes() {
|
||||||
|
if key == "key2" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
res = append(res, [2]string{key, value})
|
||||||
|
}
|
||||||
|
require.Equal(t, [][2]string{{containerAPI.SysAttributeName, "myname"}, {"key1", "value1"}, {containerAPI.SysAttributeZone, "test"}}, res)
|
||||||
|
})
|
||||||
|
t.Run("user attributes", func(t *testing.T) {
|
||||||
|
var res [][2]string
|
||||||
|
for key, value := range n.UserAttributes() {
|
||||||
|
if key == "key2" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
res = append(res, [2]string{key, value})
|
||||||
|
}
|
||||||
|
require.Equal(t, [][2]string{{"key1", "value1"}}, res)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
t.Run("attributes", func(t *testing.T) {
|
||||||
|
var res [][2]string
|
||||||
|
for key, value := range n.Attributes() {
|
||||||
|
res = append(res, [2]string{key, value})
|
||||||
|
}
|
||||||
|
require.Equal(t, [][2]string{
|
||||||
|
{containerAPI.SysAttributeName, "myname"},
|
||||||
|
{"key1", "value1"},
|
||||||
|
{"key2", "value2"},
|
||||||
|
{containerAPI.SysAttributeZone, "test"},
|
||||||
|
}, res)
|
||||||
|
})
|
||||||
|
t.Run("user attributes", func(t *testing.T) {
|
||||||
|
var res [][2]string
|
||||||
|
for key, value := range n.UserAttributes() {
|
||||||
|
res = append(res, [2]string{key, value})
|
||||||
|
}
|
||||||
|
require.Equal(t, [][2]string{{"key1", "value1"}, {"key2", "value2"}}, res)
|
||||||
|
})
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue