fix: do not error on LROs with no response or error (#258)

Co-authored-by: Tres Seaver <tseaver@palladion.com>
diff --git a/google/api_core/operation.py b/google/api_core/operation.py
index b17f753..a66e4a5 100644
--- a/google/api_core/operation.py
+++ b/google/api_core/operation.py
@@ -140,11 +140,11 @@
                 )
                 self.set_exception(exception)
             else:
-                exception = exceptions.GoogleAPICallError(
-                    "Unexpected state: Long-running operation had neither "
-                    "response nor error set."
-                )
-                self.set_exception(exception)
+                # Some APIs set `done: true`, with an empty response.
+                # Set the result to an empty message of the expected
+                # result type.
+                # https://google.aip.dev/151
+                self.set_result(self._result_type())
 
     def _refresh_and_update(self, retry=polling.DEFAULT_RETRY):
         """Refresh the operation and update the result if needed.
diff --git a/google/api_core/operation_async.py b/google/api_core/operation_async.py
index 6bae865..17624d6 100644
--- a/google/api_core/operation_async.py
+++ b/google/api_core/operation_async.py
@@ -136,11 +136,11 @@
                 )
                 self.set_exception(exception)
             else:
-                exception = exceptions.GoogleAPICallError(
-                    "Unexpected state: Long-running operation had neither "
-                    "response nor error set."
-                )
-                self.set_exception(exception)
+                # Some APIs set `done: true`, with an empty response.
+                # Set the result to an empty message of the expected
+                # result type.
+                # https://google.aip.dev/151
+                self.set_result(self._result_type())
 
     async def _refresh_and_update(self, retry=async_future.DEFAULT_RETRY):
         """Refresh the operation and update the result if needed.
diff --git a/tests/asyncio/test_operation_async.py b/tests/asyncio/test_operation_async.py
index 907cda7..342184f 100644
--- a/tests/asyncio/test_operation_async.py
+++ b/tests/asyncio/test_operation_async.py
@@ -153,7 +153,7 @@
 
 @mock.patch("asyncio.sleep", autospec=True)
 @pytest.mark.asyncio
-async def test_unexpected_result(unused_sleep):
+async def test_done_with_no_error_or_response(unused_sleep):
     responses = [
         make_operation_proto(),
         # Second operation response is done, but has not error or response.
@@ -161,9 +161,9 @@
     ]
     future, _, _ = make_operation_future(responses)
 
-    exception = await future.exception()
+    result = await future.result()
 
-    assert "Unexpected state" in "{!r}".format(exception)
+    assert isinstance(result, struct_pb2.Struct)
 
 
 def test_from_gapic():
diff --git a/tests/unit/test_operation.py b/tests/unit/test_operation.py
index 28fbfe2..7a3e3c6 100644
--- a/tests/unit/test_operation.py
+++ b/tests/unit/test_operation.py
@@ -163,7 +163,7 @@
     assert isinstance(exception, exceptions.NotFound)
 
 
-def test_unexpected_result():
+def test_done_with_no_error_or_response():
     responses = [
         make_operation_proto(),
         # Second operation response is done, but has not error or response.
@@ -171,9 +171,7 @@
     ]
     future, _, _ = make_operation_future(responses)
 
-    exception = future.exception()
-
-    assert "Unexpected state" in "{!r}".format(exception)
+    assert isinstance(future.result(), struct_pb2.Struct)
 
 
 def test__refresh_http():