refactor: simplify code

main
sundowndev 2021-06-28 14:39:14 +02:00
parent 4625be141b
commit 904e7b38f3
8 changed files with 154 additions and 97 deletions

View File

@ -48,7 +48,7 @@ type DriftCTL struct {
iacProgress globaloutput.Progress
resourceSchemaRepository resource.SchemaRepositoryInterface
opts *ScanOptions
s memstore.Store
store memstore.Store
}
func NewDriftCTL(remoteSupplier resource.Supplier,
@ -144,12 +144,12 @@ func (d DriftCTL) Run() (*analyser.Analysis, error) {
analysis.Duration = time.Since(start)
analysis.Date = time.Now()
d.s.Bucket(memstore.TelemetryBucket).Set("version", version.Current())
d.s.Bucket(memstore.TelemetryBucket).Set("os", runtime.GOOS)
d.s.Bucket(memstore.TelemetryBucket).Set("arch", runtime.GOARCH)
d.s.Bucket(memstore.TelemetryBucket).Set("total_resources", analysis.Summary().TotalResources)
d.s.Bucket(memstore.TelemetryBucket).Set("total_managed", analysis.Summary().TotalManaged)
d.s.Bucket(memstore.TelemetryBucket).Set("duration", uint(analysis.Duration.Seconds()+0.5))
d.store.Bucket(memstore.TelemetryBucket).Set("version", version.Current())
d.store.Bucket(memstore.TelemetryBucket).Set("os", runtime.GOOS)
d.store.Bucket(memstore.TelemetryBucket).Set("arch", runtime.GOARCH)
d.store.Bucket(memstore.TelemetryBucket).Set("total_resources", analysis.Summary().TotalResources)
d.store.Bucket(memstore.TelemetryBucket).Set("total_managed", analysis.Summary().TotalManaged)
d.store.Bucket(memstore.TelemetryBucket).Set("duration", uint(analysis.Duration.Seconds()+0.5))
return &analysis, nil
}

32
pkg/memstore/bucket.go Normal file
View File

@ -0,0 +1,32 @@
package memstore
import (
"sync"
)
type Bucket interface {
Set(string, interface{})
Get(string) interface{}
Values() map[string]interface{}
}
type bucket struct {
m *sync.RWMutex
values map[string]interface{}
}
func (b bucket) Set(key string, value interface{}) {
b.m.Lock()
defer b.m.Unlock()
b.values[key] = value
}
func (b bucket) Get(key string) interface{} {
b.m.RLock()
defer b.m.RUnlock()
return b.values[key]
}
func (b bucket) Values() map[string]interface{} {
return b.values
}

View File

@ -1,6 +1,8 @@
package memstore
type BucketName int
const (
// TelemetryBucket is the name of the store bucket used by the telemetry service
TelemetryBucket = "telemetry"
TelemetryBucket BucketName = iota + 1
)

View File

@ -1,63 +0,0 @@
package memstore
import (
"encoding/json"
"sync"
)
type Bucket interface {
Set(string, interface{})
Get(string) interface{}
MarshallJSON() ([]byte, error)
}
type Store interface {
Bucket(string) Bucket
}
type store struct {
m *sync.Mutex
buckets map[string]*bucket
}
type bucket struct {
m *sync.RWMutex
values map[string]interface{}
}
func New() Store {
return &store{
m: &sync.Mutex{},
buckets: map[string]*bucket{},
}
}
func (s store) Bucket(name string) Bucket {
s.m.Lock()
defer s.m.Unlock()
if _, ok := s.buckets[name]; !ok {
s.buckets[name] = &bucket{
m: &sync.RWMutex{},
values: map[string]interface{}{},
}
}
return s.buckets[name]
}
func (b bucket) Set(key string, value interface{}) {
b.m.Lock()
defer b.m.Unlock()
b.values[key] = value
}
func (b bucket) Get(key string) interface{} {
b.m.RLock()
defer b.m.RUnlock()
return b.values[key]
}
func (b bucket) MarshallJSON() ([]byte, error) {
return json.Marshal(b.values)
}

36
pkg/memstore/store.go Normal file
View File

@ -0,0 +1,36 @@
package memstore
import (
"sync"
)
type Store interface {
Bucket(BucketName) Bucket
}
type store struct {
m *sync.Mutex
buckets map[int]*bucket
}
func New() Store {
return &store{
m: &sync.Mutex{},
buckets: map[int]*bucket{},
}
}
func (s store) Bucket(name BucketName) Bucket {
s.m.Lock()
defer s.m.Unlock()
key := int(name)
if _, exist := s.buckets[key]; !exist {
s.buckets[key] = &bucket{
m: &sync.RWMutex{},
values: map[string]interface{}{},
}
}
return s.buckets[key]
}

View File

@ -1,6 +1,7 @@
package memstore
import (
"encoding/json"
"sync"
"testing"
@ -11,13 +12,13 @@ import (
func TestStore(t *testing.T) {
cases := []struct {
name string
bucket string
bucket BucketName
values map[string]interface{}
expectedJSON string
}{
{
name: "test basic store usage",
bucket: "test-bucket-1",
bucket: 0,
values: map[string]interface{}{
"test-value_|)": 13,
"duration_key": "23",
@ -28,13 +29,13 @@ func TestStore(t *testing.T) {
},
{
name: "test empty bucket",
bucket: "test-bucket-empty",
bucket: 2,
values: map[string]interface{}{},
expectedJSON: `{}`,
},
{
name: "test bucket with nil values",
bucket: "test-bucket-empty",
bucket: 1,
values: map[string]interface{}{
"version": nil,
"total_resources": nil,
@ -56,13 +57,13 @@ func TestStore(t *testing.T) {
defer wg.Done()
kv.Bucket(tt.bucket).Set(key, val)
assert.Equal(t, val, kv.Bucket(tt.bucket).Get(key))
assert.Equal(t, nil, kv.Bucket("dummybucketname").Get(key))
assert.Equal(t, nil, kv.Bucket(tt.bucket+1).Get(key))
}(key, val, &wg)
}
wg.Wait()
b, err := kv.Bucket(tt.bucket).MarshallJSON()
b, err := json.Marshal(kv.Bucket(tt.bucket).Values())
assert.Nil(t, err)
assert.Equal(t, tt.expectedJSON, string(b))
})

View File

@ -2,14 +2,50 @@ package telemetry
import (
"bytes"
"encoding/json"
"net/http"
"github.com/cloudskiff/driftctl/pkg/memstore"
"github.com/sirupsen/logrus"
)
type telemetry struct {
Version string `json:"version"`
Os string `json:"os"`
Arch string `json:"arch"`
TotalResources int `json:"total_resources"`
TotalManaged int `json:"total_managed"`
Duration uint `json:"duration"`
}
func SendTelemetry(s memstore.Store) {
body, err := s.Bucket(memstore.TelemetryBucket).MarshallJSON()
t := &telemetry{}
if val, ok := s.Bucket(memstore.TelemetryBucket).Get("version").(string); ok {
t.Version = val
}
if val, ok := s.Bucket(memstore.TelemetryBucket).Get("os").(string); ok {
t.Os = val
}
if val, ok := s.Bucket(memstore.TelemetryBucket).Get("arch").(string); ok {
t.Arch = val
}
if val, ok := s.Bucket(memstore.TelemetryBucket).Get("total_resources").(int); ok {
t.TotalResources = val
}
if val, ok := s.Bucket(memstore.TelemetryBucket).Get("total_managed").(int); ok {
t.TotalManaged = val
}
if val, ok := s.Bucket(memstore.TelemetryBucket).Get("duration").(uint); ok {
t.Duration = val
}
body, err := json.Marshal(t)
if err != nil {
logrus.Debug(err)
return

View File

@ -16,23 +16,15 @@ import (
)
func TestSendTelemetry(t *testing.T) {
type telemetry struct {
Version string `json:"version"`
Os string `json:"os"`
Arch string `json:"arch"`
TotalResources int `json:"total_resources"`
TotalManaged int `json:"total_managed"`
Duration uint `json:"duration"`
}
httpmock.Activate()
defer httpmock.DeactivateAndReset()
tests := []struct {
name string
analysis *analyser.Analysis
expectedBody *telemetry
response *http.Response
name string
analysis *analyser.Analysis
expectedBody *telemetry
response *http.Response
setStoreValues func(memstore.Store, *analyser.Analysis)
}{
{
name: "valid analysis",
@ -51,6 +43,14 @@ func TestSendTelemetry(t *testing.T) {
TotalManaged: 1,
Duration: 123,
},
setStoreValues: func(s memstore.Store, a *analyser.Analysis) {
s.Bucket(memstore.TelemetryBucket).Set("version", version.Current())
s.Bucket(memstore.TelemetryBucket).Set("os", runtime.GOOS)
s.Bucket(memstore.TelemetryBucket).Set("arch", runtime.GOARCH)
s.Bucket(memstore.TelemetryBucket).Set("total_resources", a.Summary().TotalResources)
s.Bucket(memstore.TelemetryBucket).Set("total_managed", a.Summary().TotalManaged)
s.Bucket(memstore.TelemetryBucket).Set("duration", uint(a.Duration.Seconds()+0.5))
},
},
{
name: "valid analysis with round up",
@ -65,23 +65,36 @@ func TestSendTelemetry(t *testing.T) {
Arch: runtime.GOARCH,
Duration: 124,
},
setStoreValues: func(s memstore.Store, a *analyser.Analysis) {
s.Bucket(memstore.TelemetryBucket).Set("version", version.Current())
s.Bucket(memstore.TelemetryBucket).Set("os", runtime.GOOS)
s.Bucket(memstore.TelemetryBucket).Set("arch", runtime.GOARCH)
s.Bucket(memstore.TelemetryBucket).Set("total_resources", a.Summary().TotalResources)
s.Bucket(memstore.TelemetryBucket).Set("total_managed", a.Summary().TotalManaged)
s.Bucket(memstore.TelemetryBucket).Set("duration", uint(a.Duration.Seconds()+0.5))
},
},
{
name: "nil analysis",
analysis: nil,
},
{
name: "incomplete analysis values",
analysis: func() *analyser.Analysis {
a := &analyser.Analysis{}
a.Duration = 123.5 * 1e9 // 123.5 seconds
return a
}(),
expectedBody: &telemetry{},
setStoreValues: func(s memstore.Store, a *analyser.Analysis) {},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := memstore.New()
if tt.analysis != nil {
s.Bucket(memstore.TelemetryBucket).Set("version", version.Current())
s.Bucket(memstore.TelemetryBucket).Set("os", runtime.GOOS)
s.Bucket(memstore.TelemetryBucket).Set("arch", runtime.GOARCH)
s.Bucket(memstore.TelemetryBucket).Set("total_resources", tt.analysis.Summary().TotalResources)
s.Bucket(memstore.TelemetryBucket).Set("total_managed", tt.analysis.Summary().TotalManaged)
s.Bucket(memstore.TelemetryBucket).Set("duration", uint(tt.analysis.Duration.Seconds()+0.5))
tt.setStoreValues(s, tt.analysis)
}
httpmock.Reset()