chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
from copy import deepcopy
|
||||
|
||||
import pytest
|
||||
|
||||
from scrapegraphai.graphs.csv_scraper_multi_graph import CSVScraperMultiGraph
|
||||
|
||||
# Monkey-patch _create_llm to avoid unsupported provider error during tests
|
||||
CSVScraperMultiGraph._create_llm = lambda self, llm_config: llm_config
|
||||
|
||||
|
||||
# Dummy graph classes to simulate behavior during tests
|
||||
class DummyGraph:
|
||||
"""Dummy graph that returns a predefined answer."""
|
||||
|
||||
def __init__(self, answer):
|
||||
self.answer = answer
|
||||
|
||||
def execute(self, inputs):
|
||||
# Returns a tuple of (final_state, execution_info)
|
||||
return ({"answer": self.answer}, {})
|
||||
|
||||
|
||||
class DummyGraphNoAnswer:
|
||||
"""Dummy graph that simulates absence of answer in final_state."""
|
||||
|
||||
def execute(self, inputs):
|
||||
# Returns an empty final_state
|
||||
return ({}, {})
|
||||
|
||||
|
||||
class DummyBaseGraph:
|
||||
"""Dummy BaseGraph to test _create_graph method without side effects."""
|
||||
|
||||
def __init__(self, nodes, edges, entry_point, graph_name):
|
||||
self.nodes = nodes
|
||||
self.edges = edges
|
||||
self.entry_point = entry_point
|
||||
self.graph_name = graph_name
|
||||
|
||||
config = {
|
||||
"llm": {"model": "dummy_model", "model_provider": "dummy_provider"},
|
||||
"key": "value",
|
||||
}
|
||||
"""Test that CSVScraperMultiGraph.run returns the expected answer when provided by the graph."""
|
||||
prompt = "Test prompt"
|
||||
source = ["url1", "url2"]
|
||||
|
||||
# Instantiate the graph
|
||||
multi_graph = CSVScraperMultiGraph(prompt, source, config)
|
||||
|
||||
# Override the graph attribute with a dummy graph returning an expected answer
|
||||
multi_graph.graph = DummyGraph("expected answer")
|
||||
|
||||
result = multi_graph.run()
|
||||
assert result == "expected answer"
|
||||
|
||||
|
||||
def test_run_no_answer():
|
||||
"""Test that CSVScraperMultiGraph.run returns a fallback message when no answer is provided."""
|
||||
prompt = "Another test prompt"
|
||||
source = ["url3"]
|
||||
config = {
|
||||
"llm": {"model": "dummy_model", "model_provider": "dummy_provider"},
|
||||
"another_key": "another_value",
|
||||
}
|
||||
|
||||
multi_graph = CSVScraperMultiGraph(prompt, source, config)
|
||||
multi_graph.graph = DummyGraphNoAnswer()
|
||||
|
||||
result = multi_graph.run()
|
||||
assert result == "No answer found."
|
||||
|
||||
|
||||
def test_create_graph_structure(monkeypatch):
|
||||
"""Test that _create_graph constructs a graph with the expected structure."""
|
||||
prompt = "Structure test"
|
||||
source = ["url4"]
|
||||
config = {
|
||||
"llm": {"model": "dummy_model", "model_provider": "dummy_provider"},
|
||||
"struct_key": "struct_value",
|
||||
}
|
||||
|
||||
multi_graph = CSVScraperMultiGraph(prompt, source, config)
|
||||
|
||||
# Monkey-patch the _create_graph method to avoid dependencies on external nodes
|
||||
monkeypatch.setattr(
|
||||
multi_graph,
|
||||
"_create_graph",
|
||||
lambda: DummyBaseGraph(
|
||||
nodes=["graph_iterator_node", "merge_answers_node"],
|
||||
edges=[("graph_iterator_node", "merge_answers_node")],
|
||||
entry_point="graph_iterator_node",
|
||||
graph_name=multi_graph.__class__.__name__,
|
||||
),
|
||||
)
|
||||
|
||||
graph = multi_graph._create_graph()
|
||||
assert graph.graph_name == "CSVScraperMultiGraph"
|
||||
assert len(graph.nodes) == 2
|
||||
assert len(graph.edges) == 1
|
||||
|
||||
|
||||
def test_config_deepcopy():
|
||||
"""Test that the configuration dictionary is deep-copied.
|
||||
Modifying the original config after instantiation should not affect the multi_graph copy.
|
||||
"""
|
||||
config = {
|
||||
"llm": {"model": "dummy_model", "provider": "provider1"},
|
||||
"nested": {"a": [1, 2]},
|
||||
}
|
||||
original_config = deepcopy(config)
|
||||
multi_graph = CSVScraperMultiGraph("Deep copy test", ["url_deep"], config)
|
||||
# Modify the original config after instantiation
|
||||
config["nested"]["a"].append(3)
|
||||
# The multi_graph.copy_config should remain unchanged.
|
||||
assert multi_graph.copy_config["nested"]["a"] == original_config["nested"]["a"]
|
||||
|
||||
|
||||
def test_run_argument_passing():
|
||||
"""Test that CSVScraperMultiGraph.run passes the correct input arguments
|
||||
to the graph's execute method and returns the expected answer."""
|
||||
|
||||
class DummyGraphCapture:
|
||||
def __init__(self):
|
||||
self.captured_inputs = None
|
||||
|
||||
def execute(self, inputs):
|
||||
self.captured_inputs = inputs
|
||||
return ({"answer": "captured answer"}, {})
|
||||
|
||||
prompt = "Argument test prompt"
|
||||
source = ["url_arg1", "url_arg2"]
|
||||
config = {"llm": {"model": "dummy_model", "provider": "dummy_provider"}}
|
||||
|
||||
multi_graph = CSVScraperMultiGraph(prompt, source, config)
|
||||
dummy_graph = DummyGraphCapture()
|
||||
multi_graph.graph = dummy_graph
|
||||
|
||||
result = multi_graph.run()
|
||||
# Check that the dummy graph captured the inputs as expected
|
||||
expected_inputs = {"user_prompt": prompt, "jsons": source}
|
||||
assert dummy_graph.captured_inputs == expected_inputs
|
||||
assert result == "captured answer"
|
||||
|
||||
|
||||
def test_run_with_exception_in_execute():
|
||||
"""Test that CSVScraperMultiGraph.run propagates exceptions from the graph's execute method."""
|
||||
|
||||
class DummyGraphException:
|
||||
def execute(self, inputs):
|
||||
raise Exception("Test exception")
|
||||
|
||||
prompt = "Exception test prompt"
|
||||
source = ["url_exception"]
|
||||
config = {"llm": {"model": "dummy_model", "provider": "dummy_provider"}}
|
||||
|
||||
multi_graph = CSVScraperMultiGraph(prompt, source, config)
|
||||
multi_graph.graph = DummyGraphException()
|
||||
|
||||
with pytest.raises(Exception, match="Test exception"):
|
||||
multi_graph.run()
|
||||
Reference in New Issue
Block a user