K8s/Annotations: Use manager/source annotations rather than repo (#101313)
Co-authored-by: Stephanie Hingtgen <stephanie.hingtgen@grafana.com>
This commit is contained in:
co-authored by
Stephanie Hingtgen
parent
e7baf9804e
commit
dc2defd84f
@@ -1,28 +1,27 @@
|
||||
package utils
|
||||
|
||||
import "time"
|
||||
|
||||
// ManagerProperties is used to identify the manager of the resource.
|
||||
type ManagerProperties struct {
|
||||
// The kind of manager, which is responsible for managing the resource.
|
||||
// Examples include "git", "terraform", "kubectl", etc.
|
||||
Kind ManagerKind
|
||||
Kind ManagerKind `json:"kind,omitempty"`
|
||||
|
||||
// The identity of the manager, which refers to a specific instance of the manager.
|
||||
// The format & the value depends on the manager kind.
|
||||
Identity string
|
||||
Identity string `json:"id,omitempty"`
|
||||
|
||||
// AllowsEdits indicates whether the manager allows edits to the resource.
|
||||
// If set to true, it means that other requesters can edit the resource.
|
||||
AllowsEdits bool
|
||||
AllowsEdits bool `json:"allowEdits,omitempty"`
|
||||
|
||||
// Suspended indicates whether the manager is suspended.
|
||||
// If set to true, then the manager skip updates to the resource.
|
||||
Suspended bool
|
||||
Suspended bool `json:"suspended,omitempty"`
|
||||
}
|
||||
|
||||
// ManagerKind is the type of manager, which is responsible for managing the resource.
|
||||
// It can be a user or a tool or a generic API client.
|
||||
// +enum
|
||||
type ManagerKind string
|
||||
|
||||
// Known values for ManagerKind.
|
||||
@@ -31,6 +30,11 @@ const (
|
||||
ManagerKindRepo ManagerKind = "repo"
|
||||
ManagerKindTerraform ManagerKind = "terraform"
|
||||
ManagerKindKubectl ManagerKind = "kubectl"
|
||||
ManagerKindPlugin ManagerKind = "plugin"
|
||||
|
||||
// Deprecated: this is used as a shim/migration path for legacy file provisioning
|
||||
// Previously this was a "file:" prefix
|
||||
ManagerKindClassicFP ManagerKind = "classic-file-provisioning"
|
||||
)
|
||||
|
||||
// ParseManagerKindString parses a string into a ManagerKind.
|
||||
@@ -44,6 +48,10 @@ func ParseManagerKindString(v string) ManagerKind {
|
||||
return ManagerKindTerraform
|
||||
case string(ManagerKindKubectl):
|
||||
return ManagerKindKubectl
|
||||
case string(ManagerKindPlugin):
|
||||
return ManagerKindPlugin
|
||||
case string(ManagerKindClassicFP): // nolint:staticcheck
|
||||
return ManagerKindClassicFP // nolint:staticcheck
|
||||
default:
|
||||
return ManagerKindUnknown
|
||||
}
|
||||
@@ -55,13 +63,13 @@ func ParseManagerKindString(v string) ManagerKind {
|
||||
type SourceProperties struct {
|
||||
// The path to the source of the resource.
|
||||
// Can be a file path, a URL, etc.
|
||||
Path string
|
||||
Path string `json:"path,omitempty"`
|
||||
|
||||
// The checksum of the source of the resource.
|
||||
// An example could be a git commit hash.
|
||||
Checksum string
|
||||
Checksum string `json:"checksum,omitempty"`
|
||||
|
||||
// The timestamp of the source of the resource.
|
||||
// The unix millis timestamp of the source of the resource.
|
||||
// An example could be the file modification time.
|
||||
Timestamp time.Time
|
||||
TimestampMillis int64 `json:"timestampMillis,omitempty"`
|
||||
}
|
||||
|
||||
+64
-136
@@ -41,10 +41,10 @@ const AnnoKeyMessage = "grafana.app/message"
|
||||
|
||||
// Identify where values came from
|
||||
|
||||
const AnnoKeyRepoName = "grafana.app/repoName"
|
||||
const AnnoKeyRepoPath = "grafana.app/repoPath"
|
||||
const AnnoKeyRepoHash = "grafana.app/repoHash"
|
||||
const AnnoKeyRepoTimestamp = "grafana.app/repoTimestamp"
|
||||
const oldAnnoKeyRepoName = "grafana.app/repoName"
|
||||
const oldAnnoKeyRepoPath = "grafana.app/repoPath"
|
||||
const oldAnnoKeyRepoHash = "grafana.app/repoHash"
|
||||
const oldAnnoKeyRepoTimestamp = "grafana.app/repoTimestamp"
|
||||
|
||||
// Annotations used to store manager properties
|
||||
|
||||
@@ -56,41 +56,13 @@ const AnnoKeyManagerSuspended = "grafana.app/managerSuspended"
|
||||
// Annotations used to store source properties
|
||||
|
||||
const AnnoKeySourcePath = "grafana.app/sourcePath"
|
||||
const AnnoKeySourceHash = "grafana.app/sourceHash"
|
||||
const AnnoKeySourceChecksum = "grafana.app/sourceChecksum"
|
||||
const AnnoKeySourceTimestamp = "grafana.app/sourceTimestamp"
|
||||
|
||||
// LabelKeyDeprecatedInternalID gives the deprecated internal ID of a resource
|
||||
// Deprecated: will be removed in grafana 13
|
||||
const LabelKeyDeprecatedInternalID = "grafana.app/deprecatedInternalID"
|
||||
|
||||
// These can be removed once we verify that non of the dual-write sources
|
||||
// (for dashboards/playlists/etc) depend on the saved internal ID in SQL
|
||||
const oldAnnoKeyOriginName = "grafana.app/originName"
|
||||
const oldAnnoKeyOriginPath = "grafana.app/originPath"
|
||||
const oldAnnoKeyOriginHash = "grafana.app/originHash"
|
||||
const oldAnnoKeyOriginTimestamp = "grafana.app/originTimestamp"
|
||||
|
||||
// ResourceRepositoryInfo is encoded into kubernetes metadata annotations.
|
||||
// This value identifies indicates the state of the resource in its provisioning source when
|
||||
// the spec was last saved. Currently this is derived from the dashboards provisioning table.
|
||||
type ResourceRepositoryInfo struct {
|
||||
// Name of the repository/provisioning source
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// The path within the named repository above (external_id in the existing dashboard provisioning)
|
||||
Path string `json:"path,omitempty"`
|
||||
|
||||
// Verification/identification hash (check_sum in existing dashboard provisioning)
|
||||
Hash string `json:"hash,omitempty"`
|
||||
|
||||
// Origin modification timestamp when the resource was saved
|
||||
// This will be before the resource updated time
|
||||
Timestamp *time.Time `json:"time,omitempty"`
|
||||
|
||||
// Avoid extending
|
||||
_ any `json:"-"`
|
||||
}
|
||||
|
||||
// Accessor functions for k8s objects
|
||||
type GrafanaMetaAccessor interface {
|
||||
metav1.Object
|
||||
@@ -128,13 +100,6 @@ type GrafanaMetaAccessor interface {
|
||||
// Deprecated: This will be removed in Grafana 13
|
||||
SetDeprecatedInternalID(id int64)
|
||||
|
||||
GetRepositoryInfo() (*ResourceRepositoryInfo, error)
|
||||
SetRepositoryInfo(info *ResourceRepositoryInfo)
|
||||
GetRepositoryName() string
|
||||
GetRepositoryPath() string
|
||||
GetRepositoryHash() string
|
||||
GetRepositoryTimestamp() (*time.Time, error)
|
||||
|
||||
GetSpec() (any, error)
|
||||
SetSpec(any) error
|
||||
|
||||
@@ -351,90 +316,6 @@ func (m *grafanaMetaAccessor) SetDeprecatedInternalID(id int64) {
|
||||
m.obj.SetLabels(labels)
|
||||
}
|
||||
|
||||
// This allows looking up a primary and secondary key -- if either exist the value will be returned
|
||||
func (m *grafanaMetaAccessor) getAnnoValue(primary, secondary string) (string, bool) {
|
||||
v, ok := m.obj.GetAnnotations()[primary]
|
||||
if !ok {
|
||||
v, ok = m.obj.GetAnnotations()[secondary]
|
||||
}
|
||||
return v, ok
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) SetRepositoryInfo(info *ResourceRepositoryInfo) {
|
||||
anno := m.obj.GetAnnotations()
|
||||
if anno == nil {
|
||||
if info == nil {
|
||||
return
|
||||
}
|
||||
anno = make(map[string]string, 0)
|
||||
}
|
||||
|
||||
// remove legacy values
|
||||
delete(anno, oldAnnoKeyOriginHash)
|
||||
delete(anno, oldAnnoKeyOriginPath)
|
||||
delete(anno, oldAnnoKeyOriginHash)
|
||||
delete(anno, oldAnnoKeyOriginTimestamp)
|
||||
|
||||
delete(anno, AnnoKeyRepoName)
|
||||
delete(anno, AnnoKeyRepoPath)
|
||||
delete(anno, AnnoKeyRepoHash)
|
||||
delete(anno, AnnoKeyRepoTimestamp)
|
||||
if info != nil && info.Name != "" {
|
||||
anno[AnnoKeyRepoName] = info.Name
|
||||
if info.Path != "" {
|
||||
anno[AnnoKeyRepoPath] = info.Path
|
||||
}
|
||||
if info.Hash != "" {
|
||||
anno[AnnoKeyRepoHash] = info.Hash
|
||||
}
|
||||
if info.Timestamp != nil {
|
||||
anno[AnnoKeyRepoTimestamp] = info.Timestamp.UTC().Format(time.RFC3339)
|
||||
}
|
||||
}
|
||||
m.obj.SetAnnotations(anno)
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) GetRepositoryInfo() (*ResourceRepositoryInfo, error) {
|
||||
v, ok := m.getAnnoValue(AnnoKeyRepoName, oldAnnoKeyOriginName)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
t, err := m.GetRepositoryTimestamp()
|
||||
return &ResourceRepositoryInfo{
|
||||
Name: v,
|
||||
Path: m.GetRepositoryPath(),
|
||||
Hash: m.GetRepositoryHash(),
|
||||
Timestamp: t,
|
||||
}, err
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) GetRepositoryName() string {
|
||||
v, _ := m.getAnnoValue(AnnoKeyRepoName, oldAnnoKeyOriginName)
|
||||
return v // will be empty string
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) GetRepositoryPath() string {
|
||||
v, _ := m.getAnnoValue(AnnoKeyRepoPath, oldAnnoKeyOriginPath)
|
||||
return v // will be empty string
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) GetRepositoryHash() string {
|
||||
v, _ := m.getAnnoValue(AnnoKeyRepoHash, oldAnnoKeyOriginHash)
|
||||
return v // will be empty string
|
||||
}
|
||||
|
||||
func (m *grafanaMetaAccessor) GetRepositoryTimestamp() (*time.Time, error) {
|
||||
v, ok := m.getAnnoValue(AnnoKeyRepoTimestamp, oldAnnoKeyOriginTimestamp)
|
||||
if !ok || v == "" {
|
||||
return nil, nil
|
||||
}
|
||||
t, err := time.Parse(time.RFC3339, v)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid origin timestamp: %s", err.Error())
|
||||
}
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
// GetAnnotations implements GrafanaMetaAccessor.
|
||||
func (m *grafanaMetaAccessor) GetAnnotations() map[string]string {
|
||||
return m.obj.GetAnnotations()
|
||||
@@ -751,7 +632,7 @@ func (m *grafanaMetaAccessor) GetManagerProperties() (ManagerProperties, bool) {
|
||||
res := ManagerProperties{
|
||||
Identity: "",
|
||||
Kind: ManagerKindUnknown,
|
||||
AllowsEdits: true,
|
||||
AllowsEdits: false,
|
||||
Suspended: false,
|
||||
}
|
||||
|
||||
@@ -759,6 +640,15 @@ func (m *grafanaMetaAccessor) GetManagerProperties() (ManagerProperties, bool) {
|
||||
|
||||
id, ok := annot[AnnoKeyManagerIdentity]
|
||||
if !ok || id == "" {
|
||||
// Temporarily support the repo name annotation
|
||||
repo := annot[oldAnnoKeyRepoName]
|
||||
if repo != "" {
|
||||
return ManagerProperties{
|
||||
Kind: ManagerKindRepo,
|
||||
Identity: repo,
|
||||
}, true
|
||||
}
|
||||
|
||||
// If the identity is not set, we should ignore the other annotations and return the default values.
|
||||
//
|
||||
// This is to prevent inadvertently marking resources as managed,
|
||||
@@ -788,10 +678,31 @@ func (m *grafanaMetaAccessor) SetManagerProperties(v ManagerProperties) {
|
||||
annot = make(map[string]string, 4)
|
||||
}
|
||||
|
||||
annot[AnnoKeyManagerIdentity] = v.Identity
|
||||
annot[AnnoKeyManagerKind] = string(v.Kind)
|
||||
annot[AnnoKeyManagerAllowsEdits] = strconv.FormatBool(v.AllowsEdits)
|
||||
annot[AnnoKeyManagerSuspended] = strconv.FormatBool(v.Suspended)
|
||||
if v.Identity != "" {
|
||||
annot[AnnoKeyManagerIdentity] = v.Identity
|
||||
} else {
|
||||
delete(annot, AnnoKeyManagerIdentity)
|
||||
}
|
||||
|
||||
if string(v.Kind) != "" {
|
||||
annot[AnnoKeyManagerKind] = string(v.Kind)
|
||||
} else {
|
||||
delete(annot, AnnoKeyManagerKind)
|
||||
}
|
||||
|
||||
if v.AllowsEdits {
|
||||
annot[AnnoKeyManagerAllowsEdits] = strconv.FormatBool(v.AllowsEdits)
|
||||
} else {
|
||||
delete(annot, AnnoKeyManagerAllowsEdits)
|
||||
}
|
||||
if v.Suspended {
|
||||
annot[AnnoKeyManagerSuspended] = strconv.FormatBool(v.Suspended)
|
||||
} else {
|
||||
delete(annot, AnnoKeyManagerSuspended)
|
||||
}
|
||||
|
||||
// Clean up old annotation access
|
||||
delete(annot, oldAnnoKeyRepoName)
|
||||
|
||||
m.obj.SetAnnotations(annot)
|
||||
}
|
||||
@@ -810,16 +721,27 @@ func (m *grafanaMetaAccessor) GetSourceProperties() (SourceProperties, bool) {
|
||||
if path, ok := annot[AnnoKeySourcePath]; ok && path != "" {
|
||||
res.Path = path
|
||||
found = true
|
||||
} else if path, ok := annot[oldAnnoKeyRepoPath]; ok && path != "" {
|
||||
res.Path = path
|
||||
found = true
|
||||
}
|
||||
|
||||
if hash, ok := annot[AnnoKeySourceHash]; ok && hash != "" {
|
||||
if hash, ok := annot[AnnoKeySourceChecksum]; ok && hash != "" {
|
||||
res.Checksum = hash
|
||||
found = true
|
||||
} else if hash, ok := annot[oldAnnoKeyRepoHash]; ok && hash != "" {
|
||||
res.Checksum = hash
|
||||
found = true
|
||||
}
|
||||
|
||||
if timestamp, ok := annot[AnnoKeySourceTimestamp]; ok && timestamp != "" {
|
||||
if t, err := time.Parse(time.RFC3339, timestamp); err == nil {
|
||||
res.Timestamp = t
|
||||
t, ok := annot[AnnoKeySourceTimestamp]
|
||||
if !ok {
|
||||
t, ok = annot[oldAnnoKeyRepoTimestamp]
|
||||
}
|
||||
if ok && t != "" {
|
||||
var err error
|
||||
res.TimestampMillis, err = strconv.ParseInt(t, 10, 64)
|
||||
if err != nil {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
@@ -835,14 +757,20 @@ func (m *grafanaMetaAccessor) SetSourceProperties(v SourceProperties) {
|
||||
|
||||
if v.Path != "" {
|
||||
annot[AnnoKeySourcePath] = v.Path
|
||||
} else {
|
||||
delete(annot, AnnoKeySourcePath)
|
||||
}
|
||||
|
||||
if v.Checksum != "" {
|
||||
annot[AnnoKeySourceHash] = v.Checksum
|
||||
annot[AnnoKeySourceChecksum] = v.Checksum
|
||||
} else {
|
||||
delete(annot, AnnoKeySourceChecksum)
|
||||
}
|
||||
|
||||
if !v.Timestamp.IsZero() {
|
||||
annot[AnnoKeySourceTimestamp] = v.Timestamp.Format(time.RFC3339)
|
||||
if v.TimestampMillis > 0 {
|
||||
annot[AnnoKeySourceTimestamp] = strconv.FormatInt(v.TimestampMillis, 10)
|
||||
} else {
|
||||
delete(annot, AnnoKeySourceTimestamp)
|
||||
}
|
||||
|
||||
m.obj.SetAnnotations(annot)
|
||||
|
||||
@@ -131,10 +131,13 @@ func (in *Spec2) DeepCopy() *Spec2 {
|
||||
}
|
||||
|
||||
func TestMetaAccessor(t *testing.T) {
|
||||
repoInfo := &utils.ResourceRepositoryInfo{
|
||||
Name: "test",
|
||||
Path: "a/b/c",
|
||||
Hash: "kkk",
|
||||
repoInfo := utils.ManagerProperties{
|
||||
Kind: utils.ManagerKindRepo,
|
||||
Identity: "test",
|
||||
}
|
||||
sourceInfo := utils.SourceProperties{
|
||||
Path: "a/b/c",
|
||||
Checksum: "kkk",
|
||||
}
|
||||
|
||||
t.Run("fails for non resource objects", func(t *testing.T) {
|
||||
@@ -202,14 +205,13 @@ func TestMetaAccessor(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
meta.SetRepositoryInfo(repoInfo)
|
||||
meta.SetManagerProperties(repoInfo)
|
||||
meta.SetFolder("folderUID")
|
||||
|
||||
require.Equal(t, map[string]string{
|
||||
"grafana.app/repoName": "test",
|
||||
"grafana.app/repoPath": "a/b/c",
|
||||
"grafana.app/repoHash": "kkk",
|
||||
"grafana.app/folder": "folderUID",
|
||||
"grafana.app/managedBy": "repo",
|
||||
"grafana.app/managerId": "test",
|
||||
"grafana.app/folder": "folderUID",
|
||||
}, res.GetAnnotations())
|
||||
|
||||
meta.SetNamespace("aaa")
|
||||
@@ -255,14 +257,16 @@ func TestMetaAccessor(t *testing.T) {
|
||||
meta, err := utils.MetaAccessor(res)
|
||||
require.NoError(t, err)
|
||||
|
||||
meta.SetRepositoryInfo(repoInfo)
|
||||
meta.SetManagerProperties(repoInfo)
|
||||
meta.SetSourceProperties(sourceInfo)
|
||||
meta.SetFolder("folderUID")
|
||||
|
||||
require.Equal(t, map[string]string{
|
||||
"grafana.app/repoName": "test",
|
||||
"grafana.app/repoPath": "a/b/c",
|
||||
"grafana.app/repoHash": "kkk",
|
||||
"grafana.app/folder": "folderUID",
|
||||
"grafana.app/managedBy": "repo",
|
||||
"grafana.app/managerId": "test",
|
||||
"grafana.app/sourcePath": "a/b/c",
|
||||
"grafana.app/sourceChecksum": "kkk",
|
||||
"grafana.app/folder": "folderUID",
|
||||
}, res.GetAnnotations())
|
||||
|
||||
meta.SetNamespace("aaa")
|
||||
@@ -306,14 +310,13 @@ func TestMetaAccessor(t *testing.T) {
|
||||
meta, err := utils.MetaAccessor(res)
|
||||
require.NoError(t, err)
|
||||
|
||||
meta.SetRepositoryInfo(repoInfo)
|
||||
meta.SetManagerProperties(repoInfo)
|
||||
meta.SetFolder("folderUID")
|
||||
|
||||
require.Equal(t, map[string]string{
|
||||
"grafana.app/repoName": "test",
|
||||
"grafana.app/repoPath": "a/b/c",
|
||||
"grafana.app/repoHash": "kkk",
|
||||
"grafana.app/folder": "folderUID",
|
||||
"grafana.app/managedBy": "repo",
|
||||
"grafana.app/managerId": "test",
|
||||
"grafana.app/folder": "folderUID",
|
||||
}, res.GetAnnotations())
|
||||
|
||||
meta.SetNamespace("aaa")
|
||||
@@ -347,7 +350,7 @@ func TestMetaAccessor(t *testing.T) {
|
||||
require.Equal(t, "ZZ", res.Status.Title)
|
||||
})
|
||||
|
||||
t.Run("test reading old originInfo (now repository)", func(t *testing.T) {
|
||||
t.Run("test reading old repo fields (now manager+source)", func(t *testing.T) {
|
||||
res := &TestResource2{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
@@ -362,11 +365,15 @@ func TestMetaAccessor(t *testing.T) {
|
||||
meta, err := utils.MetaAccessor(res)
|
||||
require.NoError(t, err)
|
||||
|
||||
info, err := meta.GetRepositoryInfo()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "test", info.Name)
|
||||
require.Equal(t, "a/b/c", info.Path)
|
||||
require.Equal(t, "zzz", info.Hash)
|
||||
manager, ok := meta.GetManagerProperties()
|
||||
require.True(t, ok)
|
||||
require.Equal(t, utils.ManagerKindRepo, manager.Kind)
|
||||
require.Equal(t, "test", manager.Identity)
|
||||
|
||||
source, ok := meta.GetSourceProperties()
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "a/b/c", source.Path)
|
||||
require.Equal(t, "zzz", source.Checksum)
|
||||
})
|
||||
|
||||
t.Run("blob info", func(t *testing.T) {
|
||||
@@ -391,14 +398,16 @@ func TestMetaAccessor(t *testing.T) {
|
||||
|
||||
meta, err := utils.MetaAccessor(obj)
|
||||
require.NoError(t, err)
|
||||
meta.SetRepositoryInfo(repoInfo)
|
||||
meta.SetManagerProperties(repoInfo)
|
||||
meta.SetSourceProperties(sourceInfo)
|
||||
meta.SetFolder("folderUID")
|
||||
|
||||
require.Equal(t, map[string]string{
|
||||
"grafana.app/repoName": "test",
|
||||
"grafana.app/repoPath": "a/b/c",
|
||||
"grafana.app/repoHash": "kkk",
|
||||
"grafana.app/folder": "folderUID",
|
||||
"grafana.app/managedBy": "repo",
|
||||
"grafana.app/managerId": "test",
|
||||
"grafana.app/sourcePath": "a/b/c",
|
||||
"grafana.app/sourceChecksum": "kkk",
|
||||
"grafana.app/folder": "folderUID",
|
||||
}, obj.GetAnnotations())
|
||||
|
||||
require.Equal(t, "HELLO", obj.Spec.Title)
|
||||
@@ -414,14 +423,13 @@ func TestMetaAccessor(t *testing.T) {
|
||||
|
||||
meta, err = utils.MetaAccessor(obj2)
|
||||
require.NoError(t, err)
|
||||
meta.SetRepositoryInfo(repoInfo)
|
||||
meta.SetManagerProperties(repoInfo)
|
||||
meta.SetFolder("folderUID")
|
||||
|
||||
require.Equal(t, map[string]string{
|
||||
"grafana.app/repoName": "test",
|
||||
"grafana.app/repoPath": "a/b/c",
|
||||
"grafana.app/repoHash": "kkk",
|
||||
"grafana.app/folder": "folderUID",
|
||||
"grafana.app/managedBy": "repo",
|
||||
"grafana.app/managerId": "test",
|
||||
"grafana.app/folder": "folderUID",
|
||||
}, obj2.GetAnnotations())
|
||||
|
||||
require.Equal(t, "xxx", meta.FindTitle("xxx"))
|
||||
@@ -447,7 +455,7 @@ func TestMetaAccessor(t *testing.T) {
|
||||
wantProperties: utils.ManagerProperties{
|
||||
Identity: "",
|
||||
Kind: utils.ManagerKindUnknown,
|
||||
AllowsEdits: true,
|
||||
AllowsEdits: false,
|
||||
Suspended: false,
|
||||
},
|
||||
wantOK: false,
|
||||
@@ -479,7 +487,7 @@ func TestMetaAccessor(t *testing.T) {
|
||||
wantProperties: utils.ManagerProperties{
|
||||
Identity: "",
|
||||
Kind: utils.ManagerKindUnknown,
|
||||
AllowsEdits: true,
|
||||
AllowsEdits: false,
|
||||
Suspended: false,
|
||||
},
|
||||
wantOK: false,
|
||||
@@ -534,14 +542,14 @@ func TestMetaAccessor(t *testing.T) {
|
||||
{
|
||||
name: "set and get valid values",
|
||||
setProperties: &utils.SourceProperties{
|
||||
Path: "path",
|
||||
Checksum: "hash",
|
||||
Timestamp: time.Date(2025, 1, 1, 12, 0, 0, 0, time.UTC),
|
||||
Path: "path",
|
||||
Checksum: "hash",
|
||||
TimestampMillis: time.Date(2025, 1, 1, 12, 0, 0, 0, time.UTC).UnixMilli(),
|
||||
},
|
||||
wantProperties: utils.SourceProperties{
|
||||
Path: "path",
|
||||
Checksum: "hash",
|
||||
Timestamp: time.Date(2025, 1, 1, 12, 0, 0, 0, time.UTC),
|
||||
Path: "path",
|
||||
Checksum: "hash",
|
||||
TimestampMillis: time.Date(2025, 1, 1, 12, 0, 0, 0, time.UTC).UnixMilli(),
|
||||
},
|
||||
wantOK: true,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user