blob: 7f55229911e87f7a17785e4e30e05d517696e57b [file]
# Copyright DataStax, Inc.
#
# 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 re
from cassandra import OperationTimedOut, InvalidRequest
from cassandra.protocol import SyntaxException
from cassandra.policies import WhiteListRoundRobinPolicy
from cassandra.cluster import NoHostAvailable
from cassandra.cluster import EXEC_PROFILE_GRAPH_DEFAULT, GraphExecutionProfile
from cassandra.graph import single_object_row_factory, Vertex, graph_object_row_factory, \
graph_graphson2_row_factory, graph_graphson3_row_factory
from cassandra.util import SortedSet
from tests.integration import DSE_VERSION, greaterthanorequaldse51, greaterthanorequaldse68, \
requiredse, TestCluster
from tests.integration.advanced.graph import BasicGraphUnitTestCase, GraphUnitTestCase, \
GraphProtocol, ClassicGraphSchema, CoreGraphSchema, use_single_node_with_graph
def setup_module():
if DSE_VERSION:
dse_options = {'graph': {'realtime_evaluation_timeout_in_seconds': 60}}
use_single_node_with_graph(dse_options=dse_options)
@requiredse
class GraphTimeoutTests(BasicGraphUnitTestCase):
def test_should_wait_indefinitely_by_default(self):
"""
Tests that by default the client should wait indefinitely for server timeouts
@since 1.0.0
@jira_ticket PYTHON-589
@test_category dse graph
"""
desired_timeout = 1000
graph_source = "test_timeout_1"
ep_name = graph_source
ep = self.session.execution_profile_clone_update(EXEC_PROFILE_GRAPH_DEFAULT)
ep.graph_options = ep.graph_options.copy()
ep.graph_options.graph_source = graph_source
self.cluster.add_execution_profile(ep_name, ep)
to_run = '''graph.schema().config().option("graph.traversal_sources.{0}.evaluation_timeout").set('{1} ms')'''.format(
graph_source, desired_timeout)
self.session.execute_graph(to_run, execution_profile=ep_name)
with self.assertRaises(InvalidRequest) as ir:
self.session.execute_graph("java.util.concurrent.TimeUnit.MILLISECONDS.sleep(35000L);1+1",
execution_profile=ep_name)
self.assertTrue("evaluation exceeded the configured threshold of 1000" in str(ir.exception) or
"evaluation exceeded the configured threshold of evaluation_timeout at 1000" in str(
ir.exception))
def test_request_timeout_less_then_server(self):
"""
Tests that with explicit request_timeouts set, that a server timeout is honored if it's relieved prior to the
client timeout
@since 1.0.0
@jira_ticket PYTHON-589
@test_category dse graph
"""
desired_timeout = 1000
graph_source = "test_timeout_2"
ep_name = graph_source
ep = self.session.execution_profile_clone_update(EXEC_PROFILE_GRAPH_DEFAULT, request_timeout=32)
ep.graph_options = ep.graph_options.copy()
ep.graph_options.graph_source = graph_source
self.cluster.add_execution_profile(ep_name, ep)
to_run = '''graph.schema().config().option("graph.traversal_sources.{0}.evaluation_timeout").set('{1} ms')'''.format(
graph_source, desired_timeout)
self.session.execute_graph(to_run, execution_profile=ep_name)
with self.assertRaises(InvalidRequest) as ir:
self.session.execute_graph("java.util.concurrent.TimeUnit.MILLISECONDS.sleep(35000L);1+1",
execution_profile=ep_name)
self.assertTrue("evaluation exceeded the configured threshold of 1000" in str(ir.exception) or
"evaluation exceeded the configured threshold of evaluation_timeout at 1000" in str(
ir.exception))
def test_server_timeout_less_then_request(self):
"""
Tests that with explicit request_timeouts set, that a client timeout is honored if it's triggered prior to the
server sending a timeout.
@since 1.0.0
@jira_ticket PYTHON-589
@test_category dse graph
"""
graph_source = "test_timeout_3"
ep_name = graph_source
ep = self.session.execution_profile_clone_update(EXEC_PROFILE_GRAPH_DEFAULT, request_timeout=1)
ep.graph_options = ep.graph_options.copy()
ep.graph_options.graph_source = graph_source
self.cluster.add_execution_profile(ep_name, ep)
server_timeout = 10000
to_run = '''graph.schema().config().option("graph.traversal_sources.{0}.evaluation_timeout").set('{1} ms')'''.format(
graph_source, server_timeout)
self.session.execute_graph(to_run, execution_profile=ep_name)
with self.assertRaises(Exception) as e:
self.session.execute_graph("java.util.concurrent.TimeUnit.MILLISECONDS.sleep(35000L);1+1",
execution_profile=ep_name)
self.assertTrue(isinstance(e, InvalidRequest) or isinstance(e, OperationTimedOut))
@requiredse
class GraphProfileTests(BasicGraphUnitTestCase):
def test_graph_profile(self):
"""
Test verifying various aspects of graph config properties.
@since 1.0.0
@jira_ticket PYTHON-570
@test_category dse graph
"""
hosts = self.cluster.metadata.all_hosts()
first_host = hosts[0].address
second_hosts = "1.2.3.4"
self._execute(ClassicGraphSchema.fixtures.classic(), graphson=GraphProtocol.GRAPHSON_1_0)
# Create various execution policies
exec_dif_factory = GraphExecutionProfile(row_factory=single_object_row_factory)
exec_dif_factory.graph_options.graph_name = self.graph_name
exec_dif_lbp = GraphExecutionProfile(load_balancing_policy=WhiteListRoundRobinPolicy([first_host]))
exec_dif_lbp.graph_options.graph_name = self.graph_name
exec_bad_lbp = GraphExecutionProfile(load_balancing_policy=WhiteListRoundRobinPolicy([second_hosts]))
exec_dif_lbp.graph_options.graph_name = self.graph_name
exec_short_timeout = GraphExecutionProfile(request_timeout=1,
load_balancing_policy=WhiteListRoundRobinPolicy([first_host]))
exec_short_timeout.graph_options.graph_name = self.graph_name
# Add a single execution policy on cluster creation
local_cluster = TestCluster(execution_profiles={"exec_dif_factory": exec_dif_factory})
local_session = local_cluster.connect()
self.addCleanup(local_cluster.shutdown)
rs1 = self.session.execute_graph('g.V()')
rs2 = local_session.execute_graph('g.V()', execution_profile='exec_dif_factory')
# Verify default and non default policy works
self.assertFalse(isinstance(rs2[0], Vertex))
self.assertTrue(isinstance(rs1[0], Vertex))
# Add other policies validate that lbp are honored
local_cluster.add_execution_profile("exec_dif_ldp", exec_dif_lbp)
local_session.execute_graph('g.V()', execution_profile="exec_dif_ldp")
local_cluster.add_execution_profile("exec_bad_lbp", exec_bad_lbp)
with self.assertRaises(NoHostAvailable):
local_session.execute_graph('g.V()', execution_profile="exec_bad_lbp")
# Try with missing EP
with self.assertRaises(ValueError):
local_session.execute_graph('g.V()', execution_profile='bad_exec_profile')
# Validate that timeout is honored
local_cluster.add_execution_profile("exec_short_timeout", exec_short_timeout)
with self.assertRaises(Exception) as e:
self.assertTrue(isinstance(e, InvalidRequest) or isinstance(e, OperationTimedOut))
local_session.execute_graph('java.util.concurrent.TimeUnit.MILLISECONDS.sleep(2000L);',
execution_profile='exec_short_timeout')
@requiredse
class GraphMetadataTest(BasicGraphUnitTestCase):
@greaterthanorequaldse51
def test_dse_workloads(self):
"""
Test to ensure dse_workloads is populated appropriately.
Field added in DSE 5.1
@since DSE 2.0
@jira_ticket PYTHON-667
@expected_result dse_workloads set is set on host model
@test_category metadata
"""
for host in self.cluster.metadata.all_hosts():
self.assertIsInstance(host.dse_workloads, SortedSet)
self.assertIn("Cassandra", host.dse_workloads)
self.assertIn("Graph", host.dse_workloads)
@requiredse
class GraphExecutionProfileOptionsResolveTest(GraphUnitTestCase):
"""
Test that the execution profile options are properly resolved for graph queries.
@since DSE 6.8
@jira_ticket PYTHON-1004 PYTHON-1056
@expected_result execution profile options are properly determined following the rules.
"""
def test_default_options(self):
ep = self.session.get_execution_profile(EXEC_PROFILE_GRAPH_DEFAULT)
self.assertEqual(ep.graph_options.graph_protocol, None)
self.assertEqual(ep.row_factory, None)
self.session._resolve_execution_profile_options(ep)
self.assertEqual(ep.graph_options.graph_protocol, GraphProtocol.GRAPHSON_1_0)
self.assertEqual(ep.row_factory, graph_object_row_factory)
def test_default_options_when_not_groovy(self):
ep = self.session.get_execution_profile(EXEC_PROFILE_GRAPH_DEFAULT)
self.assertEqual(ep.graph_options.graph_protocol, None)
self.assertEqual(ep.row_factory, None)
ep.graph_options.graph_language = 'whatever'
self.session._resolve_execution_profile_options(ep)
self.assertEqual(ep.graph_options.graph_protocol, GraphProtocol.GRAPHSON_2_0)
self.assertEqual(ep.row_factory, graph_graphson2_row_factory)
def test_default_options_when_explicitly_specified(self):
ep = self.session.get_execution_profile(EXEC_PROFILE_GRAPH_DEFAULT)
self.assertEqual(ep.graph_options.graph_protocol, None)
self.assertEqual(ep.row_factory, None)
obj = object()
ep.graph_options.graph_protocol = obj
ep.row_factory = obj
self.session._resolve_execution_profile_options(ep)
self.assertEqual(ep.graph_options.graph_protocol, obj)
self.assertEqual(ep.row_factory, obj)
@greaterthanorequaldse68
def test_graph_protocol_default_for_core_is_graphson3(self):
"""Test that graphson3 is automatically resolved for a core graph query"""
self.setup_graph(CoreGraphSchema)
ep = self.session.get_execution_profile(EXEC_PROFILE_GRAPH_DEFAULT)
self.assertEqual(ep.graph_options.graph_protocol, None)
self.assertEqual(ep.row_factory, None)
# Ensure we have the graph metadata
self.session.cluster.refresh_schema_metadata()
self.session._resolve_execution_profile_options(ep)
self.assertEqual(ep.graph_options.graph_protocol, GraphProtocol.GRAPHSON_3_0)
self.assertEqual(ep.row_factory, graph_graphson3_row_factory)
self.execute_graph_queries(CoreGraphSchema.fixtures.classic(), verify_graphson=GraphProtocol.GRAPHSON_3_0)
@greaterthanorequaldse68
def test_graph_protocol_default_for_core_fallback_to_graphson1_if_no_graph_name(self):
"""Test that graphson1 is set when we cannot detect if it's a core graph"""
self.setup_graph(CoreGraphSchema)
default_ep = self.session.get_execution_profile(EXEC_PROFILE_GRAPH_DEFAULT)
graph_options = default_ep.graph_options.copy()
graph_options.graph_name = None
ep = self.session.execution_profile_clone_update(EXEC_PROFILE_GRAPH_DEFAULT, graph_options=graph_options)
self.session._resolve_execution_profile_options(ep)
self.assertEqual(ep.graph_options.graph_protocol, GraphProtocol.GRAPHSON_1_0)
self.assertEqual(ep.row_factory, graph_object_row_factory)
regex = re.compile(".*Variable.*is unknown.*", re.S)
with self.assertRaisesRegex(SyntaxException, regex):
self.execute_graph_queries(CoreGraphSchema.fixtures.classic(),
execution_profile=ep, verify_graphson=GraphProtocol.GRAPHSON_1_0)