diff --git a/go.mod b/go.mod index bf03e7a..1d52ef4 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect diff --git a/go.sum b/go.sum index 31e3e30..8938bae 100644 --- a/go.sum +++ b/go.sum @@ -39,6 +39,7 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= diff --git a/internal/infra/config/agent/agent.go b/internal/infra/config/agent/agent.go index 280adf2..dcec1f2 100644 --- a/internal/infra/config/agent/agent.go +++ b/internal/infra/config/agent/agent.go @@ -15,6 +15,7 @@ const ( DefRetryAttempts = 3 DefRetryIntervalInitial = 1 * time.Second DefRetryIntervalBackoff = 2 * time.Second + DefRateLimit = 1 ) type Config struct { @@ -41,7 +42,7 @@ func InitConfig() (*Config, error) { ) pollInterval := flag.Uint("p", DefPollInterval, "How often to query metrics, seconds") hmacKey := flag.String("k", "", "HMAC key for integrity checks") - rateLimit := flag.Uint("l", 1, "Max number of active workers") + rateLimit := flag.Uint("l", DefRateLimit, "Max number of active workers") flag.Parse() if conf.Addr == "" { conf.Addr = *addr diff --git a/internal/infra/config/agent/agent_test.go b/internal/infra/config/agent/agent_test.go index df61fc8..2c6925e 100644 --- a/internal/infra/config/agent/agent_test.go +++ b/internal/infra/config/agent/agent_test.go @@ -27,6 +27,7 @@ func TestInitConfig(t *testing.T) { RetryAttempts: DefRetryAttempts, RetryIntervalBackoff: DefRetryIntervalBackoff, RetryIntervalInitial: DefRetryIntervalInitial, + RateLimit: DefRateLimit, }, }, { @@ -41,6 +42,7 @@ func TestInitConfig(t *testing.T) { RetryAttempts: DefRetryAttempts, RetryIntervalBackoff: DefRetryIntervalBackoff, RetryIntervalInitial: DefRetryIntervalInitial, + RateLimit: DefRateLimit, }, }, { @@ -55,6 +57,7 @@ func TestInitConfig(t *testing.T) { RetryAttempts: DefRetryAttempts, RetryIntervalBackoff: DefRetryIntervalBackoff, RetryIntervalInitial: DefRetryIntervalInitial, + RateLimit: DefRateLimit, }, }, { @@ -69,6 +72,7 @@ func TestInitConfig(t *testing.T) { RetryAttempts: DefRetryAttempts, RetryIntervalBackoff: DefRetryIntervalBackoff, RetryIntervalInitial: DefRetryIntervalInitial, + RateLimit: DefRateLimit, }, }, } diff --git a/internal/server/usecases/utils_test.go b/internal/server/usecases/utils_test.go new file mode 100644 index 0000000..9eab57d --- /dev/null +++ b/internal/server/usecases/utils_test.go @@ -0,0 +1,247 @@ +package usecases + +import ( + "bytes" + "context" + "errors" + "net/http" + "net/http/httptest" + "reflect" + "testing" + + "github.com/go-chi/chi/v5" + common "github.com/matthiasBT/monitoring/internal/infra/entities" +) + +func Test_handleInvalidMetric(t *testing.T) { + + tests := []struct { + name string + err error + wantCode int + wantBody string + }{ + { + name: "invalid_type", + err: common.ErrInvalidMetricType, + wantCode: http.StatusBadRequest, + wantBody: common.ErrInvalidMetricType.Error(), + }, + { + name: "no_name", + err: common.ErrMissingMetricName, + wantCode: http.StatusNotFound, + wantBody: common.ErrMissingMetricName.Error(), + }, + { + name: "invalid_val", + err: common.ErrInvalidMetricVal, + wantCode: http.StatusBadRequest, + wantBody: common.ErrInvalidMetricVal.Error(), + }, + { + name: "internal_server_error", + err: errors.New("foobar"), + wantCode: http.StatusInternalServerError, + wantBody: "foobar", + }, + } + for _, tt := range tests { + rr := httptest.NewRecorder() + t.Run(tt.name, func(t *testing.T) { + handleInvalidMetric(rr, tt.err) + }) + if tt.wantCode != rr.Code { + t.Errorf("Code mismatch. got: %v, want: %v\n", rr.Code, tt.wantCode) + } + if !bytes.Equal([]byte(tt.wantBody), rr.Body.Bytes()) { + t.Errorf("Body mismatch. got: %s, want: %s\n", rr.Body.Bytes(), tt.wantBody) + } + } +} + +func Test_parseMetric(t *testing.T) { + type args struct { + url string + body string + asJSON bool + withValue bool + paramType string + paramName string + paramValue string + } + tests := []struct { + name string + args args + want *common.Metrics + }{ + { + name: "test_valid_counter_json", args: args{ + url: "/update/", + body: `{"id": "foobar", "type": "counter", "delta": 123}`, + asJSON: true, + withValue: false, + }, want: &common.Metrics{ + ID: "foobar", + MType: "counter", + Delta: ptrint64(123), + Value: nil, + }, + }, + { + name: "test_valid_gauge_json", args: args{ + url: "/update/", + body: `{"id": "foobar", "type": "gauge", "value": 123.4}`, + asJSON: true, + withValue: false, + }, want: &common.Metrics{ + ID: "foobar", + MType: "gauge", + Delta: nil, + Value: ptrfloat64(123.4), + }, + }, + { + name: "test_invalid_counter_json", args: args{ + url: "/update/", + body: `"id": "foobar", "type": "counter", "delta": 123}`, + asJSON: true, + withValue: false, + }, want: nil, + }, + { + name: "test_valid_counter_params_noval", args: args{ + url: "/update/counter/foobar/123", + body: "", + asJSON: false, + withValue: false, + paramType: "counter", + paramName: "foobar", + paramValue: "123", + }, want: &common.Metrics{ + ID: "foobar", + MType: "counter", + Delta: nil, + Value: nil, + }, + }, + { + name: "test_valid_gauge_params_noval", args: args{ + url: "/update/gauge/foobar/123", + body: "", + asJSON: false, + withValue: false, + paramType: "gauge", + paramName: "foobar", + paramValue: "123.4", + }, want: &common.Metrics{ + ID: "foobar", + MType: "gauge", + Delta: nil, + Value: nil, + }, + }, + { + name: "test_valid_counter_params_val", args: args{ + url: "/update/counter/foobar/123", + body: "", + asJSON: false, + withValue: true, + paramType: "counter", + paramName: "foobar", + paramValue: "123", + }, want: &common.Metrics{ + ID: "foobar", + MType: "counter", + Delta: ptrint64(123), + Value: nil, + }, + }, + { + name: "test_valid_gauge_params_val", args: args{ + url: "/update/gauge/foobar/123.4", + body: "", + asJSON: false, + withValue: true, + paramType: "gauge", + paramName: "foobar", + paramValue: "123.4", + }, want: &common.Metrics{ + ID: "foobar", + MType: "gauge", + Delta: nil, + Value: ptrfloat64(123.4), + }, + }, + { + name: "test_invalid_counter_params_val", args: args{ + url: "/update/counter/foobar/123a", + body: "", + asJSON: false, + withValue: true, + paramType: "counter", + paramName: "foobar", + paramValue: "123a", + }, want: nil, + }, + { + name: "test_invalid_gauge_params_val", args: args{ + url: "/update/gauge/foobar/123.4a", + body: "", + asJSON: false, + withValue: true, + paramType: "gauge", + paramName: "foobar", + paramValue: "123.4a", + }, want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var req *http.Request + var err error + if tt.args.asJSON { + body := []byte(tt.args.body) + req, err = http.NewRequest("_", tt.args.url, bytes.NewBuffer(body)) + if err != nil { + t.Fatal(err) + } + } else { + rctx := chi.NewRouteContext() + rctx.URLParams.Add("type", tt.args.paramType) + rctx.URLParams.Add("name", tt.args.paramName) + rctx.URLParams.Add("value", tt.args.paramValue) + req, err = http.NewRequest("_", tt.args.url, bytes.NewBuffer([]byte{})) + if err != nil { + t.Fatal(err) + } + req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + } + if got := parseMetric(req, tt.args.asJSON, tt.args.withValue); !reflect.DeepEqual(got, tt.want) { + t.Errorf("parseMetric() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_writeMetric(t *testing.T) { + type args struct { + w http.ResponseWriter + asJSON bool + metrics *common.Metrics + } + tests := []struct { + name string + args args + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := writeMetric(tt.args.w, tt.args.asJSON, tt.args.metrics); (err != nil) != tt.wantErr { + t.Errorf("writeMetric() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +}