@@ -24,7 +24,7 @@ import (
2424
2525 "github.com/coreos/go-semver/semver"
2626 "github.com/stretchr/testify/assert"
27- betesting "go.etcd.io/etcd/server/v3/mvcc/backend/testing "
27+ "github.com/stretchr/testify/require "
2828 "go.uber.org/zap"
2929 "go.uber.org/zap/zaptest"
3030
@@ -33,6 +33,7 @@ import (
3333 "go.etcd.io/etcd/raft/v3/raftpb"
3434 "go.etcd.io/etcd/server/v3/etcdserver/api/v2store"
3535 "go.etcd.io/etcd/server/v3/mock/mockstore"
36+ betesting "go.etcd.io/etcd/server/v3/mvcc/backend/testing"
3637)
3738
3839func TestClusterMember (t * testing.T ) {
@@ -1210,3 +1211,160 @@ func TestRemoveMemberSyncsBackendAndStoreV2(t *testing.T) {
12101211 })
12111212 }
12121213}
1214+
1215+ func TestSyncLearnerPromotion (t * testing.T ) {
1216+ tcs := []struct {
1217+ name string
1218+
1219+ storeV2Members []* Member
1220+ backendMembers []* Member
1221+
1222+ expectV3Members map [types.ID ]* Member
1223+ }{
1224+ {
1225+ name : "v3store should keep unchanged if IsLearner isn't the only field that differs" ,
1226+ storeV2Members : []* Member {
1227+ {
1228+ ID : 100 ,
1229+ RaftAttributes : RaftAttributes {
1230+ PeerURLs : []string {"http://10.0.0.100:2380" },
1231+ IsLearner : false ,
1232+ },
1233+ },
1234+ },
1235+ backendMembers : []* Member {
1236+ {
1237+ ID : 100 ,
1238+ RaftAttributes : RaftAttributes {
1239+ PeerURLs : []string {"http://10.0.0.9:2380" },
1240+ IsLearner : true ,
1241+ },
1242+ },
1243+ },
1244+ expectV3Members : map [types.ID ]* Member {
1245+ 100 : {
1246+ ID : 100 ,
1247+ RaftAttributes : RaftAttributes {
1248+ PeerURLs : []string {"http://10.0.0.9:2380" },
1249+ IsLearner : true ,
1250+ },
1251+ },
1252+ },
1253+ },
1254+ {
1255+ name : "v3store should keep unchanged if IsLearner is the only field that differs but v3store.IsLearner is false" ,
1256+ storeV2Members : []* Member {
1257+ {
1258+ ID : 100 ,
1259+ RaftAttributes : RaftAttributes {
1260+ PeerURLs : []string {"http://10.0.0.9:2380" },
1261+ IsLearner : true ,
1262+ },
1263+ },
1264+ },
1265+ backendMembers : []* Member {
1266+ {
1267+ ID : 100 ,
1268+ RaftAttributes : RaftAttributes {
1269+ PeerURLs : []string {"http://10.0.0.9:2380" },
1270+ IsLearner : false ,
1271+ },
1272+ },
1273+ },
1274+ expectV3Members : map [types.ID ]* Member {
1275+ 100 : {
1276+ ID : 100 ,
1277+ RaftAttributes : RaftAttributes {
1278+ PeerURLs : []string {"http://10.0.0.9:2380" },
1279+ IsLearner : false ,
1280+ },
1281+ },
1282+ },
1283+ },
1284+ {
1285+ name : "v3store should be updated if IsLearner is the only field that differs and v3store.IsLearner is true" ,
1286+ storeV2Members : []* Member {
1287+ {
1288+ ID : 100 ,
1289+ RaftAttributes : RaftAttributes {
1290+ PeerURLs : []string {"http://10.0.0.9:2380" },
1291+ IsLearner : false ,
1292+ },
1293+ },
1294+ },
1295+ backendMembers : []* Member {
1296+ {
1297+ ID : 100 ,
1298+ RaftAttributes : RaftAttributes {
1299+ PeerURLs : []string {"http://10.0.0.9:2380" },
1300+ IsLearner : true ,
1301+ },
1302+ },
1303+ },
1304+ expectV3Members : map [types.ID ]* Member {
1305+ 100 : {
1306+ ID : 100 ,
1307+ RaftAttributes : RaftAttributes {
1308+ PeerURLs : []string {"http://10.0.0.9:2380" },
1309+ IsLearner : false ,
1310+ },
1311+ },
1312+ },
1313+ },
1314+ {
1315+ name : "v3store should be updated if IsLearner is the only field that differs and peerURLs are in different order in v2store and v3store" ,
1316+ storeV2Members : []* Member {
1317+ {
1318+ ID : 100 ,
1319+ RaftAttributes : RaftAttributes {
1320+ PeerURLs : []string {"http://10.0.0.9:2380" , "http://127.0.0.1:2380" },
1321+ IsLearner : false ,
1322+ },
1323+ },
1324+ },
1325+ backendMembers : []* Member {
1326+ {
1327+ ID : 100 ,
1328+ RaftAttributes : RaftAttributes {
1329+ PeerURLs : []string {"http://127.0.0.1:2380" , "http://10.0.0.9:2380" },
1330+ IsLearner : true ,
1331+ },
1332+ },
1333+ },
1334+ expectV3Members : map [types.ID ]* Member {
1335+ 100 : {
1336+ ID : 100 ,
1337+ RaftAttributes : RaftAttributes {
1338+ PeerURLs : []string {"http://127.0.0.1:2380" , "http://10.0.0.9:2380" },
1339+ IsLearner : false ,
1340+ },
1341+ },
1342+ },
1343+ },
1344+ }
1345+ for _ , tc := range tcs {
1346+ t .Run (tc .name , func (t * testing.T ) {
1347+ lg := zaptest .NewLogger (t )
1348+ be , _ := betesting .NewDefaultTmpBackend (t )
1349+ defer be .Close ()
1350+ mustCreateBackendBuckets (be )
1351+ for _ , m := range tc .backendMembers {
1352+ unsafeSaveMemberToBackend (lg , be , m )
1353+ }
1354+ be .ForceCommit ()
1355+
1356+ st := v2store .New ()
1357+ for _ , m := range tc .storeV2Members {
1358+ mustSaveMemberToStore (lg , st , m )
1359+ }
1360+
1361+ cluster := NewCluster (lg )
1362+ cluster .SetBackend (be )
1363+ cluster .SetStore (st )
1364+
1365+ cluster .SyncLearnerPromotionIfNeeded ()
1366+ v3Members , _ := cluster .MembersFromBackend ()
1367+ require .Equal (t , tc .expectV3Members , v3Members )
1368+ })
1369+ }
1370+ }
0 commit comments