setup settingstore
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/validation"
|
||||
)
|
||||
|
||||
const (
|
||||
settingsSection = "unified/settings"
|
||||
)
|
||||
|
||||
type settingStore struct {
|
||||
kv KV
|
||||
}
|
||||
|
||||
type SettingKey struct {
|
||||
Namespace string
|
||||
Group string
|
||||
Resource string
|
||||
}
|
||||
|
||||
func (k SettingKey) String() string {
|
||||
return fmt.Sprintf("%s/%s/%s", k.Group, k.Resource, k.Namespace)
|
||||
}
|
||||
|
||||
func (k SettingKey) Validate() error {
|
||||
if k.Namespace == "" {
|
||||
return NewValidationError("namespace", k.Namespace, ErrNamespaceRequired)
|
||||
}
|
||||
if err := validation.IsValidGroup(k.Group); err != nil {
|
||||
return NewValidationError("group", k.Group, err[0])
|
||||
}
|
||||
if err := validation.IsValidResource(k.Resource); err != nil {
|
||||
return NewValidationError("resource", k.Resource, err[0])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Setting struct {
|
||||
Namespace string `json:"namespace"`
|
||||
Group string `json:"group"`
|
||||
Resource string `json:"resource"`
|
||||
LastImportTime time.Time `json:"lastImportTime"`
|
||||
}
|
||||
|
||||
func newSettingStore(kv KV) *settingStore {
|
||||
return &settingStore{
|
||||
kv: kv,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *settingStore) Get(ctx context.Context, key SettingKey) (Setting, error) {
|
||||
if err := key.Validate(); err != nil {
|
||||
return Setting{}, fmt.Errorf("invalid setting key: %w", err)
|
||||
}
|
||||
|
||||
reader, err := d.kv.Get(ctx, settingsSection, key.String())
|
||||
if err != nil {
|
||||
return Setting{}, err
|
||||
}
|
||||
defer func() { _ = reader.Close() }()
|
||||
var setting Setting
|
||||
if err = json.NewDecoder(reader).Decode(&setting); err != nil {
|
||||
return Setting{}, err
|
||||
}
|
||||
return setting, nil
|
||||
}
|
||||
|
||||
func (d *settingStore) Save(ctx context.Context, setting Setting) error {
|
||||
settingKey := SettingKey{
|
||||
Namespace: setting.Namespace,
|
||||
Group: setting.Group,
|
||||
Resource: setting.Resource,
|
||||
}
|
||||
|
||||
if err := settingKey.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid settingKey key: %w", err)
|
||||
}
|
||||
|
||||
writer, err := d.kv.Save(ctx, settingsSection, settingKey.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
encoder := json.NewEncoder(writer)
|
||||
if err := encoder.Encode(setting); err != nil {
|
||||
_ = writer.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
return writer.Close()
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func setupTestSettingStore(t *testing.T) *settingStore {
|
||||
db := setupTestBadgerDB(t)
|
||||
t.Cleanup(func() {
|
||||
err := db.Close()
|
||||
require.NoError(t, err)
|
||||
})
|
||||
kv := NewBadgerKV(db)
|
||||
return newSettingStore(kv)
|
||||
}
|
||||
|
||||
func TestNewSettingStore(t *testing.T) {
|
||||
store := setupTestSettingStore(t)
|
||||
assert.NotNil(t, store.kv)
|
||||
}
|
||||
|
||||
func TestSettingStore_SettingKey_String(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
settingKey SettingKey
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "basic event key",
|
||||
settingKey: SettingKey{
|
||||
Namespace: "default",
|
||||
Group: "apps",
|
||||
Resource: "resource",
|
||||
},
|
||||
expected: "apps/resource/default",
|
||||
},
|
||||
{
|
||||
name: "empty namespace",
|
||||
settingKey: SettingKey{
|
||||
Namespace: "",
|
||||
Group: "apps",
|
||||
Resource: "resource",
|
||||
},
|
||||
expected: "apps/resource/",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := tt.settingKey.String()
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSettingStore_SettingKey_Validate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
key SettingKey
|
||||
error error
|
||||
}{
|
||||
{
|
||||
name: "valid key",
|
||||
key: SettingKey{
|
||||
Namespace: "default",
|
||||
Group: "apps",
|
||||
Resource: "resource",
|
||||
},
|
||||
error: nil,
|
||||
},
|
||||
{
|
||||
name: "empty namespace",
|
||||
key: SettingKey{
|
||||
Namespace: "",
|
||||
Group: "apps",
|
||||
Resource: "resource",
|
||||
},
|
||||
error: errors.New("namespace '' is invalid: namespace is required"),
|
||||
},
|
||||
{
|
||||
name: "empty group",
|
||||
key: SettingKey{
|
||||
Namespace: "default",
|
||||
Group: "",
|
||||
Resource: "resource",
|
||||
},
|
||||
error: errors.New("group '' is invalid: group is too short"),
|
||||
},
|
||||
{
|
||||
name: "empty resource",
|
||||
key: SettingKey{
|
||||
Namespace: "default",
|
||||
Group: "apps",
|
||||
Resource: "",
|
||||
},
|
||||
error: errors.New("resource '' is invalid: resource is too short"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.key.Validate()
|
||||
|
||||
if tt.error == nil {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.Error(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSettingStore_Save_Get(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
store := setupTestSettingStore(t)
|
||||
|
||||
setting := Setting{
|
||||
Namespace: "default",
|
||||
Group: "apps",
|
||||
Resource: "resource",
|
||||
LastImportTime: time.Now().Truncate(time.Microsecond),
|
||||
}
|
||||
|
||||
err := store.Save(ctx, setting)
|
||||
require.NoError(t, err)
|
||||
|
||||
settingKey := SettingKey{
|
||||
Namespace: "default",
|
||||
Group: "apps",
|
||||
Resource: "resource",
|
||||
}
|
||||
|
||||
retrievedSetting, err := store.Get(ctx, settingKey)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, setting, retrievedSetting)
|
||||
}
|
||||
Reference in New Issue
Block a user