datastore/internal/dal/impl_test.go
Luís Murta ac396ac259
All checks were successful
Go / build (1.21) (push) Successful in 1m33s
Go / build (1.22) (push) Successful in 1m31s
Implements /transactions PUT method
Adds PUT method to OpenAPI spec.

Given that the transaction IDs are generated on server-side, for the PUT
method to remain idempotent, it can only update existing transactions.

It also adds a TransactionExists method on the DAL.

Issue: #20
2024-08-03 22:21:19 +00:00

427 lines
9.0 KiB
Go

package dal
import (
"database/sql"
"database/sql/driver"
"reflect"
"testing"
"time"
"git.rosemyrtle.work/personal-finance/server/internal/entity"
"github.com/DATA-DOG/go-sqlmock"
"github.com/google/uuid"
"github.com/shopspring/decimal"
)
func TestDalImpl_Transaction(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatal(err)
}
date := time.Now()
type fields struct {
Db *sql.DB
}
type args struct {
transactionId int64
rows [][]driver.Value
}
tests := []struct {
name string
fields fields
args args
want *entity.Transaction
wantErr bool
}{
{
"200",
fields{db},
args{
1,
[][]driver.Value{
{1, date, "income", 1000},
}},
&entity.Transaction{Id: 1, Date: date, Description: "income", Value: decimal.NewFromInt(1000)},
false,
},
{"404", fields{db}, args{2, nil}, nil, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
d := &DalImpl{
Db: tt.fields.Db,
}
mock.
ExpectQuery("^SELECT .* FROM .*transactions t WHERE t.id = \\$1$").
WithArgs(tt.args.transactionId).
WillReturnRows(
mock.
NewRows([]string{"id", "date", "description", "amount"}).
AddRows(tt.args.rows...),
)
got, err := d.Transaction(tt.args.transactionId)
if (err != nil) != tt.wantErr {
t.Errorf("DalImpl.Transaction() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("DalImpl.Transaction() = %v, want %v", got, tt.want)
}
})
}
}
func TestDalImpl_Transactions(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatal(err)
}
date := time.Now()
type fields struct {
Db *sql.DB
}
type args struct {
rows [][]driver.Value
}
tests := []struct {
name string
fields fields
args args
want entity.Transactions
wantErr bool
}{
{
"200",
fields{db},
args{[][]driver.Value{
{1, date, "income", 1000},
{2, date, "expense", -10.50},
}},
entity.Transactions{
{Id: 1, Date: date, Description: "income", Value: decimal.NewFromInt(1000)},
{Id: 2, Date: date, Description: "expense", Value: decimal.NewFromFloat(-10.50)},
},
false,
},
{"204", fields{db}, args{}, nil, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dal := &DalImpl{
Db: tt.fields.Db,
}
mock.
ExpectQuery("^SELECT .* FROM .*transactions t$").
WithoutArgs().
WillReturnRows(
mock.
NewRows([]string{"id", "date", "description", "amount"}).
AddRows(tt.args.rows...),
)
got, err := dal.Transactions()
if (err != nil) != tt.wantErr {
t.Errorf("DalImpl.Transactions() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("DalImpl.Transactions() = %v, want %v", got, tt.want)
}
})
}
}
func TestDalImpl_Bank(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatal(err)
}
uuid := uuid.New()
type fields struct {
Db *sql.DB
}
type args struct {
bankId string
rows [][]driver.Value
}
tests := []struct {
name string
fields fields
args args
want *entity.Bank
wantErr bool
}{
{
"200",
fields{db},
args{
"Bank A",
[][]driver.Value{
{"Bank A", "Bank A", uuid.String()},
}},
&entity.Bank{Id: "Bank A", Name: "Bank A", NordigenId: uuid},
false,
},
{"404", fields{db}, args{"Bank B", nil}, nil, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
d := &DalImpl{
Db: tt.fields.Db,
}
mock.
ExpectQuery("^SELECT .* FROM .*banks b JOIN .*banks_nordigen n ON b.name = n.name WHERE b.name = \\$1$").
WithArgs(tt.args.bankId).
WillReturnRows(
mock.
NewRows([]string{"name", "name", "requisition_id"}).
AddRows(tt.args.rows...),
)
got, err := d.Bank(tt.args.bankId)
if (err != nil) != tt.wantErr {
t.Errorf("DalImpl.Bank() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("DalImpl.Bank() = %v, want %v", got, tt.want)
}
})
}
}
func TestDalImpl_Banks(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatal(err)
}
uuid := uuid.New()
type fields struct {
Db *sql.DB
}
type args struct {
rows [][]driver.Value
}
tests := []struct {
name string
fields fields
args args
want entity.Banks
wantErr bool
}{
{
"200",
fields{db},
args{[][]driver.Value{
{"Bank A", "Bank A", uuid.String()},
{"Bank B", "Bank B", uuid.String()},
}},
entity.Banks{
{Id: "Bank A", Name: "Bank A", NordigenId: uuid},
{Id: "Bank B", Name: "Bank B", NordigenId: uuid},
},
false,
},
{"204", fields{db}, args{}, nil, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
d := &DalImpl{
Db: tt.fields.Db,
}
mock.
ExpectQuery("^SELECT .* FROM .*banks b JOIN .*banks_nordigen n ON b.name = n.name$").
WithoutArgs().
WillReturnRows(
mock.
NewRows([]string{"name", "name", "requisition_id"}).
AddRows(tt.args.rows...),
)
got, err := d.Banks()
if (err != nil) != tt.wantErr {
t.Errorf("DalImpl.Banks() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("DalImpl.Banks() = %v, want %v", got, tt.want)
}
})
}
}
func TestDalImpl_InsertTransaction(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatal(err)
}
date := time.Now()
type fields struct {
Db *sql.DB
}
type args struct {
t entity.Transaction
}
tests := []struct {
name string
fields fields
args args
want entity.Transaction
wantErr bool
}{
{
"201",
fields{db},
args{entity.Transaction{Id: entity.InvalidId, Date: date, Description: "freedom", Value: decimal.NewFromInt(9000)}},
entity.Transaction{Id: 1, Date: date, Description: "freedom", Value: decimal.NewFromInt(9000)},
false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dal := &DalImpl{
Db: tt.fields.Db,
}
mock.
ExpectQuery(`
INSERT INTO .* \(date, description, amount\)
VALUES \(\$1, \$2, \$3\)
RETURNING id`).
WithArgs(tt.args.t.Date, tt.args.t.Description, tt.args.t.Value).
WillReturnRows(
mock.NewRows([]string{"id"}).
AddRows([]driver.Value{tt.want.Id}),
)
got, err := dal.InsertTransaction(tt.args.t)
if (err != nil) != tt.wantErr {
t.Errorf("DalImpl.InsertTransaction() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("DalImpl.InsertTransaction() = %v, want %v", got, tt.want)
}
})
}
}
func TestDalImpl_UpdateTransaction(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatal(err)
}
date := time.Now()
type fields struct {
Db *sql.DB
}
type args struct {
t entity.Transaction
}
tests := []struct {
name string
fields fields
args args
want entity.Transaction
wantErr bool
}{
{
"SuccessfulUpdate",
fields{db},
args{entity.Transaction{Id: entity.InvalidId, Date: date, Description: "freedom", Value: decimal.NewFromInt(9000)}},
entity.Transaction{Id: entity.InvalidId, Date: date, Description: "freedom", Value: decimal.NewFromInt(9000)},
false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dal := &DalImpl{
Db: tt.fields.Db,
}
mock.
ExpectExec(`
UPDATE pfbudget.transactions
SET date = \$2, description = \$3, amount = \$4
WHERE id = \$1`).
WithArgs(tt.args.t.Id, tt.args.t.Date, tt.args.t.Description, tt.args.t.Value).
WillReturnResult(sqlmock.NewResult(0, 1))
got, err := dal.UpdateTransaction(tt.args.t)
if (err != nil) != tt.wantErr {
t.Errorf("DalImpl.UpdateTransaction() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("DalImpl.UpdateTransaction() = %v, want %v", got, tt.want)
}
})
}
}
func TestDalImpl_TransactionExists(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatal(err)
}
type fields struct {
Db *sql.DB
}
type args struct {
id uint64
}
tests := []struct {
name string
fields fields
args args
want bool
wantErr bool
}{
{"TransactionExists", fields{db}, args{1}, true, false},
{"TransactionNotExists", fields{db}, args{1}, false, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dal := &DalImpl{
Db: tt.fields.Db,
}
mock.
ExpectQuery(`
SELECT EXISTS\(
SELECT 1
FROM pfbudget.transactions
WHERE id = \$1
\)`).
WithArgs(tt.args.id).
WillReturnRows(
mock.NewRows([]string{"exists"}).
AddRows([]driver.Value{tt.want}),
)
got, err := dal.TransactionExists(tt.args.id)
if (err != nil) != tt.wantErr {
t.Errorf("DalImpl.TransactionExists() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("DalImpl.TransactionExists() = %v, want %v", got, tt.want)
}
})
}
}