1
0
Fork 0

Separate autoclustering tests

master
Philip O'Toole 1 year ago
parent a98cd6e8c3
commit 1a29e25ca9

@ -81,6 +81,28 @@ jobs:
resource_class: large
end_to_end_multi:
docker:
- image: cimg/go:1.20.0
steps:
- checkout
- restore_cache:
keys:
- go-mod-v4-{{ checksum "go.sum" }}
- run: sudo apt-get update
- run: sudo apt-get install python3
- run: sudo apt install python3-pip
- run: python3 -m pip install requests
- run: go version
- run: go get -t -d -v ./...
- run: go install -tags osusergo,netgo,sqlite_omit_load_extension
-ldflags="-extldflags=-static" ./...
- run:
command: python3 system_test/e2e/multi_node.py
environment:
RQLITED_PATH: /home/circleci/go/bin/rqlited
resource_class: large
end_to_end_autoclustering:
docker:
- image: cimg/go:1.20.0
- image: consul
@ -99,7 +121,7 @@ jobs:
- run: go install -tags osusergo,netgo,sqlite_omit_load_extension
-ldflags="-extldflags=-static" ./...
- run:
command: python3 system_test/e2e/multi_node.py
command: python3 system_test/e2e/auto_clustering.py
environment:
RQLITED_PATH: /home/circleci/go/bin/rqlited
resource_class: large
@ -113,3 +135,4 @@ workflows:
- end_to_end_single
- end_to_end_multi
- end_to_end_joining
- end_to_end_autoclustering

@ -0,0 +1,142 @@
#!/usr/bin/env python
#
# End-to-end testing using actual rqlited binary.
#
# To run a specific test, execute
#
# python system_test/full_system_test.py Class.test
import os
import unittest
from helpers import Node, Cluster, d_, write_random_file, deprovision_node, random_string, TIMEOUT
RQLITED_PATH = os.environ['RQLITED_PATH']
class TestBootstrapping(unittest.TestCase):
'''Test simple bootstrapping works via -bootstrap-expect'''
def test(self):
n0 = Node(RQLITED_PATH, '0', boostrap_expect=3)
n1 = Node(RQLITED_PATH, '1', boostrap_expect=3)
n2 = Node(RQLITED_PATH, '2', boostrap_expect=3)
n0.start(join=','.join([n0.APIProtoAddr(), n1.APIProtoAddr(), n2.APIProtoAddr()]))
n1.start(join=','.join([n0.APIProtoAddr(), n1.APIProtoAddr(), n2.APIProtoAddr()]))
n2.start(join=','.join([n0.APIProtoAddr(), n1.APIProtoAddr(), n2.APIProtoAddr()]))
self.assertEqual(n0.wait_for_leader(), n1.wait_for_leader())
self.assertEqual(n0.wait_for_leader(), n2.wait_for_leader())
# Ensure a 4th node can join later, with same launch params.
n3 = Node(RQLITED_PATH, '4', boostrap_expect=3)
n3.start(join=','.join([n0.APIProtoAddr(), n1.APIProtoAddr(), n2.APIProtoAddr()]))
n3.wait_for_leader()
self.assertEqual(n3.wait_for_leader(), n0.wait_for_leader())
deprovision_node(n0)
deprovision_node(n1)
deprovision_node(n2)
deprovision_node(n3)
class TestAutoClustering(unittest.TestCase):
DiscoModeConsulKV = "consul-kv"
DiscoModeEtcdKV = "etcd-kv"
def autocluster(self, mode):
disco_key = random_string(10)
n0 = Node(RQLITED_PATH, '0')
n0.start(disco_mode=mode, disco_key=disco_key)
n0.wait_for_leader()
self.assertEqual(n0.disco_mode(), mode)
j = n0.execute('CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)')
self.assertEqual(j, d_("{'results': [{}]}"))
j = n0.execute('INSERT INTO foo(name) VALUES("fiona")')
n0.wait_for_all_fsm()
j = n0.query('SELECT * FROM foo')
self.assertEqual(j, d_("{'results': [{'values': [[1, 'fiona']], 'types': ['integer', 'text'], 'columns': ['id', 'name']}]}"))
# Add second node, make sure it joins the cluster fine.
n1 = Node(RQLITED_PATH, '1')
n1.start(disco_mode=mode, disco_key=disco_key)
n1.wait_for_leader()
self.assertEqual(n1.disco_mode(), mode)
j = n1.query('SELECT * FROM foo', level='none')
self.assertEqual(j, d_("{'results': [{'values': [[1, 'fiona']], 'types': ['integer', 'text'], 'columns': ['id', 'name']}]}"))
# Now a third.
n2 = Node(RQLITED_PATH, '2')
n2.start(disco_mode=mode, disco_key=disco_key)
n2.wait_for_leader()
self.assertEqual(n2.disco_mode(), mode)
j = n2.query('SELECT * FROM foo', level='none')
self.assertEqual(j, d_("{'results': [{'values': [[1, 'fiona']], 'types': ['integer', 'text'], 'columns': ['id', 'name']}]}"))
# Now, kill the leader, which should trigger a different node to report leadership.
deprovision_node(n0)
# Add a fourth node, it should join fine using updated leadership details.
# Use quick retries, as we know the leader information may be changing while
# the node is coming up.
n3 = Node(RQLITED_PATH, '3')
n3.start(disco_mode=mode, disco_key=disco_key, join_interval='1s', join_attempts=1)
n3.wait_for_leader()
self.assertEqual(n3.disco_mode(), mode)
j = n3.query('SELECT * FROM foo', level='none')
self.assertEqual(j, d_("{'results': [{'values': [[1, 'fiona']], 'types': ['integer', 'text'], 'columns': ['id', 'name']}]}"))
deprovision_node(n1)
deprovision_node(n2)
deprovision_node(n3)
def autocluster_config(self, mode, config):
disco_key = random_string(10)
n0 = Node(RQLITED_PATH, '0')
n0.start(disco_mode=mode, disco_key=disco_key, disco_config=config)
n0.wait_for_leader()
self.assertEqual(n0.disco_mode(), mode)
j = n0.execute('CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)')
self.assertEqual(j, d_("{'results': [{}]}"))
j = n0.execute('INSERT INTO foo(name) VALUES("fiona")')
n0.wait_for_all_fsm()
j = n0.query('SELECT * FROM foo')
self.assertEqual(j, d_("{'results': [{'values': [[1, 'fiona']], 'types': ['integer', 'text'], 'columns': ['id', 'name']}]}"))
# Add second node, make sure it joins the cluster fine.
n1 = Node(RQLITED_PATH, '1')
n1.start(disco_mode=mode, disco_key=disco_key, disco_config=config)
n1.wait_for_leader()
self.assertEqual(n1.disco_mode(), mode)
j = n1.query('SELECT * FROM foo', level='none')
self.assertEqual(j, d_("{'results': [{'values': [[1, 'fiona']], 'types': ['integer', 'text'], 'columns': ['id', 'name']}]}"))
deprovision_node(n0)
deprovision_node(n1)
def test_consul(self):
'''Test clustering via Consul and that leadership change is observed'''
self.autocluster(TestAutoClustering.DiscoModeConsulKV)
def test_etcd(self):
'''Test clustering via Etcd and that leadership change is observed'''
self.autocluster(TestAutoClustering.DiscoModeEtcdKV)
def test_consul_config(self):
'''Test clustering via Consul with explicit file-based config'''
filename = write_random_file('{"address": "localhost:8500"}')
self.autocluster_config(TestAutoClustering.DiscoModeConsulKV, filename)
os.remove(filename)
def test_etcd_config(self):
'''Test clustering via Etcd with explicit file-based config'''
filename = write_random_file('{"endpoints": ["localhost:2379"]}')
self.autocluster_config(TestAutoClustering.DiscoModeEtcdKV, filename)
os.remove(filename)
if __name__ == "__main__":
unittest.main(verbosity=2)

@ -13,7 +13,7 @@ import sqlite3
import unittest
from certs import x509cert, x509key
from helpers import Node, Cluster, d_, write_random_file, deprovision_node, is_sequence_number, random_string, TIMEOUT
from helpers import Node, Cluster, d_, write_random_file, deprovision_node, is_sequence_number, TIMEOUT
RQLITED_PATH = os.environ['RQLITED_PATH']
@ -227,131 +227,6 @@ class TestEndToEndAdvAddrEncryptedNode(TestEndToEnd):
self.cluster = Cluster([n0, n1, n2])
class TestBootstrapping(unittest.TestCase):
'''Test simple bootstrapping works via -bootstrap-expect'''
def test(self):
n0 = Node(RQLITED_PATH, '0', boostrap_expect=3)
n1 = Node(RQLITED_PATH, '1', boostrap_expect=3)
n2 = Node(RQLITED_PATH, '2', boostrap_expect=3)
n0.start(join=','.join([n0.APIProtoAddr(), n1.APIProtoAddr(), n2.APIProtoAddr()]))
n1.start(join=','.join([n0.APIProtoAddr(), n1.APIProtoAddr(), n2.APIProtoAddr()]))
n2.start(join=','.join([n0.APIProtoAddr(), n1.APIProtoAddr(), n2.APIProtoAddr()]))
self.assertEqual(n0.wait_for_leader(), n1.wait_for_leader())
self.assertEqual(n0.wait_for_leader(), n2.wait_for_leader())
# Ensure a 4th node can join later, with same launch params.
n3 = Node(RQLITED_PATH, '4', boostrap_expect=3)
n3.start(join=','.join([n0.APIProtoAddr(), n1.APIProtoAddr(), n2.APIProtoAddr()]))
n3.wait_for_leader()
self.assertEqual(n3.wait_for_leader(), n0.wait_for_leader())
deprovision_node(n0)
deprovision_node(n1)
deprovision_node(n2)
deprovision_node(n3)
class TestAutoClustering(unittest.TestCase):
DiscoModeConsulKV = "consul-kv"
DiscoModeEtcdKV = "etcd-kv"
def autocluster(self, mode):
disco_key = random_string(10)
n0 = Node(RQLITED_PATH, '0')
n0.start(disco_mode=mode, disco_key=disco_key)
n0.wait_for_leader()
self.assertEqual(n0.disco_mode(), mode)
j = n0.execute('CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)')
self.assertEqual(j, d_("{'results': [{}]}"))
j = n0.execute('INSERT INTO foo(name) VALUES("fiona")')
n0.wait_for_all_fsm()
j = n0.query('SELECT * FROM foo')
self.assertEqual(j, d_("{'results': [{'values': [[1, 'fiona']], 'types': ['integer', 'text'], 'columns': ['id', 'name']}]}"))
# Add second node, make sure it joins the cluster fine.
n1 = Node(RQLITED_PATH, '1')
n1.start(disco_mode=mode, disco_key=disco_key)
n1.wait_for_leader()
self.assertEqual(n1.disco_mode(), mode)
j = n1.query('SELECT * FROM foo', level='none')
self.assertEqual(j, d_("{'results': [{'values': [[1, 'fiona']], 'types': ['integer', 'text'], 'columns': ['id', 'name']}]}"))
# Now a third.
n2 = Node(RQLITED_PATH, '2')
n2.start(disco_mode=mode, disco_key=disco_key)
n2.wait_for_leader()
self.assertEqual(n2.disco_mode(), mode)
j = n2.query('SELECT * FROM foo', level='none')
self.assertEqual(j, d_("{'results': [{'values': [[1, 'fiona']], 'types': ['integer', 'text'], 'columns': ['id', 'name']}]}"))
# Now, kill the leader, which should trigger a different node to report leadership.
deprovision_node(n0)
# Add a fourth node, it should join fine using updated leadership details.
# Use quick retries, as we know the leader information may be changing while
# the node is coming up.
n3 = Node(RQLITED_PATH, '3')
n3.start(disco_mode=mode, disco_key=disco_key, join_interval='1s', join_attempts=1)
n3.wait_for_leader()
self.assertEqual(n3.disco_mode(), mode)
j = n3.query('SELECT * FROM foo', level='none')
self.assertEqual(j, d_("{'results': [{'values': [[1, 'fiona']], 'types': ['integer', 'text'], 'columns': ['id', 'name']}]}"))
deprovision_node(n1)
deprovision_node(n2)
deprovision_node(n3)
def autocluster_config(self, mode, config):
disco_key = random_string(10)
n0 = Node(RQLITED_PATH, '0')
n0.start(disco_mode=mode, disco_key=disco_key, disco_config=config)
n0.wait_for_leader()
self.assertEqual(n0.disco_mode(), mode)
j = n0.execute('CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)')
self.assertEqual(j, d_("{'results': [{}]}"))
j = n0.execute('INSERT INTO foo(name) VALUES("fiona")')
n0.wait_for_all_fsm()
j = n0.query('SELECT * FROM foo')
self.assertEqual(j, d_("{'results': [{'values': [[1, 'fiona']], 'types': ['integer', 'text'], 'columns': ['id', 'name']}]}"))
# Add second node, make sure it joins the cluster fine.
n1 = Node(RQLITED_PATH, '1')
n1.start(disco_mode=mode, disco_key=disco_key, disco_config=config)
n1.wait_for_leader()
self.assertEqual(n1.disco_mode(), mode)
j = n1.query('SELECT * FROM foo', level='none')
self.assertEqual(j, d_("{'results': [{'values': [[1, 'fiona']], 'types': ['integer', 'text'], 'columns': ['id', 'name']}]}"))
deprovision_node(n0)
deprovision_node(n1)
def test_consul(self):
'''Test clustering via Consul and that leadership change is observed'''
self.autocluster(TestAutoClustering.DiscoModeConsulKV)
def test_etcd(self):
'''Test clustering via Etcd and that leadership change is observed'''
self.autocluster(TestAutoClustering.DiscoModeEtcdKV)
def test_consul_config(self):
'''Test clustering via Consul with explicit file-based config'''
filename = write_random_file('{"address": "localhost:8500"}')
self.autocluster_config(TestAutoClustering.DiscoModeConsulKV, filename)
os.remove(filename)
def test_etcd_config(self):
'''Test clustering via Etcd with explicit file-based config'''
filename = write_random_file('{"endpoints": ["localhost:2379"]}')
self.autocluster_config(TestAutoClustering.DiscoModeEtcdKV, filename)
os.remove(filename)
class TestClusterRecovery(unittest.TestCase):
'''Test that a cluster can recover after all Raft network addresses change'''
def test(self):

Loading…
Cancel
Save