From 3f3ba7e6fa5aba89c9c9150861d8a04a0845711c Mon Sep 17 00:00:00 2001 From: Shamim Mohamed Date: Tue, 28 Aug 2018 15:55:03 -0700 Subject: [PATCH 1/3] PoC: ScopeMetadata and PrefixMetadata --- connector.go | 108 ------------------- metadata.go | 102 ++++++++++++++++++ prefix_metadata.go | 217 +++++++++++++++++++++++++++++++++++++ scope_metadata.go | 259 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 578 insertions(+), 108 deletions(-) create mode 100644 metadata.go create mode 100644 prefix_metadata.go create mode 100644 scope_metadata.go diff --git a/connector.go b/connector.go index da21e38b..c103d20e 100644 --- a/connector.go +++ b/connector.go @@ -22,9 +22,6 @@ package dosa import ( "context" - "fmt" - "sort" - "strings" "time" ) @@ -77,56 +74,6 @@ type EntityInfo struct { TTL *time.Duration } -// StringSet is a set of strings. -type StringSet map[string]struct{} - -// ScopeMetadata is metadata about a scope. (JSON tags to support MD setting CLI tools.) The scope -// may be qualified by a prefix, as in "production.vsoffers". -type ScopeMetadata struct { - Entity `dosa:"primaryKey=(Name)" json:"-"` - Name string `json:"name"` - Owner string `json:"owner"` // Owning group name (or the same as Creator) - Type int32 `json:"type"` // Production, Staging, or Development - Flags int64 `json:"flags"` - Version int32 `json:"version"` - PrefixStr string `json:"prefix_str,omitempty"` // With ":" separators - Cluster string `json:"cluster,omitempty"` // Host DB cluster - Creator string `json:"creator"` - CreatedOn time.Time `json:"created_on"` - ExpiresOn *time.Time `json:"expires_on,omitempty"` - ExtendCount int32 `json:"extend_count,omitempty"` - NotifyCount int32 `json:"notify_count,omitempty"` - ReadMaxRPS int32 `json:"read_max_rps"` - WriteMaxRPS int32 `json:"write_max_rps"` - // This is for convenience only, not stored in the DB: - Prefixes StringSet `dosa:"-" json:"-"` -} - -// MetadataSchemaVersion is the version of the schema of the scope metadata -const MetadataSchemaVersion = 1 - -// ScopeType is the type of a scope -type ScopeType int32 - -// Scope types -const ( - // Development scope (also the default, so should be 0) - Development ScopeType = iota - // Staging doesn't really exist yet, but may in the future - Staging - // Production scope - Production -) - -// ScopeFlagType is a set of scope flags -type ScopeFlagType int64 - -// Scope flags (remember to update ScopeFlagType.String) -const ( - // AccessFromProd means access is allowed from production (only relevant for Dev scopes) - AccessFromProd ScopeFlagType = 1 << iota -) - // FieldValue holds a field value. It's just a marker. type FieldValue interface{} @@ -206,58 +153,3 @@ type Connector interface { // Shutdown finishes the connector to do clean up work Shutdown() error } - -func (t ScopeType) String() string { - switch t { - case Production: - return "production" - case Staging: - return "staging" - case Development: - return "development" - } - return fmt.Sprintf("unknown scope type %d", t) -} - -func (md *ScopeMetadata) String() string { - s := fmt.Sprintf(" 0 { - s += fmt.Sprintf(", prefixes=%s", md.Prefixes) - } - if len(md.PrefixStr) > 0 { - s += fmt.Sprintf(", prefixes=%v", md.PrefixStr) - } - if len(md.Cluster) > 0 { - s += fmt.Sprintf(", cluster=%v", md.Cluster) - } - if md.ExtendCount > 0 { - s += fmt.Sprintf(", extended=%d", md.ExtendCount) - } - if md.NotifyCount > 0 { - s += fmt.Sprintf(", notified=%d", md.ExtendCount) - } - return s + ">" -} - -func (s StringSet) String() string { - ss := make([]string, len(s)) - i := 0 - for k := range s { - ss[i] = k - i++ - } - sort.Strings(ss) - return "{" + strings.Join(ss, ", ") + "}" -} - -func (f ScopeFlagType) String() string { - fs := make([]string, 1) - if f&AccessFromProd != 0 { - fs = append(fs, "AccessFromProd") - } - return "{" + strings.Join(fs, ", ") + "}" -} diff --git a/metadata.go b/metadata.go new file mode 100644 index 00000000..2460857a --- /dev/null +++ b/metadata.go @@ -0,0 +1,102 @@ +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package dosa + +import ( + "sort" + "strings" + "time" +) + +// Metadata objects are abstracted by an interface that defines getters and setters. Getters are +// named Get*() because we can't have fields and methods with the same name (and all fields must +// be exported in a DOSA entity). + +// Metadata is an interface abstracting both ScopeMetadata and PrefixMetadata. +type Metadata interface { + // GetName is the name of the object. + GetName() string + // GetOwner is the owner of the object. + GetOwner() string + // GetType is the type of the object. + GetType() int32 + // GetFlags is the flags of the object. + GetFlags() int64 + // GetVersion is the version of the object. + GetVersion() int32 + // GetCluster is the cluster name of the object. + GetCluster() string + // GetCreator is the creator of the object. + GetCreator() string + // GetCreatedOn is the create timestamp of the object. + GetCreatedOn() time.Time + // GetExpiresOn is the expiration timestamp of the object. + GetExpiresOn() time.Time + // GetExtendCount is the extend count of the object. + GetExtendCount() int32 + // GetNotifyCount is the notify count of the object. + GetNotifyCount() int32 + // GetReadMaxRPS is the max read rate for the object. + GetReadMaxRPS() int32 + // GetWriteMaxRPS is the max write rate for the object. + GetWriteMaxRPS() int32 + + // SetName sets the name of the object. + SetName(string) + // SetOwner sets the owner of the object. + SetOwner(string) + // SetType sets the type of the object. + SetType(int32) + // SetFlags sets the flags of the object. + SetFlags(int64) + // SetVersion sets the version of the object. + SetVersion(int32) + // SetCluster sets the cluster name of the object. + SetCluster(string) + // SetCreator sets the creator of the object. + SetCreator(string) + // SetCreatedOn sets the create timestamp of the object. + SetCreatedOn(time.Time) + // SetExpiresOn sets the expiration timestamp of the object. + SetExpiresOn(time.Time) + // SetExtendCount sets the extend count of the object. + SetExtendCount(int32) + // SetNotifyCount sets the notify count of the object. + SetNotifyCount(int32) + // SetReadMaxRPS sets the max read rate for the object. + SetReadMaxRPS(int32) + // SetWriteMaxRPS sets the max write rate for the object. + SetWriteMaxRPS(int32) +} + +// StringSet is a set of strings. +type StringSet map[string]struct{} + +func (s StringSet) String() string { + ss := make([]string, len(s)) + i := 0 + for k := range s { + ss[i] = k + i++ + } + sort.Strings(ss) + return "{" + strings.Join(ss, ", ") + "}" +} diff --git a/prefix_metadata.go b/prefix_metadata.go new file mode 100644 index 00000000..c75f9e89 --- /dev/null +++ b/prefix_metadata.go @@ -0,0 +1,217 @@ +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package dosa + +import ( + "fmt" + "time" +) + +// PrefixMetadata is metadata about a prefix in production (note: we do not track prefixes for dev scopes). +type PrefixMetadata struct { + Entity `dosa:"primaryKey=(Name)" json:"-"` + Name string `json:"name"` + Owner string `json:"owner"` // Owning group name (or the same as Creator) + Flags int64 `json:"flags"` + Version int32 `json:"version"` + EntityStr string `json:"entity_str,omitempty"` // With ":" separators + Cluster string `json:"cluster,omitempty"` // Host DB cluster + Creator string `json:"creator"` + CreatedOn time.Time `json:"created_on"` + ExpiresOn *time.Time `json:"expires_on,omitempty"` + ExtendCount int32 `json:"extend_count,omitempty"` + NotifyCount int32 `json:"notify_count,omitempty"` + ReadMaxRPS int32 `json:"read_max_rps"` + WriteMaxRPS int32 `json:"write_max_rps"` + + // This is for convenience only, not stored in the DB: + Entities StringSet `dosa:"-" json:"-"` +} + +func (md *PrefixMetadata) String() string { + s := fmt.Sprintf(" 0 { + s += fmt.Sprintf(", entities=%s", md.Entities) + } + if len(md.Cluster) > 0 { + s += fmt.Sprintf(", cluster=%v", md.Cluster) + } + if md.ExtendCount > 0 { + s += fmt.Sprintf(", extended=%d", md.ExtendCount) + } + if md.NotifyCount > 0 { + s += fmt.Sprintf(", notified=%d", md.ExtendCount) + } + return s + ">" +} + +// PrefixFlagType is a set of prefix flags +type PrefixFlagType int64 + +// G E T T E R S + +// GetName is the name of the prefix. +func (md *PrefixMetadata) GetName() string { + return md.Name +} + +// GetOwner is the owner of the prefix. +func (md *PrefixMetadata) GetOwner() string { + return md.Owner +} + +// GetType is the type of the prefix. +func (md *PrefixMetadata) GetType() int32 { + return int32(Production) +} + +// GetFlags is the flags of the prefix. +func (md *PrefixMetadata) GetFlags() int64 { + return md.Flags +} + +// GetVersion is the version of the prefix. +func (md *PrefixMetadata) GetVersion() int32 { + return md.Version +} + +// GetEntityStr is the encoded list of all prefixes. +func (md *PrefixMetadata) GetEntityStr() string { + return md.EntityStr +} + +// GetCluster is the cluster name of the prefix. +func (md *PrefixMetadata) GetCluster() string { + return md.Cluster +} + +// GetCreator is the creator of the prefix. +func (md *PrefixMetadata) GetCreator() string { + return md.Creator +} + +// GetCreatedOn is the create timestamp of the prefix. +func (md *PrefixMetadata) GetCreatedOn() time.Time { + return md.CreatedOn +} + +// GetExpiresOn is the expiration timestamp of the prefix. +func (md *PrefixMetadata) GetExpiresOn() *time.Time { + return md.ExpiresOn +} + +// GetExtendCount is the extend count of the prefix. +func (md *PrefixMetadata) GetExtendCount() int32 { + return md.ExtendCount +} + +// GetNotifyCount is the notify count of the prefix. +func (md *PrefixMetadata) GetNotifyCount() int32 { + return md.NotifyCount +} + +// GetReadMaxRPS is the max read rate for the prefix. +func (md *PrefixMetadata) GetReadMaxRPS() int32 { + return md.ReadMaxRPS +} + +// GetWriteMaxRPS is the max write rate for the prefix. +func (md *PrefixMetadata) GetWriteMaxRPS() int32 { + return md.WriteMaxRPS +} + +// S E T T E R S + +// SetName sets the name of the prefix. +func (md *PrefixMetadata) SetName(x string) { + md.Name = x +} + +// SetOwner sets the owner of the prefix. +func (md *PrefixMetadata) SetOwner(x string) { + md.Owner = x +} + +// SetType sets the type of the prefix. +func (md *PrefixMetadata) SetType(x int32) { + if ScopeType(x) != Production { + panic(fmt.Errorf("attempt to set prefix type to %s", ScopeType(x))) + } +} + +// SetFlags sets the flags of the prefix. +func (md *PrefixMetadata) SetFlags(x int64) { + md.Flags = x +} + +// SetVersion sets the version of the prefix. +func (md *PrefixMetadata) SetVersion(x int32) { + md.Version = x +} + +// SetEntityStr sets the encoded list of all entities. +func (md *PrefixMetadata) SetEntityStr(x string) { + md.EntityStr = x +} + +// SetCluster sets the cluster name of the prefix. +func (md *PrefixMetadata) SetCluster(x string) { + md.Cluster = x +} + +// SetCreator sets the creator of the prefix. +func (md *PrefixMetadata) SetCreator(x string) { + md.Creator = x +} + +// SetCreatedOn sets the create timestamp of the prefix. +func (md *PrefixMetadata) SetCreatedOn(x time.Time) { + md.CreatedOn = x +} + +// SetExpiresOn sets the expiration timestamp of the prefix. +func (md *PrefixMetadata) SetExpiresOn(x time.Time) { + md.ExpiresOn = &x +} + +// SetExtendCount sets the extend count of the prefix. +func (md *PrefixMetadata) SetExtendCount(x int32) { + md.ExtendCount = x +} + +// SetNotifyCount sets the notify count of the prefix. +func (md *PrefixMetadata) SetNotifyCount(x int32) { + md.NotifyCount = x +} + +// SetReadMaxRPS sets the max read rate for the prefix. +func (md *PrefixMetadata) SetReadMaxRPS(x int32) { + md.ReadMaxRPS = x +} + +// SetWriteMaxRPS sets the max write rate for the prefix. +func (md *PrefixMetadata) SetWriteMaxRPS(x int32) { + md.WriteMaxRPS = x +} diff --git a/scope_metadata.go b/scope_metadata.go new file mode 100644 index 00000000..777955d9 --- /dev/null +++ b/scope_metadata.go @@ -0,0 +1,259 @@ +// Copyright (c) 2018 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package dosa + +import ( + "fmt" + "strings" + "time" +) + +// ScopeMetadata is metadata about a scope. (JSON tags to support MD setting CLI tools.) +type ScopeMetadata struct { + Entity `dosa:"primaryKey=(Name)" json:"-"` + Name string `json:"name"` + Owner string `json:"owner"` // Owning group name (or the same as Creator) + Type int32 `json:"type"` // Production, Staging, or Development + Flags int64 `json:"flags"` + Version int32 `json:"version"` + PrefixStr string `json:"prefix_str,omitempty"` // With ":" separators + Cluster string `json:"cluster,omitempty"` // Host DB cluster + Creator string `json:"creator"` + CreatedOn time.Time `json:"created_on"` + ExpiresOn *time.Time `json:"expires_on,omitempty"` + ExtendCount int32 `json:"extend_count,omitempty"` + NotifyCount int32 `json:"notify_count,omitempty"` + ReadMaxRPS int32 `json:"read_max_rps"` + WriteMaxRPS int32 `json:"write_max_rps"` + + // This is for convenience only, not stored in the DB: + Prefixes StringSet `dosa:"-" json:"-"` +} + +// MetadataSchemaVersion is the version of the schema of the scope metadata +const MetadataSchemaVersion = 1 + +func (md *ScopeMetadata) String() string { + s := fmt.Sprintf(" 0 { + s += fmt.Sprintf(", prefixes=%s", md.Prefixes) + } + if len(md.Cluster) > 0 { + s += fmt.Sprintf(", cluster=%v", md.Cluster) + } + if md.ExtendCount > 0 { + s += fmt.Sprintf(", extended=%d", md.ExtendCount) + } + if md.NotifyCount > 0 { + s += fmt.Sprintf(", notified=%d", md.ExtendCount) + } + return s + ">" +} + +// ScopeType is the type of a scope +type ScopeType int32 + +// Scope types +const ( + // Development scope (also the default, so should be 0) + Development ScopeType = iota + // Staging doesn't really exist yet, but may in the future + Staging + // Production scope + Production +) + +func (t ScopeType) String() string { + switch t { + case Production: + return "production" + case Staging: + return "staging" + case Development: + return "development" + } + return fmt.Sprintf("unknown scope type %d", t) +} + +// ScopeFlagType is a set of scope flags +type ScopeFlagType int64 + +// Scope flags (remember to update ScopeFlagType.String) +const ( + // AccessFromProd means access is allowed from production (only relevant for Dev scopes) + AccessFromProd ScopeFlagType = 1 << iota +) + +func (f ScopeFlagType) String() string { + fs := make([]string, 1) + if f&AccessFromProd != 0 { + fs = append(fs, "AccessFromProd") + } + return "{" + strings.Join(fs, ", ") + "}" +} + +// G E T T E R S + +// GetName is the name of the scope. +func (md *ScopeMetadata) GetName() string { + return md.Name +} + +// GetOwner is the owner of the scope. +func (md *ScopeMetadata) GetOwner() string { + return md.Owner +} + +// GetType is the type of the scope. +func (md *ScopeMetadata) GetType() int32 { + return md.Type +} + +// GetFlags is the flags of the scope. +func (md *ScopeMetadata) GetFlags() int64 { + return md.Flags +} + +// GetVersion is the version of the scope. +func (md *ScopeMetadata) GetVersion() int32 { + return md.Version +} + +// GetPrefixStr is the encoded list of all prefixes. +func (md *ScopeMetadata) GetPrefixStr() string { + return md.PrefixStr +} + +// GetCluster is the cluster name of the scope. +func (md *ScopeMetadata) GetCluster() string { + return md.Cluster +} + +// GetCreator is the creator of the scope. +func (md *ScopeMetadata) GetCreator() string { + return md.Creator +} + +// GetCreatedOn is the create timestamp of the scope. +func (md *ScopeMetadata) GetCreatedOn() time.Time { + return md.CreatedOn +} + +// GetExpiresOn is the expiration timestamp of the scope. +func (md *ScopeMetadata) GetExpiresOn() *time.Time { + return md.ExpiresOn +} + +// GetExtendCount is the extend count of the scope. +func (md *ScopeMetadata) GetExtendCount() int32 { + return md.ExtendCount +} + +// GetNotifyCount is the notify count of the scope. +func (md *ScopeMetadata) GetNotifyCount() int32 { + return md.NotifyCount +} + +// GetReadMaxRPS is the max read rate for the scope. +func (md *ScopeMetadata) GetReadMaxRPS() int32 { + return md.ReadMaxRPS +} + +// GetWriteMaxRPS is the max write rate for the scope. +func (md *ScopeMetadata) GetWriteMaxRPS() int32 { + return md.WriteMaxRPS +} + +// S E T T E R S + +// SetName sets the name of the scope. +func (md *ScopeMetadata) SetName(x string) { + md.Name = x +} + +// SetOwner sets the owner of the scope. +func (md *ScopeMetadata) SetOwner(x string) { + md.Owner = x +} + +// SetType sets the type of the scope. +func (md *ScopeMetadata) SetType(x int32) { + md.Type = x +} + +// SetFlags sets the flags of the scope. +func (md *ScopeMetadata) SetFlags(x int64) { + md.Flags = x +} + +// SetVersion sets the version of the scope. +func (md *ScopeMetadata) SetVersion(x int32) { + md.Version = x +} + +// SetPrefixStr sets the encoded list of all prefixes. +func (md *ScopeMetadata) SetPrefixStr(x string) { + md.PrefixStr = x +} + +// SetCluster sets the cluster name of the scope. +func (md *ScopeMetadata) SetCluster(x string) { + md.Cluster = x +} + +// SetCreator sets the creator of the scope. +func (md *ScopeMetadata) SetCreator(x string) { + md.Creator = x +} + +// SetCreatedOn sets the create timestamp of the scope. +func (md *ScopeMetadata) SetCreatedOn(x time.Time) { + md.CreatedOn = x +} + +// SetExpiresOn sets the expiration timestamp of the scope. +func (md *ScopeMetadata) SetExpiresOn(x time.Time) { + md.ExpiresOn = &x +} + +// SetExtendCount sets the extend count of the scope. +func (md *ScopeMetadata) SetExtendCount(x int32) { + md.ExtendCount = x +} + +// SetNotifyCount sets the notify count of the scope. +func (md *ScopeMetadata) SetNotifyCount(x int32) { + md.NotifyCount = x +} + +// SetReadMaxRPS sets the max read rate for the scope. +func (md *ScopeMetadata) SetReadMaxRPS(x int32) { + md.ReadMaxRPS = x +} + +// SetWriteMaxRPS sets the max write rate for the scope. +func (md *ScopeMetadata) SetWriteMaxRPS(x int32) { + md.WriteMaxRPS = x +} From 6e82ac251bc719670c3678bd656980901721db35 Mon Sep 17 00:00:00 2001 From: Shamim Mohamed Date: Tue, 28 Aug 2018 16:41:48 -0700 Subject: [PATCH 2/3] don't give getter callers a ref to the object --- prefix_metadata.go | 6 +++++- scope_metadata.go | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/prefix_metadata.go b/prefix_metadata.go index c75f9e89..38928955 100644 --- a/prefix_metadata.go +++ b/prefix_metadata.go @@ -119,7 +119,11 @@ func (md *PrefixMetadata) GetCreatedOn() time.Time { // GetExpiresOn is the expiration timestamp of the prefix. func (md *PrefixMetadata) GetExpiresOn() *time.Time { - return md.ExpiresOn + if md.ExpiresOn == nil { + return nil + } + rv := *md.ExpiresOn + return &rv } // GetExtendCount is the extend count of the prefix. diff --git a/scope_metadata.go b/scope_metadata.go index 777955d9..6f9e135e 100644 --- a/scope_metadata.go +++ b/scope_metadata.go @@ -163,7 +163,11 @@ func (md *ScopeMetadata) GetCreatedOn() time.Time { // GetExpiresOn is the expiration timestamp of the scope. func (md *ScopeMetadata) GetExpiresOn() *time.Time { - return md.ExpiresOn + if md.ExpiresOn == nil { + return nil + } + rv := *md.ExpiresOn + return &rv } // GetExtendCount is the extend count of the scope. From 2a757d5ba6f0cbea52f048d54eee1959ecca600a Mon Sep 17 00:00:00 2001 From: Shamim Mohamed Date: Wed, 29 Aug 2018 11:15:41 -0700 Subject: [PATCH 3/3] fix finder test --- finder_test.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/finder_test.go b/finder_test.go index e8fc2b6a..81c11373 100644 --- a/finder_test.go +++ b/finder_test.go @@ -24,6 +24,7 @@ import ( "fmt" "io/ioutil" "os" + "sort" "testing" "github.com/stretchr/testify/assert" @@ -76,6 +77,7 @@ func TestParser(t *testing.T) { "multipleindexes": &MultipleIndexes{}, "complexindexes": &ComplexIndexes{}, "scopemetadata": &ScopeMetadata{}, + "prefixmetadata": &PrefixMetadata{}, } entitiesExcludedForTest := map[string]interface{}{ "clienttestentity1": struct{}{}, // skip, see https://jira.uberinternal.com/browse/DOSA-788 @@ -104,11 +106,13 @@ func TestParser(t *testing.T) { func TestExclusion(t *testing.T) { entities, errs, err := findEntities([]string{"."}, []string{"*_test.go"}) - // We expect to find only ScopeMetadata - assert.Equal(t, 1, len(entities)) - assert.Equal(t, "ScopeMetadata", entities[0].StructName) - assert.Equal(t, 0, len(errs)) assert.Nil(t, err) + assert.Equal(t, 0, len(errs)) + // We expect to find only ScopeMetadata and Prefixmetadata + assert.Equal(t, 2, len(entities)) + enames := []string{entities[0].StructName, entities[1].StructName} + sort.Strings(enames) + assert.Equal(t, []string{"PrefixMetadata", "ScopeMetadata"}, enames) } func TestFindEntitiesInOtherPkg(t *testing.T) {