github.com/turingchain2020/turingchain@v1.1.21/blockchain/push_test.go (about)

     1  package blockchain
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math/rand"
     7  	"os"
     8  	"sync/atomic"
     9  	"testing"
    10  	"time"
    11  
    12  	bcMocks "github.com/turingchain2020/turingchain/blockchain/mocks"
    13  	"github.com/turingchain2020/turingchain/client"
    14  	"github.com/turingchain2020/turingchain/common"
    15  	"github.com/turingchain2020/turingchain/common/crypto"
    16  	"github.com/turingchain2020/turingchain/consensus"
    17  	"github.com/turingchain2020/turingchain/executor"
    18  	"github.com/turingchain2020/turingchain/mempool"
    19  	"github.com/turingchain2020/turingchain/p2p"
    20  	"github.com/turingchain2020/turingchain/queue"
    21  	"github.com/turingchain2020/turingchain/rpc"
    22  	"github.com/turingchain2020/turingchain/rpc/jsonclient"
    23  	rpctypes "github.com/turingchain2020/turingchain/rpc/types"
    24  	"github.com/turingchain2020/turingchain/store"
    25  	"github.com/turingchain2020/turingchain/types"
    26  	"github.com/turingchain2020/turingchain/util"
    27  	"github.com/turingchain2020/turingchain/wallet"
    28  	"github.com/stretchr/testify/assert"
    29  	"github.com/stretchr/testify/mock"
    30  	"github.com/stretchr/testify/require"
    31  )
    32  
    33  var sendTxWait = time.Millisecond * 5
    34  
    35  type TuringchainMock struct {
    36  	random  *rand.Rand
    37  	q       queue.Queue
    38  	client  queue.Client
    39  	api     client.QueueProtocolAPI
    40  	chain   *BlockChain
    41  	mem     queue.Module
    42  	cs      queue.Module
    43  	exec    *executor.Executor
    44  	wallet  queue.Module
    45  	network queue.Module
    46  	store   queue.Module
    47  	rpc     *rpc.RPC
    48  	cfg     *types.Config
    49  	sub     *types.ConfigSubModule
    50  	datadir string
    51  }
    52  
    53  //GetAPI :
    54  func (mock *TuringchainMock) GetAPI() client.QueueProtocolAPI {
    55  	return mock.api
    56  }
    57  
    58  //GetRPC :
    59  func (mock *TuringchainMock) GetRPC() *rpc.RPC {
    60  	return mock.rpc
    61  }
    62  
    63  //GetCfg :
    64  func (mock *TuringchainMock) GetCfg() *types.Config {
    65  	return mock.cfg
    66  }
    67  
    68  //Close :
    69  func (mock *TuringchainMock) Close() {
    70  	mock.closeNoLock()
    71  }
    72  
    73  func (mock *TuringchainMock) closeNoLock() {
    74  	mock.network.Close()
    75  	mock.rpc.Close()
    76  	mock.mem.Close()
    77  	mock.exec.Close()
    78  	mock.cs.Close()
    79  	mock.wallet.Close()
    80  	mock.chain.Close()
    81  	mock.store.Close()
    82  	mock.client.Close()
    83  	err := os.RemoveAll(mock.datadir)
    84  	if err != nil {
    85  		return
    86  	}
    87  }
    88  
    89  //GetClient :
    90  func (mock *TuringchainMock) GetClient() queue.Client {
    91  	return mock.client
    92  }
    93  
    94  //GetBlockChain :
    95  func (mock *TuringchainMock) GetBlockChain() *BlockChain {
    96  	return mock.chain
    97  }
    98  
    99  //GetGenesisKey :
   100  func (mock *TuringchainMock) GetGenesisKey() crypto.PrivKey {
   101  	return util.TestPrivkeyList[1]
   102  }
   103  
   104  //WaitHeight :
   105  func (mock *TuringchainMock) WaitHeight(height int64) error {
   106  	for {
   107  		header, err := mock.api.GetLastHeader()
   108  		if err != nil {
   109  			return err
   110  		}
   111  		if header.Height >= height {
   112  			break
   113  		}
   114  		time.Sleep(time.Second / 10)
   115  	}
   116  	return nil
   117  }
   118  
   119  func (mock *TuringchainMock) GetJSONC() *jsonclient.JSONClient {
   120  	jsonc, err := jsonclient.NewJSONClient("http://" + mock.cfg.RPC.JrpcBindAddr + "/")
   121  	if err != nil {
   122  		return nil
   123  	}
   124  	return jsonc
   125  }
   126  
   127  //WaitTx :
   128  func (mock *TuringchainMock) WaitTx(hash []byte) (*rpctypes.TransactionDetail, error) {
   129  	if hash == nil {
   130  		return nil, nil
   131  	}
   132  	for {
   133  		param := &types.ReqHash{Hash: hash}
   134  		_, err := mock.api.QueryTx(param)
   135  		if err != nil {
   136  			time.Sleep(time.Second / 10)
   137  			continue
   138  		}
   139  		var testResult rpctypes.TransactionDetail
   140  		data := rpctypes.QueryParm{
   141  			Hash: common.ToHex(hash),
   142  		}
   143  		err = mock.GetJSONC().Call("Turingchain.QueryTransaction", data, &testResult)
   144  		return &testResult, err
   145  	}
   146  }
   147  
   148  func Test_procSubscribePush_pushSupport(t *testing.T) {
   149  	chain, mock33 := createBlockChainWithFalgSet(t, false, false)
   150  	defer mock33.Close()
   151  	subscribe := new(types.PushSubscribeReq)
   152  	err := chain.procSubscribePush(subscribe)
   153  	assert.Equal(t, types.ErrPushNotSupport, err)
   154  }
   155  
   156  func Test_procSubscribePush_nilParacheck(t *testing.T) {
   157  	chain, mock33 := createBlockChain(t)
   158  	defer mock33.Close()
   159  	err := chain.procSubscribePush(nil)
   160  	assert.Equal(t, err, types.ErrInvalidParam)
   161  }
   162  
   163  func Test_addSubscriber_Paracheck(t *testing.T) {
   164  	chain, mock33 := createBlockChain(t)
   165  	defer mock33.Close()
   166  	subscribe := new(types.PushSubscribeReq)
   167  	subscribe.LastSequence = 1
   168  	err := chain.procSubscribePush(subscribe)
   169  	assert.Equal(t, err, types.ErrInvalidParam)
   170  }
   171  
   172  func Test_addSubscriber_conflictPara(t *testing.T) {
   173  	chain, mock33 := createBlockChain(t)
   174  	defer mock33.Close()
   175  	subscribe := new(types.PushSubscribeReq)
   176  	subscribe.LastSequence = 1
   177  	err := chain.procSubscribePush(subscribe)
   178  	assert.Equal(t, err, types.ErrInvalidParam)
   179  }
   180  
   181  func Test_addSubscriber_InvalidURL(t *testing.T) {
   182  	chain, mock33 := createBlockChain(t)
   183  	defer mock33.Close()
   184  	subscribe := new(types.PushSubscribeReq)
   185  	subscribe.Name = "push-test"
   186  	subscribe.URL = ""
   187  	err := chain.push.addSubscriber(subscribe)
   188  	assert.Equal(t, err, types.ErrInvalidParam)
   189  }
   190  
   191  func Test_addSubscriber_InvalidType(t *testing.T) {
   192  	chain, mock33 := createBlockChain(t)
   193  	defer mock33.Close()
   194  	subscribe := new(types.PushSubscribeReq)
   195  	subscribe.Name = "push-test"
   196  	subscribe.Type = int32(4)
   197  	err := chain.push.addSubscriber(subscribe)
   198  	assert.Equal(t, err, types.ErrInvalidParam)
   199  }
   200  
   201  func Test_addSubscriber_inconsistentSeqHash(t *testing.T) {
   202  	chain, mock33 := createBlockChain(t)
   203  	defer mock33.Close()
   204  	subscribe := new(types.PushSubscribeReq)
   205  	subscribe.Name = "push-test"
   206  	subscribe.URL = "http://localhost"
   207  	subscribe.LastSequence = 1
   208  	err := chain.push.addSubscriber(subscribe)
   209  	assert.Equal(t, err, types.ErrInvalidParam)
   210  
   211  	subscribe.LastSequence = 0
   212  	subscribe.LastHeight = 1
   213  	err = chain.push.addSubscriber(subscribe)
   214  	assert.Equal(t, err, types.ErrInvalidParam)
   215  }
   216  
   217  func Test_addSubscriber_Success(t *testing.T) {
   218  	chain, mock33 := createBlockChain(t)
   219  	defer mock33.Close()
   220  	subscribe := new(types.PushSubscribeReq)
   221  	subscribe.Name = "push-test"
   222  	subscribe.URL = "http://localhost"
   223  	key := calcPushKey(subscribe.Name)
   224  	subInfo, err := chain.push.store.GetKey(key)
   225  	assert.NotEqual(t, err, nil)
   226  	assert.NotEqual(t, subInfo, nil)
   227  
   228  	err = chain.push.addSubscriber(subscribe)
   229  	assert.Equal(t, err, nil)
   230  	subInfo, err = chain.push.store.GetKey(key)
   231  	assert.Equal(t, err, nil)
   232  	assert.NotEqual(t, subInfo, nil)
   233  
   234  	var originSubInfo types.PushWithStatus
   235  	err = types.Decode(subInfo, &originSubInfo)
   236  	assert.Equal(t, err, nil)
   237  	assert.Equal(t, originSubInfo.Push.URL, subscribe.URL)
   238  
   239  	pushes, _ := chain.ProcListPush()
   240  	assert.Equal(t, subscribe.Name, pushes.Pushes[0].Name)
   241  
   242  	//重新创建push,能够从数据库中恢复原先注册成功的push
   243  	chainAnother := &BlockChain{
   244  		isRecordBlockSequence: true,
   245  		enablePushSubscribe:   true,
   246  	}
   247  	chainAnother.push = newpush(chain.blockStore, chain.blockStore, chain.client.GetConfig())
   248  	recoverpushes, _ := chainAnother.ProcListPush()
   249  	assert.Equal(t, subscribe.Name, recoverpushes.Pushes[0].Name)
   250  }
   251  
   252  func Test_addSubscriber_WithSeqHashHeight(t *testing.T) {
   253  	chain, mock33 := createBlockChain(t)
   254  	defer mock33.Close()
   255  
   256  	blockSeq, err := chain.blockStore.GetBlockSequence(5)
   257  	assert.Equal(t, err, nil)
   258  	header, err := chain.blockStore.GetBlockHeaderByHash(blockSeq.Hash)
   259  	assert.Equal(t, err, nil)
   260  
   261  	subscribe := new(types.PushSubscribeReq)
   262  	subscribe.Name = "push-test"
   263  	subscribe.URL = "http://localhost"
   264  	subscribe.LastSequence = 5
   265  	subscribe.LastHeight = header.Height
   266  	subscribe.LastBlockHash = common.ToHex(blockSeq.Hash)
   267  	key := calcPushKey(subscribe.Name)
   268  	_, err = chain.push.store.GetKey(key)
   269  	assert.NotEqual(t, err, nil)
   270  
   271  	err = chain.push.addSubscriber(subscribe)
   272  	assert.Equal(t, err, nil)
   273  	subInfo, err := chain.push.store.GetKey(key)
   274  	assert.Equal(t, err, nil)
   275  	assert.NotEqual(t, subInfo, nil)
   276  
   277  	var originSubInfo types.PushWithStatus
   278  	err = types.Decode(subInfo, &originSubInfo)
   279  	assert.Equal(t, err, nil)
   280  	assert.Equal(t, originSubInfo.Push.URL, subscribe.URL)
   281  
   282  	pushes, _ := chain.ProcListPush()
   283  	assert.Equal(t, subscribe.Name, pushes.Pushes[0].Name)
   284  }
   285  
   286  func Test_PostBlockFail(t *testing.T) {
   287  	chain, mock33 := createBlockChain(t)
   288  	ps := &bcMocks.PostService{}
   289  	ps.On("PostData", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("timeout"))
   290  	chain.push.postService = ps
   291  
   292  	subscribe := new(types.PushSubscribeReq)
   293  	subscribe.Name = "push-test"
   294  	subscribe.URL = "http://localhost"
   295  	subscribe.Type = PushBlock
   296  
   297  	err := chain.push.addSubscriber(subscribe)
   298  	time.Sleep(2 * time.Second)
   299  	assert.Equal(t, err, nil)
   300  	createBlocks(t, mock33, chain, 10)
   301  	keyStr := string(calcPushKey(subscribe.Name))
   302  	pushNotify := chain.push.tasks[keyStr]
   303  	assert.Equal(t, pushNotify.subscribe.Name, subscribe.Name)
   304  	assert.Equal(t, pushNotify.status, running)
   305  	time.Sleep(1 * time.Second)
   306  	createBlocks(t, mock33, chain, 1)
   307  
   308  	assert.Greater(t, atomic.LoadInt32(&pushNotify.postFail2Sleep), int32(0))
   309  	time.Sleep(1 * time.Second)
   310  
   311  	lastSeq, _ := chain.ProcGetLastPushSeq(subscribe.Name)
   312  	assert.Equal(t, lastSeq, int64(-1))
   313  
   314  	mock33.Close()
   315  }
   316  
   317  func Test_GetLastPushSeqFailDue2RecordBlockSequence(t *testing.T) {
   318  	chain, mock33 := createBlockChainWithFalgSet(t, false, false)
   319  	_, err := chain.ProcGetLastPushSeq("test")
   320  	assert.Equal(t, types.ErrRecordBlockSequence, err)
   321  	mock33.Close()
   322  }
   323  
   324  func Test_GetLastPushSeqFailDue2enablePushSubscribe(t *testing.T) {
   325  	chain, mock33 := createBlockChainWithFalgSet(t, true, false)
   326  	_, err := chain.ProcGetLastPushSeq("test")
   327  	assert.Equal(t, types.ErrPushNotSupport, err)
   328  	mock33.Close()
   329  }
   330  
   331  func Test_GetLastPushSeqFailDue2NotSubscribed(t *testing.T) {
   332  	chain, mock33 := createBlockChain(t)
   333  	_, err := chain.ProcGetLastPushSeq("test")
   334  	assert.Equal(t, types.ErrPushNotSubscribed, err)
   335  	mock33.Close()
   336  }
   337  
   338  func Test_PostDataFail(t *testing.T) {
   339  	chain, mock33 := createBlockChain(t)
   340  
   341  	subscribe := new(types.PushSubscribeReq)
   342  	subscribe.Name = "push-test"
   343  	subscribe.URL = "http://localhost"
   344  	subscribe.Type = PushBlock
   345  
   346  	err := chain.push.addSubscriber(subscribe)
   347  	time.Sleep(2 * time.Second)
   348  	assert.Equal(t, err, nil)
   349  	createBlocks(t, mock33, chain, 10)
   350  	keyStr := string(calcPushKey(subscribe.Name))
   351  	pushNotify := chain.push.tasks[keyStr]
   352  	assert.Equal(t, pushNotify.subscribe.Name, subscribe.Name)
   353  	assert.Equal(t, pushNotify.status, running)
   354  
   355  	err = chain.push.postService.PostData(subscribe, []byte("1"), 1)
   356  	assert.NotEqual(t, nil, err)
   357  
   358  	mock33.Close()
   359  }
   360  
   361  func Test_PostBlockSuccess(t *testing.T) {
   362  	chain, mock33 := createBlockChain(t)
   363  	ps := &bcMocks.PostService{}
   364  	ps.On("PostData", mock.Anything, mock.Anything, mock.Anything).Return(nil)
   365  	chain.push.postService = ps
   366  
   367  	subscribe := new(types.PushSubscribeReq)
   368  	subscribe.Name = "push-test"
   369  	subscribe.URL = "http://localhost"
   370  	subscribe.Type = PushBlock
   371  
   372  	err := chain.push.addSubscriber(subscribe)
   373  	time.Sleep(2 * time.Second)
   374  	assert.Equal(t, err, nil)
   375  	createBlocks(t, mock33, chain, 10)
   376  	keyStr := string(calcPushKey(subscribe.Name))
   377  	pushNotify := chain.push.tasks[keyStr]
   378  	assert.Equal(t, pushNotify.subscribe.Name, subscribe.Name)
   379  	assert.Equal(t, pushNotify.status, running)
   380  	time.Sleep(1 * time.Second)
   381  	//注册相同的push,不会有什么问题
   382  	err = chain.push.addSubscriber(subscribe)
   383  	assert.Equal(t, err, nil)
   384  
   385  	createBlocks(t, mock33, chain, 1)
   386  
   387  	assert.Equal(t, atomic.LoadInt32(&pushNotify.postFail2Sleep), int32(0))
   388  	time.Sleep(1 * time.Second)
   389  
   390  	lastSeq, _ := chain.ProcGetLastPushSeq(subscribe.Name)
   391  	assert.Greater(t, lastSeq, int64(21))
   392  
   393  	mock33.Close()
   394  }
   395  
   396  func Test_PostBlockHeaderSuccess(t *testing.T) {
   397  	chain, mock33 := createBlockChain(t)
   398  	ps := &bcMocks.PostService{}
   399  	ps.On("PostData", mock.Anything, mock.Anything, mock.Anything).Return(nil)
   400  	chain.push.postService = ps
   401  
   402  	subscribe := new(types.PushSubscribeReq)
   403  	subscribe.Name = "push-test"
   404  	subscribe.URL = "http://localhost"
   405  	subscribe.Type = PushBlockHeader
   406  
   407  	err := chain.push.addSubscriber(subscribe)
   408  	time.Sleep(2 * time.Second)
   409  	assert.Equal(t, err, nil)
   410  	createBlocks(t, mock33, chain, 10)
   411  	keyStr := string(calcPushKey(subscribe.Name))
   412  	pushNotify := chain.push.tasks[keyStr]
   413  	assert.Equal(t, pushNotify.subscribe.Name, subscribe.Name)
   414  	assert.Equal(t, pushNotify.status, running)
   415  
   416  	createBlocks(t, mock33, chain, 1)
   417  
   418  	assert.Equal(t, atomic.LoadInt32(&pushNotify.postFail2Sleep), int32(0))
   419  	time.Sleep(1 * time.Second)
   420  
   421  	lastSeq, _ := chain.ProcGetLastPushSeq(subscribe.Name)
   422  	assert.Greater(t, lastSeq, int64(21))
   423  
   424  	mock33.Close()
   425  }
   426  
   427  func Test_PostTxReceipt(t *testing.T) {
   428  	chain, mock33 := createBlockChain(t)
   429  
   430  	ps := &bcMocks.PostService{}
   431  	ps.On("PostData", mock.Anything, mock.Anything, mock.Anything).Return(nil)
   432  	chain.push.postService = ps
   433  	subscribe := new(types.PushSubscribeReq)
   434  	subscribe.Name = "push-test"
   435  	subscribe.URL = "http://localhost"
   436  	subscribe.Type = PushTxReceipt
   437  	subscribe.Contract = make(map[string]bool)
   438  	subscribe.Contract["coins"] = true
   439  
   440  	err := chain.push.addSubscriber(subscribe)
   441  	assert.Equal(t, err, nil)
   442  	createBlocks(t, mock33, chain, 1)
   443  	keyStr := string(calcPushKey(subscribe.Name))
   444  	pushNotify := chain.push.tasks[keyStr]
   445  	assert.Equal(t, pushNotify.subscribe.Name, subscribe.Name)
   446  
   447  	assert.Equal(t, atomic.LoadInt32(&pushNotify.status), running)
   448  	time.Sleep(2 * time.Second)
   449  	assert.Equal(t, atomic.LoadInt32(&pushNotify.postFail2Sleep), int32(0))
   450  	defer mock33.Close()
   451  }
   452  
   453  func Test_AddPush_reachMaxNum(t *testing.T) {
   454  	chain, mock33 := createBlockChain(t)
   455  
   456  	ps := &bcMocks.PostService{}
   457  	ps.On("PostData", mock.Anything, mock.Anything, mock.Anything).Return(nil)
   458  	chain.push.postService = ps
   459  
   460  	for i := 0; i < maxPushSubscriber; i++ {
   461  		subscribe := new(types.PushSubscribeReq)
   462  		subscribe.Name = "push-test"
   463  		subscribe.URL = "http://localhost"
   464  		subscribe.Type = PushTxReceipt
   465  		subscribe.Contract = make(map[string]bool)
   466  		subscribe.Contract["coins"] = true
   467  		subscribe.Name = "push-test-" + fmt.Sprintf("%d", i)
   468  		err := chain.push.addSubscriber(subscribe)
   469  		assert.Equal(t, err, nil)
   470  	}
   471  	subscribe := new(types.PushSubscribeReq)
   472  	subscribe.Name = "push-test"
   473  	subscribe.URL = "http://localhost"
   474  	subscribe.Type = PushTxReceipt
   475  	subscribe.Contract = make(map[string]bool)
   476  	subscribe.Contract["coins"] = true
   477  	subscribe.Name = "push-test-lastOne"
   478  	err := chain.push.addSubscriber(subscribe)
   479  	assert.Equal(t, err, types.ErrTooManySeqCB)
   480  	defer mock33.Close()
   481  }
   482  
   483  func Test_AddPush_PushNameShouldDiff(t *testing.T) {
   484  	chain, mock33 := createBlockChain(t)
   485  
   486  	ps := &bcMocks.PostService{}
   487  	ps.On("PostData", mock.Anything, mock.Anything, mock.Anything).Return(nil)
   488  	chain.push.postService = ps
   489  
   490  	var pushNames []string
   491  	for i := 0; i < 10; i++ {
   492  		subscribe := new(types.PushSubscribeReq)
   493  		subscribe.Name = "push-test"
   494  		subscribe.URL = "http://localhost"
   495  		subscribe.Type = PushTxReceipt
   496  		subscribe.Contract = make(map[string]bool)
   497  		subscribe.Contract["coins"] = true
   498  		subscribe.Name = "push-test-" + fmt.Sprintf("%d", i)
   499  		err := chain.push.addSubscriber(subscribe)
   500  		pushNames = append(pushNames, subscribe.Name)
   501  		assert.Equal(t, err, nil)
   502  	}
   503  	assert.Equal(t, len(chain.push.tasks), 10)
   504  	//不允许注册相同name不同url的push
   505  	subscribe := new(types.PushSubscribeReq)
   506  	subscribe.Name = "push-test"
   507  	subscribe.URL = "http://localhost"
   508  	subscribe.Type = PushTxReceipt
   509  	subscribe.Contract = make(map[string]bool)
   510  	subscribe.Contract["coins"] = true
   511  	subscribe.Name = "push-test-" + fmt.Sprintf("%d", 9)
   512  	subscribe.URL = "http://localhost:9671"
   513  	err := chain.push.addSubscriber(subscribe)
   514  	assert.Equal(t, err, types.ErrNotAllowModifyPush)
   515  
   516  	//push 能够正常从数据库恢复
   517  	chainAnother := &BlockChain{
   518  		isRecordBlockSequence: true,
   519  		enablePushSubscribe:   true,
   520  	}
   521  	chainAnother.push = newpush(chain.blockStore, chain.blockStore, chain.client.GetConfig())
   522  	assert.Equal(t, 10, len(chainAnother.push.tasks))
   523  	for _, name := range pushNames {
   524  		assert.NotEqual(t, chainAnother.push.tasks[string(calcPushKey(name))], nil)
   525  	}
   526  	defer mock33.Close()
   527  }
   528  
   529  func Test_rmPushFailTask(t *testing.T) {
   530  	chain, mock33 := createBlockChain(t)
   531  	chain.push.postFail2Sleep = int32(1)
   532  	ps := &bcMocks.PostService{}
   533  	ps.On("PostData", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("timeout"))
   534  	chain.push.postService = ps
   535  
   536  	createBlocks(t, mock33, chain, 10)
   537  	var pushNames []string
   538  	subCnt := 10
   539  	for i := 0; i < subCnt; i++ {
   540  		subscribe := new(types.PushSubscribeReq)
   541  		subscribe.Name = "push-test"
   542  		subscribe.URL = "http://localhost"
   543  		subscribe.Type = PushTxReceipt
   544  		subscribe.Contract = make(map[string]bool)
   545  		subscribe.Contract["coins"] = true
   546  
   547  		subscribe.Name = fmt.Sprintf("%d", i) + "-push-test-"
   548  		err := chain.push.addSubscriber(subscribe)
   549  		pushNames = append(pushNames, subscribe.Name)
   550  		assert.Equal(t, err, nil)
   551  	}
   552  	chain.push.mu.Lock()
   553  	assert.Equal(t, len(chain.push.tasks), subCnt)
   554  	chain.push.mu.Unlock()
   555  	createBlocks(t, mock33, chain, 10)
   556  	time.Sleep(1 * time.Second)
   557  
   558  	createBlocks(t, mock33, chain, 10)
   559  	time.Sleep(1 * time.Second)
   560  	closeChan := make(chan struct{})
   561  
   562  	go func() {
   563  		sleepCnt := 30
   564  		for {
   565  			chain.push.mu.Lock()
   566  			if 0 == len(chain.push.tasks) {
   567  				chain.push.mu.Unlock()
   568  				close(closeChan)
   569  				return
   570  			}
   571  			chain.push.mu.Unlock()
   572  			sleepCnt--
   573  			if sleepCnt <= 0 {
   574  				close(closeChan)
   575  				return
   576  			}
   577  			time.Sleep(time.Second)
   578  		}
   579  	}()
   580  
   581  	<-closeChan
   582  	fmt.Println("stoping Test_rmPushFailTask")
   583  	chain.push.mu.Lock()
   584  	assert.Equal(t, 0, len(chain.push.tasks))
   585  	chain.push.mu.Unlock()
   586  
   587  	defer mock33.Close()
   588  }
   589  
   590  //推送失败之后能够重新激活并成功推送
   591  func Test_ReactivePush(t *testing.T) {
   592  	chain, mock33 := createBlockChain(t)
   593  	ps := &bcMocks.PostService{}
   594  	ps.On("PostData", mock.Anything, mock.Anything, mock.Anything).Return(nil)
   595  	chain.push.postService = ps
   596  
   597  	subscribe := new(types.PushSubscribeReq)
   598  	subscribe.Name = "push-test"
   599  	subscribe.URL = "http://localhost"
   600  	subscribe.Type = PushBlock
   601  
   602  	err := chain.push.addSubscriber(subscribe)
   603  	time.Sleep(2 * time.Second)
   604  	assert.Equal(t, err, nil)
   605  	createBlocks(t, mock33, chain, 10)
   606  	keyStr := string(calcPushKey(subscribe.Name))
   607  	pushNotify := chain.push.tasks[keyStr]
   608  	assert.Equal(t, pushNotify.subscribe.Name, subscribe.Name)
   609  	assert.Equal(t, pushNotify.status, running)
   610  	time.Sleep(1 * time.Second)
   611  
   612  	createBlocks(t, mock33, chain, 1)
   613  
   614  	assert.Equal(t, atomic.LoadInt32(&pushNotify.postFail2Sleep), int32(0))
   615  	time.Sleep(1 * time.Second)
   616  
   617  	lastSeq, _ := chain.ProcGetLastPushSeq(subscribe.Name)
   618  	assert.Greater(t, lastSeq, int64(21))
   619  
   620  	mockpsFail := &bcMocks.PostService{}
   621  	mockpsFail.On("PostData", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("timeout"))
   622  	chain.push.postService = mockpsFail
   623  	chain.push.postFail2Sleep = int32(1)
   624  	createBlocks(t, mock33, chain, 10)
   625  	time.Sleep(4 * time.Second)
   626  	assert.Equal(t, atomic.LoadInt32(&pushNotify.status), notRunning)
   627  	lastSeq, _ = chain.ProcGetLastPushSeq(subscribe.Name)
   628  
   629  	//重新激活
   630  	chain.push.postService = ps
   631  	err = chain.push.addSubscriber(subscribe)
   632  	assert.Equal(t, err, nil)
   633  	time.Sleep(1 * time.Second)
   634  	chain.push.mu.Lock()
   635  	pushNotify = chain.push.tasks[keyStr]
   636  	chain.push.mu.Unlock()
   637  	assert.Equal(t, atomic.LoadInt32(&pushNotify.status), running)
   638  	lastSeqAfter, _ := chain.ProcGetLastPushSeq(subscribe.Name)
   639  	assert.Greater(t, lastSeqAfter, lastSeq)
   640  
   641  	mock33.Close()
   642  }
   643  
   644  //
   645  func Test_RecoverPush(t *testing.T) {
   646  	chain, mock33 := createBlockChain(t)
   647  	ps := &bcMocks.PostService{}
   648  	ps.On("PostData", mock.Anything, mock.Anything, mock.Anything).Return(nil)
   649  	chain.push.postService = ps
   650  
   651  	subscribe := new(types.PushSubscribeReq)
   652  	subscribe.Name = "push-test"
   653  	subscribe.URL = "http://localhost"
   654  	subscribe.Type = PushBlock
   655  
   656  	err := chain.push.addSubscriber(subscribe)
   657  	time.Sleep(2 * time.Second)
   658  	assert.Equal(t, err, nil)
   659  	createBlocks(t, mock33, chain, 10)
   660  	keyStr := string(calcPushKey(subscribe.Name))
   661  	pushNotifyInfo := chain.push.tasks[keyStr]
   662  	assert.Equal(t, pushNotifyInfo.subscribe.Name, subscribe.Name)
   663  	assert.Equal(t, pushNotifyInfo.status, running)
   664  	time.Sleep(1 * time.Second)
   665  
   666  	createBlocks(t, mock33, chain, 1)
   667  
   668  	assert.Equal(t, atomic.LoadInt32(&pushNotifyInfo.postFail2Sleep), int32(0))
   669  	time.Sleep(1 * time.Second)
   670  
   671  	lastSeq, _ := chain.ProcGetLastPushSeq(subscribe.Name)
   672  	assert.Greater(t, lastSeq, int64(21))
   673  
   674  	mockpsFail := &bcMocks.PostService{}
   675  	mockpsFail.On("PostData", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("timeout"))
   676  	chain.push.postService = mockpsFail
   677  	chain.push.postFail2Sleep = int32(1)
   678  	createBlocks(t, mock33, chain, 10)
   679  	time.Sleep(3 * time.Second)
   680  	assert.Equal(t, atomic.LoadInt32(&pushNotifyInfo.status), notRunning)
   681  	chain.ProcGetLastPushSeq(subscribe.Name)
   682  
   683  	//turingchain的push服务重启后,不会将其添加到task中,
   684  	chainAnother := &BlockChain{
   685  		isRecordBlockSequence: true,
   686  		enablePushSubscribe:   true,
   687  	}
   688  	chainAnother.push = newpush(chain.blockStore, chain.blockStore, chain.client.GetConfig())
   689  	var nilInfo *pushNotify
   690  	assert.Equal(t, chainAnother.push.tasks[string(calcPushKey(subscribe.Name))], nilInfo)
   691  
   692  	mock33.Close()
   693  }
   694  
   695  //init work
   696  func NewTuringchainMock(cfgpath string, mockapi client.QueueProtocolAPI) *TuringchainMock {
   697  	cfg := types.NewTuringchainConfig(types.GetDefaultCfgstring())
   698  	return newWithConfigNoLock(cfg, mockapi)
   699  }
   700  
   701  func NewTuringchainMockWithFlag(cfgpath string, mockapi client.QueueProtocolAPI, isRecordBlockSequence, enablePushSubscribe bool) *TuringchainMock {
   702  	cfg := types.NewTuringchainConfig(types.GetDefaultCfgstring())
   703  	cfg.GetModuleConfig().BlockChain.IsRecordBlockSequence = isRecordBlockSequence
   704  	cfg.GetModuleConfig().BlockChain.EnablePushSubscribe = enablePushSubscribe
   705  	return newWithConfigNoLock(cfg, mockapi)
   706  }
   707  
   708  func newWithConfigNoLock(cfg *types.TuringchainConfig, mockapi client.QueueProtocolAPI) *TuringchainMock {
   709  	mfg := cfg.GetModuleConfig()
   710  	sub := cfg.GetSubConfig()
   711  	q := queue.New("channel")
   712  	q.SetConfig(cfg)
   713  	types.Debug = false
   714  	datadir := util.ResetDatadir(mfg, "$TEMP/")
   715  	mock := &TuringchainMock{cfg: mfg, sub: sub, q: q, datadir: datadir}
   716  	mock.random = rand.New(rand.NewSource(types.Now().UnixNano()))
   717  
   718  	mock.exec = executor.New(cfg)
   719  	mock.exec.SetQueueClient(q.Client())
   720  
   721  	mock.store = store.New(cfg)
   722  	mock.store.SetQueueClient(q.Client())
   723  
   724  	mock.chain = New(cfg)
   725  	mock.chain.SetQueueClient(q.Client())
   726  
   727  	mock.cs = consensus.New(cfg)
   728  	mock.cs.SetQueueClient(q.Client())
   729  	fmt.Print("init consensus " + mfg.Consensus.Name)
   730  
   731  	mock.mem = mempool.New(cfg)
   732  	mock.mem.SetQueueClient(q.Client())
   733  	mock.mem.Wait()
   734  	fmt.Print("init mempool")
   735  	if mfg.P2P.Enable {
   736  		mock.network = p2p.NewP2PMgr(cfg)
   737  		mock.network.SetQueueClient(q.Client())
   738  	} else {
   739  		mock.network = &mockP2P{}
   740  		mock.network.SetQueueClient(q.Client())
   741  	}
   742  	fmt.Print("init P2P")
   743  	cli := q.Client()
   744  	w := wallet.New(cfg)
   745  	mock.client = q.Client()
   746  	mock.wallet = w
   747  	mock.wallet.SetQueueClient(cli)
   748  	fmt.Print("init wallet")
   749  	if mockapi == nil {
   750  		var err error
   751  		mockapi, err = client.New(q.Client(), nil)
   752  		if err != nil {
   753  			return nil
   754  		}
   755  		newWalletRealize(mockapi)
   756  	}
   757  	mock.api = mockapi
   758  	server := rpc.New(cfg)
   759  	server.SetAPI(mock.api)
   760  	server.SetQueueClientNoListen(q.Client())
   761  	mock.rpc = server
   762  	return mock
   763  }
   764  
   765  func addTx(cfg *types.TuringchainConfig, priv crypto.PrivKey, api client.QueueProtocolAPI) ([]*types.Transaction, string, error) {
   766  	txs := util.GenCoinsTxs(cfg, priv, 1)
   767  	hash := common.ToHex(txs[0].Hash())
   768  	reply, err := api.SendTx(txs[0])
   769  	if err != nil {
   770  		return nil, hash, err
   771  	}
   772  	if !reply.GetIsOk() {
   773  		return nil, hash, errors.New("sendtx unknow error")
   774  	}
   775  	return txs, hash, nil
   776  }
   777  
   778  func createBlocks(t *testing.T, mock33 *TuringchainMock, blockchain *BlockChain, number int64) {
   779  	chainlog.Info("testProcAddBlockMsg begin --------------------")
   780  
   781  	curheight := blockchain.GetBlockHeight()
   782  	addblockheight := curheight + number
   783  
   784  	_, err := blockchain.GetBlock(curheight)
   785  	if err != nil {
   786  		require.NoError(t, err)
   787  	}
   788  	cfg := mock33.GetClient().GetConfig()
   789  	for {
   790  		_, _, err = addTx(cfg, mock33.GetGenesisKey(), mock33.GetAPI())
   791  		require.NoError(t, err)
   792  		curheight = blockchain.GetBlockHeight()
   793  		chainlog.Info("testProcAddBlockMsg ", "curheight", curheight)
   794  		_, err = blockchain.GetBlock(curheight)
   795  		require.NoError(t, err)
   796  		if curheight >= addblockheight {
   797  			break
   798  		}
   799  		time.Sleep(sendTxWait)
   800  	}
   801  	chainlog.Info("testProcAddBlockMsg end --------------------")
   802  }
   803  
   804  func createBlockChain(t *testing.T) (*BlockChain, *TuringchainMock) {
   805  	mock33 := NewTuringchainMock("", nil)
   806  
   807  	//cfg := mock33.GetClient().GetConfig()
   808  	blockchain := mock33.GetBlockChain()
   809  	//等待共识模块增长10个区块
   810  	createBlocks(t, mock33, blockchain, 10)
   811  	return blockchain, mock33
   812  }
   813  
   814  func createBlockChainWithFalgSet(t *testing.T, isRecordBlockSequence, enablePushSubscribe bool) (*BlockChain, *TuringchainMock) {
   815  	mock33 := NewTuringchainMockWithFlag("", nil, isRecordBlockSequence, enablePushSubscribe)
   816  
   817  	//cfg := mock33.GetClient().GetConfig()
   818  	blockchain := mock33.GetBlockChain()
   819  	//等待共识模块增长10个区块
   820  	createBlocks(t, mock33, blockchain, 10)
   821  	return blockchain, mock33
   822  }
   823  
   824  func newWalletRealize(qAPI client.QueueProtocolAPI) {
   825  	seed := &types.SaveSeedByPw{
   826  		Seed:   "subject hamster apple parent vital can adult chapter fork business humor pen tiger void elephant",
   827  		Passwd: "123456fuzamei",
   828  	}
   829  	reply, err := qAPI.ExecWalletFunc("wallet", "SaveSeed", seed)
   830  	if !reply.(*types.Reply).IsOk && err != nil {
   831  		panic(err)
   832  	}
   833  	reply, err = qAPI.ExecWalletFunc("wallet", "WalletUnLock", &types.WalletUnLock{Passwd: "123456fuzamei"})
   834  	if !reply.(*types.Reply).IsOk && err != nil {
   835  		panic(err)
   836  	}
   837  	for i, priv := range util.TestPrivkeyHex {
   838  		privkey := &types.ReqWalletImportPrivkey{Privkey: priv, Label: fmt.Sprintf("label%d", i)}
   839  		acc, err := qAPI.ExecWalletFunc("wallet", "WalletImportPrivkey", privkey)
   840  		if err != nil {
   841  			panic(err)
   842  		}
   843  		fmt.Print("import", "index", i, "addr", acc.(*types.WalletAccount).Acc.Addr)
   844  	}
   845  	req := &types.ReqAccountList{WithoutBalance: true}
   846  	_, err = qAPI.ExecWalletFunc("wallet", "WalletGetAccountList", req)
   847  	if err != nil {
   848  		panic(err)
   849  	}
   850  }
   851  
   852  type mockP2P struct {
   853  }
   854  
   855  //SetQueueClient :
   856  func (m *mockP2P) SetQueueClient(client queue.Client) {
   857  	go func() {
   858  		p2pKey := "p2p"
   859  		client.Sub(p2pKey)
   860  		for msg := range client.Recv() {
   861  			switch msg.Ty {
   862  			case types.EventPeerInfo:
   863  				msg.Reply(client.NewMessage(p2pKey, types.EventPeerList, &types.PeerList{}))
   864  			case types.EventGetNetInfo:
   865  				msg.Reply(client.NewMessage(p2pKey, types.EventPeerList, &types.NodeNetInfo{}))
   866  			case types.EventTxBroadcast, types.EventBlockBroadcast:
   867  			default:
   868  				msg.ReplyErr("p2p->Do not support "+types.GetEventName(int(msg.Ty)), types.ErrNotSupport)
   869  			}
   870  		}
   871  	}()
   872  }
   873  
   874  //Wait for ready
   875  func (m *mockP2P) Wait() {}
   876  
   877  //Close :
   878  func (m *mockP2P) Close() {
   879  }