Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion service/status/help_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ func testStatus() (status *Status) {
&dashboard.Options{
Icon: "https://example.com/icon.png",
IconLinkTo: "https://example.com/icon-link",
WebURL: "https://example.com"})
WebURL: "https://example.com",
Tags: []string{"foo", "bar"}})

status.SetApprovedVersion("1.1.1", false)
status.SetLatestVersion("2.2.2", "2002-02-02T02:02:02Z", false)
Expand Down
4 changes: 3 additions & 1 deletion service/status/info/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import "sync"

// ServiceInfo holds information about a service.
type ServiceInfo struct {
mutex *sync.RWMutex `json:"-"` // Mutex for thread-safe access
mutex *sync.RWMutex // Mutex for thread-safe access

ID string `json:"id,omitempty"` // Service ID
Name string `json:"name,omitempty"` // Service name
Expand All @@ -32,6 +32,8 @@ type ServiceInfo struct {
ApprovedVersion string `json:"approved_version,omitempty"` // The version of the Service that has been approved for deployment.
DeployedVersion string `json:"deployed_version,omitempty"` // The version of the Service that is deployed.
LatestVersion string `json:"latest_version,omitempty"` // The latest version of the Service found from query().

Tags []string `json:"tags,omitempty"` // Tags for the Service.
}

// SetMutex sets the mutex pointer for thread-safe access.
Expand Down
1 change: 1 addition & 0 deletions service/status/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ func (s *Status) Init(
s.ServiceInfo.ID = serviceID
s.ServiceInfo.Name = serviceName
s.ServiceInfo.URL = serviceURL
s.ServiceInfo.Tags = dashboard.Tags

s.Dashboard = dashboard
s.ServiceInfo.SetMutex(&s.mutex)
Expand Down
12 changes: 8 additions & 4 deletions service/status/status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,12 @@ func TestStatus_Unmarshal(t *testing.T) {

// WHEN UnmarshalX is called on the Status.
var status Status
if tc.format == "YAML" {
switch tc.format {
case "YAML":
var node yaml.Node
status.UnmarshalYAML(&node)
} else if tc.format == "JSON" {
status.UnmarshalJSON([]byte(""))
_ = status.UnmarshalYAML(&node)
case "JSON":
_ = status.UnmarshalJSON([]byte(""))
}

// THEN the mutex is correctly handed to the ServiceInfo.
Expand Down Expand Up @@ -189,6 +190,8 @@ func TestService_ServiceInfo(t *testing.T) {
status.Dashboard.IconLinkTo = iconLinkTo
webURL := "https://example.com/web"
status.Dashboard.WebURL = webURL
tags := []string{"tag1", "tag2"}
status.ServiceInfo.Tags = tags

approvedVersion := "approved.version"
status.SetApprovedVersion(approvedVersion, false)
Expand All @@ -210,6 +213,7 @@ func TestService_ServiceInfo(t *testing.T) {
Icon: icon,
IconLinkTo: iconLinkTo,
WebURL: webURL,
Tags: tags,

DeployedVersion: deployedVersion,
ApprovedVersion: approvedVersion,
Expand Down
5 changes: 4 additions & 1 deletion util/help_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

package util

import serviceinfo "github.com/release-argus/Argus/service/status/info"
import (
serviceinfo "github.com/release-argus/Argus/service/status/info"
)

var packageName = "util"

Expand All @@ -33,5 +35,6 @@ func testServiceInfo() serviceinfo.ServiceInfo {
ApprovedVersion: "APPROVED",
DeployedVersion: "DEPLOYED",
LatestVersion: "NEW",
Tags: []string{"tag1", "tag2"},
}
}
3 changes: 2 additions & 1 deletion util/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@ func TemplateString(template string, context serviceinfo.ServiceInfo) string {
"icon": context.Icon,
"icon_link_to": context.IconLinkTo,
"web_url": context.WebURL,
"version": context.LatestVersion,
"approved_version": context.ApprovedVersion,
"deployed_version": context.DeployedVersion,
"version": context.LatestVersion,
"latest_version": context.LatestVersion,
"tags": context.Tags,
})
if err != nil {
panic(err)
Expand Down
19 changes: 16 additions & 3 deletions util/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,29 @@ func TestTemplate_String(t *testing.T) {
WebURL: svcInfo.WebURL,
LatestVersion: svcInfo.LatestVersion},
},
"valid django template with array access": {
template: "{{ tags | first }}-{{ tags.0 }}_{{ tags|slice:'1:2'|first }}-{{ tags | last }}-{{ tags.1 }}_{{ tags | join:',' }}",
want: fmt.Sprintf("%s-%s_%s-%s-%s_%s,%s",
svcInfo.Tags[0], svcInfo.Tags[0],
svcInfo.Tags[1], svcInfo.Tags[1], svcInfo.Tags[1],
svcInfo.Tags[0], svcInfo.Tags[1]),
serviceInfo: svcInfo},
"valid django template with array access out of bounds": {
template: "{{ tags.0 }}-{{ tags.1 }}-{{ tags.2 }}-{{ tags.3 }}",
want: fmt.Sprintf("%s-%s--",
svcInfo.Tags[0], svcInfo.Tags[1]),
serviceInfo: svcInfo},
"invalid django template panic": {
template: "-{% 'a' == 'a' %}{{ service_id }}{% endif %}-{{ service_url }}-{{ web_url }}-{{ version }}",
panicRegex: test.StringPtr("Tag name must be an identifier"),
serviceInfo: svcInfo},
"all django vars": {
template: "{{ service_id }}-{{ service_name }}-{{ service_url }}--{{ icon }}-{{ icon_link_to }}-{{ web_url }}--{{ version }}-{{ approved_version }}-{{ deployed_version }}-{{ latest_version }}",
want: fmt.Sprintf("%s-%s-%s--%s-%s-%s--%s-%s-%s-%s",
template: "{{ service_id }}-{{ service_name }}-{{ service_url }}--{{ icon }}-{{ icon_link_to }}-{{ web_url }}--{{ version }}-{{ approved_version }}-{{ deployed_version }}-{{ latest_version }}-{{ tags|first }}-{{ tags.1 }}",
want: fmt.Sprintf("%s-%s-%s--%s-%s-%s--%s-%s-%s-%s-%s-%s",
svcInfo.ID, svcInfo.Name, svcInfo.URL,
svcInfo.Icon, svcInfo.IconLinkTo, svcInfo.WebURL,
svcInfo.LatestVersion, svcInfo.ApprovedVersion, svcInfo.DeployedVersion, svcInfo.LatestVersion),
svcInfo.LatestVersion, svcInfo.ApprovedVersion, svcInfo.DeployedVersion, svcInfo.LatestVersion,
svcInfo.Tags[0], svcInfo.Tags[1]),
serviceInfo: svcInfo},
}

Expand Down
12 changes: 6 additions & 6 deletions util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,26 +64,26 @@ func ValueOrValue[T comparable](first T, second T) T {
return second
}

// DereferenceOrDefault returns the value of `check` if not nil,
// DereferenceOrDefault returns the value of `ptr` if not nil,
// otherwise default for the type.
func DereferenceOrDefault[T comparable](check *T) T {
if check == nil {
func DereferenceOrDefault[T any](ptr *T) T {
if ptr == nil {
return *new(T)
}
return *check
return *ptr
}

// DereferenceOrValue returns the value of 'ptr' if non-nil,
// otherwise the 'fallback'.
func DereferenceOrValue[T comparable](ptr *T, fallback T) T {
func DereferenceOrValue[T any](ptr *T, fallback T) T {
if ptr != nil {
return *ptr
}
return fallback
}

// CopyPointer returns a pointer to a copy of the value of `ptr`.
func CopyPointer[T comparable](ptr *T) *T {
func CopyPointer[T any](ptr *T) *T {
if ptr == nil {
return nil
}
Expand Down
56 changes: 44 additions & 12 deletions util/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package util

import (
"fmt"
"reflect"
"strings"
"testing"

Expand Down Expand Up @@ -188,6 +189,12 @@ func TestDereferenceOrValue(t *testing.T) {
"non-nil int pointer": {
ptr: test.IntPtr(3),
value: 2, want: 3},
"nil string slice": {
ptr: (*[]string)(nil),
value: []string{"baz"}, want: []string{"baz"}},
"non-nil string slice": {
ptr: test.StringSlicePtr([]string{"foo", "bar"}),
value: []string{"baz"}, want: []string{"foo", "bar"}},
}

for name, tc := range tests {
Expand All @@ -203,10 +210,12 @@ func TestDereferenceOrValue(t *testing.T) {
got = DereferenceOrValue(v, tc.value.(bool))
case *int:
got = DereferenceOrValue(v, tc.value.(int))
case *[]string:
got = DereferenceOrValue(v, tc.value.([]string))
}

// THEN the pointer is returned if it's nil, otherwise the value.
if got != tc.want {
if !reflect.DeepEqual(got, tc.want) {
t.Errorf("%s\nwant: %v\ngot: %v",
packageName, tc.want, got)
}
Expand All @@ -216,15 +225,28 @@ func TestDereferenceOrValue(t *testing.T) {

func TestCopyPointer(t *testing.T) {
tests := map[string]struct {
input, want *int
input any
doesCopy bool
}{
"nil pointer": {
input: nil,
want: nil,
input: nil,
doesCopy: false,
},
"non-nil int pointer": {
input: test.IntPtr(6),
doesCopy: true,
},
"non-nil string pointer": {
input: test.StringPtr("foo"),
doesCopy: true,
},
"non-nil bool pointer": {
input: test.BoolPtr(true),
doesCopy: true,
},
"non-nil pointer": {
input: test.IntPtr(6),
want: test.IntPtr(6),
"non-nil string slice pointer": {
input: test.StringSlicePtr([]string{"foo", "bar"}),
doesCopy: true,
},
}

Expand All @@ -233,14 +255,24 @@ func TestCopyPointer(t *testing.T) {
t.Parallel()

// WHEN CopyPointer is called.
got := CopyPointer(tc.input)
var got any
switch v := tc.input.(type) {
case *string:
got = CopyPointer(v)
case *bool:
got = CopyPointer(v)
case *int:
got = CopyPointer(v)
case *[]string:
got = CopyPointer(v)
}

// THEN the result should be a pointer to a copy of the value.
if (tc.want != nil && got == nil) ||
(tc.want == nil && got != nil) ||
(got != nil && *tc.want != *got) {
if (tc.doesCopy && got == nil) ||
(tc.doesCopy && !reflect.DeepEqual(got, tc.input)) ||
(!tc.doesCopy && got != nil) {
t.Errorf("%s\nwant %v, got %v",
packageName, tc.want, got)
packageName, tc.input, got)
}
})
}
Expand Down