1616# See the License for the specific language governing permissions and
1717# limitations under the License.
1818
19- import sys
2019import logging
2120from unittest .mock import Mock , patch
2221
2322import pytest
24- from django .test import TestCase
2523from requests .exceptions import ReadTimeout
2624
27- from beeswax .api import _autocomplete , get_functions
25+ from beeswax .api import _autocomplete , _get_functions , _get_sample_data
2826from desktop .lib .django_test_util import make_logged_in_client
29- from desktop . lib . test_utils import add_to_group , grant_access
27+ from metastore . conf import ALLOW_SAMPLE_DATA_FROM_VIEWS
3028from useradmin .models import User
3129
3230LOG = logging .getLogger ()
3331
3432
3533@pytest .mark .django_db
36- class TestApi ():
37-
34+ class TestApi :
3835 def setup_method (self ):
3936 self .client = make_logged_in_client (username = "test" , groupname = "default" , recreate = True , is_superuser = False )
4037 self .user = User .objects .get (username = "test" )
@@ -43,75 +40,99 @@ def test_autocomplete_time_out(self):
4340 get_tables_meta = Mock (
4441 side_effect = ReadTimeout ("HTTPSConnectionPool(host='gethue.com', port=10001): Read timed out. (read timeout=120)" )
4542 )
46- db = Mock (
47- get_tables_meta = get_tables_meta
48- )
43+ db = Mock (get_tables_meta = get_tables_meta )
4944
50- resp = _autocomplete (db , database = ' database' )
45+ resp = _autocomplete (db , database = " database" )
5146
52- assert (
53- resp ==
54- {
55- 'code' : 500 ,
56- 'error' : "HTTPSConnectionPool(host='gethue.com', port=10001): Read timed out. (read timeout=120)"
57- })
47+ assert resp == {"code" : 500 , "error" : "HTTPSConnectionPool(host='gethue.com', port=10001): Read timed out. (read timeout=120)" }
5848
5949 def test_get_functions (self ):
60- db = Mock (
61- get_functions = Mock (
62- return_value = Mock (
63- rows = Mock (
64- return_value = [{'name' : 'f1' }, {'name' : 'f2' }]
65- )
66- )
67- )
68- )
50+ # Mock db.get_functions() to return rows that escape_rows can process
51+ # Each row should be a list where row[0] is the function name
52+ db = Mock ()
53+ db .get_functions = Mock (return_value = [["f1" ], ["f2" ]]) # Return list of rows
54+ db .client = Mock (query_server = {"dialect" : "hive" }) # Non-Impala dialect
6955
70- resp = get_functions (db )
56+ resp = _get_functions (db ) # Call the internal function
7157
72- assert (
73- resp ==
74- [{'name' : 'f1' }, {'name' : 'f2' }])
58+ assert resp == [{"name" : "f1" }, {"name" : "f2" }]
7559
76- def test_get_functions (self ):
77- with patch (' beeswax.api._get_functions' ) as _get_functions :
60+ def test_autocomplete_functions (self ):
61+ with patch (" beeswax.api._get_functions" ) as _get_functions :
7862 db = Mock ()
79- _get_functions .return_value = [
80- {'name' : 'f1' }, {'name' : 'f2' }, {'name' : 'f3' }
81- ]
63+ _get_functions .return_value = [{"name" : "f1" }, {"name" : "f2" }, {"name" : "f3" }]
8264
83- resp = _autocomplete (db , database = ' default' , operation = ' functions' )
65+ resp = _autocomplete (db , database = " default" , operation = " functions" )
8466
85- assert (
86- resp ['functions' ] ==
87- [{'name' : 'f1' }, {'name' : 'f2' }, {'name' : 'f3' }])
67+ assert resp ["functions" ] == [{"name" : "f1" }, {"name" : "f2" }, {"name" : "f3" }]
8868
8969 def test_get_function (self ):
9070 db = Mock ()
91- db .client = Mock (query_server = {' dialect' : ' hive' })
71+ db .client = Mock (query_server = {" dialect" : " hive" })
9272 db .get_function = Mock (
9373 return_value = [
94- [' floor_month(param) - Returns the timestamp at a month granularity' ],
95- [' param needs to be a timestamp value' ],
96- [' Example:' ],
74+ [" floor_month(param) - Returns the timestamp at a month granularity" ],
75+ [" param needs to be a timestamp value" ],
76+ [" Example:" ],
9777 ["> SELECT floor_month(CAST('yyyy-MM-dd HH:mm:ss' AS TIMESTAMP)) FROM src;" ],
98- [' yyyy-MM-01 00:00:00' ]
78+ [" yyyy-MM-01 00:00:00" ],
9979 ]
10080 )
10181
102- data = _autocomplete (db , database = 'floor_month' , operation = 'function' )
103-
104- assert (
105- data ['function' ] ==
106- {
107- 'name' : 'floor_month' ,
108- 'signature' : 'floor_month(param)' ,
109- 'description' :
110- 'Returns the timestamp at a month granularity\n param needs to be a timestamp value\n Example:\n '
111- '> SELECT floor_month(CAST(\' yyyy-MM-dd HH:mm:ss\' AS TIMESTAMP)) FROM src;\n yyyy-MM-01 00:00:00'
112- })
113-
114- db .client = Mock (query_server = {'dialect' : 'impala' })
115- data = _autocomplete (db , operation = 'function' )
116-
117- assert data ['function' ] == {}
82+ data = _autocomplete (db , database = "floor_month" , operation = "function" )
83+
84+ assert data ["function" ] == {
85+ "name" : "floor_month" ,
86+ "signature" : "floor_month(param)" ,
87+ "description" : "Returns the timestamp at a month granularity\n param needs to be a timestamp value\n Example:\n "
88+ "> SELECT floor_month(CAST('yyyy-MM-dd HH:mm:ss' AS TIMESTAMP)) FROM src;\n yyyy-MM-01 00:00:00" ,
89+ }
90+
91+ db .client = Mock (query_server = {"dialect" : "impala" })
92+ data = _autocomplete (db , operation = "function" )
93+
94+ assert data ["function" ] == {}
95+
96+ @patch ("beeswax.api.dbms.get" )
97+ def test_get_sample_data_for_views (self , mock_dbms_get ):
98+ # Mock table_obj
99+ table_obj_mock = Mock (is_view = True , is_impala_only = False )
100+
101+ # Mock the db object that dbms.get() would return
102+ db_mock = Mock (get_table = Mock (return_value = table_obj_mock ))
103+ mock_dbms_get .return_value = db_mock
104+
105+ # Scenario 1: allow_sample_data_from_views is False
106+ reset = ALLOW_SAMPLE_DATA_FROM_VIEWS .set_for_testing (False )
107+ try :
108+ response = _get_sample_data (db_mock , "default_db" , "test_view_table" , None , None )
109+
110+ assert response == {
111+ "status" : - 1 ,
112+ "message" : "Not getting sample data as this is a view which can be expensive when run." ,
113+ }
114+ finally :
115+ reset ()
116+
117+ # Scenario 2: allow_sample_data_from_views is True
118+ reset = ALLOW_SAMPLE_DATA_FROM_VIEWS .set_for_testing (True )
119+ try :
120+ # Mock db.get_sample to simulate successful data fetching past the view check
121+ # We expect it to be called if the view check is passed.
122+ db_mock .get_sample .return_value = Mock (
123+ rows = Mock (return_value = [["col1_val" , "col2_val" ]]),
124+ cols = Mock (return_value = ["col1" , "col2" ]),
125+ full_cols = Mock (return_value = [{"name" : "col1" }, {"name" : "col2" }]),
126+ )
127+ mock_dbms_get .return_value = db_mock
128+
129+ response = _get_sample_data (db_mock , "default_db" , "test_view_table" , None , None )
130+ assert response == {
131+ "status" : 0 ,
132+ "headers" : ["col1" , "col2" ],
133+ "full_headers" : [{"name" : "col1" }, {"name" : "col2" }],
134+ "rows" : [["col1_val" , "col2_val" ]],
135+ }
136+ db_mock .get_sample .assert_called_once_with ("default_db" , table_obj_mock , None , None , generate_sql_only = False , operation = None )
137+ finally :
138+ reset ()
0 commit comments