summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/resource/multi.go39
-rw-r--r--internal/resource/multi_test.go81
-rw-r--r--internal/resource/repository.go2
-rw-r--r--internal/resource/repository_test.go14
-rw-r--r--internal/resource/resource.go8
5 files changed, 134 insertions, 10 deletions
diff --git a/internal/resource/multi.go b/internal/resource/multi.go
new file mode 100644
index 0000000..1694814
--- /dev/null
+++ b/internal/resource/multi.go
@@ -0,0 +1,39 @@
+package resource
+
+import (
+ "errors"
+ "strings"
+)
+
+// Multi is a collection of resources that satisfies the api.Resource interface.
+type Multi []Resource
+
+func (m Multi) String() string {
+ strs := make([]string, 0, len(m))
+
+ for _, res := range m {
+ strs = append(strs, res.String())
+ }
+
+ return strings.Join(strs, ", ")
+}
+
+func (m Multi) ID() string {
+ ids := make([]string, 0, len(m))
+
+ for _, res := range m {
+ ids = append(ids, res.String())
+ }
+
+ return strings.Join(ids, "+")
+}
+
+func (m Multi) Apply() error {
+ var errs []error
+
+ for _, res := range m {
+ errs = append(errs, res.Apply())
+ }
+
+ return errors.Join(errs...)
+}
diff --git a/internal/resource/multi_test.go b/internal/resource/multi_test.go
new file mode 100644
index 0000000..3443afb
--- /dev/null
+++ b/internal/resource/multi_test.go
@@ -0,0 +1,81 @@
+package resource
+
+import (
+ "errors"
+ "testing"
+)
+
+func TestMultiString(t *testing.T) {
+ m := Multi{
+ Resource{Type: "File", Name: "/tmp/a"},
+ Resource{Type: "File", Name: "/tmp/b"},
+ }
+
+ want := "File[/tmp/a], File[/tmp/b]"
+ if got := m.String(); got != want {
+ t.Errorf("Multi.String() = %q, want %q", got, want)
+ }
+}
+
+func TestMultiID(t *testing.T) {
+ m := Multi{
+ Resource{Type: "File", Name: "/tmp/a"},
+ Resource{Type: "File", Name: "/tmp/b"},
+ }
+
+ want := "File[/tmp/a]+File[/tmp/b]"
+ if got := m.ID(); got != want {
+ t.Errorf("Multi.ID() = %q, want %q", got, want)
+ }
+}
+
+func TestMultiApply(t *testing.T) {
+ tests := []struct {
+ name string
+ appliers []Applier
+ wantErr bool
+ }{
+ {
+ name: "all success",
+ appliers: []Applier{
+ ApplierFunc(func() error { return nil }),
+ ApplierFunc(func() error { return nil }),
+ },
+ wantErr: false,
+ },
+ {
+ name: "one failure",
+ appliers: []Applier{
+ ApplierFunc(func() error { return nil }),
+ ApplierFunc(func() error { return errors.New("fail 1") }),
+ },
+ wantErr: true,
+ },
+ {
+ name: "multiple failures",
+ appliers: []Applier{
+ ApplierFunc(func() error { return errors.New("fail 1") }),
+ ApplierFunc(func() error { return errors.New("fail 2") }),
+ },
+ wantErr: true,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ var resources []Resource
+ for _, app := range tt.appliers {
+ resources = append(resources, Resource{
+ applier: app,
+ })
+ }
+
+ m := Multi(resources)
+ err := m.Apply()
+
+ if (err != nil) != tt.wantErr {
+ t.Errorf("Multi.Apply() error = %v, wantErr %v", err, tt.wantErr)
+ }
+ })
+ }
+}
diff --git a/internal/resource/repository.go b/internal/resource/repository.go
index 215f7e1..0771ef8 100644
--- a/internal/resource/repository.go
+++ b/internal/resource/repository.go
@@ -89,7 +89,7 @@ func (r *repository) apply() error {
for _, res := range order {
log.Printf("Applying resource %v", res)
- if err := res.Apply.Apply(); err != nil {
+ if err := res.Apply(); err != nil {
return fmt.Errorf("failed to apply %v: %w", res, err)
}
}
diff --git a/internal/resource/repository_test.go b/internal/resource/repository_test.go
index 8f1aef6..f939fca 100644
--- a/internal/resource/repository_test.go
+++ b/internal/resource/repository_test.go
@@ -32,17 +32,17 @@ func TestApply(t *testing.T) {
// A depends on B, B depends on C
r.registered["A"] = Resource{
Type: "T", Name: "A",
- Apply: &mockApplier{name: "A", logs: logs},
+ applier: &mockApplier{name: "A", logs: logs},
dependsOn: map[string]struct{}{"B": {}},
}
r.registered["B"] = Resource{
Type: "T", Name: "B",
- Apply: &mockApplier{name: "B", logs: logs},
+ applier: &mockApplier{name: "B", logs: logs},
dependsOn: map[string]struct{}{"C": {}},
}
r.registered["C"] = Resource{
Type: "T", Name: "C",
- Apply: &mockApplier{name: "C", logs: logs},
+ applier: &mockApplier{name: "C", logs: logs},
}
},
wantOrder: []string{"C", "B", "A"},
@@ -52,12 +52,12 @@ func TestApply(t *testing.T) {
setup: func(r *repository, logs *[]string) {
r.registered["A"] = Resource{
Type: "T", Name: "A",
- Apply: &mockApplier{name: "A", logs: logs},
+ applier: &mockApplier{name: "A", logs: logs},
dependsOn: map[string]struct{}{"B": {}},
}
r.registered["B"] = Resource{
Type: "T", Name: "B",
- Apply: &mockApplier{name: "B", logs: logs},
+ applier: &mockApplier{name: "B", logs: logs},
dependsOn: map[string]struct{}{"A": {}},
}
},
@@ -69,7 +69,7 @@ func TestApply(t *testing.T) {
setup: func(r *repository, logs *[]string) {
r.registered["A"] = Resource{
Type: "T", Name: "A",
- Apply: &mockApplier{name: "A", logs: logs},
+ applier: &mockApplier{name: "A", logs: logs},
dependsOn: map[string]struct{}{"Missing": {}},
}
},
@@ -81,7 +81,7 @@ func TestApply(t *testing.T) {
setup: func(r *repository, logs *[]string) {
r.registered["A"] = Resource{
Type: "T", Name: "A",
- Apply: &mockApplier{name: "A", err: errors.New("fail A"), logs: logs},
+ applier: &mockApplier{name: "A", err: errors.New("fail A"), logs: logs},
}
},
wantError: true,
diff --git a/internal/resource/resource.go b/internal/resource/resource.go
index 4e72485..2a01629 100644
--- a/internal/resource/resource.go
+++ b/internal/resource/resource.go
@@ -18,7 +18,7 @@ func (f ApplierFunc) Apply() error {
type Resource struct {
Type string
Name string
- Apply Applier
+ applier Applier
dependsOn map[string]struct{}
}
@@ -26,7 +26,7 @@ func Register(type_, name string, apply Applier) Resource {
r := Resource{
Type: type_,
Name: name,
- Apply: apply,
+ applier: apply,
dependsOn: make(map[string]struct{}),
}
@@ -44,3 +44,7 @@ func (r Resource) String() string {
func (r Resource) ID() string {
return fmt.Sprintf("%s[%s]", r.Type, r.Name)
}
+
+func (r Resource) Apply() error {
+ return r.applier.Apply()
+}