def test_slice_with_string_empty_slice(self): for ii in range(len(self.sequence)): sliced = CurieUtil.slice_with_string(self.sequence, "%d:%d" % (ii, ii)) self.assertEqual(sliced.values(), []) self.assertEqual(sliced.keys(), []) # Consistency with python built-in slice behavior allowing empty # out-of-bounds slices. out_of_bounds = len(self.sequence) + 10 sliced = CurieUtil.slice_with_string( self.sequence, "%d:%d" % (out_of_bounds, out_of_bounds)) self.assertEqual(sliced.values(), []) self.assertEqual(sliced.keys(), [])
def verify(self): # NB: This must reference metadata and *not* the actual 'CurieNode' # instances to avoid blocking queries to Prism on AHV. node_vec = self.scenario.cluster.metadata().cluster_nodes try: CurieUtil.slice_with_string(node_vec, self.nodes_slice_str) except IndexError: raise CurieTestException( cause="Node slice '%s' is out of bounds." % self.nodes_slice_str, impact= "The scenario '%s' can not be used with cluster '%s' because the %s " "step refers to one or more nodes by an index that is either larger " "or smaller than the number of nodes in the cluster (%d)." % (self.scenario.display_name, self.scenario.cluster.name(), self.name, len(node_vec)), corrective_action= "Please retry the scenario using a cluster with a compatible number " "of nodes. If you are the author of the scenario, please check the " "syntax of the %s step to make it compatible with clusters of this " "size." % self.name) except ValueError as exc: raise CurieTestException( cause="Syntax error for node slice '%s': %s" % (self.nodes_slice_str, exc), impact="The scenario '%s' can not be used." % self.scenario.display_name, corrective_action= "Please check the syntax of the %s step. Python-flavored slice " "strings are accepted. Additionally, several slice strings can be " "combined using commas. The word 'all' can be used to refer to all " "nodes, and the letter 'n' can refer to the number of nodes in the " "cluster. Arithmetic operations are also supported using the +, -, *, " "and / operators. For example, the following strings are valid:\n" " '0' # The first node.\n" " '0, 1' # The first two nodes.\n" " '0:2' # The first two nodes.\n" " '0:2, n-2:n' # The first two nodes and the last two nodes.\n" " ':2, n-2:' # The first two nodes and the last two nodes.\n" " ':n/2' # The first half of the nodes.\n" " 'n/2:' # The last half of the nodes.\n" " 'all' # All nodes." % self.name)
def get_nodes(scenario, slice_string): """Get a list of CurieClusterNodes for a given node index slice string. Args: scenario (Scenario): Scenario that owns the node. slice_string (str): String containing indices of the desired nodes. Returns: (list): CurieClusterNodes in an order matching that specified by 'slice_string' . Raises: CurieTestException: If slice_string is out of bounds. """ nodes = scenario.cluster.nodes() try: return CurieUtil.slice_with_string(nodes, slice_string).values() except IndexError as err: raise CurieTestException( "Node slice is out of bounds (cluster contains %d nodes): %s" % (len(nodes), err))
def test_slice_with_string_negative_range_converted_to_positive(self): sliced = CurieUtil.slice_with_string(self.sequence, ":-3") self.assertEqual(sliced.values(), ["item_0", "item_1", "item_2"]) self.assertEqual(sliced.keys(), [0, 1, 2])
def test_slice_with_string_negative_indices_converted_to_positive(self): sliced = CurieUtil.slice_with_string(self.sequence, "-1, -2") self.assertEqual(sliced.values(), ["item_5", "item_4"]) self.assertEqual(sliced.keys(), [5, 4])
def test_slice_with_string_three_indices_mixed_order(self): sliced = CurieUtil.slice_with_string(self.sequence, "4, 1, 3") self.assertEqual(sliced.values(), ["item_4", "item_1", "item_3"]) self.assertEqual(sliced.keys(), [4, 1, 3])
def test_slice_with_string_mixed_range_reverse(self): sliced = CurieUtil.slice_with_string(self.sequence, "4, 1:3") self.assertEqual(sliced.values(), ["item_4", "item_1", "item_2"]) self.assertEqual(sliced.keys(), [4, 1, 2])
def test_slice_with_string_mixed_range(self): sliced = CurieUtil.slice_with_string(self.sequence, "1:3, 4") self.assertEqual(sliced.values(), ["item_1", "item_2", "item_4"]) self.assertEqual(sliced.keys(), [1, 2, 4])
def node_metadatas(self): return CurieUtil.slice_with_string( self.scenario.cluster.metadata().cluster_nodes, self.nodes_slice_str).items()
def test_slice_with_string_single_index_out_of_bounds_max(self): with self.assertRaises(IndexError): CurieUtil.slice_with_string(self.sequence, "0, 6")
def test_slice_with_string_two_indices(self): sliced = CurieUtil.slice_with_string(self.sequence, "2, 4") self.assertEqual(sliced.values(), ["item_2", "item_4"]) self.assertEqual(sliced.keys(), [2, 4])
def test_slice_with_string_single(self): sliced = CurieUtil.slice_with_string(self.sequence, "2") self.assertEqual(sliced.values(), ["item_2"]) self.assertEqual(sliced.keys(), [2])
def test_slice_with_string_all(self): for text in ["all", ":"]: sliced = CurieUtil.slice_with_string(self.sequence, text) self.assertEqual(sliced.values(), self.sequence) self.assertEqual(sliced.keys(), range(6))
def test_slice_with_invalid_input(self): with self.assertRaises(ValueError): CurieUtil.slice_with_string(self.sequence, "(m/2)-1:") with self.assertRaises(ValueError): CurieUtil.slice_with_string( self.sequence, "import os; os.execv(\"/bin/ls\", [\".\"])")
def test_slice_with_n_start(self): sliced = CurieUtil.slice_with_string(self.sequence, "(n/2)-1:") self.assertEqual(sliced.values(), ["item_2", "item_3", "item_4", "item_5"]) self.assertEqual(sliced.keys(), [2, 3, 4, 5])
def test_slice_with_string_single_index_max(self): sliced = CurieUtil.slice_with_string(self.sequence, "5") self.assertEqual(sliced.values(), ["item_5"]) self.assertEqual(sliced.keys(), [5])
def test_slice_with_string_single_range_max(self): sliced = CurieUtil.slice_with_string(self.sequence, ":6") self.assertEqual(sliced.values(), self.sequence) self.assertEqual(sliced.keys(), range(6))
def test_slice_with_string_two_indices_reverse(self): sliced = CurieUtil.slice_with_string(self.sequence, "4, 2") self.assertEqual(sliced.values(), ["item_4", "item_2"]) self.assertEqual(sliced.keys(), [4, 2])
def test_slice_with_n_end(self): sliced = CurieUtil.slice_with_string(self.sequence, "1:(n/2)+1") self.assertEqual(sliced.values(), ["item_1", "item_2", "item_3"]) self.assertEqual(sliced.keys(), [1, 2, 3])
def test_slice_with_string_two_ranges(self): sliced = CurieUtil.slice_with_string(self.sequence, "1:3, 4:") self.assertEqual(sliced.values(), ["item_1", "item_2", "item_4", "item_5"]) self.assertEqual(sliced.keys(), [1, 2, 4, 5])