Skip to content

Commit

Permalink
Merge pull request #9 from kj455/refactor/test
Browse files Browse the repository at this point in the history
refactor/test
  • Loading branch information
kj455 authored Dec 13, 2024
2 parents 6c94715 + 188a5c5 commit 3c6af93
Show file tree
Hide file tree
Showing 84 changed files with 2,981 additions and 3,334 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ on:

jobs:
test:
permissions:
contents: write
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: ./go.mod
- name: Generate mocks
run: |
go install go.uber.org/mock/mockgen@v0.4.0
make mockgen
- name: Setup
run: make setup
- name: Test
run: make test

Expand Down
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ lint:
clean:
rm -rf .coverage
rm -rf ./pkg/**/mock
rm -rf .tmp/**
setup:
make import-tools
make mockgen
coverage:
mkdir -p .coverage
go test -coverprofile=.coverage/coverage.out $(PKG)
Expand All @@ -23,3 +27,6 @@ mockgen:
done' sh {} +
fmt:
go fmt $(PKG)
import-tools:
go install gotest.tools/gotestsum@v1.12.0
go install go.uber.org/mock/mockgen@v0.4.0
39 changes: 30 additions & 9 deletions pkg/buffer/buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,28 @@ import (
"github.com/kj455/db/pkg/log"
)

const (
INIT_TX_NUM = -1
INIT_LSN = -1
)

type ReadPage interface {
GetInt(offset int) uint32
GetBytes(offset int) []byte
GetString(offset int) string
}

type WritePage interface {
SetInt(offset int, value uint32)
SetBytes(offset int, value []byte)
SetString(offset int, value string)
}

type ReadWritePage interface {
ReadPage
WritePage
}

type BufferImpl struct {
fileMgr file.FileMgr
logMgr log.LogMgr
Expand All @@ -22,18 +44,17 @@ func NewBuffer(fm file.FileMgr, lm log.LogMgr, blockSize int) *BufferImpl {
fileMgr: fm,
logMgr: lm,
contents: file.NewPage(blockSize),
block: nil,
pins: 0,
txNum: -1,
lsn: -1,
txNum: INIT_TX_NUM,
lsn: INIT_LSN,
}
}

func (b *BufferImpl) Contents() file.ReadPage {
func (b *BufferImpl) Contents() ReadPage {
return b.contents
}

func (b *BufferImpl) WriteContents(txNum, lsn int, write func(p file.ReadWritePage)) {
func (b *BufferImpl) WriteContents(txNum, lsn int, write func(p ReadWritePage)) {
b.setModified(txNum, lsn)
write(b.contents)
}
Expand All @@ -52,7 +73,7 @@ func (b *BufferImpl) ModifyingTx() int {

func (b *BufferImpl) AssignToBlock(block file.BlockId) error {
if err := b.Flush(); err != nil {
return fmt.Errorf("buffer: failed to flush: %w", err)
return err
}
if err := b.fileMgr.Read(block, b.contents); err != nil {
return fmt.Errorf("buffer: failed to read block: %w", err)
Expand All @@ -63,7 +84,7 @@ func (b *BufferImpl) AssignToBlock(block file.BlockId) error {
}

func (b *BufferImpl) Flush() error {
if b.txNum < 0 {
if b.txNum == INIT_TX_NUM {
return nil
}
if err := b.logMgr.Flush(b.lsn); err != nil {
Expand All @@ -72,7 +93,7 @@ func (b *BufferImpl) Flush() error {
if err := b.fileMgr.Write(b.block, b.contents); err != nil {
return fmt.Errorf("buffer: failed to write block: %w", err)
}
b.txNum = -1
b.txNum = INIT_TX_NUM
return nil
}

Expand All @@ -86,7 +107,7 @@ func (b *BufferImpl) Unpin() {

func (b *BufferImpl) setModified(txNum, lsn int) {
b.txNum = txNum
if lsn >= 0 {
if lsn > INIT_LSN {
b.lsn = lsn
}
}
203 changes: 91 additions & 112 deletions pkg/buffer/buffer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,130 +4,109 @@ import (
"testing"

"github.com/kj455/db/pkg/file"
fmock "github.com/kj455/db/pkg/file/mock"
lmock "github.com/kj455/db/pkg/log/mock"
tmock "github.com/kj455/db/pkg/time/mock"
"github.com/kj455/db/pkg/log"
"github.com/kj455/db/pkg/testutil"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
)

type mocks struct {
fileMgr *fmock.MockFileMgr
page *fmock.MockPage
block *fmock.MockBlockId
logMgr *lmock.MockLogMgr
time *tmock.MockTime
}

func newMocks(ctrl *gomock.Controller) *mocks {
return &mocks{
fileMgr: fmock.NewMockFileMgr(ctrl),
page: fmock.NewMockPage(ctrl),
block: fmock.NewMockBlockId(ctrl),
logMgr: lmock.NewMockLogMgr(ctrl),
time: tmock.NewMockTime(ctrl),
}
}

func TestNewBuffer(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

fm := fmock.NewMockFileMgr(ctrl)
lm := lmock.NewMockLogMgr(ctrl)

b := NewBuffer(fm, lm, 400)

assert.NotNil(t, b)
assert.Equal(t, fm, b.fileMgr)
assert.Equal(t, lm, b.logMgr)
assert.NotNil(t, b.contents)
assert.Nil(t, b.block)
assert.Equal(t, 0, b.pins)
assert.Equal(t, -1, b.txNum)
assert.Equal(t, -1, b.lsn)
}

func TestBuffer_IsPinned(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

fm := fmock.NewMockFileMgr(ctrl)
lm := lmock.NewMockLogMgr(ctrl)

b := NewBuffer(fm, lm, 400)

assert.False(t, b.IsPinned())
b.pins++
assert.True(t, b.IsPinned())
}

func TestBuffer_WriteContents(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

fm := fmock.NewMockFileMgr(ctrl)
lm := lmock.NewMockLogMgr(ctrl)

b := NewBuffer(fm, lm, 400)

b.WriteContents(1, 2, func(p file.ReadWritePage) {
p.SetInt(0, 1)
const (
blockSize = 400
logFileName = "test_buffer_write_contents"
txNum = 1
lsn = 2
)
dir, _, cleanup := testutil.SetupFile(logFileName)
defer cleanup()
fileMgr := file.NewFileMgr(dir, blockSize)
logMgr, err := log.NewLogMgr(fileMgr, logFileName)
assert.NoError(t, err)
buf := NewBuffer(fileMgr, logMgr, blockSize)

buf.WriteContents(txNum, lsn, func(p ReadWritePage) {
p.SetInt(100, 200)
})
assert.Equal(t, uint32(1), b.contents.GetInt(0))
assert.Equal(t, 1, b.txNum)
assert.Equal(t, 2, b.lsn)

assert.Equal(t, uint32(200), buf.contents.GetInt(100))
assert.Equal(t, txNum, buf.ModifyingTx())
assert.Equal(t, lsn, buf.lsn)
}

func TestBuffer_AssignToBlock(t *testing.T) {
func TestBuffer_Flush(t *testing.T) {
t.Parallel()
const (
blockSize = 400
tx = 1
lsn = 2
)
tests := []struct {
name string
setup func(m *mocks, b *BufferImpl)
expect func(res error, b *BufferImpl)
}{
{
name: "assign",
setup: func(m *mocks, b *BufferImpl) {
m.fileMgr.EXPECT().Read(m.block, gomock.Any()).Return(nil)
},
expect: func(res error, b *BufferImpl) {
assert.Nil(t, res)
assert.Equal(t, 0, b.pins)
assert.Equal(t, -1, b.txNum)
},
},
{
name: "flush and assign",
setup: func(m *mocks, b *BufferImpl) {
b.txNum = tx
b.lsn = lsn
m.logMgr.EXPECT().Flush(lsn).Return(nil)
m.fileMgr.EXPECT().Write(nil, gomock.Any()).Return(nil)
m.fileMgr.EXPECT().Read(m.block, gomock.Any()).Return(nil)
},
expect: func(res error, b *BufferImpl) {
assert.Nil(t, res)
assert.Equal(t, 0, b.pins)
assert.Equal(t, -1, b.txNum)
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
t.Run("skip flush", func(t *testing.T) {
t.Parallel()
const logFileName = "test_buffer_flush_skip"
dir, _, cleanup := testutil.SetupFile(logFileName)
defer cleanup()
fileMgr := file.NewFileMgr(dir, blockSize)
logMgr, err := log.NewLogMgr(fileMgr, logFileName)
assert.NoError(t, err)
buf := NewBuffer(fileMgr, logMgr, blockSize)

buf.Flush()

assert.Equal(t, INIT_TX_NUM, buf.ModifyingTx())
assert.Equal(t, INIT_LSN, buf.lsn)
})
t.Run("flush", func(t *testing.T) {
t.Parallel()
const logFileName = "test_buffer_flush"
dir, _, cleanup := testutil.SetupFile(logFileName)
defer cleanup()
fileMgr := file.NewFileMgr(dir, blockSize)
logMgr, err := log.NewLogMgr(fileMgr, logFileName)
assert.NoError(t, err)
buf := NewBuffer(fileMgr, logMgr, blockSize)
buf.block = file.NewBlockId(logFileName, 0)
// setup not flushed buffer
buf.logMgr.Append([]byte("test"))
buf.WriteContents(tx, lsn, func(p ReadWritePage) {
p.SetInt(100, 200)
})

m := newMocks(ctrl)
b := NewBuffer(m.fileMgr, m.logMgr, blockSize)
tt.setup(m, b)
buf.Flush()

err := b.AssignToBlock(m.block)
tt.expect(err, b)
})
}
assert.Equal(t, INIT_TX_NUM, buf.ModifyingTx())
assert.Equal(t, lsn, buf.lsn)
iter, err := logMgr.Iterator()
assert.NoError(t, err)
assert.True(t, iter.HasNext())
record, err := iter.Next()
assert.NoError(t, err)
assert.Equal(t, []byte("test"), record)
})
}

func TestBuffer_AssignToBlock(t *testing.T) {
const (
blockSize = 400
blockNum = 0
tx = 1
lsn = 2
logFileName = "test_buffer_assign_to_block"
)
dir, _, cleanup := testutil.SetupFile(logFileName)
defer cleanup()
fileMgr := file.NewFileMgr(dir, blockSize)
logMgr, err := log.NewLogMgr(fileMgr, logFileName)
assert.NoError(t, err)
buf := NewBuffer(fileMgr, logMgr, blockSize)
buf.pins = 99
// setup block content
page := file.NewPage(blockSize)
page.SetInt(100, 200)
block := file.NewBlockId(logFileName, blockNum)
fileMgr.Write(block, page)

buf.AssignToBlock(block)

assert.Equal(t, block, buf.Block())
assert.Equal(t, 0, buf.pins)
assert.Equal(t, uint32(200), buf.Contents().GetInt(100))
}
4 changes: 2 additions & 2 deletions pkg/buffer/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import "github.com/kj455/db/pkg/file"
type Buffer interface {
Block() file.BlockId
IsPinned() bool
Contents() file.ReadPage
WriteContents(txNum, lsn int, write func(p file.ReadWritePage))
Contents() ReadPage
WriteContents(txNum, lsn int, write func(p ReadWritePage))
ModifyingTx() int
AssignToBlock(block file.BlockId) error
Flush() error
Expand Down
Loading

0 comments on commit 3c6af93

Please sign in to comment.