Skip to content

Commit 9c65897

Browse files
chore: add unit test
1 parent 52d7aa2 commit 9c65897

11 files changed

Lines changed: 334 additions & 8 deletions

File tree

app/server_test.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,11 @@ func isClosed(ch <-chan collection.CollectRequest) bool {
6969
// mockKafkaClient is a mock for the Client interface
7070
type mockKafkaClient struct {
7171
// Tracking flags
72-
ProduceCalled bool
73-
CloseCalled bool
74-
FlushCalled bool
75-
EventsCalled bool
72+
ProduceCalled bool
73+
CloseCalled bool
74+
FlushCalled bool
75+
EventsCalled bool
76+
GetMetadataCalled bool
7677

7778
ReturnFlushLeft int
7879
EventChan chan kafka.Event
@@ -99,3 +100,8 @@ func (m *mockKafkaClient) Events() chan kafka.Event {
99100
}
100101
return m.EventChan
101102
}
103+
104+
func (m *mockKafkaClient) GetMetadata(topic *string, allTopics bool, timeoutMs int) (*kafka.Metadata, error) {
105+
m.GetMetadataCalled = true
106+
return &kafka.Metadata{}, nil
107+
}

config/load_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,35 @@ func TestGRPCServerConfig(t *testing.T) {
5252
assert.Equal(t, "8081", ServerGRPC.Port)
5353
}
5454

55+
func TestServerMQTTConfig(t *testing.T) {
56+
os.Setenv("SERVER_MQTT_CONSUL_ADDRESS", "consul:8081")
57+
os.Setenv("SERVER_MQTT_CONSUL_KV_KEY", "kv/path")
58+
os.Setenv("SERVER_MQTT_CONSUL_HEALTH_ONLY", "true")
59+
os.Setenv("SERVER_MQTT_CONSUL_WAIT_TIME", "300")
60+
os.Setenv("SERVER_MQTT_AUTH_USERNAME", "test")
61+
os.Setenv("SERVER_MQTT_AUTH_PASSWORD", "pass")
62+
os.Setenv("SERVER_MQTT_CONSUMER_RETRY_INTERVAL_IN_SEC", "1")
63+
os.Setenv("SERVER_MQTT_CONSUMER_WRITE_TIMEOUT_IN_SEC", "1")
64+
os.Setenv("SERVER_MQTT_CONSUMER_LOG_LEVEL", "warn")
65+
os.Setenv("SERVER_MQTT_CONSUMER_POOL_SIZE", "1")
66+
os.Setenv("SERVER_MQTT_CONSUMER_TOPIC_FORMAT", "default-topic")
67+
os.Setenv("SERVER_MQTT_CONNECTION_GROUP", "consumer")
68+
serverMQTTConfigLoader()
69+
assert.Equal(t, "consul:8081", ServerMQTT.ConsulConfig.Address)
70+
assert.Equal(t, "kv/path", ServerMQTT.ConsulConfig.KVKey)
71+
assert.Equal(t, true, ServerMQTT.ConsulConfig.HealthOnly)
72+
assert.Equal(t, 300*time.Second, ServerMQTT.ConsulConfig.WaitTime)
73+
assert.Equal(t, "test", ServerMQTT.AuthConfig.Username)
74+
assert.Equal(t, "pass", ServerMQTT.AuthConfig.Password)
75+
assert.Equal(t, 1*time.Second, ServerMQTT.ConsumerConfig.RetryIntervalInSec)
76+
assert.Equal(t, 1*time.Second, ServerMQTT.ConsumerConfig.WriteTimeoutInSec)
77+
assert.Equal(t, "warn", ServerMQTT.ConsumerConfig.LogLevel)
78+
assert.Equal(t, 1, ServerMQTT.ConsumerConfig.PoolSize)
79+
assert.Equal(t, "default-topic", ServerMQTT.ConsumerConfig.TopicFormat)
80+
assert.Equal(t, "consumer", ServerMQTT.ConnGroup)
81+
82+
}
83+
5584
func TestDynamicConfigLoad(t *testing.T) {
5685
os.Setenv("PUBLISHER_KAFKA_CLIENT_RANDOM", "anything")
5786
os.Setenv("PUBLISHER_KAFKA_CLIENT_BOOTSTRAP_SERVERS", "localhost:9092")
@@ -67,6 +96,8 @@ func TestKafkaConfig_ToKafkaConfigMap(t *testing.T) {
6796
os.Setenv("PUBLISHER_KAFKA_CLIENT_ACKS", "1")
6897
os.Setenv("PUBLISHER_KAFKA_CLIENT_QUEUE_BUFFERING_MAX_MESSAGES", "10000")
6998
os.Setenv("SOMETHING_PUBLISHER_KAFKA_CLIENT_SOMETHING", "anything")
99+
os.Setenv("PUBLISHER_KAFKA_HEALTHCHECK_TOPIC_NAME", "test-log")
100+
os.Setenv("PUBLISHER_KAFKA_HEALTHCHECK_TIMEOUT_MS", "5000")
70101
publisherKafkaConfigLoader()
71102
kafkaConfig := PublisherKafka.ToKafkaConfigMap()
72103
bootstrapServer, _ := kafkaConfig.Get("bootstrap.servers", "")
@@ -76,6 +107,8 @@ func TestKafkaConfig_ToKafkaConfigMap(t *testing.T) {
76107
assert.Equal(t, "", topic)
77108
assert.NotEqual(t, something, "anything")
78109
assert.Equal(t, 4, len(*kafkaConfig))
110+
assert.Equal(t, "test-log", PublisherKafka.HealthCheckConfig.TopicName)
111+
assert.Equal(t, 5000, PublisherKafka.HealthCheckConfig.TimeOut)
79112
}
80113

81114
func TestWorkerConfig(t *testing.T) {

config/publisher.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@ var PublisherKafka publisherKafka
1414
var dynamicKafkaClientConfigPrefix = "PUBLISHER_KAFKA_CLIENT_"
1515

1616
type publisherKafka struct {
17-
FlushInterval int
17+
FlushInterval int
18+
HealthCheckConfig healthcheck
19+
}
20+
21+
type healthcheck struct {
22+
TopicName string
23+
TimeOut int
1824
}
1925

2026
func (k publisherKafka) ToKafkaConfigMap() *confluent.ConfigMap {
@@ -43,9 +49,15 @@ func dynamicKafkaClientConfigLoad() []byte {
4349
func publisherKafkaConfigLoader() {
4450
viper.SetDefault("PUBLISHER_KAFKA_CLIENT_QUEUE_BUFFERING_MAX_MESSAGES", "100000")
4551
viper.SetDefault("PUBLISHER_KAFKA_FLUSH_INTERVAL_MS", "1000")
52+
viper.SetDefault("PUBLISHER_KAFKA_HEALTHCHECK_TOPIC_NAME", "clickstream-test-log")
53+
viper.SetDefault("PUBLISHER_KAFKA_HEALTHCHECK_TIMEOUT_MS", "5000")
4654
viper.MergeConfig(bytes.NewBuffer(dynamicKafkaClientConfigLoad()))
4755

4856
PublisherKafka = publisherKafka{
4957
FlushInterval: util.MustGetInt("PUBLISHER_KAFKA_FLUSH_INTERVAL_MS"),
58+
HealthCheckConfig: healthcheck{
59+
TopicName: util.MustGetString("PUBLISHER_KAFKA_HEALTHCHECK_TOPIC_NAME"),
60+
TimeOut: util.MustGetInt("PUBLISHER_KAFKA_HEALTHCHECK_TIMEOUT_MS"),
61+
},
5062
}
5163
}

health/registry_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package health
2+
3+
import (
4+
"errors"
5+
"reflect"
6+
"testing"
7+
)
8+
9+
func TestRegister(t *testing.T) {
10+
resetCheckers()
11+
12+
mockChecker := func() error { return nil }
13+
14+
Register("db", mockChecker)
15+
16+
mu.RLock()
17+
defer mu.RUnlock()
18+
19+
if len(checkers) != 1 {
20+
t.Fatalf("expected 1 checker, got %d", len(checkers))
21+
}
22+
23+
if _, ok := checkers["db"]; !ok {
24+
t.Errorf("expected checker 'db' to be registered")
25+
}
26+
}
27+
28+
func TestCheckAll(t *testing.T) {
29+
tests := []struct {
30+
name string
31+
register map[string]Checker
32+
expected map[string]string
33+
}{
34+
{
35+
name: "single healthy service on register map",
36+
register: map[string]Checker{
37+
"serviceA": func() error { return nil },
38+
},
39+
expected: map[string]string{
40+
"serviceA": "healthy",
41+
},
42+
},
43+
{
44+
name: "single unhealthy service on register map",
45+
register: map[string]Checker{
46+
"serviceB": func() error { return errors.New("timeout") },
47+
},
48+
expected: map[string]string{
49+
"serviceB": "unhealthy: timeout",
50+
},
51+
},
52+
{
53+
name: "multiple services on register map",
54+
register: map[string]Checker{
55+
"ok": func() error { return nil },
56+
"fail": func() error { return errors.New("db down") },
57+
},
58+
expected: map[string]string{
59+
"ok": "healthy",
60+
"fail": "unhealthy: db down",
61+
},
62+
},
63+
}
64+
65+
for _, tt := range tests {
66+
t.Run(tt.name, func(t *testing.T) {
67+
//rest the register map for every test scenario
68+
resetCheckers()
69+
70+
for name, fn := range tt.register {
71+
Register(name, fn)
72+
}
73+
74+
actual := CheckAll()
75+
if !reflect.DeepEqual(actual, tt.expected) {
76+
t.Errorf("CheckAll() = %v, want %v", actual, tt.expected)
77+
}
78+
})
79+
}
80+
}
81+
82+
func resetCheckers() {
83+
mu.Lock()
84+
defer mu.Unlock()
85+
checkers = make(map[string]Checker)
86+
}

publisher/kafka.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ func (b BulkError) Error() string {
220220
}
221221

222222
func (pr *Kafka) HealthCheck() error {
223-
topic := "clickstream-page-log"
224-
_, err := pr.kp.GetMetadata(&topic, false, 5000)
223+
topic := config.PublisherKafka.HealthCheckConfig.TopicName
224+
_, err := pr.kp.GetMetadata(&topic, false, config.PublisherKafka.HealthCheckConfig.TimeOut)
225225
return err
226226
}

publisher/mockclient.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,8 @@ func (p *mockClient) Flush(config int) int {
2626
func (p *mockClient) Events() chan kafka.Event {
2727
return make(chan kafka.Event)
2828
}
29+
30+
func (p *mockClient) GetMetadata(topic *string, allTopics bool, timeoutMs int) (*kafka.Metadata, error) {
31+
args := p.Called(topic, allTopics, timeoutMs)
32+
return &kafka.Metadata{}, args.Error(0)
33+
}

services/mqtt/client/cred_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package client
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/gojek/courier-go"
8+
"github.com/goto/raccoon/config"
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestNewCredentialFetcher(t *testing.T) {
13+
tests := []struct {
14+
name string
15+
username string
16+
password string
17+
expectError bool
18+
}{
19+
{
20+
name: "success - valid username and password",
21+
username: "testUser",
22+
password: "testPass",
23+
expectError: false,
24+
},
25+
{
26+
name: "error - missing username",
27+
username: "",
28+
password: "somePass",
29+
expectError: true,
30+
},
31+
{
32+
name: "error - missing password",
33+
username: "someUser",
34+
password: "",
35+
expectError: true,
36+
},
37+
}
38+
39+
for _, tt := range tests {
40+
t.Run(tt.name, func(t *testing.T) {
41+
// mock config
42+
config.ServerMQTT.AuthConfig.Username = tt.username
43+
config.ServerMQTT.AuthConfig.Password = tt.password
44+
45+
fetcher, err := newCredentialFetcher()
46+
47+
if tt.expectError {
48+
assert.Nil(t, fetcher)
49+
assert.Error(t, err)
50+
} else {
51+
assert.NoError(t, err)
52+
assert.NotNil(t, fetcher)
53+
assert.Equal(t, tt.username, fetcher.username)
54+
assert.Equal(t, tt.password, fetcher.password)
55+
}
56+
})
57+
}
58+
}
59+
60+
func TestCredentials(t *testing.T) {
61+
fetcher := &credentialFetcher{
62+
username: "myUser",
63+
password: "myPass",
64+
}
65+
66+
cred, err := fetcher.Credentials(context.Background())
67+
assert.NoError(t, err)
68+
assert.NotNil(t, cred)
69+
assert.Equal(t, &courier.Credential{
70+
Username: "myUser",
71+
Password: "myPass",
72+
}, cred)
73+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package client
2+
3+
import (
4+
"context"
5+
"errors"
6+
"testing"
7+
8+
"github.com/goto/raccoon/logger"
9+
"github.com/sirupsen/logrus"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
// testHook captures log entries emitted by logrus.
14+
type testHook struct {
15+
entries []logrus.Entry
16+
}
17+
18+
func (h *testHook) Levels() []logrus.Level {
19+
return logrus.AllLevels
20+
}
21+
22+
func (h *testHook) Fire(e *logrus.Entry) error {
23+
h.entries = append(h.entries, *e)
24+
return nil
25+
}
26+
27+
func TestLogger_InfoAndError(t *testing.T) {
28+
// Arrange
29+
baseLogger := logrus.New()
30+
hook := &testHook{}
31+
baseLogger.AddHook(hook)
32+
33+
l := Logger{log: baseLogger}
34+
ctx := context.Background()
35+
36+
tests := []struct {
37+
name string
38+
callFunc func()
39+
expected logrus.Level
40+
expectedMsg string
41+
}{
42+
{
43+
name: "Info logs message with attrs",
44+
callFunc: func() {
45+
l.Info(ctx, "info message", map[string]any{"key": "value"})
46+
},
47+
expected: logrus.InfoLevel,
48+
expectedMsg: "info message",
49+
},
50+
{
51+
name: "Error logs error with attrs",
52+
callFunc: func() {
53+
l.Error(ctx, errors.New("some error"), map[string]any{"code": 500})
54+
},
55+
expected: logrus.ErrorLevel,
56+
expectedMsg: "some error",
57+
},
58+
}
59+
60+
for _, tt := range tests {
61+
t.Run(tt.name, func(t *testing.T) {
62+
hook.entries = nil // reset before each run
63+
tt.callFunc()
64+
65+
assert.NotEmpty(t, hook.entries)
66+
lastEntry := hook.entries[len(hook.entries)-1]
67+
68+
assert.Equal(t, tt.expected, lastEntry.Level)
69+
assert.Contains(t, lastEntry.Message, tt.expectedMsg)
70+
})
71+
}
72+
}
73+
74+
func TestNewLogger(t *testing.T) {
75+
l := NewLogger()
76+
assert.NotNil(t, l)
77+
assert.NotNil(t, l.log)
78+
assert.Equal(t, logger.GetLogger(), l.log)
79+
}

services/rest/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func (h *Handler) RESTAPIHandler(rw http.ResponseWriter, r *http.Request) {
9898

9999
b, err := ioutil.ReadAll(r.Body)
100100
if err != nil {
101-
logger.Errorf(fmt.Sprintf("[rest.GetRESTAPIHandler] %s error reading request body, error: %v", identifier, err))
101+
logger.Errorf("[rest.GetRESTAPIHandler] %s error reading request body, error: %v", identifier, err)
102102
metrics.Increment("batches_read_total", fmt.Sprintf("status=failed,reason=readerr,conn_group=%s", identifier.Group))
103103
rw.WriteHeader(http.StatusInternalServerError)
104104
_, err := res.SetCode(pb.Code_CODE_INTERNAL_ERROR).SetStatus(pb.Status_STATUS_ERROR).SetReason("deserialization failure").

0 commit comments

Comments
 (0)