carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package awsinv
2
3import (
4 "context"
5 "errors"
6 "strings"
7 "testing"
8
9 "github.com/aws/aws-sdk-go-v2/aws"
10 "github.com/aws/aws-sdk-go-v2/service/ec2"
11 ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
12 "github.com/carlosframework/platform/internal/infraview"
13)
14
15// fakeEC2 answers whatever the test hands it; a non-nil err field for a
16// call makes that ONE call fail, which is how the partial-failure rule
17// below is proven.
18type fakeEC2 struct {
19 instances *ec2.DescribeInstancesOutput
20 volumes *ec2.DescribeVolumesOutput
21 addresses *ec2.DescribeAddressesOutput
22 groups *ec2.DescribeSecurityGroupsOutput
23 vpcs *ec2.DescribeVpcsOutput
24 subnets *ec2.DescribeSubnetsOutput
25 regions *ec2.DescribeRegionsOutput
26 errVols error
27}
28
29func (f *fakeEC2) DescribeInstances(context.Context, *ec2.DescribeInstancesInput, ...func(*ec2.Options)) (*ec2.DescribeInstancesOutput, error) {
30 return f.instances, nil
31}
32func (f *fakeEC2) DescribeVolumes(context.Context, *ec2.DescribeVolumesInput, ...func(*ec2.Options)) (*ec2.DescribeVolumesOutput, error) {
33 if f.errVols != nil {
34 return nil, f.errVols
35 }
36 return f.volumes, nil
37}
38func (f *fakeEC2) DescribeAddresses(context.Context, *ec2.DescribeAddressesInput, ...func(*ec2.Options)) (*ec2.DescribeAddressesOutput, error) {
39 return f.addresses, nil
40}
41func (f *fakeEC2) DescribeSecurityGroups(context.Context, *ec2.DescribeSecurityGroupsInput, ...func(*ec2.Options)) (*ec2.DescribeSecurityGroupsOutput, error) {
42 return f.groups, nil
43}
44func (f *fakeEC2) DescribeVpcs(context.Context, *ec2.DescribeVpcsInput, ...func(*ec2.Options)) (*ec2.DescribeVpcsOutput, error) {
45 return f.vpcs, nil
46}
47func (f *fakeEC2) DescribeSubnets(context.Context, *ec2.DescribeSubnetsInput, ...func(*ec2.Options)) (*ec2.DescribeSubnetsOutput, error) {
48 return f.subnets, nil
49}
50func (f *fakeEC2) DescribeRegions(context.Context, *ec2.DescribeRegionsInput, ...func(*ec2.Options)) (*ec2.DescribeRegionsOutput, error) {
51 return f.regions, nil
52}
53
54func find(rs []infraview.Resource, kind, id string) *infraview.Resource {
55 for i := range rs {
56 if rs[i].Kind == kind && rs[i].ID == id {
57 return &rs[i]
58 }
59 }
60 return nil
61}
62
63func TestEC2InstanceMapping(t *testing.T) {
64 f := &fakeEC2{instances: &ec2.DescribeInstancesOutput{
65 Reservations: []ec2types.Reservation{{Instances: []ec2types.Instance{{
66 InstanceId: aws.String("i-123"),
67 InstanceType: ec2types.InstanceTypeT4gMedium,
68 State: &ec2types.InstanceState{Name: ec2types.InstanceStateNameRunning},
69 Placement: &ec2types.Placement{AvailabilityZone: aws.String("eu-west-1a")},
70 PublicIpAddress: aws.String("52.0.0.1"),
71 PrivateIpAddress: aws.String("10.0.0.5"),
72 Tags: []ec2types.Tag{{Key: aws.String("Name"), Value: aws.String("carlos-eu-west-1")}},
73 }}}},
74 }}
75
76 rs, partial := ec2Resources(context.Background(), f, "eu-west-1")
77 if len(partial) != 0 {
78 t.Fatalf("partial = %v, want none", partial)
79 }
80 m := find(rs, infraview.KindMachine, "i-123")
81 if m == nil {
82 t.Fatalf("no machine in %+v", rs)
83 }
84 if m.Name != "carlos-eu-west-1" {
85 t.Errorf("Name = %q, want the Name tag", m.Name)
86 }
87 if m.Region != "eu-west-1" || m.NativeType != "ec2:instance" {
88 t.Errorf("region/type = %q/%q", m.Region, m.NativeType)
89 }
90 for k, want := range map[string]string{
91 "type": "t4g.medium", "state": "running", "az": "eu-west-1a",
92 "public_ip": "52.0.0.1", "private_ip": "10.0.0.5",
93 } {
94 if got := m.Attr(k); got != want {
95 t.Errorf("attr %s = %q, want %q", k, got, want)
96 }
97 }
98}
99
100// One failing call costs its own resources and nothing else — the rule the
101// whole inventory depends on, since a page that shows eleven of twelve
102// classes is worth far more than one that shows none.
103func TestEC2PartialFailureCostsOnlyItsOwnCall(t *testing.T) {
104 f := &fakeEC2{
105 instances: &ec2.DescribeInstancesOutput{Reservations: []ec2types.Reservation{{
106 Instances: []ec2types.Instance{{InstanceId: aws.String("i-123")}},
107 }}},
108 errVols: errors.New("Throttling: rate exceeded"),
109 }
110 rs, partial := ec2Resources(context.Background(), f, "eu-west-1")
111 if find(rs, infraview.KindMachine, "i-123") == nil {
112 t.Fatalf("a failed volume read must not cost the instances")
113 }
114 if len(partial) != 1 {
115 t.Fatalf("partial = %v, want exactly the volumes line", partial)
116 }
117 if !strings.Contains(partial[0], "volumes") || !strings.Contains(partial[0], "eu-west-1") {
118 t.Errorf("partial line %q must name what failed and where", partial[0])
119 }
120}
121