Files
tidb/timer/api/client_test.go

230 lines
7.0 KiB
Go

// Copyright 2023 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package api
import (
"context"
"testing"
"time"
"github.com/pingcap/errors"
"github.com/stretchr/testify/require"
)
func TestGetTimerOption(t *testing.T) {
var cond TimerCond
require.Empty(t, cond.FieldsSet())
// test 'Key' field
require.False(t, cond.Key.Present())
WithKey("k1")(&cond)
key, ok := cond.Key.Get()
require.True(t, ok)
require.Equal(t, "k1", key)
require.False(t, cond.KeyPrefix)
require.Equal(t, []string{"Key"}, cond.FieldsSet())
WithKeyPrefix("k2")(&cond)
key, ok = cond.Key.Get()
require.True(t, ok)
require.Equal(t, "k2", key)
require.True(t, cond.KeyPrefix)
require.Equal(t, []string{"Key"}, cond.FieldsSet())
WithKey("k3")(&cond)
key, ok = cond.Key.Get()
require.True(t, ok)
require.Equal(t, "k3", key)
require.False(t, cond.KeyPrefix)
require.Equal(t, []string{"Key"}, cond.FieldsSet())
// test 'ID' field
require.False(t, cond.ID.Present())
WithID("id1")(&cond)
id, ok := cond.ID.Get()
require.True(t, ok)
require.Equal(t, "id1", id)
require.Equal(t, []string{"ID", "Key"}, cond.FieldsSet())
}
func TestUpdateTimerOption(t *testing.T) {
var update TimerUpdate
require.Empty(t, update)
// test 'Enable' field
require.False(t, update.Enable.Present())
WithSetEnable(true)(&update)
setEnable, ok := update.Enable.Get()
require.True(t, ok)
require.True(t, setEnable)
require.Equal(t, []string{"Enable"}, update.FieldsSet())
WithSetEnable(false)(&update)
setEnable, ok = update.Enable.Get()
require.True(t, ok)
require.False(t, setEnable)
require.Equal(t, []string{"Enable"}, update.FieldsSet())
// test schedule policy
require.False(t, update.SchedPolicyType.Present())
require.False(t, update.SchedPolicyExpr.Present())
WithSetSchedExpr(SchedEventInterval, "3h")(&update)
stp, ok := update.SchedPolicyType.Get()
require.True(t, ok)
require.Equal(t, SchedEventInterval, stp)
expr, ok := update.SchedPolicyExpr.Get()
require.True(t, ok)
require.Equal(t, "3h", expr)
require.Equal(t, []string{"Enable", "SchedPolicyType", "SchedPolicyExpr"}, update.FieldsSet())
WithSetSchedExpr(SchedEventInterval, "1h")(&update)
stp, ok = update.SchedPolicyType.Get()
require.True(t, ok)
require.Equal(t, SchedEventInterval, stp)
expr, ok = update.SchedPolicyExpr.Get()
require.True(t, ok)
require.Equal(t, "1h", expr)
require.Equal(t, []string{"Enable", "SchedPolicyType", "SchedPolicyExpr"}, update.FieldsSet())
// test 'Watermark' field
require.False(t, update.Watermark.Present())
WithSetWatermark(time.Unix(1234, 5678))(&update)
watermark, ok := update.Watermark.Get()
require.True(t, ok)
require.Equal(t, time.Unix(1234, 5678), watermark)
require.Equal(t, []string{"Enable", "SchedPolicyType", "SchedPolicyExpr", "Watermark"}, update.FieldsSet())
// test 'SummaryData' field
require.False(t, update.SummaryData.Present())
WithSetSummaryData([]byte("hello"))(&update)
summary, ok := update.SummaryData.Get()
require.True(t, ok)
require.Equal(t, []byte("hello"), summary)
require.Equal(t, []string{"Enable", "SchedPolicyType", "SchedPolicyExpr", "Watermark", "SummaryData"}, update.FieldsSet())
}
func TestDefaultClient(t *testing.T) {
store := NewMemoryTimerStore()
cli := NewDefaultTimerClient(store)
ctx := context.Background()
spec := TimerSpec{
Key: "k1",
SchedPolicyType: SchedEventInterval,
SchedPolicyExpr: "1h",
Data: []byte("data1"),
}
// create
timer, err := cli.CreateTimer(ctx, spec)
require.NoError(t, err)
spec.Namespace = "default"
require.NotEmpty(t, timer.ID)
require.Equal(t, spec, timer.TimerSpec)
require.Equal(t, SchedEventIdle, timer.EventStatus)
require.Equal(t, "", timer.EventID)
require.Empty(t, timer.EventData)
require.Empty(t, timer.SummaryData)
// get by id
got, err := cli.GetTimerByID(ctx, timer.ID)
require.NoError(t, err)
require.Equal(t, timer, got)
// get by key
got, err = cli.GetTimerByKey(ctx, timer.Key)
require.NoError(t, err)
require.Equal(t, timer, got)
// get by key prefix
tms, err := cli.GetTimers(ctx, WithKeyPrefix("k"))
require.NoError(t, err)
require.Equal(t, 1, len(tms))
require.Equal(t, timer, tms[0])
// update
err = cli.UpdateTimer(ctx, timer.ID, WithSetSchedExpr(SchedEventInterval, "3h"))
require.NoError(t, err)
timer.SchedPolicyType = SchedEventInterval
timer.SchedPolicyExpr = "3h"
got, err = cli.GetTimerByID(ctx, timer.ID)
require.NoError(t, err)
require.Greater(t, got.Version, timer.Version)
timer.Version = got.Version
require.Equal(t, timer, got)
// close event
eventStart := time.Now().Add(-time.Second)
err = store.Update(ctx, timer.ID, &TimerUpdate{
EventStatus: NewOptionalVal(SchedEventTrigger),
EventID: NewOptionalVal("event1"),
EventData: NewOptionalVal([]byte("d1")),
SummaryData: NewOptionalVal([]byte("s1")),
EventStart: NewOptionalVal(eventStart),
})
require.NoError(t, err)
err = cli.CloseTimerEvent(ctx, timer.ID, "event2")
require.True(t, errors.ErrorEqual(ErrEventIDNotMatch, err))
err = cli.CloseTimerEvent(ctx, timer.ID, "event2", WithSetSchedExpr(SchedEventInterval, "1h"))
require.EqualError(t, err, "The field(s) [SchedPolicyType, SchedPolicyExpr] are not allowed to update when close event")
err = cli.CloseTimerEvent(ctx, timer.ID, "event1")
require.NoError(t, err)
timer, err = cli.GetTimerByID(ctx, timer.ID)
require.NoError(t, err)
require.Equal(t, SchedEventIdle, timer.EventStatus)
require.Empty(t, timer.EventID)
require.Empty(t, timer.EventData)
require.True(t, timer.EventStart.IsZero())
require.Equal(t, []byte("s1"), timer.SummaryData)
require.Equal(t, eventStart, timer.Watermark)
// close event with option
err = store.Update(ctx, timer.ID, &TimerUpdate{
EventID: NewOptionalVal("event1"),
EventData: NewOptionalVal([]byte("d1")),
SummaryData: NewOptionalVal([]byte("s1")),
})
require.NoError(t, err)
watermark := time.Now().Add(time.Hour)
err = cli.CloseTimerEvent(ctx, timer.ID, "event1", WithSetWatermark(watermark), WithSetSummaryData([]byte("s2")))
require.NoError(t, err)
timer, err = cli.GetTimerByID(ctx, timer.ID)
require.NoError(t, err)
require.Equal(t, SchedEventIdle, timer.EventStatus)
require.Empty(t, timer.EventID)
require.Empty(t, timer.EventData)
require.True(t, timer.EventStart.IsZero())
require.Equal(t, []byte("s2"), timer.SummaryData)
require.Equal(t, watermark, timer.Watermark)
// delete
exit, err := cli.DeleteTimer(ctx, timer.ID)
require.NoError(t, err)
require.True(t, exit)
// delete no exist
exit, err = cli.DeleteTimer(ctx, timer.ID)
require.NoError(t, err)
require.False(t, exit)
}