update tests

This commit is contained in:
AlteredCoder 2020-07-24 13:26:55 +02:00
parent 72ff2fbc12
commit 60a5aa3800
10 changed files with 898 additions and 96 deletions

View file

@ -1,7 +1,6 @@
package cwapi
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
@ -169,20 +168,13 @@ func (ctx *ApiCtx) Signin() error {
func (ctx *ApiCtx) RegisterMachine(machineID string, password string) error {
ctx.Creds.User = machineID
ctx.Creds.Password = password
jsonResp := &ApiResp{}
req, err := ctx.Http.New().Post(ctx.RegisterPath).BodyJSON(ctx.Creds).Request()
resp, err := ctx.Http.Post(ctx.RegisterPath).BodyJSON(ctx.Creds).ReceiveSuccess(jsonResp)
if err != nil {
return fmt.Errorf("api register machine: HTTP request creation failed: %s", err)
}
log.Debugf("api register: URL: '%s'", req.URL)
httpClient := http.Client{Timeout: 20 * time.Second}
resp, err := httpClient.Do(req)
if err != nil {
return fmt.Errorf("api register machine: API call failed : %s", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("api register machine: unable to read API response body: %s", err.Error())
@ -192,10 +184,8 @@ func (ctx *ApiCtx) RegisterMachine(machineID string, password string) error {
return fmt.Errorf("api register machine: return bad HTTP code (%d): %s", resp.StatusCode, string(body))
}
jsonResp := ApiResp{}
err = json.Unmarshal(body, &jsonResp)
if err != nil {
return fmt.Errorf("api register machine: unable to unmarshall api response '%s': %s", string(body), err.Error())
if jsonResp.Message == "" || jsonResp.Message != "OK" || jsonResp.StatusCode != 200 {
return fmt.Errorf("api signin failed. http response: %s", body)
}
return nil
}
@ -203,19 +193,14 @@ func (ctx *ApiCtx) RegisterMachine(machineID string, password string) error {
func (ctx *ApiCtx) ResetPassword(machineID string, password string) error {
ctx.Creds.User = machineID
ctx.Creds.Password = password
jsonResp := &ApiResp{}
data := map[string]string{"machine_id": ctx.Creds.User, "password": ctx.Creds.Password}
req, err := ctx.Http.New().Post(ctx.ResetPwdPath).BodyJSON(data).Request()
resp, err := ctx.Http.Post(ctx.ResetPwdPath).BodyJSON(data).ReceiveSuccess(jsonResp)
if err != nil {
return fmt.Errorf("api reset password: HTTP request creation failed: %s", err)
}
log.Debugf("api reset: URL: '%s'", req.URL)
httpClient := http.Client{Timeout: 20 * time.Second}
resp, err := httpClient.Do(req)
if err != nil {
return fmt.Errorf("api reset password: API call failed : %s", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
@ -227,13 +212,8 @@ func (ctx *ApiCtx) ResetPassword(machineID string, password string) error {
return fmt.Errorf("api reset password: return bad HTTP code (%d): %s", resp.StatusCode, string(body))
}
jsonResp := ApiResp{}
err = json.Unmarshal(body, &jsonResp)
if err != nil {
return fmt.Errorf("api reset password: unable to unmarshall api response '%s': %s", string(body), err.Error())
}
if jsonResp.StatusCode != 200 {
return fmt.Errorf("api reset password: return bad HTTP code (%d): %s", jsonResp.StatusCode, string(body))
if jsonResp.Message == "" || jsonResp.Message != "password updated successfully" || jsonResp.StatusCode != 200 {
return fmt.Errorf("api signin failed. http response: %s", body)
}
return nil
}

View file

@ -1,59 +1,51 @@
package cwapi
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
"testing"
"github.com/dghubble/sling"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"gopkg.in/tomb.v2"
"gopkg.in/yaml.v2"
)
const configFile = "./tests/api_config.yaml"
const apiVersion = "v1"
const apiURL = "https://my_test_endpoint"
var apiBaseURL = fmt.Sprintf("%s/%s/", apiURL, apiVersion)
var httpClientMock = &http.Client{
Transport: newMockTransport(),
}
type mockTransport struct{}
func newMockTransport() http.RoundTripper {
return &mockTransport{}
}
// Implement http.RoundTripper
func (t *mockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
var responseBody string
var statusCode int
// Create mocked http.Response
response := &http.Response{
Header: make(http.Header),
Request: req,
func assertConfigFileEqual(t *testing.T, filepath1 string, filepath2 string) {
file1, err := ioutil.ReadFile(filepath1)
if err != nil {
t.Fatalf("unable to read file '%s': %s", filepath1, err)
}
response.Header.Set("Content-Type", "application/json")
if req.URL.Path == "/v1/signin" {
responseBody = `{"statusCode": 200, "message": "crowdsec_api_token"}`
statusCode = 200
apiCtx1 := &ApiCtx{}
if err := yaml.UnmarshalStrict(file1, &apiCtx1); err != nil {
t.Fatalf("unable to unmarshall configuration file '%s' : %s", filepath1, err)
}
response.StatusCode = statusCode
response.Body = ioutil.NopCloser(strings.NewReader(responseBody))
return response, nil
file2, err := ioutil.ReadFile(filepath2)
if err != nil {
t.Fatalf("unable to read file '%s': %s", filepath2, err)
}
apiCtx2 := &ApiCtx{}
if err := yaml.UnmarshalStrict(file2, &apiCtx2); err != nil {
t.Fatalf("unable to unmarshall configuration file '%s' : %s", filepath2, err)
}
assert.Equal(t, apiCtx1, apiCtx2)
}
func TestSignin(t *testing.T) {
func TestWriteConfig(t *testing.T) {
tests := []struct {
apiCtx *ApiCtx
err error
name string
configPath string
compareToFile string
expectedErr bool
givenAPICtx *ApiCtx
}{
{
apiCtx: &ApiCtx{
name: "basic write config",
configPath: "./tests/tmp_api_config.yaml",
compareToFile: "./tests/api_config.yaml",
expectedErr: false,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
PullPath: "pull",
PushPath: "signals",
@ -62,6 +54,176 @@ func TestSignin(t *testing.T) {
ResetPwdPath: "resetpassword",
EnrollPath: "enroll",
BaseURL: "https://my_testendpoint.com",
CfgUser: "test",
CfgPassword: "test",
Creds: ApiCreds{
User: "test",
Password: "test",
},
Muted: false,
DebugDump: false,
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
},
}
for _, test := range tests {
err := test.givenAPICtx.WriteConfig(test.configPath)
if test.expectedErr && err == nil {
t.Fatalf("test '%s' should return an error", test.name)
}
if !test.expectedErr && err != nil {
t.Fatalf("test '%s' returned an error", test.name)
}
if test.expectedErr {
continue
}
assertConfigFileEqual(t, test.configPath, test.compareToFile)
}
}
func TestLoadConfig(t *testing.T) {
tests := []struct {
name string
configPath string
expectedErr bool
expectedAPICtx *ApiCtx
}{
{
name: "basic load config",
configPath: "./tests/api_config.yaml",
expectedErr: false,
expectedAPICtx: &ApiCtx{
ApiVersion: "v1",
PullPath: "pull",
PushPath: "signals",
SigninPath: "signin",
RegisterPath: "register",
ResetPwdPath: "resetpassword",
EnrollPath: "enroll",
BaseURL: "https://my_testendpoint.com",
CfgUser: "test",
CfgPassword: "test",
Creds: ApiCreds{
User: "test",
Password: "test",
},
Muted: false,
DebugDump: false,
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
},
{
name: "load config with bad api version",
configPath: "./tests/api_config_bad_api_version.yaml",
expectedErr: true,
},
{
name: "load config with bad format file",
configPath: "./tests/api_config_bad_format.yaml",
expectedErr: true,
},
}
for _, test := range tests {
apiCtx := &ApiCtx{}
err := apiCtx.LoadConfig(test.configPath)
if test.expectedErr && err == nil {
t.Fatalf("test '%s' should return an error", test.name)
}
if !test.expectedErr && err != nil {
t.Fatalf("test '%s' return an error : %s", test.name, err)
}
if test.expectedErr {
continue
}
apiCtx.Http = test.expectedAPICtx.Http // if we don't do that, assert will fail
assert.Equal(t, test.expectedAPICtx, apiCtx)
}
}
func TestSignin(t *testing.T) {
tests := []struct {
name string
givenAPICtx *ApiCtx
expectedErr bool
}{
{
name: "basic api signin",
expectedErr: false,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
SigninPath: "signin",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
},
{
name: "api signin missing credentials",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
SigninPath: "signin",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
},
{
name: "api signin unknown api PATH",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
SigninPath: "unknown_path",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
},
{
name: "api signin malformed response",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
SigninPath: "malformed_response",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
},
{
name: "api signin bad response",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
SigninPath: "bad_response",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
@ -69,27 +231,221 @@ func TestSignin(t *testing.T) {
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
Muted: false,
DebugDump: false,
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
PusherTomb: tomb.Tomb{},
},
},
}
for _, test := range tests {
if err := test.apiCtx.Signin(); err != nil {
t.Fatalf(err.Error())
err := test.givenAPICtx.Signin()
if !test.expectedErr && err != nil {
t.Fatalf("test '%s' failed : %s", test.name, err)
}
if test.expectedErr && err == nil {
t.Fatalf("test '%s' should return an err", test.name)
}
log.Printf("test '%s' : OK", test.name)
}
}
/*func TestRegister(t *testing.T) {
prepTest()
func TestRegisterMachine(t *testing.T) {
if err := apiCtx.RegisterMachine(); err != nil {
t.Fatalf(err.Error())
tests := []struct {
name string
givenAPICtx *ApiCtx
expectedErr bool
expectedAPICtx *ApiCtx
expectedAPICreds *ApiCreds
}{
{
name: "basic api register machine",
expectedErr: false,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
RegisterPath: "register",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
expectedAPICreds: &ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
},
{
name: "api register unknown api PATH",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
RegisterPath: "unknown_path",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
},
{
name: "api register malformed response",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
RegisterPath: "malformed_response",
BaseURL: "https://my_testendpoint.com",
Creds: ApiCreds{
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
PusherTomb: tomb.Tomb{},
},
},
{
name: "api register bad response",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
RegisterPath: "bad_response",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
},
}
for _, test := range tests {
err := test.givenAPICtx.RegisterMachine(test.givenAPICtx.CfgUser, test.givenAPICtx.CfgPassword)
if !test.expectedErr && err != nil {
t.Fatalf("test '%s' failed : %s", test.name, err)
}
if test.expectedErr && err == nil {
t.Fatalf("test '%s' should return an err", test.name)
}
if test.expectedAPICreds != nil {
assert.Equal(t, *test.expectedAPICreds, test.givenAPICtx.Creds)
}
log.Printf("test '%s' : OK", test.name)
}
}
func TestResetPassword(t *testing.T) {
tests := []struct {
name string
givenAPICtx *ApiCtx
expectedErr bool
expectedAPICtx *ApiCtx
expectedAPICreds *ApiCreds
}{
{
name: "basic api machine reset password",
expectedErr: false,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
ResetPwdPath: "resetpassword",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "new_machine_password",
Creds: ApiCreds{
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
expectedAPICreds: &ApiCreds{
User: "machine_id",
Password: "new_machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
},
{
name: "api reset password unknown api PATH",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
ResetPwdPath: "unknown_path",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
},
{
name: "api reset password malformed response",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
ResetPwdPath: "malformed_response",
BaseURL: "https://my_testendpoint.com",
Creds: ApiCreds{
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
PusherTomb: tomb.Tomb{},
},
},
{
name: "api reset password bad response",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
ResetPwdPath: "bad_response",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
},
{
name: "api reset password unknown user",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
ResetPwdPath: "resestpassword_unknown_user",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
},
}
for _, test := range tests {
err := test.givenAPICtx.ResetPassword(test.givenAPICtx.CfgUser, test.givenAPICtx.CfgPassword)
if !test.expectedErr && err != nil {
t.Fatalf("test '%s' failed : %s", test.name, err)
}
if test.expectedErr && err == nil {
t.Fatalf("test '%s' should return an err", test.name)
}
if test.expectedAPICreds != nil {
assert.Equal(t, *test.expectedAPICreds, test.givenAPICtx.Creds)
}
log.Printf("test '%s' : OK", test.name)
}
}
*/

View file

@ -3,25 +3,18 @@ package cwapi
import (
"fmt"
"io/ioutil"
"net/http"
"time"
log "github.com/sirupsen/logrus"
)
func (ctx *ApiCtx) Enroll(userID string) error {
toPush := map[string]string{"user_id": userID}
jsonResp := &ApiResp{}
req, err := ctx.Http.New().Post(ctx.EnrollPath).BodyJSON(&toPush).Request()
resp, err := ctx.Http.Post(ctx.EnrollPath).BodyJSON(&toPush).ReceiveSuccess(jsonResp)
if err != nil {
return fmt.Errorf("api enroll: HTTP request creation failed: %s", err)
}
log.Debugf("api enroll: URL: '%s'", req.URL)
httpClient := http.Client{Timeout: 20 * time.Second}
resp, err := httpClient.Do(req)
if err != nil {
return fmt.Errorf("api enroll: API call failed : %s", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
@ -31,6 +24,9 @@ func (ctx *ApiCtx) Enroll(userID string) error {
if resp.StatusCode != 200 {
return fmt.Errorf("api enroll: user '%s' return bad HTTP code (%d): %s", userID, resp.StatusCode, string(body))
}
if jsonResp.Message == "" || jsonResp.Message != "OK" || jsonResp.StatusCode != 200 {
return fmt.Errorf("api user enroll failed. http response: %s", body)
}
log.Printf("user '%s' is enrolled successfully", string(userID))
return nil
}

103
pkg/cwapi/enroll_test.go Normal file
View file

@ -0,0 +1,103 @@
package cwapi
import (
"testing"
"github.com/dghubble/sling"
log "github.com/sirupsen/logrus"
)
func TestEnroll(t *testing.T) {
tests := []struct {
name string
givenAPICtx *ApiCtx
expectedErr bool
userID string
}{
{
name: "basic api user enroll",
expectedErr: false,
userID: "1234",
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
EnrollPath: "enroll",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
},
{
name: "api signin unknown api PATH",
expectedErr: true,
userID: "1234",
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
EnrollPath: "unknown_path",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
},
{
name: "api signin malformed response",
expectedErr: true,
userID: "1234",
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
EnrollPath: "malformed_response",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
},
{
name: "api signin bad response",
expectedErr: true,
userID: "1234",
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
EnrollPath: "bad_response",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
Http: sling.New().Client(httpClientMock).Base(apiBaseURL),
},
},
}
for _, test := range tests {
err := test.givenAPICtx.Enroll(test.userID)
if !test.expectedErr && err != nil {
t.Fatalf("test '%s' failed : %s", test.name, err)
}
if test.expectedErr && err == nil {
t.Fatalf("test '%s' should return an err", test.name)
}
log.Printf("test '%s' : OK", test.name)
}
}

View file

@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
"github.com/crowdsecurity/crowdsec/pkg/types"
@ -22,18 +21,11 @@ func (ctx *ApiCtx) pushSignals() error {
if len(ctx.toPush) == 0 {
return nil
}
req, err := ctx.Http.New().Put(ctx.PushPath).BodyJSON(&ctx.toPush).Request()
jsonResp := &ApiResp{}
resp, err := ctx.Http.New().Put(ctx.PushPath).BodyJSON(&ctx.toPush).ReceiveSuccess(jsonResp)
if err != nil {
return fmt.Errorf("api push signal: HTTP request creation failed: %s", err)
}
log.Debugf("api push: URL: '%s'", req.URL)
httpClient := http.Client{Timeout: 20 * time.Second}
resp, err := httpClient.Do(req)
if err != nil {
return fmt.Errorf("api push signal: API call failed : %s", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
@ -57,6 +49,11 @@ func (ctx *ApiCtx) pushSignals() error {
return fmt.Errorf("api push signal: return bad HTTP code (%d): %s", resp.StatusCode, string(body))
}
}
if resp.StatusCode != 401 && (jsonResp.Message == "" || jsonResp.Message != "OK" || jsonResp.StatusCode != 200) {
return fmt.Errorf("api push failed. http response: %s", body)
}
if len(ctx.toPush) > 0 {
log.Infof("api push signal: pushed %d signals successfully", len(ctx.toPush))
}

248
pkg/cwapi/signals_test.go Normal file
View file

@ -0,0 +1,248 @@
package cwapi
import (
"testing"
"time"
"github.com/crowdsecurity/crowdsec/pkg/types"
"github.com/dghubble/sling"
log "github.com/sirupsen/logrus"
)
var signalList = []types.Event{
{
Overflow: types.SignalOccurence{
Scenario: "crowdsec/test",
Bucket_id: "1234",
Events_count: 1,
Events_sequence: []types.EventSequence{},
Start_at: time.Now(),
BanApplications: []types.BanApplication{},
Stop_at: time.Now(),
Source_ip: "1.2.3.4",
Source_range: "1.2.3.0/24",
Source_AutonomousSystemNumber: "1234",
Source_AutonomousSystemOrganization: "TestAS",
Source_Country: "FR",
Dest_ip: "1.2.3.5",
Capacity: 1,
Whitelisted: false,
Simulation: false,
},
},
{
Overflow: types.SignalOccurence{
Scenario: "crowdsec/test",
Bucket_id: "1235",
Events_count: 1,
Events_sequence: []types.EventSequence{},
Start_at: time.Now(),
BanApplications: []types.BanApplication{},
Stop_at: time.Now(),
Source_ip: "1.2.3.5",
Source_range: "1.2.3.0/24",
Source_AutonomousSystemNumber: "1234",
Source_AutonomousSystemOrganization: "TestAS",
Source_Country: "FR",
Dest_ip: "1.2.3.6",
Capacity: 1,
Whitelisted: false,
Simulation: false,
},
},
}
func TestPushSignal(t *testing.T) {
tests := []struct {
name string
givenAPICtx *ApiCtx
expectedErr bool
}{
{
name: "basic api push signal",
expectedErr: false,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
PushPath: "signals",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
toPush: signalList,
Http: sling.New().Client(newMockClient()).Base(apiBaseURL),
},
},
{
name: "api push signal unknown api PATH",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
PushPath: "unknown_path",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
toPush: signalList,
Http: sling.New().Client(newMockClient()).Base(apiBaseURL),
},
},
{
name: "api push signal malformed response",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
PushPath: "malformed_response",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
toPush: signalList,
Http: sling.New().Client(newMockClient()).Base(apiBaseURL),
},
},
{
name: "api push signal bad response",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
PushPath: "bad_response",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
toPush: signalList,
Http: sling.New().Client(newMockClient()).Base(apiBaseURL),
},
},
{
name: "api push signal empty signal list",
expectedErr: false,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
PushPath: "signals",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
toPush: []types.Event{},
Http: sling.New().Client(newMockClient()).Base(apiBaseURL),
},
},
{
name: "api push signal expired token",
expectedErr: false,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
PushPath: "signals_token_expired",
SigninPath: "signin",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
toPush: signalList,
tokenExpired: false,
Http: sling.New().Client(newMockClient()).Base(apiBaseURL),
},
},
{
name: "api push signal unable to renew expired token",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
PushPath: "signals_token_renew_fail",
SigninPath: "signin",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
toPush: signalList,
tokenExpired: false,
Http: sling.New().Client(newMockClient()).Base(apiBaseURL),
},
},
{
name: "api push signal bad response code",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
PushPath: "signals_bad_response_code",
SigninPath: "signin",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
toPush: signalList,
tokenExpired: false,
Http: sling.New().Client(newMockClient()).Base(apiBaseURL),
},
},
{
name: "api push signal signin while token expired failed",
expectedErr: true,
givenAPICtx: &ApiCtx{
ApiVersion: "v1",
PushPath: "signals_token_expired",
SigninPath: "bad_response",
BaseURL: "https://my_testendpoint.com",
CfgUser: "machine_id",
CfgPassword: "machine_password",
Creds: ApiCreds{
User: "machine_id",
Password: "machine_password",
Profile: "crowdsec/test1,crowdsec/test2",
},
toPush: signalList,
tokenExpired: false,
Http: sling.New().Client(newMockClient()).Base(apiBaseURL),
},
},
}
for _, test := range tests {
err := test.givenAPICtx.pushSignals()
if !test.expectedErr && err != nil {
t.Fatalf("test '%s' failed : %s", test.name, err)
}
if test.expectedErr && err == nil {
t.Fatalf("test '%s' should return an err", test.name)
}
if test.expectedErr {
continue
}
log.Printf("test '%s' : OK", test.name)
}
}

View file

@ -1,5 +1,5 @@
version: v1
url: https://test_endpoint
url: https://my_testendpoint.com
signin_path: signin
push_path: signals
pull_path: pull

View file

@ -0,0 +1,10 @@
version: v0
url: https://test_endpoint
signin_path: signin
push_path: signals
pull_path: pull
enroll_path: enroll
reset_pwd_path: resetpassword
register_path: register
machine_id: test
password: test

View file

@ -0,0 +1,11 @@
bad_key: test
version: v1
url: https://test_endpoint
signin_path: signin
push_path: signals
pull_path: pull
enroll_path: enroll
reset_pwd_path: resetpassword
register_path: register
machine_id: test
password: test

101
pkg/cwapi/utils_test.go Normal file
View file

@ -0,0 +1,101 @@
package cwapi
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
)
const configFile = "./tests/api_config.yaml"
const apiVersion = "v1"
const apiURL = "https://my_test_endpoint"
var apiBaseURL = fmt.Sprintf("%s/%s/", apiURL, apiVersion)
var httpClientMock = &http.Client{
Transport: newMockTransport(),
Timeout: time.Second * 20,
}
type mockTransport struct {
nbTryTokenOK int // to test token expiration
nbTryTokenNOK int
}
func newMockTransport() http.RoundTripper {
return &mockTransport{}
}
func newMockClient() *http.Client {
return &http.Client{
Transport: newMockTransport(),
Timeout: time.Second * 20,
}
}
// Implement http.RoundTripper
func (t *mockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
var responseBody string
var statusCode int
// Create mocked http.Response
response := &http.Response{
Header: make(http.Header),
Request: req,
}
response.Header.Set("Content-Type", "application/json")
switch req.URL.Path {
case "/v1/signin":
responseBody = `{"statusCode": 200, "message": "crowdsec_api_token"}`
statusCode = 200
case "/v1/register":
responseBody = `{"statusCode": 200, "message": "OK"}`
statusCode = 200
case "/v1/signals":
responseBody = `{"statusCode": 200, "message": "OK"}`
statusCode = 200
case "/v1/signals_token_expired":
if t.nbTryTokenOK == 0 {
responseBody = `{"statusCode": 200, "message": "crowdsec_api_token"}`
statusCode = 401
t.nbTryTokenOK++
} else {
responseBody = `{"statusCode": 200, "message": "OK"}`
statusCode = 200
}
case "/v1/signals_token_renew_fail":
if t.nbTryTokenNOK == 0 {
responseBody = `{"statusCode": 200, "message": "crowdsec_api_token"}`
statusCode = 401
t.nbTryTokenNOK++
} else {
responseBody = `{"statusCode": 500, "message": "token expired"}`
statusCode = 500
}
case "/v1/signals_bad_response_code":
responseBody = `{"statusCode": 200, "message": "OK"}`
statusCode = 500
case "/v1/enroll":
responseBody = `{"statusCode": 200, "message": "OK"}`
statusCode = 200
case "/v1/resetpassword":
responseBody = `{"statusCode": 200, "message": "password updated successfully"}`
statusCode = 200
case "/v1/resetpassword_unknown_user":
responseBody = `{"statusCode": 500, "message": "User not found"}`
statusCode = 200
case "/v1/unknown_path":
statusCode = 404
responseBody = `{"error": "unknown URI"}`
case "/v1/malformed_response":
statusCode = 200
responseBody = `{"statusCode" : 200, "msg" : "api_token"`
case "/v1/bad_response":
statusCode = 200
responseBody = `{"statusCode" : 200, "msg" : "api_token"}`
}
response.StatusCode = statusCode
response.Body = ioutil.NopCloser(strings.NewReader(responseBody))
return response, nil
}