Go, test first bir dil. Yani testler hayati derecede önemli. Bir projenin ne kadar iyi test coverage’ı olursa, o proje / kütüphane / servis o kadar sağlam çalışır anlamına gelir.
Kabaca, yazdığımız her satır kod, fonksiyon, metot, yani her şey test edilebilir şeylerdir. Eğer yazdığınız kodu test edemiyorsanız, o zaman bir sıkıntı var demektir. Bir şeyleri hatalı yapmış ya da atlamışsınızdır.
Nelerin testlerini yapmamız iyi olur?
- Ek paket yaptık mı? (
kverror
) - Storage katmanı (tüm metotları)
- Service katmanı (tüm metotları)
- HTTP Handler katmanı (tüm metotları)
İyi bir test coverage yüzdesi ~ %80
civarındadır. Yani yazılan kodun en az
%80
’i cover edilmişse bu iş OK’dir. (%80 - %20 yaklaşımı) Coverage ne
kadar yüksek olursa kendimizi o kadar güvende hissederiz.
Şimdi testlere başlayalım; önce kverror
:
$ touch src/internal/kverror/kverror_test.go
src/internal/kverror/kverror_test.go
package kverror_test
import (
"errors"
"testing"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror"
)
func TestError(t *testing.T) {
err := kverror.New("some error", true)
var kvErr *kverror.Error
if !errors.As(err, &kvErr) {
t.Errorf("error does not match the target type, want: %T, got: %v", kvErr, err)
}
shouldEqual := "some error"
if kvErr.Message != shouldEqual {
t.Errorf("error message does not match, want: %s, got: %s", shouldEqual, kvErr.Message)
}
shouldLoggable := true
if kvErr.Loggable != shouldLoggable {
t.Errorf("error should be loggable, want: %t, got: %t", shouldLoggable, kvErr.Loggable)
}
}
func TestWrap(t *testing.T) {
err := kverror.New("some error", false)
wrappedErr := err.Wrap(errors.New("inner")) // nolint
var kvErr *kverror.Error
if !errors.As(wrappedErr, &kvErr) {
t.Errorf("error does not match the target type, want: %T, got: %v", kvErr, err)
}
if kvErr.Err == nil {
t.Errorf("wrapped error can not be nil, want: %v, got: nil", kvErr.Err)
}
shouldEqual := "inner, some error"
if err.Error() != shouldEqual {
t.Errorf("wrapped error does not match, want: %s, got: %s", shouldEqual, err.Error())
}
}
func TestUnwrap(t *testing.T) {
err := kverror.New("some error", false)
wrappedErr := err.Wrap(errors.New("inner")) // nolint
var kvErr *kverror.Error
if !errors.As(wrappedErr, &kvErr) {
t.Errorf("error does not match the target type, want: %T, got: %v", kvErr, err)
}
shouldEqual := "inner"
unwrappedErr := kvErr.Unwrap()
if unwrappedErr.Error() != shouldEqual {
t.Errorf("unwrapped error does not match, want: %s, got: %s", shouldEqual, unwrappedErr.Error())
}
}
func TestAddDataDestroyData(t *testing.T) {
err := kverror.New("some error", false).AddData("hello")
var kvErr *kverror.Error
if !errors.As(err, &kvErr) {
t.Errorf("error does not match the target type, want: %T, got: %v", kvErr, err)
}
if kvErr.Data == nil {
t.Errorf("data should not be nil, want: %v, got: nil", kvErr.Data)
}
shouldEqual := "hello"
data, ok := kvErr.Data.(string)
if !ok {
t.Error("data should be assertable to string")
}
if data != shouldEqual {
t.Errorf("data does not match, want: %s, got: %s", shouldEqual, data)
}
shouldEqual = "some error"
if err.Error() != shouldEqual {
t.Errorf("error does not match, want: %s, got: %s", shouldEqual, err.Error())
}
err = err.DestoryData()
if !errors.As(err, &kvErr) {
t.Errorf("error does not match the target type, want: %T, got: %v", kvErr, err)
}
if kvErr.Data != nil {
t.Errorf("data should be nil, want: nil, got: %v", kvErr.Data)
}
}
şimdi testi çalıştıralım; önce paketleri bulalım;
$ go list ./... | grep 'kverror'
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror
$ go test -race -v github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror
$ go test -cover -race -v github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror
:
:
coverage: 100.0% of statements
sonra;
$ git add src/internal/kverror/kverror_test.go
$ git commit -m 'add kverror test'
$ touch src/internal/storage/memory/kvstorage/{delete,get,list,set,update}_test.go
src/internal/storage/memory/kvstorage/delete_test.go
package kvstorage_test
import (
"testing"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage"
)
func TestDeleteEmpty(t *testing.T) {
storage := kvstorage.New()
if err := storage.Delete("key"); err == nil {
t.Error("error not occurred")
}
}
func TestDelete(t *testing.T) {
key := "key"
memoryStorage := map[string]any{
key: "value",
}
storage := kvstorage.New(
kvstorage.WithMemoryDB(memoryStorage),
)
if err := storage.Delete(key); err != nil {
t.Error("error occurred")
}
}
src/internal/storage/memory/kvstorage/get_test.go
package kvstorage_test
import (
"testing"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage"
)
func TestGetEmpty(t *testing.T) {
storage := kvstorage.New()
if _, err := storage.Get("key"); err == nil {
t.Error("error not occurred")
}
}
func TestGet(t *testing.T) {
key := "key"
memoryStorage := map[string]any{
key: "value",
}
storage := kvstorage.New(
kvstorage.WithMemoryDB(memoryStorage),
)
value, err := storage.Get(key)
if err != nil {
t.Error("error occurred")
}
if value != "value" {
t.Error("value not equal")
}
}
src/internal/storage/memory/kvstorage/list_test.go
package kvstorage_test
import (
"reflect"
"testing"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage"
)
func TestList(t *testing.T) {
key := "key"
memoryStorage := kvstorage.MemoryDB(map[string]any{
key: "value",
})
storage := kvstorage.New(
kvstorage.WithMemoryDB(memoryStorage),
)
value := storage.List()
if !reflect.DeepEqual(value, memoryStorage) {
t.Error("value not equal")
}
}
src/internal/storage/memory/kvstorage/set_test.go
package kvstorage_test
import (
"testing"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage"
)
func TestSet(t *testing.T) {
key := "key"
memoryStorage := kvstorage.MemoryDB(map[string]any{})
storage := kvstorage.New(
kvstorage.WithMemoryDB(memoryStorage),
)
val, err := storage.Set(key, "value")
if err != nil {
t.Errorf("want: value, got: %v, err: %v", val, err)
}
if _, err := storage.Set(key, "xxx"); err == nil {
t.Error("error not occurred")
}
}
src/internal/storage/memory/kvstorage/update_test.go
package kvstorage_test
import (
"testing"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage"
)
func TestUpdateEmpty(t *testing.T) {
storage := kvstorage.New()
if _, err := storage.Update("key", "value"); err == nil {
t.Error("error not occurred")
}
}
func TestUpdate(t *testing.T) {
key := "key"
memoryStorage := map[string]any{
key: "value",
}
storage := kvstorage.New(
kvstorage.WithMemoryDB(memoryStorage),
)
value, err := storage.Update(key, "value2")
if err != nil {
t.Error("error occurred")
}
if value != "value2" {
t.Error("value not equal")
}
}
Durum ne?
$ tree .
.
├── cmd
│ └── server
│ └── main.go
├── go.mod
└── src
├── apiserver
│ ├── apiserver.go
│ └── middlewares.go
├── internal
│ ├── kverror
│ │ ├── kverror.go
│ │ └── kverror_test.go
│ ├── service
│ │ └── kvstoreservice
│ │ ├── base.go
│ │ ├── delete.go
│ │ ├── get.go
│ │ ├── list.go
│ │ ├── requests.go
│ │ ├── responses.go
│ │ ├── set.go
│ │ └── update.go
│ ├── storage
│ │ └── memory
│ │ └── kvstorage
│ │ ├── base.go
│ │ ├── delete.go
│ │ ├── delete_test.go
│ │ ├── get.go
│ │ ├── get_test.go
│ │ ├── list.go
│ │ ├── list_test.go
│ │ ├── set.go
│ │ ├── set_test.go
│ │ ├── update.go
│ │ └── update_test.go
│ └── transport
│ └── http
│ ├── basehttphandler
│ │ └── basehttphandler.go
│ └── kvstorehandler
│ └── base.go
└── releaseinfo
└── releaseinfo.go
şimdi testi çalıştıralım; önce paketleri bulalım;
$ go list ./... | grep 'kvstorage'
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage
$ go test -race -v github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage
$ go test -cover -race -v github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage
:
:
coverage: 100.0% of statements
sonra;
$ git add .
$ git commit -m 'add storage tests'
$ touch src/internal/service/kvstoreservice/{base,delete,get,list,set,update}_test.go
$ tree .
.
├── cmd
│ └── server
│ └── main.go
├── go.mod
└── src
├── apiserver
│ ├── apiserver.go
│ └── middlewares.go
├── internal
│ ├── kverror
│ │ ├── kverror.go
│ │ └── kverror_test.go
│ ├── service
│ │ └── kvstoreservice
│ │ ├── base.go
│ │ ├── base_test.go
│ │ ├── delete.go
│ │ ├── delete_test.go
│ │ ├── get.go
│ │ ├── get_test.go
│ │ ├── list.go
│ │ ├── list_test.go
│ │ ├── requests.go
│ │ ├── responses.go
│ │ ├── set.go
│ │ ├── set_test.go
│ │ ├── update.go
│ │ └── update_test.go
│ ├── storage
│ │ └── memory
│ │ └── kvstorage
│ │ ├── base.go
│ │ ├── delete.go
│ │ ├── delete_test.go
│ │ ├── get.go
│ │ ├── get_test.go
│ │ ├── list.go
│ │ ├── list_test.go
│ │ ├── set.go
│ │ ├── set_test.go
│ │ ├── update.go
│ │ └── update_test.go
│ └── transport
│ └── http
│ ├── basehttphandler
│ │ └── basehttphandler.go
│ └── kvstorehandler
│ ├── base.go
│ ├── delete.go
│ ├── get.go
│ ├── list.go
│ ├── set.go
│ └── update.go
└── releaseinfo
└── releaseinfo.go
src/internal/service/kvstoreservice/base_test.go
package kvstoreservice_test
import (
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage"
)
var _ kvstorage.Storer = (*mockStorage)(nil) // compile time proof
type mockStorage struct {
deleteErr error
getErr error
updateErr error
setErr error
memoryDB kvstorage.MemoryDB
}
func (m *mockStorage) Delete(k string) error {
if m.deleteErr == nil {
delete(m.memoryDB, k)
return nil
}
return m.deleteErr
}
func (m *mockStorage) Get(k string) (any, error) {
if m.getErr == nil {
v, ok := m.memoryDB[k]
if !ok {
return nil, m.getErr
}
return v, nil
}
return nil, m.getErr
}
func (m *mockStorage) List() kvstorage.MemoryDB {
return m.memoryDB
}
func (m *mockStorage) Set(k string, v any) (any, error) {
if m.setErr == nil {
if _, ok := m.memoryDB[k]; ok {
return nil, m.setErr
}
m.memoryDB[k] = v
return v, nil
}
return nil, m.setErr
}
func (m *mockStorage) Update(k string, v any) (any, error) {
if m.updateErr == nil {
if _, ok := m.memoryDB[k]; !ok {
return nil, m.updateErr
}
m.memoryDB[k] = v
return v, nil
}
return nil, m.updateErr
}
src/internal/service/kvstoreservice/delete_test.go
package kvstoreservice_test
import (
"context"
"errors"
"testing"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice"
)
func TestDeleteWithCancel(t *testing.T) {
mockStorage := &mockStorage{}
kvsStoreService := kvstoreservice.New(
kvstoreservice.WithStorage(mockStorage),
)
ctx, cancel := context.WithCancel(context.Background())
cancel()
if err := kvsStoreService.Delete(ctx, "key"); !errors.Is(err, ctx.Err()) {
t.Error("error not occurred")
}
}
func TestDeleteWithStorageError(t *testing.T) {
mockStorage := &mockStorage{
deleteErr: kverror.ErrKeyNotFound,
}
kvsStoreService := kvstoreservice.New(
kvstoreservice.WithStorage(mockStorage),
)
err := kvsStoreService.Delete(context.Background(), "key")
if err == nil {
t.Error("error not occurred")
}
var kvErr *kverror.Error
if !errors.As(err, &kvErr) {
t.Error("error must be kverror.ErrKeyNotFound")
}
}
func TestDelete(t *testing.T) {
mockStorage := &mockStorage{
memoryDB: map[string]any{
"key": "value",
},
}
kvsStoreService := kvstoreservice.New(
kvstoreservice.WithStorage(mockStorage),
)
if err := kvsStoreService.Delete(context.Background(), "key"); err != nil {
t.Error("error occurred")
}
_, ok := mockStorage.memoryDB["key"]
if ok {
t.Error("delete is not working!")
}
}
src/internal/service/kvstoreservice/get_test.go
package kvstoreservice_test
import (
"context"
"errors"
"testing"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice"
)
func TestGetWithCancel(t *testing.T) {
mockStorage := &mockStorage{}
kvsStoreService := kvstoreservice.New(kvstoreservice.WithStorage(mockStorage))
ctx, cancel := context.WithCancel(context.Background())
cancel()
if _, err := kvsStoreService.Get(ctx, "key"); !errors.Is(err, ctx.Err()) {
t.Error("error not occurred")
}
}
func TestGetWithStorageError(t *testing.T) {
mockStorage := &mockStorage{
getErr: kverror.ErrKeyNotFound, // get raises ErrKeyNotFound
}
kvsStoreService := kvstoreservice.New(kvstoreservice.WithStorage(mockStorage))
res, err := kvsStoreService.Get(context.Background(), "key")
if err == nil {
t.Error("error not occurred")
}
if res != nil {
t.Errorf("response must be nil!")
}
var kvErr *kverror.Error
if !errors.As(err, &kvErr) {
t.Error("error must be kverror.ErrKeyNotFound")
}
}
func TestGet(t *testing.T) {
mockStorage := &mockStorage{
memoryDB: map[string]any{
"key": "value",
},
}
kvsStoreService := kvstoreservice.New(kvstoreservice.WithStorage(mockStorage))
res, err := kvsStoreService.Get(context.Background(), "key")
if err != nil {
t.Error("error occurred")
}
if res == nil {
t.Error("result should not be nil")
}
if res != nil {
val := *res
if val.Value != "value" {
t.Errorf("want: value, got: %s", val.Value)
}
}
}
src/internal/service/kvstoreservice/list_test.go
package kvstoreservice_test
import (
"context"
"errors"
"testing"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice"
)
func TestListWithCancel(t *testing.T) {
mockStorage := &mockStorage{}
kvsStoreService := kvstoreservice.New(kvstoreservice.WithStorage(mockStorage))
ctx, cancel := context.WithCancel(context.Background())
cancel()
if _, err := kvsStoreService.List(ctx); !errors.Is(err, ctx.Err()) {
t.Error("error not occurred")
}
}
func TestList(t *testing.T) {
mockStorage := &mockStorage{
memoryDB: map[string]any{
"key": "value",
},
}
kvsStoreService := kvstoreservice.New(kvstoreservice.WithStorage(mockStorage))
if _, err := kvsStoreService.List(context.Background()); err != nil {
t.Error("error occurred")
}
}
src/internal/service/kvstoreservice/set_test.go
package kvstoreservice_test
import (
"context"
"errors"
"testing"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice"
)
func TestSetWithCancel(t *testing.T) {
mockStorage := &mockStorage{}
kvsStoreService := kvstoreservice.New(
kvstoreservice.WithStorage(mockStorage),
)
ctx, cancel := context.WithCancel(context.Background())
cancel()
if _, err := kvsStoreService.Set(ctx, nil); !errors.Is(err, ctx.Err()) {
t.Error("error not occurred")
}
}
func TestSetWithStorageError(t *testing.T) {
mockStorage := &mockStorage{
setErr: kverror.ErrKeyExists,
}
kvsStoreService := kvstoreservice.New(
kvstoreservice.WithStorage(mockStorage),
)
serviceRequest := kvstoreservice.SetRequest{
Key: "vigo",
Value: "lego",
}
res, err := kvsStoreService.Set(context.Background(), &serviceRequest)
if res != nil {
t.Errorf("response must be nil!")
}
var kvErr *kverror.Error
if !errors.As(err, &kvErr) {
t.Error("error must be kverror.ErrKeyExists")
}
}
func TestSet(t *testing.T) {
mockStorage := &mockStorage{
memoryDB: map[string]any{},
}
kvsStoreService := kvstoreservice.New(
kvstoreservice.WithStorage(mockStorage),
)
setRequest := kvstoreservice.SetRequest{
Key: "username",
Value: "vigo",
}
res, err := kvsStoreService.Set(context.Background(), &setRequest)
if err != nil {
t.Errorf("error occurred, err: %v", err)
}
if res == nil {
t.Error("result should not be nil")
}
if res != nil {
val := *res
if val.Value != "vigo" {
t.Errorf("want: vigo, got: %s", val.Value)
}
}
}
src/internal/service/kvstoreservice/update_test.go
package kvstoreservice_test
import (
"context"
"errors"
"testing"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice"
)
func TestUpdateWithCancel(t *testing.T) {
mockStorage := &mockStorage{}
kvsStoreService := kvstoreservice.New(
kvstoreservice.WithStorage(mockStorage),
)
ctx, cancel := context.WithCancel(context.Background())
cancel()
if _, err := kvsStoreService.Update(ctx, nil); !errors.Is(err, ctx.Err()) {
t.Error("error not occurred")
}
}
func TestUpdateWithStorageError(t *testing.T) {
mockStorage := &mockStorage{
updateErr: kverror.ErrKeyNotFound, // raises kverror.ErrKeyNotFound
}
kvsStoreService := kvstoreservice.New(
kvstoreservice.WithStorage(mockStorage),
)
updateRequest := kvstoreservice.UpdateRequest{
Key: "key",
Value: "value",
}
res, err := kvsStoreService.Update(context.Background(), &updateRequest)
if res != nil {
t.Errorf("response must be nil!")
}
var kvErr *kverror.Error
if !errors.As(err, &kvErr) {
t.Error("error must be kverror.ErrKeyNotFound")
}
}
func TestUpdate(t *testing.T) {
mockStorage := &mockStorage{
memoryDB: map[string]any{
"key": "value",
},
}
kvsStoreService := kvstoreservice.New(
kvstoreservice.WithStorage(mockStorage),
)
updateRequest := kvstoreservice.UpdateRequest{
Key: "key",
Value: "vigo",
}
res, err := kvsStoreService.Update(context.Background(), &updateRequest)
if err != nil {
t.Errorf("error occurred, err: %v", err)
}
if res == nil {
t.Error("result should not be nil")
}
if res != nil {
val := *res
if val.Value != "vigo" {
t.Errorf("want: vigo, got: %s", val.Value)
}
}
}
şimdi testi çalıştıralım; önce paketleri bulalım;
$ go list ./... | grep 'kvstoreservice'
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice
$ go test -race -v github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice
$ go test -cover -race -v github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice
:
:
coverage: 100.0% of statements
sonra;
$ git add .
$ git commit -m 'add service tests'
$ touch src/internal/transport/http/kvstorehandler/{base,delete,get,list,set,update}_test.go
$ tree .
.
├── cmd
│ └── server
│ └── main.go
├── go.mod
└── src
├── apiserver
│ ├── apiserver.go
│ └── middlewares.go
├── internal
│ ├── kverror
│ │ ├── kverror.go
│ │ └── kverror_test.go
│ ├── service
│ │ └── kvstoreservice
│ │ ├── base.go
│ │ ├── base_test.go
│ │ ├── delete.go
│ │ ├── delete_test.go
│ │ ├── get.go
│ │ ├── get_test.go
│ │ ├── list.go
│ │ ├── list_test.go
│ │ ├── requests.go
│ │ ├── responses.go
│ │ ├── set.go
│ │ ├── set_test.go
│ │ ├── update.go
│ │ └── update_test.go
│ ├── storage
│ │ └── memory
│ │ └── kvstorage
│ │ ├── base.go
│ │ ├── delete.go
│ │ ├── delete_test.go
│ │ ├── get.go
│ │ ├── get_test.go
│ │ ├── list.go
│ │ ├── list_test.go
│ │ ├── set.go
│ │ ├── set_test.go
│ │ ├── update.go
│ │ └── update_test.go
│ └── transport
│ └── http
│ ├── basehttphandler
│ │ └── basehttphandler.go
│ └── kvstorehandler
│ ├── base.go
│ ├── base_test.go
│ ├── delete.go
│ ├── delete_test.go
│ ├── get.go
│ ├── get_test.go
│ ├── list.go
│ ├── list_test.go
│ ├── set.go
│ ├── set_test.go
│ ├── update.go
│ └── update_test.go
└── releaseinfo
└── releaseinfo.go
src/internal/transport/http/kvstorehandler/base_test.go
package kvstorehandler_test
import (
"context"
"log/slog"
"os"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice"
)
var logger = slog.New(slog.NewJSONHandler(os.Stdout, nil))
type mockService struct {
deleteErr error
getErr error
getResponse *kvstoreservice.ItemResponse
listErr error
listResponse *kvstoreservice.ListResponse
setErr error
setResponse *kvstoreservice.ItemResponse
updateErr error
updateResponse *kvstoreservice.ItemResponse
}
func (m *mockService) Delete(_ context.Context, _ string) error {
return m.deleteErr
}
func (m *mockService) Get(_ context.Context, _ string) (*kvstoreservice.ItemResponse, error) {
return m.getResponse, m.getErr
}
func (m *mockService) List(_ context.Context) (*kvstoreservice.ListResponse, error) {
return m.listResponse, m.listErr
}
func (m *mockService) Set(_ context.Context, _ *kvstoreservice.SetRequest) (*kvstoreservice.ItemResponse, error) {
return m.setResponse, m.setErr
}
func (m *mockService) Update(_ context.Context, _ *kvstoreservice.UpdateRequest) (*kvstoreservice.ItemResponse, error) {
return m.updateResponse, m.updateErr
}
src/internal/transport/http/kvstorehandler/delete_test.go
package kvstorehandler_test
import (
"context"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler"
)
func TestDeleteInvalidMethod(t *testing.T) {
handler := kvstorehandler.New()
req := httptest.NewRequest(http.MethodGet, "/key", nil)
w := httptest.NewRecorder()
handler.Delete(w, req)
if w.Code != http.StatusMethodNotAllowed {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusMethodNotAllowed, w.Code)
}
shouldContain := "method GET not allowed"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestDeleteQueryParamRequired(t *testing.T) {
handler := kvstorehandler.New()
req := httptest.NewRequest(http.MethodDelete, "/", nil)
w := httptest.NewRecorder()
handler.Delete(w, req)
if w.Code != http.StatusNotFound {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusNotFound, w.Code)
}
shouldContain := "key query param required"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestDeleteQueryParamKeyNotFound(t *testing.T) {
handler := kvstorehandler.New()
req := httptest.NewRequest(http.MethodDelete, "/?foo=test", nil)
w := httptest.NewRecorder()
handler.Delete(w, req)
if w.Code != http.StatusNotFound {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusNotFound, w.Code)
}
shouldContain := "key not present"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestDeleteTimeout(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithContextTimeout(time.Second*-1),
kvstorehandler.WithService(&mockService{
deleteErr: context.DeadlineExceeded,
}),
)
req := httptest.NewRequest(http.MethodDelete, "/?key=test", nil)
w := httptest.NewRecorder()
handler.Delete(w, req)
if w.Code != http.StatusGatewayTimeout {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusGatewayTimeout, w.Code)
}
shouldContain := "context deadline exceeded"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestDeleteErrUnknown(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{
deleteErr: kverror.ErrUnknown,
}),
kvstorehandler.WithLogger(logger),
)
req := httptest.NewRequest(http.MethodDelete, "/?key=test", nil)
w := httptest.NewRecorder()
handler.Delete(w, req)
if w.Code != http.StatusInternalServerError {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusInternalServerError, w.Code)
}
shouldContain := "unknown error"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestDeleteErrKeyNotFound(t *testing.T) {
_ = kverror.ErrKeyNotFound.AddData("key=test") // ignore error.
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{
deleteErr: kverror.ErrKeyNotFound,
}),
kvstorehandler.WithLogger(logger),
)
req := httptest.NewRequest(http.MethodDelete, "/?key=test", nil)
w := httptest.NewRecorder()
handler.Delete(w, req)
if w.Code != http.StatusNotFound {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusNotFound, w.Code)
}
if !strings.Contains(w.Body.String(), "key not found") {
t.Error("body not equal")
}
shouldContain := "key=test"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
_ = kverror.ErrKeyNotFound.DestoryData() // ignore error.
}
func TestDeleteSuccess(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{}),
kvstorehandler.WithLogger(logger),
)
req := httptest.NewRequest(http.MethodDelete, "/?key=test", nil)
w := httptest.NewRecorder()
handler.Delete(w, req)
if w.Code != http.StatusNoContent {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusNoContent, w.Code)
}
if w.Body.Len() != 0 {
t.Errorf("wrong body size, want: 0, got: %d", w.Body.Len())
}
}
src/internal/transport/http/kvstorehandler/get_test.go
package kvstorehandler_test
import (
"context"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler"
)
func TestGetInvalidMethod(t *testing.T) {
handler := kvstorehandler.New()
req := httptest.NewRequest(http.MethodDelete, "/key", nil)
w := httptest.NewRecorder()
handler.Get(w, req)
if w.Code != http.StatusMethodNotAllowed {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusMethodNotAllowed, w.Code)
}
shouldContain := "method DELETE not allowed"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestGetQueryParamRequired(t *testing.T) {
handler := kvstorehandler.New()
req := httptest.NewRequest(http.MethodGet, "/", nil)
w := httptest.NewRecorder()
handler.Get(w, req)
if w.Code != http.StatusNotFound {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusNotFound, w.Code)
}
shouldContain := "key query param required"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestGetQueryParamKeyNotFound(t *testing.T) {
handler := kvstorehandler.New()
req := httptest.NewRequest(http.MethodGet, "/?foo=test", nil)
w := httptest.NewRecorder()
handler.Get(w, req)
if w.Code != http.StatusNotFound {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusNotFound, w.Code)
}
shouldContain := "key not present"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestGetTimeout(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithContextTimeout(time.Second*-1),
kvstorehandler.WithService(&mockService{
getErr: context.DeadlineExceeded,
}),
)
req := httptest.NewRequest(http.MethodGet, "/?key=test", nil)
w := httptest.NewRecorder()
handler.Get(w, req)
if w.Code != http.StatusGatewayTimeout {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusGatewayTimeout, w.Code)
}
shouldContain := "context deadline exceeded"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestGetErrUnknown(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{
getErr: kverror.ErrUnknown,
}),
kvstorehandler.WithLogger(logger),
)
req := httptest.NewRequest(http.MethodGet, "/?key=test", nil)
w := httptest.NewRecorder()
handler.Get(w, req)
if w.Code != http.StatusInternalServerError {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusInternalServerError, w.Code)
}
shouldContain := "unknown error"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestGetErrKeyNotFound(t *testing.T) {
_ = kverror.ErrKeyNotFound.AddData("key=test") // ignore error.
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{
getErr: kverror.ErrKeyNotFound,
}),
kvstorehandler.WithLogger(logger),
)
req := httptest.NewRequest(http.MethodGet, "/?key=test", nil)
w := httptest.NewRecorder()
handler.Get(w, req)
if w.Code != http.StatusNotFound {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusNotFound, w.Code)
}
shouldContain := "key not found"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
shouldContain = "key=test"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
_ = kverror.ErrKeyNotFound.DestoryData() // ignore error.
}
func TestGetSuccess(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{}),
kvstorehandler.WithLogger(logger),
kvstorehandler.WithService(&mockService{
getResponse: &kvstoreservice.ItemResponse{
Key: "test",
Value: "test",
},
}),
)
req := httptest.NewRequest(http.MethodGet, "/?key=test", nil)
w := httptest.NewRecorder()
handler.Get(w, req)
if w.Code != http.StatusOK {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusOK, w.Code)
}
shouldEqual := `{"key":"test","value":"test"}`
if w.Body.String() != shouldEqual {
t.Errorf("wrong body message, want: %s, got: %s", shouldEqual, w.Body.String())
}
}
src/internal/transport/http/kvstorehandler/list_test.go
package kvstorehandler_test
import (
"context"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler"
)
func TestListInvalidMethod(t *testing.T) {
handler := kvstorehandler.New()
req := httptest.NewRequest(http.MethodDelete, "/key", nil)
w := httptest.NewRecorder()
handler.List(w, req)
if w.Code != http.StatusMethodNotAllowed {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusMethodNotAllowed, w.Code)
}
shouldContain := "method DELETE not allowed"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestListTimeout(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithContextTimeout(time.Second*-1),
kvstorehandler.WithService(&mockService{
listErr: context.DeadlineExceeded,
}),
)
req := httptest.NewRequest(http.MethodGet, "/", nil)
w := httptest.NewRecorder()
handler.List(w, req)
if w.Code != http.StatusGatewayTimeout {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusGatewayTimeout, w.Code)
}
shouldContain := "context deadline exceeded"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestListErrUnknown(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{
listErr: kverror.ErrUnknown.AddData("fake error"),
}),
kvstorehandler.WithLogger(logger),
)
req := httptest.NewRequest(http.MethodGet, "/", nil)
w := httptest.NewRecorder()
handler.List(w, req)
if w.Code != http.StatusInternalServerError {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusInternalServerError, w.Code)
}
shouldContain := "unknown error"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestEmptyList(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{}),
kvstorehandler.WithLogger(logger),
kvstorehandler.WithService(&mockService{
listResponse: &kvstoreservice.ListResponse{},
}),
)
req := httptest.NewRequest(http.MethodGet, "/", nil)
w := httptest.NewRecorder()
handler.List(w, req)
if w.Code != http.StatusNotFound {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusNotFound, w.Code)
}
}
func TestListSuccess(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{}),
kvstorehandler.WithLogger(logger),
kvstorehandler.WithService(&mockService{
listResponse: &kvstoreservice.ListResponse{
{
Key: "test",
Value: "test",
},
},
}),
)
req := httptest.NewRequest(http.MethodGet, "/", nil)
w := httptest.NewRecorder()
handler.List(w, req)
if w.Code != http.StatusOK {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusOK, w.Code)
}
shouldEqual := `[{"key":"test","value":"test"}]`
if w.Body.String() != shouldEqual {
t.Errorf("wrong body message, want: %s, got: %s", shouldEqual, w.Body.String())
}
}
src/internal/transport/http/kvstorehandler/set_test.go
package kvstorehandler_test
import (
"bytes"
"context"
"errors"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler"
)
type errorReader struct{}
func (e *errorReader) Read(_ []byte) (n int, err error) {
return 0, errors.New("forced error") // nolint
}
func TestSetInvalidMethod(t *testing.T) {
handler := kvstorehandler.New()
req := httptest.NewRequest(http.MethodDelete, "/key", nil)
w := httptest.NewRecorder()
handler.Set(w, req)
if w.Code != http.StatusMethodNotAllowed {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusMethodNotAllowed, w.Code)
}
shouldContain := "method DELETE not allowed"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestSetBodyReadError(t *testing.T) {
handler := kvstorehandler.New()
req := httptest.NewRequest(http.MethodPost, "/key", &errorReader{})
w := httptest.NewRecorder()
handler.Set(w, req)
if w.Code != http.StatusBadRequest {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusBadRequest, w.Code)
}
}
func TestSetBodyUnmarshal(t *testing.T) {
handler := kvstorehandler.New()
handlerRequest := bytes.NewBufferString(`{"key": "key", "value": "123}`)
req := httptest.NewRequest(http.MethodPost, "/key", handlerRequest)
w := httptest.NewRecorder()
handler.Set(w, req)
if w.Code != http.StatusInternalServerError {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusInternalServerError, w.Code)
}
}
func TestSetEmptyBody(t *testing.T) {
handler := kvstorehandler.New()
req := httptest.NewRequest(http.MethodPost, "/", nil)
w := httptest.NewRecorder()
handler.Set(w, req)
if w.Code != http.StatusBadRequest {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusBadRequest, w.Code)
}
shouldContain := "empty body/payload"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestSetKeyIsEmpty(t *testing.T) {
handler := kvstorehandler.New()
payload := strings.NewReader("{}")
req := httptest.NewRequest(http.MethodPost, "/", payload)
w := httptest.NewRecorder()
handler.Set(w, req)
if w.Code != http.StatusBadRequest {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusBadRequest, w.Code)
}
shouldContain := "key is empty"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestSetValueIsEmpty(t *testing.T) {
handler := kvstorehandler.New()
payload := strings.NewReader(`{"key":"test"}`)
req := httptest.NewRequest(http.MethodPost, "/", payload)
w := httptest.NewRecorder()
handler.Set(w, req)
if w.Code != http.StatusBadRequest {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusBadRequest, w.Code)
}
shouldContain := "value is empty"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestSetTimeout(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithContextTimeout(time.Second*-1),
kvstorehandler.WithService(&mockService{
getErr: context.DeadlineExceeded,
}),
)
payload := strings.NewReader(`{"key":"test","value":"test"}`)
req := httptest.NewRequest(http.MethodPost, "/?key=test", payload)
w := httptest.NewRecorder()
handler.Set(w, req)
if w.Code != http.StatusGatewayTimeout {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusGatewayTimeout, w.Code)
}
shouldContain := "context deadline exceeded"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestSetErrUnknown(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{
setErr: kverror.ErrUnknown,
}),
kvstorehandler.WithLogger(logger),
)
payload := strings.NewReader(`{"key":"test","value":"test"}`)
req := httptest.NewRequest(http.MethodPost, "/", payload)
w := httptest.NewRecorder()
handler.Set(w, req)
if w.Code != http.StatusInternalServerError {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusInternalServerError, w.Code)
}
shouldContain := "unknown error"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestSetServiceUnknownError(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{
getErr: kverror.ErrUnknown.AddData("fake error"),
}),
kvstorehandler.WithLogger(logger),
)
payload := strings.NewReader(`{"key":"test","value":"test"}`)
req := httptest.NewRequest(http.MethodPost, "/", payload)
w := httptest.NewRecorder()
handler.Set(w, req)
if w.Code != http.StatusBadRequest {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusBadRequest, w.Code)
}
}
func TestSetServiceNilExistingItem(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{}),
kvstorehandler.WithLogger(logger),
kvstorehandler.WithService(&mockService{
getResponse: &kvstoreservice.ItemResponse{
Key: "test",
Value: "test",
},
}),
)
payload := strings.NewReader(`{"key":"test","value":"test"}`)
req := httptest.NewRequest(http.MethodPost, "/", payload)
w := httptest.NewRecorder()
handler.Set(w, req)
if w.Code != http.StatusConflict {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusConflict, w.Code)
}
}
func TestSetErrKeyExists(t *testing.T) {
_ = kverror.ErrKeyExists.AddData("key=test") // ignore error.
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{
setErr: kverror.ErrKeyExists,
}),
kvstorehandler.WithLogger(logger),
)
payload := strings.NewReader(`{"key":"test","value":"test"}`)
req := httptest.NewRequest(http.MethodPost, "/", payload)
w := httptest.NewRecorder()
handler.Set(w, req)
if w.Code != http.StatusConflict {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusConflict, w.Code)
}
shouldContain := "key exist"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
shouldContain = "key=test"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
_ = kverror.ErrKeyExists.DestoryData() // ignore error.
}
func TestSetSuccess(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{}),
kvstorehandler.WithLogger(logger),
kvstorehandler.WithService(&mockService{
setResponse: &kvstoreservice.ItemResponse{
Key: "test",
Value: "test",
},
}),
)
payload := strings.NewReader(`{"key":"test","value":"test"}`)
req := httptest.NewRequest(http.MethodPost, "/", payload)
w := httptest.NewRecorder()
handler.Set(w, req)
if w.Code != http.StatusCreated {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusCreated, w.Code)
}
shouldEqual := `{"key":"test","value":"test"}`
if w.Body.String() != shouldEqual {
t.Errorf("wrong body message, want: %s, got: %s", shouldEqual, w.Body.String())
}
}
src/internal/transport/http/kvstorehandler/update_test.go
package kvstorehandler_test
import (
"bytes"
"context"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice"
"github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler"
)
func TestUpdateInvalidMethod(t *testing.T) {
handler := kvstorehandler.New()
req := httptest.NewRequest(http.MethodDelete, "/key", nil)
w := httptest.NewRecorder()
handler.Update(w, req)
if w.Code != http.StatusMethodNotAllowed {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusMethodNotAllowed, w.Code)
}
shouldContain := "method DELETE not allowed"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestUpdateBodyReadError(t *testing.T) {
handler := kvstorehandler.New()
req := httptest.NewRequest(http.MethodPut, "/", &errorReader{})
w := httptest.NewRecorder()
handler.Update(w, req)
if w.Code != http.StatusBadRequest {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusBadRequest, w.Code)
}
}
func TestUpdateEmptyBody(t *testing.T) {
handler := kvstorehandler.New()
req := httptest.NewRequest(http.MethodPut, "/", nil)
w := httptest.NewRecorder()
handler.Update(w, req)
if w.Code != http.StatusBadRequest {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusBadRequest, w.Code)
}
shouldContain := "empty body/payload"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestUpdateBodyUnmarshal(t *testing.T) {
handler := kvstorehandler.New()
handlerRequest := bytes.NewBufferString(`{"key": "key", "value": "123}`)
req := httptest.NewRequest(http.MethodPut, "/", handlerRequest)
w := httptest.NewRecorder()
handler.Update(w, req)
if w.Code != http.StatusInternalServerError {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusInternalServerError, w.Code)
}
}
func TestUpdateKeyIsEmpty(t *testing.T) {
handler := kvstorehandler.New()
payload := strings.NewReader("{}")
req := httptest.NewRequest(http.MethodPut, "/", payload)
w := httptest.NewRecorder()
handler.Update(w, req)
if w.Code != http.StatusBadRequest {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusBadRequest, w.Code)
}
shouldContain := "key is empty"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestUpdateValueIsEmpty(t *testing.T) {
handler := kvstorehandler.New()
payload := strings.NewReader(`{"key":"test"}`)
req := httptest.NewRequest(http.MethodPut, "/", payload)
w := httptest.NewRecorder()
handler.Update(w, req)
if w.Code != http.StatusBadRequest {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusBadRequest, w.Code)
}
shouldContain := "value is empty"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestUpdateTimeout(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithContextTimeout(time.Second*-1),
kvstorehandler.WithService(&mockService{
updateErr: context.DeadlineExceeded,
}),
)
payload := strings.NewReader(`{"key":"test","value":"test"}`)
req := httptest.NewRequest(http.MethodPut, "/?key=test", payload)
w := httptest.NewRecorder()
handler.Update(w, req)
if w.Code != http.StatusGatewayTimeout {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusGatewayTimeout, w.Code)
}
shouldContain := "context deadline exceeded"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestUpdateErrUnknown(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{
updateErr: kverror.ErrUnknown,
}),
kvstorehandler.WithLogger(logger),
)
payload := strings.NewReader(`{"key":"test","value":"test"}`)
req := httptest.NewRequest(http.MethodPut, "/", payload)
w := httptest.NewRecorder()
handler.Update(w, req)
if w.Code != http.StatusInternalServerError {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusInternalServerError, w.Code)
}
shouldContain := "unknown error"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
}
func TestUpdateErrKeyExists(t *testing.T) {
_ = kverror.ErrKeyNotFound.AddData("key=test") // ignore return no need
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{
updateErr: kverror.ErrKeyNotFound,
}),
kvstorehandler.WithLogger(logger),
)
payload := strings.NewReader(`{"key":"test","value":"test"}`)
req := httptest.NewRequest(http.MethodPut, "/", payload)
w := httptest.NewRecorder()
handler.Update(w, req)
if w.Code != http.StatusNotFound {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusNotFound, w.Code)
}
shouldContain := "key not found"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
shouldContain = "key=test"
if !strings.Contains(w.Body.String(), shouldContain) {
t.Errorf("wrong body message, want: %s, got: %s", shouldContain, w.Body.String())
}
_ = kverror.ErrKeyNotFound.DestoryData() // ignore error
}
func TestUpdateSuccess(t *testing.T) {
handler := kvstorehandler.New(
kvstorehandler.WithService(&mockService{}),
kvstorehandler.WithLogger(logger),
kvstorehandler.WithService(&mockService{
updateResponse: &kvstoreservice.ItemResponse{
Key: "test",
Value: "test",
},
}),
)
payload := strings.NewReader(`{"key":"test","value":"test"}`)
req := httptest.NewRequest(http.MethodPut, "/", payload)
w := httptest.NewRecorder()
handler.Update(w, req)
if w.Code != http.StatusOK {
t.Errorf("wrong status code, want: %d, got: %d", http.StatusOK, w.Code)
}
shouldEqual := `{"key":"test","value":"test"}`
if w.Body.String() != shouldEqual {
t.Errorf("wrong body message, want: %s, got: %s", shouldEqual, w.Body.String())
}
}
şimdi testi çalıştıralım; önce paketleri bulalım;
$ go list ./... | grep 'kvstorehandler'
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler
$ go test -race -v github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler
$ go test -cover -race -v github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler
:
:
coverage: 99.1% of statements
evet, testler bitti, tüm test coverage ne durumda?
$ go test -coverpkg=./... -coverprofile=coverage.out ./...
$ go tool cover -func=coverage.out
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror/kverror.go:33: AddData 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror/kverror.go:39: Unwrap 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror/kverror.go:44: DestoryData 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror/kverror.go:50: Wrap 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror/kverror.go:55: Error 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/kverror/kverror.go:63: New 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice/base.go:28: WithStorage 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice/base.go:35: New 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice/delete.go:8: Delete 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice/get.go:8: Get 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice/list.go:7: List 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice/set.go:8: Set 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/service/kvstoreservice/update.go:8: Update 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage/base.go:30: WithMemoryDB 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage/base.go:37: New 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage/delete.go:3: Delete 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage/get.go:9: Get 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage/list.go:3: List 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage/set.go:9: Set 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/storage/memory/kvstorage/update.go:3: Update 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/basehttphandler/basehttphandler.go:18: JSON 71.4%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler/base.go:33: WithService 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler/base.go:40: WithContextTimeout 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler/base.go:47: WithServerEnv 0.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler/base.go:54: WithLogger 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler/base.go:61: New 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler/delete.go:11: Delete 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler/get.go:11: Get 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler/list.go:11: List 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler/set.go:14: Set 100.0%
github.com/<GITHUB-KULLANICI-ADINIZ>/kvstore/src/internal/transport/http/kvstorehandler/update.go:14: Update 100.0%
total: (statements) 98.7%
yani tüm projenin toplam test coverage’ı 98.7%. Sonra;
$ git add .
$ git commit -m 'add http handler tests'