- Notifications
You must be signed in to change notification settings - Fork321
fix: QueryJob.exception() *returns* the errors, not raises them#467
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
a85fe8f07af7747d9a7e8a19f07ef3ddc14ef2fe8e56c4e96739627aFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -16,6 +16,7 @@ | ||
| import copy | ||
| import http | ||
| import textwrap | ||
| import types | ||
| import freezegun | ||
| from google.api_core import exceptions | ||
| @@ -308,7 +309,7 @@ def test_cancelled(self): | ||
| self.assertTrue(job.cancelled()) | ||
| deftest_done_job_complete(self): | ||
| client = _make_client(project=self.PROJECT) | ||
| resource = self._make_resource(ended=True) | ||
| job = self._get_target_class().from_api_repr(resource, client) | ||
| @@ -356,6 +357,84 @@ def test_done_w_timeout_and_longer_internal_api_timeout(self): | ||
| call_args = fake_reload.call_args | ||
| self.assertAlmostEqual(call_args.kwargs.get("timeout"), expected_timeout) | ||
| def test_done_w_query_results_error_reload_ok_job_finished(self): | ||
| client = _make_client(project=self.PROJECT) | ||
| bad_request_error = exceptions.BadRequest("Error in query") | ||
| client._get_query_results = mock.Mock(side_effect=bad_request_error) | ||
| resource = self._make_resource(ended=False) | ||
| job = self._get_target_class().from_api_repr(resource, client) | ||
| job._exception = None | ||
| def fake_reload(self, *args, **kwargs): | ||
| self._properties["status"]["state"] = "DONE" | ||
| self.set_exception(copy.copy(bad_request_error)) | ||
| fake_reload_method = types.MethodType(fake_reload, job) | ||
| with mock.patch.object(job, "reload", new=fake_reload_method): | ||
| is_done = job.done() | ||
| assert is_done | ||
| assert isinstance(job._exception, exceptions.BadRequest) | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. why use the private property in this and the other tests? any objections to calling ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. The reasoning was that One could argue that the chosen unit of test is too small, and that the class itself should represent a unit as opposed to its individual methods, but addressing that would require quite some refactoring (we already tinker with internal Here, practicality beats purity IMHO, thus the "cheating" by examining the internal state of the class. Or do you have a strong opinion on this? Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Works for me. I agree that ideally we'd have higher-level tests than this, but makes sense to stay with existing conventions, especially given our 100% coverage requirement. | ||
| def test_done_w_query_results_error_reload_ok_job_still_running(self): | ||
| client = _make_client(project=self.PROJECT) | ||
| retry_error = exceptions.RetryError("Too many retries", cause=TimeoutError) | ||
| client._get_query_results = mock.Mock(side_effect=retry_error) | ||
| resource = self._make_resource(ended=False) | ||
| job = self._get_target_class().from_api_repr(resource, client) | ||
| job._exception = None | ||
| def fake_reload(self, *args, **kwargs): | ||
| self._properties["status"]["state"] = "RUNNING" | ||
| fake_reload_method = types.MethodType(fake_reload, job) | ||
| with mock.patch.object(job, "reload", new=fake_reload_method): | ||
| is_done = job.done() | ||
| assert not is_done | ||
| assert job._exception is None | ||
| def test_done_w_query_results_error_reload_error(self): | ||
| client = _make_client(project=self.PROJECT) | ||
| bad_request_error = exceptions.BadRequest("Error in query") | ||
| client._get_query_results = mock.Mock(side_effect=bad_request_error) | ||
| resource = self._make_resource(ended=False) | ||
| job = self._get_target_class().from_api_repr(resource, client) | ||
| reload_error = exceptions.DataLoss("Oops, sorry!") | ||
| job.reload = mock.Mock(side_effect=reload_error) | ||
| job._exception = None | ||
| is_done = job.done() | ||
| assert is_done | ||
| assert job._exception is bad_request_error | ||
| def test_done_w_job_query_results_ok_reload_error(self): | ||
| client = _make_client(project=self.PROJECT) | ||
| query_results = google.cloud.bigquery.query._QueryResults( | ||
| properties={ | ||
| "jobComplete": True, | ||
| "jobReference": {"projectId": self.PROJECT, "jobId": "12345"}, | ||
| } | ||
| ) | ||
| client._get_query_results = mock.Mock(return_value=query_results) | ||
| resource = self._make_resource(ended=False) | ||
| job = self._get_target_class().from_api_repr(resource, client) | ||
| retry_error = exceptions.RetryError("Too many retries", cause=TimeoutError) | ||
| job.reload = mock.Mock(side_effect=retry_error) | ||
| job._exception = None | ||
| is_done = job.done() | ||
| assert is_done | ||
| assert job._exception is retry_error | ||
| def test_query_plan(self): | ||
| from google.cloud._helpers import _RFC3339_MICROS | ||
| from google.cloud.bigquery.job import QueryPlanEntry | ||
| @@ -973,7 +1052,7 @@ def test_result_w_retry(self): | ||
| initial=0.001, | ||
| maximum=0.001, | ||
| multiplier=1.0, | ||
| deadline=0.1, | ||
| predicate=custom_predicate, | ||
| ) | ||