Add tests for swift-ring-builder
Add some tests for essential methods in swift-ring-builder. Tests for removing or changing device settings are executed with different search values to cover many possible command line arguments. Currently tested methods: - create ring - add device - remove device - set weight - set info - set min_part_hours - set replicas Tests use swift.common.ring.RingBuilder to verify actions. Catching and testing output from print statements is not tested, because this requires redirecting sys.stdout during tests and that might have some sideeffects for testing tools. bin/swift-ring-builder has been moved to swift/cli/ringbuilder.py and slightly modified to work as before (mainly due to no more existing global variables since that part of the code has been moved inside a main() function). Change-Id: Ia63f59a8faca1fad990784f27532ca07a2125454
This commit is contained in:
parent
b1cacf4c93
commit
24657b2b39
@ -53,7 +53,6 @@ scripts =
|
||||
bin/swift-orphans
|
||||
bin/swift-proxy-server
|
||||
bin/swift-recon-cron
|
||||
bin/swift-ring-builder
|
||||
bin/swift-temp-url
|
||||
|
||||
[entry_points]
|
||||
@ -90,6 +89,7 @@ paste.filter_factory =
|
||||
|
||||
console_scripts =
|
||||
swift-recon = swift.cli.recon:main
|
||||
swift-ring-builder = swift.cli.ringbuilder:main
|
||||
|
||||
[build_sphinx]
|
||||
all_files = 1
|
||||
|
@ -20,7 +20,7 @@ from itertools import islice, izip
|
||||
from math import ceil
|
||||
from os import mkdir
|
||||
from os.path import basename, abspath, dirname, exists, join as pathjoin
|
||||
from sys import argv, exit, stderr
|
||||
from sys import argv as sys_argv, exit, stderr
|
||||
from textwrap import wrap
|
||||
from time import time
|
||||
|
||||
@ -37,6 +37,9 @@ EXIT_SUCCESS = 0
|
||||
EXIT_WARNING = 1
|
||||
EXIT_ERROR = 2
|
||||
|
||||
global argv, backup_dir, builder, builder_file, ring_file
|
||||
argv = backup_dir = builder = builder_file = ring_file = None
|
||||
|
||||
|
||||
def format_device(dev):
|
||||
"""
|
||||
@ -796,7 +799,14 @@ swift-ring-builder <builder_file> set_replicas <replicas>
|
||||
builder.save(argv[1])
|
||||
exit(EXIT_SUCCESS)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
def main(arguments=None):
|
||||
global argv, backup_dir, builder, builder_file, ring_file
|
||||
if arguments:
|
||||
argv = arguments
|
||||
else:
|
||||
argv = sys_argv
|
||||
|
||||
if len(argv) < 2:
|
||||
print "swift-ring-builder %(MAJOR_VERSION)s.%(MINOR_VERSION)s\n" % \
|
||||
globals()
|
||||
@ -846,3 +856,7 @@ if __name__ == '__main__':
|
||||
exit(2)
|
||||
else:
|
||||
Commands.__dict__.get(command, Commands.unknown.im_func)()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
204
test/unit/cli/test_ringbuilder.py
Normal file
204
test/unit/cli/test_ringbuilder.py
Normal file
@ -0,0 +1,204 @@
|
||||
# Copyright (c) 2014 Christian Schwede <christian.schwede@enovance.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import swift.cli.ringbuilder
|
||||
from swift.common.ring import RingBuilder
|
||||
|
||||
|
||||
class TestCommands(unittest.TestCase):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TestCommands, self).__init__(*args, **kwargs)
|
||||
|
||||
# List of search values for various actions
|
||||
# These should all match the first device in the sample ring
|
||||
# (see below) but not the second device
|
||||
self.search_values = ["d0", "/sda1", "r0", "z0", "z0-127.0.0.1",
|
||||
"127.0.0.1", "z0:6000", ":6000", "R127.0.0.1",
|
||||
"127.0.0.1R127.0.0.1", "R:6000",
|
||||
"_some meta data"]
|
||||
tmpf = tempfile.NamedTemporaryFile()
|
||||
self.tmpfile = tmpf.name
|
||||
|
||||
def tearDown(self):
|
||||
try:
|
||||
os.remove(self.tmpfile)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def create_sample_ring(self):
|
||||
""" Create a sample ring with two devices
|
||||
|
||||
At least two devices are needed to test removing
|
||||
a device, since removing the last device of a ring
|
||||
is not allowed """
|
||||
|
||||
# Ensure there is no existing test builder file because
|
||||
# create_sample_ring() might be used more than once in a single test
|
||||
try:
|
||||
os.remove(self.tmpfile)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
ring = RingBuilder(6, 3, 1)
|
||||
ring.add_dev({'weight': 100.0,
|
||||
'region': 0,
|
||||
'zone': 0,
|
||||
'ip': '127.0.0.1',
|
||||
'port': 6000,
|
||||
'device': 'sda1',
|
||||
'meta': 'some meta data',
|
||||
})
|
||||
ring.add_dev({'weight': 100.0,
|
||||
'region': 1,
|
||||
'zone': 1,
|
||||
'ip': '127.0.0.2',
|
||||
'port': 6001,
|
||||
'device': 'sda2'
|
||||
})
|
||||
ring.save(self.tmpfile)
|
||||
|
||||
def test_create_ring(self):
|
||||
argv = ["", self.tmpfile, "create", "6", "3.14159265359", "1"]
|
||||
self.assertRaises(SystemExit, swift.cli.ringbuilder.main, argv)
|
||||
ring = RingBuilder.load(self.tmpfile)
|
||||
self.assertEqual(ring.part_power, 6)
|
||||
self.assertEqual(ring.replicas, 3.14159265359)
|
||||
self.assertEqual(ring.min_part_hours, 1)
|
||||
|
||||
def test_add_device(self):
|
||||
self.create_sample_ring()
|
||||
argv = ["", self.tmpfile, "add",
|
||||
"r2z3-127.0.0.1:6000/sda3_some meta data", "3.14159265359"]
|
||||
self.assertRaises(SystemExit, swift.cli.ringbuilder.main, argv)
|
||||
|
||||
# Check that device was created with given data
|
||||
ring = RingBuilder.load(self.tmpfile)
|
||||
dev = [d for d in ring.devs if d['id'] == 2][0]
|
||||
self.assertEqual(dev['region'], 2)
|
||||
self.assertEqual(dev['zone'], 3)
|
||||
self.assertEqual(dev['ip'], '127.0.0.1')
|
||||
self.assertEqual(dev['port'], 6000)
|
||||
self.assertEqual(dev['device'], 'sda3')
|
||||
self.assertEqual(dev['weight'], 3.14159265359)
|
||||
self.assertEqual(dev['replication_ip'], '127.0.0.1')
|
||||
self.assertEqual(dev['replication_port'], 6000)
|
||||
self.assertEqual(dev['meta'], 'some meta data')
|
||||
|
||||
# Final check, rebalance and check ring is ok
|
||||
ring.rebalance()
|
||||
self.assertTrue(ring.validate())
|
||||
|
||||
def test_remove_device(self):
|
||||
for search_value in self.search_values:
|
||||
self.create_sample_ring()
|
||||
argv = ["", self.tmpfile, "remove", search_value]
|
||||
self.assertRaises(SystemExit, swift.cli.ringbuilder.main, argv)
|
||||
ring = RingBuilder.load(self.tmpfile)
|
||||
|
||||
# Check that weight was set to 0
|
||||
dev = [d for d in ring.devs if d['id'] == 0][0]
|
||||
self.assertEqual(dev['weight'], 0)
|
||||
|
||||
# Check that device is in list of devices to be removed
|
||||
dev = [d for d in ring._remove_devs if d['id'] == 0][0]
|
||||
self.assertEqual(dev['region'], 0)
|
||||
self.assertEqual(dev['zone'], 0)
|
||||
self.assertEqual(dev['ip'], '127.0.0.1')
|
||||
self.assertEqual(dev['port'], 6000)
|
||||
self.assertEqual(dev['device'], 'sda1')
|
||||
self.assertEqual(dev['weight'], 0)
|
||||
self.assertEqual(dev['replication_ip'], '127.0.0.1')
|
||||
self.assertEqual(dev['replication_port'], 6000)
|
||||
self.assertEqual(dev['meta'], 'some meta data')
|
||||
|
||||
# Check that second device in ring is not affected
|
||||
dev = [d for d in ring.devs if d['id'] == 1][0]
|
||||
self.assertEqual(dev['weight'], 100)
|
||||
self.assertFalse([d for d in ring._remove_devs if d['id'] == 1])
|
||||
|
||||
# Final check, rebalance and check ring is ok
|
||||
ring.rebalance()
|
||||
self.assertTrue(ring.validate())
|
||||
|
||||
def test_set_weight(self):
|
||||
for search_value in self.search_values:
|
||||
self.create_sample_ring()
|
||||
|
||||
argv = ["", self.tmpfile, "set_weight",
|
||||
search_value, "3.14159265359"]
|
||||
self.assertRaises(SystemExit, swift.cli.ringbuilder.main, argv)
|
||||
ring = RingBuilder.load(self.tmpfile)
|
||||
|
||||
# Check that weight was changed
|
||||
dev = [d for d in ring.devs if d['id'] == 0][0]
|
||||
self.assertEqual(dev['weight'], 3.14159265359)
|
||||
|
||||
# Check that second device in ring is not affected
|
||||
dev = [d for d in ring.devs if d['id'] == 1][0]
|
||||
self.assertEqual(dev['weight'], 100)
|
||||
|
||||
# Final check, rebalance and check ring is ok
|
||||
ring.rebalance()
|
||||
self.assertTrue(ring.validate())
|
||||
|
||||
def test_set_info(self):
|
||||
for search_value in self.search_values:
|
||||
|
||||
self.create_sample_ring()
|
||||
argv = ["", self.tmpfile, "set_info", search_value,
|
||||
"127.0.1.1:8000/sda1_other meta data"]
|
||||
self.assertRaises(SystemExit, swift.cli.ringbuilder.main, argv)
|
||||
|
||||
# Check that device was created with given data
|
||||
ring = RingBuilder.load(self.tmpfile)
|
||||
dev = [d for d in ring.devs if d['id'] == 0][0]
|
||||
self.assertEqual(dev['ip'], '127.0.1.1')
|
||||
self.assertEqual(dev['port'], 8000)
|
||||
self.assertEqual(dev['device'], 'sda1')
|
||||
self.assertEqual(dev['meta'], 'other meta data')
|
||||
|
||||
# Check that second device in ring is not affected
|
||||
dev = [d for d in ring.devs if d['id'] == 1][0]
|
||||
self.assertEqual(dev['ip'], '127.0.0.2')
|
||||
self.assertEqual(dev['port'], 6001)
|
||||
self.assertEqual(dev['device'], 'sda2')
|
||||
self.assertEqual(dev['meta'], '')
|
||||
|
||||
# Final check, rebalance and check ring is ok
|
||||
ring.rebalance()
|
||||
self.assertTrue(ring.validate())
|
||||
|
||||
def test_set_min_part_hours(self):
|
||||
self.create_sample_ring()
|
||||
argv = ["", self.tmpfile, "set_min_part_hours", "24"]
|
||||
self.assertRaises(SystemExit, swift.cli.ringbuilder.main, argv)
|
||||
ring = RingBuilder.load(self.tmpfile)
|
||||
self.assertEqual(ring.min_part_hours, 24)
|
||||
|
||||
def test_set_replicas(self):
|
||||
self.create_sample_ring()
|
||||
argv = ["", self.tmpfile, "set_replicas", "3.14159265359"]
|
||||
self.assertRaises(SystemExit, swift.cli.ringbuilder.main, argv)
|
||||
ring = RingBuilder.load(self.tmpfile)
|
||||
self.assertEqual(ring.replicas, 3.14159265359)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
Reference in New Issue
Block a user