github.com/projecteru2/core@v0.0.0-20240321043226-06bcc1c23f58/wal/hydro_test.go (about)

     1  package wal
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"path"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/projecteru2/core/wal/kv"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  )
    14  
    15  func TestLogFailedAsNoSuchHandler(t *testing.T) {
    16  	hydro, _ := NewHydro(path.Join(t.TempDir(), "1"), time.Second)
    17  	commit, err := hydro.Log("create", struct{}{})
    18  	assert.Error(t, err)
    19  	assert.Nil(t, commit)
    20  }
    21  
    22  func TestLogFailedAsEncodeError(t *testing.T) {
    23  	var checked, handled, encoded, decoded bool
    24  	eventype := "create"
    25  	handler := newTestEventHandler(eventype, &checked, &handled, &encoded, &decoded)
    26  	handler.encode = func(interface{}) ([]byte, error) { return nil, fmt.Errorf("encode error") }
    27  
    28  	hydro, _ := NewHydro(path.Join(t.TempDir(), "1"), time.Second)
    29  	hydro.store = kv.NewMockedKV()
    30  	hydro.Register(handler)
    31  
    32  	commit, err := hydro.Log(eventype, struct{}{})
    33  	assert.Error(t, err)
    34  	assert.Nil(t, commit)
    35  	assert.False(t, encoded)
    36  	assert.False(t, checked)
    37  	assert.False(t, decoded)
    38  	assert.False(t, handled)
    39  }
    40  
    41  func TestLogWithCommitEvent(t *testing.T) {
    42  	var checked, handled, encoded, decoded bool
    43  	eventype := "create"
    44  	handler := newTestEventHandler(eventype, &checked, &handled, &encoded, &decoded)
    45  
    46  	hydro, _ := NewHydro(path.Join(t.TempDir(), "1"), time.Second)
    47  	hydro.store = kv.NewMockedKV()
    48  	hydro.Register(handler)
    49  
    50  	commit, err := hydro.Log(eventype, struct{}{})
    51  	assert.NoError(t, err)
    52  	assert.NotNil(t, commit)
    53  
    54  	assert.NoError(t, commit())
    55  	assert.True(t, encoded)
    56  	assert.False(t, decoded)
    57  	assert.False(t, checked)
    58  	assert.False(t, handled)
    59  }
    60  
    61  func TestRecoverFailedAsNoSuchHandler(t *testing.T) {
    62  	var checked, handled, encoded, decoded bool
    63  	eventype := "create"
    64  	handler := newTestEventHandler(eventype, &checked, &handled, &encoded, &decoded)
    65  
    66  	hydro, _ := NewHydro(path.Join(t.TempDir(), "1"), time.Second)
    67  	hydro.store = kv.NewMockedKV()
    68  	hydro.Register(handler)
    69  
    70  	commit, err := hydro.Log(eventype, struct{}{})
    71  	assert.NoError(t, err)
    72  	assert.NotNil(t, commit)
    73  
    74  	hydro.Del(eventype)
    75  
    76  	hydro.Recover(context.Background())
    77  	assert.True(t, encoded)
    78  	assert.False(t, decoded)
    79  	assert.False(t, checked)
    80  	assert.False(t, handled)
    81  }
    82  
    83  func TestRecoverFailedAsCheckError(t *testing.T) {
    84  	var checked, handled, encoded, decoded bool
    85  	eventype := "create"
    86  	handler := newTestEventHandler(eventype, &checked, &handled, &encoded, &decoded)
    87  	handler.check = func(interface{}) (bool, error) {
    88  		checked = true
    89  		return false, fmt.Errorf("check error")
    90  	}
    91  
    92  	hydro, _ := NewHydro(path.Join(t.TempDir(), "1"), time.Second)
    93  	hydro.store = kv.NewMockedKV()
    94  	hydro.Register(handler)
    95  
    96  	commit, err := hydro.Log(eventype, struct{}{})
    97  	assert.NoError(t, err)
    98  	assert.NotNil(t, commit)
    99  
   100  	hydro.Recover(context.Background())
   101  	assert.True(t, encoded)
   102  	assert.True(t, decoded)
   103  	assert.True(t, checked)
   104  	assert.False(t, handled)
   105  }
   106  
   107  func TestDecodeEventFailedAsDecodeEntryError(t *testing.T) {
   108  	hydro, _ := NewHydro(path.Join(t.TempDir(), "1"), time.Second)
   109  	ent := kv.MockedScanEntry{Value: []byte("x")}
   110  	_, err := hydro.decodeEvent(ent)
   111  	assert.Error(t, err)
   112  }
   113  
   114  func TestDecodeEventFailedAsInvalidEventID(t *testing.T) {
   115  	hydro, _ := NewHydro(path.Join(t.TempDir(), "1"), time.Second)
   116  	ent := kv.MockedScanEntry{Key: "/events/x", Value: []byte("{}")}
   117  	_, err := hydro.decodeEvent(ent)
   118  	assert.Error(t, err)
   119  }
   120  
   121  func TestDecodeEventFailedAsEntryError(t *testing.T) {
   122  	hydro, _ := NewHydro(path.Join(t.TempDir(), "1"), time.Second)
   123  	expErr := fmt.Errorf("expects an error")
   124  	ent := kv.MockedScanEntry{Err: expErr}
   125  	_, err := hydro.decodeEvent(ent)
   126  	assert.Error(t, err)
   127  	assert.Equal(t, expErr.Error(), err.Error())
   128  }
   129  
   130  func TestRecoverFailedAsDecodeLogError(t *testing.T) {
   131  	var checked, handled, encoded, decoded bool
   132  	eventype := "create"
   133  	handler := newTestEventHandler(eventype, &checked, &handled, &encoded, &decoded)
   134  	handler.decode = func([]byte) (interface{}, error) {
   135  		decoded = true
   136  		return nil, fmt.Errorf("decode error")
   137  	}
   138  
   139  	hydro, _ := NewHydro(path.Join(t.TempDir(), "1"), time.Second)
   140  	hydro.store = kv.NewMockedKV()
   141  	hydro.Register(handler)
   142  
   143  	commit, err := hydro.Log(eventype, struct{}{})
   144  	assert.NoError(t, err)
   145  	assert.NotNil(t, commit)
   146  
   147  	hydro.Recover(context.Background())
   148  	assert.True(t, encoded)
   149  	assert.True(t, decoded)
   150  	assert.False(t, checked)
   151  	assert.False(t, handled)
   152  }
   153  
   154  func TestHydroRecoverDiscardNoNeedEvent(t *testing.T) {
   155  	var checked, handled, encoded, decoded bool
   156  	check := func(interface{}) (need bool, err error) {
   157  		checked = true
   158  		return
   159  	}
   160  
   161  	eventype := "create"
   162  	handler := newTestEventHandler(eventype, &checked, &handled, &encoded, &decoded)
   163  	handler.check = check
   164  
   165  	hydro, _ := NewHydro(path.Join(t.TempDir(), "1"), time.Second)
   166  	hydro.store = kv.NewMockedKV()
   167  	hydro.Register(handler)
   168  
   169  	commit, err := hydro.Log(eventype, struct{}{})
   170  	assert.NoError(t, err)
   171  	assert.NotNil(t, commit)
   172  
   173  	hydro.Recover(context.Background())
   174  	assert.True(t, encoded)
   175  	assert.True(t, decoded)
   176  	assert.True(t, checked)
   177  	assert.False(t, handled)
   178  }
   179  
   180  func TestHydroRecover(t *testing.T) {
   181  	var checked, handled, encoded, decoded bool
   182  	eventype := "create"
   183  	handler := newTestEventHandler(eventype, &checked, &handled, &encoded, &decoded)
   184  
   185  	hydro, _ := NewHydro(path.Join(t.TempDir(), "1"), time.Second)
   186  	hydro.store = kv.NewMockedKV()
   187  	hydro.Register(handler)
   188  
   189  	commit, err := hydro.Log(eventype, struct{}{})
   190  	assert.NoError(t, err)
   191  	assert.NotNil(t, commit)
   192  
   193  	hydro.Recover(context.Background())
   194  	assert.True(t, encoded)
   195  	assert.True(t, decoded)
   196  	assert.True(t, checked)
   197  	assert.True(t, handled)
   198  
   199  	// The handled events should be removed.
   200  	ch, _ := hydro.store.Scan([]byte(eventPrefix))
   201  	select {
   202  	case <-ch:
   203  		assert.Fail(t, "the events should be deleted")
   204  	default:
   205  	}
   206  }
   207  
   208  func TestHydroEventKeyMustPadZero(t *testing.T) {
   209  	event := HydroEvent{ID: 15}
   210  	assert.Equal(t, "/events/000000000000000f", string(event.Key()))
   211  }
   212  
   213  func TestHydroEventParseIDShouldRemovePadding(t *testing.T) {
   214  	id, err := parseHydroEventID([]byte("/events/00000000000000000000000000f"))
   215  	assert.NoError(t, err)
   216  	assert.Equal(t, uint64(15), id)
   217  }
   218  
   219  func TestHydroRecoverWithRealLithium(t *testing.T) {
   220  	p := path.Join(t.TempDir(), "temp.wal")
   221  	hydro, err := NewHydro(p, time.Second)
   222  	assert.NoError(t, err)
   223  
   224  	handler := simpleEventHandler{
   225  		event:  "create",
   226  		encode: func(interface{}) ([]byte, error) { return []byte("{}"), nil },
   227  		decode: func([]byte) (interface{}, error) { return struct{}{}, nil },
   228  		check:  func(interface{}) (bool, error) { return true, nil },
   229  		handle: func(interface{}) error { return nil },
   230  	}
   231  	hydro.Register(handler)
   232  
   233  	hydro.Log(handler.event, struct{}{})
   234  	hydro.Log(handler.event, struct{}{})
   235  	hydro.Log(handler.event, struct{}{})
   236  
   237  	hydro.Recover(context.Background())
   238  
   239  	ch, _ := hydro.store.Scan([]byte(eventPrefix))
   240  	select {
   241  	case <-ch:
   242  		assert.FailNow(t, "expects no data")
   243  	default:
   244  	}
   245  }
   246  
   247  func newTestEventHandler(eventype string, checked, handled, encoded, decoded *bool) simpleEventHandler {
   248  	check := func(interface{}) (bool, error) {
   249  		*checked = true
   250  		return true, nil
   251  	}
   252  
   253  	handle := func(interface{}) (err error) {
   254  		*handled = true
   255  		return
   256  	}
   257  
   258  	encode := func(interface{}) (bs []byte, err error) {
   259  		*encoded = true
   260  		return
   261  	}
   262  
   263  	decode := func([]byte) (item interface{}, err error) {
   264  		*decoded = true
   265  		return
   266  	}
   267  
   268  	return simpleEventHandler{
   269  		event:  eventype,
   270  		encode: encode,
   271  		decode: decode,
   272  		check:  check,
   273  		handle: handle,
   274  	}
   275  }