Repository: googleapis/google-cloud-python

Issue:
BigQuery: 'test_undelete_table' systest
See: https://circleci.com/gh/GoogleCloudPlatform/google-cloud-python/7481

```python
_____________________________ test_undelete_table ______________________________

client = <google.cloud.bigquery.client.Client object at 0x7f7bd1a56e50>
to_delete = [Dataset(DatasetReference(u'precise-truck-742', u'undelete_table_dataset_1532973955590'))]

    def test_undelete_table(client, to_delete):
        dataset_id = 'undelete_table_dataset_{}'.format(_millis())
        table_id = 'undelete_table_table_{}'.format(_millis())
        dataset = bigquery.Dataset(client.dataset(dataset_id))
        dataset.location = 'US'
        dataset = client.create_dataset(dataset)
        to_delete.append(dataset)
    
        table = bigquery.Table(dataset.table(table_id), schema=SCHEMA)
        client.create_table(table)
    
        # [START bigquery_undelete_table]
        # import time
        # from google.cloud import bigquery
        # client = bigquery.Client()
        # dataset_id = 'my_dataset'
        # table_id = 'my_table'
    
        table_ref = client.dataset(dataset_id).table(table_id)
    
        # Record the current time in milliseconds. We'll use this as the snapshot
        # time for recovering the table.
        snapshot_time = int(time.time() * 1000)
    
        # "Accidentally" delete the table.
        client.delete_table(table_ref)  # API request
    
        # Construct the restore-from table ID using a snapshot decorator.
        snapshot_table_id = '{}@{}'.format(table_id, snapshot_time)
        source_table_ref = client.dataset(dataset_id).table(snapshot_table_id)
    
        # Choose a new table ID for the recovered table data.
        recovered_table_id = '{}_recovered'.format(table_id)
        dest_table_ref = client.dataset(dataset_id).table(recovered_table_id)
    
        # Construct and run a copy job.
        job = client.copy_table(
            source_table_ref,
            dest_table_ref,
            # Location must match that of the source and destination tables.
            location='US')  # API request
    
>       job.result()  # Waits for job to complete.

../docs/bigquery/snippets.py:2172: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
google/cloud/bigquery/job.py:688: in result
    return super(_AsyncJob, self).result(timeout=timeout)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <google.cloud.bigquery.job.CopyJob object at 0x7f7bc173ec10>
timeout = None

    def result(self, timeout=None):
        """Get the result of the operation, blocking if necessary.
    
            Args:
                timeout (int):
                    How long (in seconds) to wait for the operation to complete.
                    If None, wait indefinitely.
    
            Returns:
                google.protobuf.Message: The Operation's result.
    
            Raises:
                google.api_core.GoogleAPICallError: If the operation errors or if
                    the timeout is reached before the operation completes.
            """
        self._blocking_poll(timeout=timeout)
    
        if self._exception is not None:
            # pylint: disable=raising-bad-type
            # Pylint doesn't recognize that this is valid in this case.
>           raise self._exception
E           BadRequest: 400 Invalid snapshot time 1532973956207 for table precise-truck-742:undelete_table_dataset_1532973955590.undelete_table_table_1532973955590@1532973956207. Cannot read before 1532973956237

../.nox/snip-2-7/lib/python2.7/site-packages/google/api_core/future/polling.py:120: BadRequest
```

@tswast Can you suggest a fix for the test?


Discussion:
I suspect this is time drift between the backend and the test node where the code is running, since the table create time is determined by backend, and we're picking the snapshot time based on the current time of the test node immediately thereafter.

We could pick the snapshot time based on the response from table_create, but it requires reworking the sample a bit.  I'll grab this one.

Resolving patch:
diff --git a/docs/bigquery/snippets.py b/docs/bigquery/snippets.py
--- a/docs/bigquery/snippets.py
+++ b/docs/bigquery/snippets.py
@@ -2151,6 +2151,13 @@ def test_undelete_table(client, to_delete):
     # time for recovering the table.
     snapshot_time = int(time.time() * 1000)
 
+    # Because local system time may have some drift, we ensure the snapshot
+    # time is at least within the creation lifespan of the table.  Trying
+    # to snapshot a table prior to its creation time is an error.
+    table = client.get_table(table_ref)
+    if table.created_time > snapshot_time:
+      snapshot_time = table.created_time
+
     # "Accidentally" delete the table.
     client.delete_table(table_ref)  # API request
 


Test patch: