Skip to content

Commit 618f192

Browse files
busunkim96tseaver
andauthored
fix: do not error on LROs with no response or error (#258)
Co-authored-by: Tres Seaver <[email protected]>
1 parent 82ca2fd commit 618f192

File tree

4 files changed

+15
-17
lines changed

4 files changed

+15
-17
lines changed

google/api_core/operation.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,11 @@ def _set_result_from_operation(self):
140140
)
141141
self.set_exception(exception)
142142
else:
143-
exception = exceptions.GoogleAPICallError(
144-
"Unexpected state: Long-running operation had neither "
145-
"response nor error set."
146-
)
147-
self.set_exception(exception)
143+
# Some APIs set `done: true`, with an empty response.
144+
# Set the result to an empty message of the expected
145+
# result type.
146+
# https://google.aip.dev/151
147+
self.set_result(self._result_type())
148148

149149
def _refresh_and_update(self, retry=polling.DEFAULT_RETRY):
150150
"""Refresh the operation and update the result if needed.

google/api_core/operation_async.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,11 @@ def _set_result_from_operation(self):
136136
)
137137
self.set_exception(exception)
138138
else:
139-
exception = exceptions.GoogleAPICallError(
140-
"Unexpected state: Long-running operation had neither "
141-
"response nor error set."
142-
)
143-
self.set_exception(exception)
139+
# Some APIs set `done: true`, with an empty response.
140+
# Set the result to an empty message of the expected
141+
# result type.
142+
# https://google.aip.dev/151
143+
self.set_result(self._result_type())
144144

145145
async def _refresh_and_update(self, retry=async_future.DEFAULT_RETRY):
146146
"""Refresh the operation and update the result if needed.

tests/asyncio/test_operation_async.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,17 +153,17 @@ async def test_exception():
153153

154154
@mock.patch("asyncio.sleep", autospec=True)
155155
@pytest.mark.asyncio
156-
async def test_unexpected_result(unused_sleep):
156+
async def test_done_with_no_error_or_response(unused_sleep):
157157
responses = [
158158
make_operation_proto(),
159159
# Second operation response is done, but has not error or response.
160160
make_operation_proto(done=True),
161161
]
162162
future, _, _ = make_operation_future(responses)
163163

164-
exception = await future.exception()
164+
result = await future.result()
165165

166-
assert "Unexpected state" in "{!r}".format(exception)
166+
assert isinstance(result, struct_pb2.Struct)
167167

168168

169169
def test_from_gapic():

tests/unit/test_operation.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,17 +163,15 @@ def test_exception_with_error_code():
163163
assert isinstance(exception, exceptions.NotFound)
164164

165165

166-
def test_unexpected_result():
166+
def test_done_with_no_error_or_response():
167167
responses = [
168168
make_operation_proto(),
169169
# Second operation response is done, but has not error or response.
170170
make_operation_proto(done=True),
171171
]
172172
future, _, _ = make_operation_future(responses)
173173

174-
exception = future.exception()
175-
176-
assert "Unexpected state" in "{!r}".format(exception)
174+
assert isinstance(future.result(), struct_pb2.Struct)
177175

178176

179177
def test__refresh_http():

0 commit comments

Comments
 (0)