@@ -241,23 +241,78 @@ def test__run_query_dry_run_without_errors_is_silent():
241241 assert len (captured .stdout ) == 0
242242
243243
244- def test__get_graph_name ():
245- assert magics ._get_graph_name ("GRAPH foo.bar" ) == ("foo" , "bar" )
246- assert magics ._get_graph_name ("GRAPH `foo.bar`" ) is None
247- assert magics ._get_graph_name ("GRAPH `foo`.bar" ) is None
248- assert magics ._get_graph_name ("SELECT 1" ) is None
249-
250-
251244def test__get_graph_schema_exception ():
252245 bq_client = mock .create_autospec (bigquery .Client , instance = True )
253246 bq_client .query .side_effect = Exception ("error" )
254247 query_text = "GRAPH foo.bar"
255248 query_job = mock .Mock ()
256- query_job .configuration .destination .project = "my-project"
249+
250+ graph_ref = mock .Mock ()
251+ graph_ref .project = "my-project"
252+ graph_ref .dataset_id = "dataset"
253+ graph_ref .property_graph_id = "graph"
254+ query_job .referenced_property_graphs = [graph_ref ]
257255
258256 assert magics ._get_graph_schema (bq_client , query_text , query_job ) is None
259257
260258
259+ def test__get_graph_schema_zero_references ():
260+ bq_client = mock .create_autospec (bigquery .Client , instance = True )
261+ query_job = mock .Mock ()
262+ query_job .referenced_property_graphs = []
263+
264+ assert magics ._get_graph_schema (bq_client , "SELECT 1" , query_job ) is None
265+
266+
267+ def test__get_graph_schema_two_references ():
268+ bq_client = mock .create_autospec (bigquery .Client , instance = True )
269+ query_job = mock .Mock ()
270+
271+ ref1 = mock .Mock ()
272+ ref2 = mock .Mock ()
273+ query_job .referenced_property_graphs = [ref1 , ref2 ]
274+
275+ assert magics ._get_graph_schema (bq_client , "SELECT 1" , query_job ) is None
276+
277+
278+ def test__get_graph_schema_success ():
279+ bq_client = mock .create_autospec (bigquery .Client , instance = True )
280+ query_job = mock .Mock ()
281+
282+ graph_ref = mock .Mock ()
283+ graph_ref .project = "my-project"
284+ graph_ref .dataset_id = "dataset"
285+ graph_ref .property_graph_id = "graph"
286+ query_job .referenced_property_graphs = [graph_ref ]
287+
288+ mock_df = mock .MagicMock ()
289+ mock_df .shape = (1 , 1 )
290+ mock_df .iloc .__getitem__ .return_value = "schema_json"
291+ bq_client .query .return_value .to_dataframe .return_value = mock_df
292+
293+ with mock .patch (
294+ "bigquery_magics.bigquery.graph_server._convert_schema"
295+ ) as convert_mock :
296+ convert_mock .return_value = {"nodes" : [], "edges" : []}
297+
298+ result = magics ._get_graph_schema (bq_client , "SELECT 1" , query_job )
299+
300+ assert result == {"nodes" : [], "edges" : []}
301+ convert_mock .assert_called_once_with ("schema_json" )
302+
303+ called_query = bq_client .query .call_args [0 ][0 ]
304+ assert (
305+ "FROM `my-project.dataset`.INFORMATION_SCHEMA.PROPERTY_GRAPHS"
306+ in called_query
307+ )
308+
309+ called_config = bq_client .query .call_args [1 ]["job_config" ]
310+ called_params = called_config .query_parameters
311+ assert len (called_params ) == 1
312+ assert called_params [0 ].name == "graph_id"
313+ assert called_params [0 ].value == "graph"
314+
315+
261316@pytest .mark .skipif (
262317 bigquery_storage is None , reason = "Requires `google-cloud-bigquery-storage`"
263318)
@@ -417,6 +472,12 @@ def test_bigquery_magic_without_optional_arguments(monkeypatch):
417472 reason = "Requires `spanner-graph-notebook` to be missing and `google-cloud-bigquery-storage` to be present" ,
418473)
419474def test_bigquery_graph_spanner_graph_notebook_missing (monkeypatch ):
475+ """If `spanner-graph-notebook` is not installed, the graph visualizer
476+ widget cannot be displayed.
477+ """
478+ monkeypatch .setattr (
479+ "bigquery_magics.bigquery._get_graph_schema" , lambda * args : None
480+ )
420481 globalipapp .start_ipython ()
421482 ip = globalipapp .get_ipython ()
422483 ip .extension_manager .load_extension ("bigquery_magics" )
@@ -468,6 +529,10 @@ def test_bigquery_graph_spanner_graph_notebook_missing(monkeypatch):
468529 reason = "Requires `spanner-graph-notebook` and `google-cloud-bigquery-storage`" ,
469530)
470531def test_bigquery_graph_int_result (monkeypatch ):
532+ """Graph visualization of integer scalars is supported."""
533+ monkeypatch .setattr (
534+ "bigquery_magics.bigquery._get_graph_schema" , lambda * args : None
535+ )
471536 globalipapp .start_ipython ()
472537 ip = globalipapp .get_ipython ()
473538 ip .extension_manager .load_extension ("bigquery_magics" )
@@ -519,6 +584,10 @@ def test_bigquery_graph_int_result(monkeypatch):
519584 reason = "Requires `spanner-graph-notebook` and `google-cloud-bigquery-storage`" ,
520585)
521586def test_bigquery_graph_str_result (monkeypatch ):
587+ """Graph visualization of string scalars is supported."""
588+ monkeypatch .setattr (
589+ "bigquery_magics.bigquery._get_graph_schema" , lambda * args : None
590+ )
522591 globalipapp .start_ipython ()
523592 ip = globalipapp .get_ipython ()
524593 ip .extension_manager .load_extension ("bigquery_magics" )
@@ -570,6 +639,10 @@ def test_bigquery_graph_str_result(monkeypatch):
570639 reason = "Requires `spanner-graph-notebook` and `google-cloud-bigquery-storage`" ,
571640)
572641def test_bigquery_graph_json_json_result (monkeypatch ):
642+ """Graph visualization of JSON objects with valid JSON string fields is supported."""
643+ monkeypatch .setattr (
644+ "bigquery_magics.bigquery._get_graph_schema" , lambda * args : None
645+ )
573646 globalipapp .start_ipython ()
574647 ip = globalipapp .get_ipython ()
575648 ip .extension_manager .load_extension ("bigquery_magics" )
@@ -639,6 +712,9 @@ def test_bigquery_graph_json_json_result(monkeypatch):
639712 reason = "Requires `spanner-graph-notebook` and `google-cloud-bigquery-storage`" ,
640713)
641714def test_bigquery_graph_json_result (monkeypatch ):
715+ monkeypatch .setattr (
716+ "bigquery_magics.bigquery._get_graph_schema" , lambda * args : None
717+ )
642718 globalipapp .start_ipython ()
643719 ip = globalipapp .get_ipython ()
644720 ip .extension_manager .load_extension ("bigquery_magics" )
@@ -758,6 +834,9 @@ def test_bigquery_graph_json_result(monkeypatch):
758834 reason = "Requires `spanner-graph-notebook` and `google-cloud-bigquery-storage`" ,
759835)
760836def test_bigquery_graph_size_exceeds_max (monkeypatch ):
837+ monkeypatch .setattr (
838+ "bigquery_magics.bigquery._get_graph_schema" , lambda * args : None
839+ )
761840 globalipapp .start_ipython ()
762841 ip = globalipapp .get_ipython ()
763842 ip .extension_manager .load_extension ("bigquery_magics" )
@@ -813,6 +892,9 @@ def test_bigquery_graph_size_exceeds_max(monkeypatch):
813892 reason = "Requires `spanner-graph-notebook` and `google-cloud-bigquery-storage`" ,
814893)
815894def test_bigquery_graph_size_exceeds_query_result_max (monkeypatch ):
895+ monkeypatch .setattr (
896+ "bigquery_magics.bigquery._get_graph_schema" , lambda * args : None
897+ )
816898 globalipapp .start_ipython ()
817899 ip = globalipapp .get_ipython ()
818900 ip .extension_manager .load_extension ("bigquery_magics" )
@@ -869,6 +951,9 @@ def test_bigquery_graph_size_exceeds_query_result_max(monkeypatch):
869951 reason = "Requires `spanner-graph-notebook` and `google-cloud-bigquery-storage`" ,
870952)
871953def test_bigquery_graph_with_args_serialization (monkeypatch ):
954+ monkeypatch .setattr (
955+ "bigquery_magics.bigquery._get_graph_schema" , lambda * args : None
956+ )
872957 globalipapp .start_ipython ()
873958 ip = globalipapp .get_ipython ()
874959 ip .extension_manager .load_extension ("bigquery_magics" )
@@ -938,6 +1023,9 @@ def test_bigquery_graph_with_args_serialization(monkeypatch):
9381023 reason = "Requires `spanner-graph-notebook` and `google-cloud-bigquery-storage`" ,
9391024)
9401025def test_bigquery_graph_colab (monkeypatch ):
1026+ monkeypatch .setattr (
1027+ "bigquery_magics.bigquery._get_graph_schema" , lambda * args : None
1028+ )
9411029 # Mock the colab module so the code under test uses colab.register_callback(), rather than
9421030 # GraphServer.
9431031 sys .modules ["google.colab" ] = mock .Mock ()
@@ -1073,6 +1161,9 @@ def test_colab_node_expansion_callback():
10731161 reason = "Requires `spanner-graph-notebook` to be missing and `google-cloud-bigquery-storage` to be present" ,
10741162)
10751163def test_bigquery_graph_missing_spanner_deps (monkeypatch ):
1164+ monkeypatch .setattr (
1165+ "bigquery_magics.bigquery._get_graph_schema" , lambda * args : None
1166+ )
10761167 globalipapp .start_ipython ()
10771168 ip = globalipapp .get_ipython ()
10781169 ip .extension_manager .load_extension ("bigquery_magics" )
@@ -1142,11 +1233,17 @@ def test_add_graph_widget_with_schema(monkeypatch):
11421233 query_result = pandas .DataFrame ([{"id" : 1 }], columns = ["result" ])
11431234 query_text = "GRAPH my_dataset.my_graph"
11441235
1145- query_job = mock .create_autospec ( bigquery . job . QueryJob , instance = True )
1236+ query_job = mock .Mock ( )
11461237 query_job .configuration .destination .project = "p"
11471238 query_job .configuration .destination .dataset_id = "d"
11481239 query_job .configuration .destination .table_id = "t"
11491240
1241+ graph_ref = mock .Mock ()
1242+ graph_ref .project = "p"
1243+ graph_ref .dataset_id = "my_dataset"
1244+ graph_ref .property_graph_id = "my_graph"
1245+ query_job .referenced_property_graphs = [graph_ref ]
1246+
11501247 args = mock .Mock ()
11511248 args .bigquery_api_endpoint = "e"
11521249 args .project = "p"
@@ -1203,11 +1300,13 @@ def test_add_graph_widget_no_graph_name(monkeypatch):
12031300 query_result = pandas .DataFrame ([{"id" : 1 }], columns = ["result" ])
12041301 query_text = "SELECT * FROM my_dataset.my_table"
12051302
1206- query_job = mock .create_autospec ( bigquery . job . QueryJob , instance = True )
1303+ query_job = mock .Mock ( )
12071304 query_job .configuration .destination .project = "p"
12081305 query_job .configuration .destination .dataset_id = "d"
12091306 query_job .configuration .destination .table_id = "t"
12101307
1308+ query_job .referenced_property_graphs = []
1309+
12111310 args = mock .Mock ()
12121311 args .bigquery_api_endpoint = "e"
12131312 args .project = "p"
@@ -1244,11 +1343,17 @@ def test_add_graph_widget_schema_not_found(monkeypatch):
12441343 query_result = pandas .DataFrame ([{"id" : 1 }], columns = ["result" ])
12451344 query_text = "GRAPH my_dataset.my_graph"
12461345
1247- query_job = mock .create_autospec ( bigquery . job . QueryJob , instance = True )
1346+ query_job = mock .Mock ( )
12481347 query_job .configuration .destination .project = "p"
12491348 query_job .configuration .destination .dataset_id = "d"
12501349 query_job .configuration .destination .table_id = "t"
12511350
1351+ graph_ref = mock .Mock ()
1352+ graph_ref .project = "p"
1353+ graph_ref .dataset_id = "my_dataset"
1354+ graph_ref .property_graph_id = "my_graph"
1355+ query_job .referenced_property_graphs = [graph_ref ]
1356+
12521357 args = mock .Mock ()
12531358 args .bigquery_api_endpoint = "e"
12541359 args .project = "p"
@@ -1293,9 +1398,8 @@ def test_bigquery_magic_default_connection_user_agent():
12931398
12941399 client_info_arg = conn .call_args [1 ].get ("client_info" )
12951400 assert client_info_arg is not None
1296- assert (
1297- client_info_arg .user_agent
1298- == f"ipython-{ IPython .__version__ } bigquery-magics/{ bigquery_magics .__version__ } "
1401+ assert client_info_arg .user_agent .startswith (
1402+ f"ipython-{ IPython .__version__ } bigquery-magics/{ bigquery_magics .__version__ } "
12991403 )
13001404
13011405
@@ -1611,9 +1715,8 @@ def warning_match(warning):
16111715 assert kwargs .get ("credentials" ) is mock_credentials
16121716 client_info = kwargs .get ("client_info" )
16131717 assert client_info is not None
1614- assert (
1615- client_info .user_agent
1616- == f"ipython-{ IPython .__version__ } bigquery-magics/{ bigquery_magics .__version__ } "
1718+ assert client_info .user_agent .startswith (
1719+ f"ipython-{ IPython .__version__ } bigquery-magics/{ bigquery_magics .__version__ } "
16171720 )
16181721
16191722 query_job_mock .to_dataframe .assert_called_once_with (
0 commit comments