// Copyright 2019 The dexon-consensus Authors // This file is part of the dexon-consensus library. // // The dexon-consensus library is free software: you can redistribute it // and/or modify it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // The dexon-consensus library is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser // General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the dexon-consensus library. If not, see // . package syncer import ( "sync" "testing" "time" "github.com/stretchr/testify/suite" "github.com/dexon-foundation/dexon-consensus/common" "github.com/dexon-foundation/dexon-consensus/core/types" ) type WatchCatTestSuite struct { suite.Suite } type testConfigAccessor struct { notarySetSize uint32 } func (cfg *testConfigAccessor) Configuration(uint64) *types.Config { return &types.Config{ NotarySetSize: cfg.notarySetSize, } } type recovery struct { lock sync.RWMutex votes map[uint64]uint64 } func (rec *recovery) ProposeSkipBlock(height uint64) error { rec.lock.Lock() defer rec.lock.Unlock() rec.votes[height]++ return nil } func (rec *recovery) Votes(height uint64) (uint64, error) { rec.lock.RLock() defer rec.lock.RUnlock() return rec.votes[height], nil } func (s *WatchCatTestSuite) newWatchCat( notarySetSize uint32, polling, timeout time.Duration) (*WatchCat, *recovery) { cfg := &testConfigAccessor{ notarySetSize: notarySetSize, } recovery := &recovery{ votes: make(map[uint64]uint64), } wc := NewWatchCat(recovery, cfg, polling, timeout, &common.NullLogger{}) return wc, recovery } func (s *WatchCatTestSuite) TestBasicUsage() { polling := 50 * time.Millisecond timeout := 50 * time.Millisecond notarySet := uint32(24) watchCat, rec := s.newWatchCat(notarySet, polling, timeout) watchCat.Start() defer watchCat.Stop() pos := types.Position{ Height: 10, } for i := 0; i < 10; i++ { pos.Height++ watchCat.Feed(pos) time.Sleep(timeout / 2) select { case <-watchCat.Meow(): s.FailNow("unexpected terminated") default: } } time.Sleep(timeout) rec.lock.RLock() s.Require().Equal(1, len(rec.votes)) s.Require().Equal(uint64(1), rec.votes[pos.Height]) rec.lock.RUnlock() time.Sleep(polling * 2) select { case <-watchCat.Meow(): s.FailNow("unexpected terminated") default: } rec.lock.Lock() rec.votes[pos.Height] = uint64(notarySet/2 + 1) rec.lock.Unlock() time.Sleep(polling * 2) select { case <-watchCat.Meow(): default: s.FailNow("expecting terminated") } } func TestWatchCat(t *testing.T) { suite.Run(t, new(WatchCatTestSuite)) }