Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,9 @@
# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Configuration file
config/*.yml
!config/webhooks.example.yml

# Dependency directories (remove the comment below to include it)
# vendor/
9 changes: 3 additions & 6 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,11 @@ internal/server/v1alpha1 @42Atomys
# core package is initially coded and managed by @42Atomys
pkg/core @42Atomys

# Webhook Entries is initially coded and managed by @42Atomys
pkg/core/entry* @42Atomys
pkg/entries @42Atomys
# Webhook Factories is initially coded and managed by @42Atomys
pkg/factory @42Atomys

# Webhook Security is initially coded and managed by @42Atomys
pkg/core/security* @42Atomys
pkg/security @42Atomys

# Webhook Storage is initially coded and managed by @rgaiffe
pkg/core/storage* @rgaiffe
pkg/storages @rgaiffe
pkg/storage @rgaiffe
35 changes: 13 additions & 22 deletions internal/config/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import (
"errors"
"fmt"

"42stellar.org/webhooks/pkg/factory"
"42stellar.org/webhooks/pkg/storages"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"

"42stellar.org/webhooks/pkg/factory"
"42stellar.org/webhooks/pkg/storage"
)

var (
Expand All @@ -23,7 +24,7 @@ func Load() error {
}

for _, spec := range currentConfig.Specs {
if err := LoadSecurityFactory(spec); err != nil {
if err := loadSecurityFactory(spec); err != nil {
return err
}
if err = loadStorage(spec); err != nil {
Expand All @@ -34,9 +35,9 @@ func Load() error {
return Validate(currentConfig)
}

// LoadSecurityFactory loads the security factory for the given spec
// loadSecurityFactory loads the security factory for the given spec
// if an error is occured, return an error
func LoadSecurityFactory(spec *WebhookSpec) error {
func loadSecurityFactory(spec *WebhookSpec) error {
for _, security := range spec.Security {
for securityName, securityConfig := range security {
factoryFunc, ok := factory.GetFunctionByName(securityName)
Expand Down Expand Up @@ -83,25 +84,15 @@ func Validate(config *Configuration) error {
// initialization or connection, the error is returned during the
// validation
func loadStorage(spec *WebhookSpec) (err error) {
for _, storage := range spec.Storage {
switch storage.Type {
case "redis":
storage.Client, err = storages.NewRedisStorage(storage.Specs)
if err != nil {
return err
}

case "postgres":
storage.Client, err = storages.NewPostgresStorage(storage.Specs)
if err != nil {
return err
}

default:
return fmt.Errorf("storage %s is undefined", storage.Type)
for _, s := range spec.Storage {
s.Client, err = storage.Load(s.Type, s.Specs)
if err != nil {
return
}
}
return nil

log.Debug().Msgf("%d storages loaded for spec %s", len(spec.Storage), spec.Name)
return
}

// Current returns the aftual configuration
Expand Down
68 changes: 67 additions & 1 deletion internal/config/configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func TestLoadSecurityFactory(t *testing.T) {
}

for _, test := range tests {
err := LoadSecurityFactory(test.input)
err := loadSecurityFactory(test.input)
if test.wantErr {
assert.Error(err)
} else {
Expand All @@ -147,3 +147,69 @@ func TestLoadSecurityFactory(t *testing.T) {
assert.Len(test.input.SecurityFactories, test.wantLen)
}
}

func TestLoadStorage(t *testing.T) {
assert := assert.New(t)

tests := []struct {
name string
storageName string
input *WebhookSpec
wantErr bool
wantStorage bool
}{
{"no spec", "", &WebhookSpec{Name: "test"}, false, false},
{
"full valid storage",
"connection invalid must return an error",
&WebhookSpec{
Name: "test",
Storage: map[string]StorageSpec{
"redis": {
Type: "redis",
Specs: map[string]interface{}{
"host": "localhost",
"port": 0,
},
},
},
},
true,
false,
},
{
"empty storage configuration",
"",
&WebhookSpec{
Name: "test",
Storage: make(map[string]StorageSpec),
},
false,
false,
},
{
"invalid storage name in configuration",
"",
&WebhookSpec{
Name: "test",
Storage: map[string]StorageSpec{
"invalid": {},
},
},
true,
false,
},
}

for _, test := range tests {
err := loadStorage(test.input)
if test.wantErr {
assert.Error(err)
} else {
assert.NoError(err)
}

_, ok := test.input.Storage[test.storageName]
assert.Equal(test.wantStorage, ok)
}
}
6 changes: 3 additions & 3 deletions internal/config/structs.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package config

import (
"42stellar.org/webhooks/pkg/core"
"42stellar.org/webhooks/pkg/factory"
"42stellar.org/webhooks/pkg/factory"
"42stellar.org/webhooks/pkg/storage"
)

type Configuration struct {
Expand All @@ -21,5 +21,5 @@ type WebhookSpec struct {
type StorageSpec struct {
Type string `mapstructure:"type"`
Specs map[string]interface{} `mapstructure:"specs"`
Client core.Pusher
Client storage.Pusher
}
9 changes: 0 additions & 9 deletions pkg/core/storage.go

This file was deleted.

26 changes: 13 additions & 13 deletions pkg/storages/postgres.go → pkg/storage/postgres/postgres.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package storages
package postgres

import (
"database/sql"
Expand All @@ -8,34 +8,34 @@ import (
"github.com/mitchellh/mapstructure"
)

// PostgresStorage is the struct contains client and config
// storage is the struct contains client and config
// Run is made from external caller at begins programs
type PostgresStorage struct {
type storage struct {
client *sql.DB
config *postgresConfig
config *config
}

// postgresConfig is the struct contains config for connect client
// config is the struct contains config for connect client
// Run is made from internal caller
type postgresConfig struct {
type config struct {
DatabaseURL string
TableName string
DataField string
}

// NewPostgresStorage is the function for create new Postgres client storage
// NewStorage is the function for create new Postgres client storage
// Run is made from external caller at begins programs
// @param config contains config define in the webhooks yaml file
// @return PostgresStorage the struct contains client connected and config
// @error an error if the the client is not initialized succesfully
func NewPostgresStorage(config map[string]interface{}) (*PostgresStorage, error) {
func NewStorage(configRaw map[string]interface{}) (*storage, error) {
var err error

newClient := PostgresStorage{
config: &postgresConfig{},
newClient := storage{
config: &config{},
}

if err := mapstructure.Decode(config, &newClient.config); err != nil {
if err := mapstructure.Decode(configRaw, &newClient.config); err != nil {
return nil, err
}

Expand All @@ -48,15 +48,15 @@ func NewPostgresStorage(config map[string]interface{}) (*PostgresStorage, error)

// Name is the function for identified if the storage config is define in the webhooks
// Run is made from external caller
func (c PostgresStorage) Name() string {
func (c storage) Name() string {
return "postgres"
}

// Push is the function for push data in the storage
// A run is made from external caller
// @param value that will be pushed
// @return an error if the push failed
func (c PostgresStorage) Push(value interface{}) error {
func (c storage) Push(value interface{}) error {
request := fmt.Sprintf("INSERT INTO %s(%s) VALUES ('%s')", c.config.TableName, c.config.DataField, value)
if _, err := c.client.Query(request); err != nil {
return err
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package storages
package postgres

import (
"database/sql"
Expand Down Expand Up @@ -32,17 +32,17 @@ func (suite *PostgresSetupTestSuite) AfterTest(suiteName, testName string) {
}

func TestPostgresName(t *testing.T) {
newPostgres := PostgresStorage{}
newPostgres := storage{}
assert.Equal(t, "postgres", newPostgres.Name())
}

func TestPostgresNewPostgresStorage(t *testing.T) {
_, err := NewPostgresStorage(map[string]interface{}{
func TestPostgresNewStorage(t *testing.T) {
_, err := NewStorage(map[string]interface{}{
"databaseURL": []int{1},
})
assert.Error(t, err)

_, err = NewPostgresStorage(map[string]interface{}{
_, err = NewStorage(map[string]interface{}{
"databaseURL": "postgresql://webhook:test@127.0.0.1:5432/webhook_db?sslmode=disable",
"tableName": "test",
"dataField": "test_field",
Expand All @@ -51,15 +51,15 @@ func TestPostgresNewPostgresStorage(t *testing.T) {
}

func (suite *PostgresSetupTestSuite) TestPostgresPush() {
newClient, _ := NewPostgresStorage(map[string]interface{}{
newClient, _ := NewStorage(map[string]interface{}{
"databaseURL": "postgresql://webhook:test@127.0.0.1:5432/webhook_db?sslmode=disable",
"tableName": "Not Exist",
"dataField": "Not exist",
})
err := newClient.Push("Hello")
assert.Error(suite.T(), err)

newClient, err = NewPostgresStorage(map[string]interface{}{
newClient, err = NewStorage(map[string]interface{}{
"databaseURL": "postgresql://webhook:test@127.0.0.1:5432/webhook_db?sslmode=disable",
"tableName": "test",
"dataField": "test_field",
Expand Down
20 changes: 10 additions & 10 deletions pkg/storages/redis.go → pkg/storage/redis/redis.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package storages
package redis

import (
"context"
Expand All @@ -8,13 +8,13 @@ import (
"github.com/mitchellh/mapstructure"
)

type RedisStorage struct {
type storage struct {
client *redis.Client
config *redisConfig
config *config
ctx context.Context
}

type redisConfig struct {
type config struct {
Host string
Port string
Database int
Expand All @@ -23,14 +23,14 @@ type redisConfig struct {
Channel string
}

func NewRedisStorage(config map[string]interface{}) (*RedisStorage, error) {
func NewStorage(configRaw map[string]interface{}) (*storage, error) {

newClient := RedisStorage{
config: &redisConfig{},
newClient := storage{
config: &config{},
ctx: context.Background(),
}

if err := mapstructure.Decode(config, &newClient.config); err != nil {
if err := mapstructure.Decode(configRaw, &newClient.config); err != nil {
return nil, err
}

Expand All @@ -53,15 +53,15 @@ func NewRedisStorage(config map[string]interface{}) (*RedisStorage, error) {

// Name is the function for identified if the storage config is define in the webhooks
// @return name of the storage
func (c RedisStorage) Name() string {
func (c storage) Name() string {
return "redis"
}

// Push is the function for push data in the storage
// A run is made from external caller
// @param value that will be pushed
// @return an error if the push failed
func (c RedisStorage) Push(value interface{}) error {
func (c storage) Push(value interface{}) error {
if err := c.client.Publish(c.ctx, c.config.Channel, value).Err(); err != nil {
return err
}
Expand Down
Loading