github.com/hdt3213/godis@v1.2.9/database/replication_slave_test.go (about)

     1  package database
     2  
     3  import (
     4  	"bytes"
     5  	"github.com/hdt3213/godis/aof"
     6  	"github.com/hdt3213/godis/config"
     7  	"github.com/hdt3213/godis/lib/utils"
     8  	"github.com/hdt3213/godis/redis/client"
     9  	"github.com/hdt3213/godis/redis/connection"
    10  	"github.com/hdt3213/godis/redis/protocol"
    11  	"github.com/hdt3213/godis/redis/protocol/asserts"
    12  	"io/ioutil"
    13  	"os"
    14  	"path"
    15  	"testing"
    16  	"time"
    17  )
    18  
    19  func TestReplicationSlaveSide(t *testing.T) {
    20  	tmpDir, err := ioutil.TempDir("", "godis")
    21  	if err != nil {
    22  		t.Error(err)
    23  		return
    24  	}
    25  	aofFilename := path.Join(tmpDir, "a.aof")
    26  	defer func() {
    27  		_ = os.Remove(aofFilename)
    28  	}()
    29  	config.Properties = &config.ServerProperties{
    30  		Databases:      16,
    31  		AppendOnly:     true,
    32  		AppendFilename: aofFilename,
    33  	}
    34  	conn := connection.NewFakeConn()
    35  	server := mockServer()
    36  	masterCli, err := client.MakeClient("127.0.0.1:6379")
    37  	if err != nil {
    38  		t.Error(err)
    39  		return
    40  	}
    41  	aofHandler, err := NewPersister(server, config.Properties.AppendFilename, true, aof.FsyncNo)
    42  	if err != nil {
    43  		t.Error(err)
    44  		return
    45  	}
    46  	server.bindPersister(aofHandler)
    47  	server.Exec(conn, utils.ToCmdLine("set", "zz", "zz"))
    48  	masterCli.Start()
    49  
    50  	// sync with master
    51  	ret := masterCli.Send(utils.ToCmdLine("set", "1", "1"))
    52  	asserts.AssertStatusReply(t, ret, "OK")
    53  	ret = server.Exec(conn, utils.ToCmdLine("SLAVEOF", "127.0.0.1", "6379"))
    54  	asserts.AssertStatusReply(t, ret, "OK")
    55  	success := false
    56  	for i := 0; i < 30; i++ {
    57  		// wait for sync
    58  		time.Sleep(time.Second)
    59  		ret = server.Exec(conn, utils.ToCmdLine("GET", "1"))
    60  		bulkRet, ok := ret.(*protocol.BulkReply)
    61  		if ok {
    62  			if bytes.Equal(bulkRet.Arg, []byte("1")) {
    63  				success = true
    64  				break
    65  			}
    66  		}
    67  	}
    68  	if !success {
    69  		t.Error("sync failed")
    70  		return
    71  	}
    72  
    73  	// receive aof
    74  	ret = masterCli.Send(utils.ToCmdLine("set", "1", "2"))
    75  	asserts.AssertStatusReply(t, ret, "OK")
    76  	success = false
    77  	for i := 0; i < 10; i++ {
    78  		// wait for sync
    79  		time.Sleep(time.Second)
    80  		ret = server.Exec(conn, utils.ToCmdLine("GET", "1"))
    81  		bulkRet, ok := ret.(*protocol.BulkReply)
    82  		if ok {
    83  			if bytes.Equal(bulkRet.Arg, []byte("2")) {
    84  				success = true
    85  				break
    86  			}
    87  		}
    88  	}
    89  	if !success {
    90  		t.Error("sync failed")
    91  		return
    92  	}
    93  	err = server.slaveStatus.sendAck2Master()
    94  	if err != nil {
    95  		t.Error(err)
    96  		return
    97  	}
    98  	time.Sleep(3 * time.Second)
    99  
   100  	// test reconnect
   101  	config.Properties.ReplTimeout = 1
   102  	_ = server.slaveStatus.masterConn.Close()
   103  	server.slaveStatus.lastRecvTime = time.Now().Add(-time.Hour) // mock timeout
   104  	server.slaveCron()
   105  	time.Sleep(3 * time.Second)
   106  	ret = masterCli.Send(utils.ToCmdLine("set", "1", "3"))
   107  	asserts.AssertStatusReply(t, ret, "OK")
   108  	success = false
   109  	for i := 0; i < 10; i++ {
   110  		// wait for sync
   111  		time.Sleep(time.Second)
   112  		ret = server.Exec(conn, utils.ToCmdLine("GET", "1"))
   113  		bulkRet, ok := ret.(*protocol.BulkReply)
   114  		if ok {
   115  			if bytes.Equal(bulkRet.Arg, []byte("3")) {
   116  				success = true
   117  				break
   118  			}
   119  		}
   120  	}
   121  	if !success {
   122  		t.Error("sync failed")
   123  		return
   124  	}
   125  
   126  	// test slave of no one
   127  	ret = server.Exec(conn, utils.ToCmdLine("SLAVEOF", "NO", "ONE"))
   128  	asserts.AssertStatusReply(t, ret, "OK")
   129  	ret = masterCli.Send(utils.ToCmdLine("set", "1", "4"))
   130  	asserts.AssertStatusReply(t, ret, "OK")
   131  	ret = server.Exec(conn, utils.ToCmdLine("GET", "1"))
   132  	asserts.AssertBulkReply(t, ret, "3")
   133  	ret = server.Exec(conn, utils.ToCmdLine("SLAVEOF", "127.0.0.1", "6379"))
   134  	asserts.AssertStatusReply(t, ret, "OK")
   135  	success = false
   136  	for i := 0; i < 30; i++ {
   137  		// wait for sync
   138  		time.Sleep(time.Second)
   139  		ret = server.Exec(conn, utils.ToCmdLine("GET", "1"))
   140  		bulkRet, ok := ret.(*protocol.BulkReply)
   141  		if ok {
   142  			if bytes.Equal(bulkRet.Arg, []byte("4")) {
   143  				success = true
   144  				break
   145  			}
   146  		}
   147  	}
   148  	if !success {
   149  		t.Error("sync failed")
   150  		return
   151  	}
   152  
   153  	// check slave aof file
   154  	aofLoader := MakeAuxiliaryServer()
   155  	aofHandler2, err := NewPersister(aofLoader, config.Properties.AppendFilename, true, aof.FsyncNo)
   156  	aofLoader.bindPersister(aofHandler2)
   157  	ret = aofLoader.Exec(conn, utils.ToCmdLine("get", "zz"))
   158  	asserts.AssertNullBulk(t, ret)
   159  	ret = aofLoader.Exec(conn, utils.ToCmdLine("get", "1"))
   160  	asserts.AssertBulkReply(t, ret, "4")
   161  
   162  	err = server.slaveStatus.close()
   163  	if err != nil {
   164  		t.Error("cannot close")
   165  	}
   166  }