def test_execute_lists_wildcard_followed_by_object_properly(self, client):
    """Any parent directory will do. Make sure object name matches."""
    client.list_objects.side_effect = [
        self.bucket1_top_level_resources, self.bucket1_dir1_resources,
        self.bucket1_dir2_resources
    ]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/*/object2'))
    task.execute()

    output = self.GetOutput()
    expected_output = 'gs://bucket1/dir1/object2\n'
    self.assertEqual(output, expected_output)

    self.assertEqual(client.list_objects.mock_calls, [
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix=None),
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix='dir1/object2'),
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix='dir2/object2')
    ])
Example #2
0
  def Run(self, args):
    """Command execution logic."""
    encryption_util.initialize_key_store(args)
    if args.path:
      storage_urls = [storage_url.storage_url_from_string(path)
                      for path in args.path]
      for url in storage_urls:
        if not isinstance(url, storage_url.CloudUrl):
          raise errors.InvalidUrlError('Ls only works for cloud URLs.'
                                       ' Error for: {}'.format(url.url_string))
    else:
      storage_urls = [storage_url.CloudUrl(cloud_api.DEFAULT_PROVIDER)]

    if args.full:
      display_detail = cloud_list_task.DisplayDetail.FULL
    elif args.json:
      display_detail = cloud_list_task.DisplayDetail.JSON
    elif args.long:
      display_detail = cloud_list_task.DisplayDetail.LONG
    else:
      display_detail = cloud_list_task.DisplayDetail.SHORT

    tasks = []
    for url in storage_urls:
      tasks.append(
          cloud_list_task.CloudListTask(
              url,
              all_versions=args.all_versions,
              buckets_flag=args.buckets,
              display_detail=display_detail,
              include_etag=args.etag,
              readable_sizes=args.readable_sizes,
              recursion_flag=args.recursive))
    task_executor.execute_tasks(tasks, parallelizable=False)
  def test_execute_lists_bucket_url_with_wildcard_properly(self, query_url,
                                                           client):
    """Test if list_buckets gets hit but only second bucket is shown."""
    client.list_buckets.side_effect = [self.bucket_resources]
    client.list_objects.side_effect = [self.bucket2_top_level_resources]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string(query_url))
    task.execute()

    output = self.GetOutput()
    expected_output = textwrap.dedent(
        """\
        gs://bucket2/dir_object
        gs://bucket2/dir_object/
        """
    )
    self.assertEqual(output, expected_output)

    client.list_buckets.assert_called_once_with(cloud_api.FieldsScope.SHORT)
    client.list_objects.assert_called_once_with(
        all_versions=False,
        bucket_name=self.bucket2.name,
        delimiter='/',
        fields_scope=cloud_api.FieldsScope.SHORT,
        prefix=None)
  def test_execute_lists_object_url_with_double_wildcard_properly(
      self, client):
    """Test if all contents of bucket are shown without formatting."""
    client.list_objects.side_effect = [self.bucket1_all_objects]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/**'))
    task.execute()

    output = self.GetOutput()
    expected_output = textwrap.dedent(
        """\
        gs://bucket1/object1
        gs://bucket1/dir1/object2
        gs://bucket1/dir1/subdir1/object3
        gs://bucket1/dir1/subdir2/object4
        gs://bucket1/dir2/subdir3/object5
        """
    )
    self.assertEqual(output, expected_output)

    client.list_objects.assert_called_once_with(
        all_versions=False,
        bucket_name=self.bucket1.name,
        delimiter=None,
        fields_scope=cloud_api.FieldsScope.SHORT,
        prefix=None)
  def test_long_display_detail_prints_object_etag_and_metageneration(
      self, client):
    """Etag, generation, and metageneration shown, and prefixes are aligned."""
    self.object1.etag = 'CJqt6aup7uoCEAQ='
    self.object1.metageneration = 1
    client.get_bucket.side_effect = [self.bucket1]
    client.list_objects.side_effect = [self.bucket1_top_level_resources]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/'),
        display_detail=cloud_list_task.DisplayDetail.LONG,
        all_versions=True,
        include_etag=True)
    task.execute()

    output = self.GetOutput()
    expected_output = textwrap.dedent(
        """\
                 0  1111-01-01T00:00:00Z  gs://bucket1/object1#1  metageneration=1  etag=CJqt6aup7uoCEAQ=
                                          gs://bucket1/dir1/
                                          gs://bucket1/dir2/
        TOTAL: 1 objects, 0 bytes (0B)
        """
    )
    self.assertEqual(output, expected_output)
  def test_execute_lists_prefix_no_trailing_delimiter(self, client):
    """Two API calls are made, and prefix top-level contents are shown."""
    client.get_object_metadata.side_effect = api_errors.NotFoundError
    client.list_objects.side_effect = [[self.dir2], self.bucket1_dir2_resources]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/dir2'))
    task.execute()

    output = self.GetOutput()
    expected_output = 'gs://bucket1/dir2/subdir3/\n'
    self.assertEqual(output, expected_output)

    client.get_object_metadata.assert_called_once_with(
        self.bucket1.name, 'dir2', None, cloud_api.FieldsScope.SHORT)
    client.list_objects.assert_has_calls([
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix='dir2'),
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix=self.dir2.prefix)
    ])
  def test_execute_lists_execute_lists_bucket_url_properly(self, query_url,
                                                           client):
    """Show top-level bucket items are shown but not subdirectory items."""
    client.get_bucket.side_effect = [self.bucket1]
    client.list_objects.side_effect = [self.bucket1_top_level_resources]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string(query_url))
    task.execute()

    output = self.GetOutput()
    expected_output = textwrap.dedent(
        """\
        gs://bucket1/object1
        gs://bucket1/dir1/
        gs://bucket1/dir2/
        """
    )
    self.assertEqual(output, expected_output)

    client.get_bucket.assert_called_once_with(
        self.bucket1.name, cloud_api.FieldsScope.SHORT)
    client.list_objects.assert_called_once_with(
        all_versions=False, bucket_name=self.bucket1.name,
        delimiter='/', fields_scope=cloud_api.FieldsScope.SHORT, prefix=None)
  def test_execute_lists_object_url_with_double_wildcard_followed_by_single_wildcard_properly(
      self, client):
    """Should list all matches recursively without line breaks or colons."""

    client.list_objects.side_effect = [self.bucket1_all_objects]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/**/s*'))
    task.execute()

    output = self.GetOutput()
    expected_output = textwrap.dedent(
        """\
        gs://bucket1/dir1/subdir1/object3
        gs://bucket1/dir1/subdir2/object4
        gs://bucket1/dir2/subdir3/object5
        """
    )
    self.assertEqual(output, expected_output)

    client.list_objects.assert_called_once_with(
        all_versions=False,
        bucket_name=self.bucket1.name,
        delimiter=None,
        fields_scope=cloud_api.FieldsScope.SHORT,
        prefix=None)
  def test_execute_lists_object_url_with_recursive_flag_and_double_wildcard_properly(
      self, client):
    """Should behave like recursive flag is not present."""
    client.list_objects.side_effect = [self.bucket1_all_objects]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/**'),
        recursion_flag=True)
    task.execute()

    output = self.GetOutput()
    expected_output = textwrap.dedent(
        """\
        gs://bucket1/object1
        gs://bucket1/dir1/object2
        gs://bucket1/dir1/subdir1/object3
        gs://bucket1/dir1/subdir2/object4
        gs://bucket1/dir2/subdir3/object5
        """
    )
    self.assertEqual(output, expected_output)

    client.list_objects.assert_called_once_with(
        all_versions=False,
        bucket_name=self.bucket1.name,
        delimiter=None,
        fields_scope=cloud_api.FieldsScope.SHORT,
        prefix=None)
  def test_execute_lists_prefix_with_center_wildcard(self, client):
    """Two API calls are made, and prefix top-level contents are shown."""
    client.list_objects.side_effect = [[self.dir2], self.bucket1_dir2_resources]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/d*2/'))
    task.execute()

    output = self.GetOutput()
    expected_output = 'gs://bucket1/dir2/subdir3/\n'

    self.assertEqual(output, expected_output)
    self.assertEqual(client.list_objects.mock_calls, [
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix='d'),
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix=self.dir2.prefix)
    ])
  def test_execute_does_not_list_object_if_trailing_delimiter(self, client):
    """Gsutil would list an object matching the query. Breaking change."""
    client.list_objects.side_effect = [
        self.bucket2_top_level_resources, self.bucket2_dir_object_resources
    ]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket2/d*/'))
    task.execute()

    output = self.GetOutput()
    expected_output = 'gs://bucket2/dir_object/object6\n'
    self.assertEqual(output, expected_output)

    self.assertEqual(client.list_objects.mock_calls, [
        mock.call(
            all_versions=False,
            bucket_name=self.bucket2.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix='d'),
        mock.call(
            all_versions=False,
            bucket_name=self.bucket2.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix='dir_object/')
    ])
  def test_long_display_detail_prints_multiple_object_details(
      self, client):
    """Long lists multiple objects and adds their sizes for a TOTAL stat."""
    self.object1.size = 1000
    self.object_duplicate_of_dir.size = 50000000
    self.object_duplicate_of_dir.creation_time = DATETIME
    client.list_buckets.side_effect = [self.bucket_resources]
    client.list_objects.side_effect = [
        self.bucket1_top_level_resources, self.bucket2_top_level_resources
    ]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://*'),
        display_detail=cloud_list_task.DisplayDetail.LONG)
    task.execute()

    output = self.GetOutput()
    expected_output = textwrap.dedent(
        """\
        gs://bucket1:
              1000  1111-01-01T00:00:00Z  gs://bucket1/object1
                                          gs://bucket1/dir1/
                                          gs://bucket1/dir2/

        gs://bucket2:
          50000000  1111-01-01T00:00:00Z  gs://bucket2/dir_object
                                          gs://bucket2/dir_object/
        TOTAL: 2 objects, 50001000 bytes (47.68MiB)
        """
    )
    self.assertEqual(output, expected_output)
  def test_long_display_detail_prints_null_object_details(
      self, client):
    """Unknown values print 'None', and prefixes are aligned."""
    self.object1.creation_time = self.object1.size = None
    self.object1.storage_url = storage_url.storage_url_from_string(
        'gs://bucket1/object1')
    client.get_bucket.side_effect = [self.bucket1]
    client.list_objects.side_effect = [self.bucket1_top_level_resources]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/'),
        display_detail=cloud_list_task.DisplayDetail.LONG,
        all_versions=True,
        include_etag=True)
    task.execute()

    output = self.GetOutput()
    expected_output = textwrap.dedent(
        """\
              None                  None  gs://bucket1/object1  metageneration=None  etag=None
                                          gs://bucket1/dir1/
                                          gs://bucket1/dir2/
        TOTAL: 1 objects, 0 bytes (0B)
        """
    )
    self.assertEqual(output, expected_output)
Example #14
0
    def Run(self, args):
        """Command execution logic."""
        if args.path:
            storage_urls = [
                storage_url.storage_url_from_string(path) for path in args.path
            ]
            for url in storage_urls:
                if not isinstance(url, storage_url.CloudUrl):
                    raise errors.InvalidUrlError(
                        'Ls only works for cloud URLs.'
                        ' Error for: {}'.format(url.url_string))
        else:
            storage_urls = [storage_url.CloudUrl(cloud_api.DEFAULT_PROVIDER)]

        display_detail = cloud_list_task.DisplayDetail.SHORT
        if args.full:
            display_detail = cloud_list_task.DisplayDetail.FULL
        if args.json:
            display_detail = cloud_list_task.DisplayDetail.JSON
        if args.long:
            display_detail = cloud_list_task.DisplayDetail.LONG

        tasks = []
        for url in storage_urls:
            tasks.append(
                cloud_list_task.CloudListTask(url,
                                              all_versions=args.all_versions,
                                              display_detail=display_detail,
                                              include_etag=args.etag,
                                              recursion_flag=args.recursive))
        task_executor.ExecuteTasks(tasks, is_parallel=False)
  def test_execute_lists_single_prefix_properly(self, client):
    """API should return prefix contents. Task should display contents."""
    client.get_object_metadata.side_effect = api_errors.NotFoundError
    client.list_objects.side_effect = [[self.dir2], self.bucket1_dir2_resources]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/dir2/'))
    task.execute()

    output = self.GetOutput()
    expected_output = 'gs://bucket1/dir2/subdir3/\n'
    self.assertEqual(output, expected_output)

    client.get_object_metadata.assert_called_once_with(
        self.bucket1.name, 'dir2/', None, cloud_api.FieldsScope.SHORT)
    client.list_objects.assert_has_calls([
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix='dir2'),
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix='dir2/')
    ])
  def test_execute_lists_provider_url_properly(self, client):
    """Test all buckets are shown."""
    client.list_buckets.side_effect = [self.bucket_resources]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://'))
    task.execute()

    output = self.GetOutput()
    expected_output = 'gs://bucket1\ngs://bucket2\n'
    self.assertEqual(output, expected_output)

    client.list_buckets.assert_called_once_with(cloud_api.FieldsScope.SHORT)
  def test_execute_lists_provider_with_recursive_flag_properly(
      self, client):
    """Should be the same as no recursive flag."""
    client.list_buckets.side_effect = [self.bucket_resources]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://'), recursion_flag=True)
    task.execute()

    output = self.GetOutput()
    expected_output = 'gs://bucket1\ngs://bucket2\n'
    self.assertEqual(output, expected_output)

    client.list_buckets.assert_called_once_with(cloud_api.FieldsScope.SHORT)
  def test_execute_raises_error_if_no_bucket_matches(self, client):
    """No buckets match pattern."""
    # We don't have to test a no-wildcard query that would trigger get_bucket
    # because Apitools has error handling for that.
    client.list_buckets.side_effect = [self.bucket_resources]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://pail*'))

    with self.assertRaisesRegex(errors.InvalidUrlError,
                                'One or more URLs matched no objects.'):
      task.execute()

    client.list_buckets.assert_called_once_with(cloud_api.FieldsScope.SHORT)
  def test_execute_lists_object_url_properly(self, client):
    """Test if list_objects is hit and object name is shown."""
    client.get_object_metadata.side_effect = [self.object1]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/object1'))
    task.execute()

    output = self.GetOutput()
    expected_output = 'gs://bucket1/object1\n'
    self.assertEqual(output, expected_output)

    self.assertFalse(client.list_objects.called)
    client.get_object_metadata.assert_called_once_with(
        self.bucket1.name, self.object1.name, None, cloud_api.FieldsScope.SHORT)
  def test_execute_translates_display_detail_to_fields_scope_for_non_buckets(
      self, display_detail, fields_scope, mock_wildcard_iterator):
    """Should translate cloud_list_task arg to cloud_api arg."""
    cloud_url = storage_url.storage_url_from_string('gs://bucket1/object1')
    # Will need get_metadata_dump for DisplayDetail.FULL.
    self.object1 = gcs_resource_reference.GcsObjectResource(
        cloud_url, metadata=self.messages.Object(name='o'))
    mock_wildcard_iterator.return_value = [self.object1]

    task = cloud_list_task.CloudListTask(
        cloud_url, display_detail=display_detail)
    task.execute()

    mock_wildcard_iterator.assert_called_once_with(
        cloud_url, fields_scope=fields_scope)
  def test_execute_lists_object_url_with_wildcard_properly(self, client):
    """One recursion level of prefixes are shown and formatted."""
    client.list_objects.side_effect = [
        self.bucket1_top_level_resources, self.bucket1_dir1_resources,
        self.bucket1_dir2_resources
    ]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/*'))
    task.execute()

    output = self.GetOutput()
    expected_output = textwrap.dedent(
        """\
        gs://bucket1/object1

        gs://bucket1/dir1/:
        gs://bucket1/dir1/object2
        gs://bucket1/dir1/subdir1/
        gs://bucket1/dir1/subdir2/

        gs://bucket1/dir2/:
        gs://bucket1/dir2/subdir3/
        """
    )
    self.assertEqual(output, expected_output)

    self.assertEqual(client.list_objects.mock_calls, [
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix=None),
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix=self.dir1.prefix),
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix=self.dir2.prefix)
    ])
  def test_execute_lists_multiple_prefix_match_properly(
      self, query_url, query_prefix, client):
    """Test if top two levels of resources are shown with proper formatting."""
    client.list_objects.side_effect = [[self.dir1,
                                        self.dir2], self.bucket1_dir1_resources,
                                       self.bucket1_dir2_resources]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string(query_url))
    task.execute()

    output = self.GetOutput()
    expected_output = textwrap.dedent(
        """\
        gs://bucket1/dir1/:
        gs://bucket1/dir1/object2
        gs://bucket1/dir1/subdir1/
        gs://bucket1/dir1/subdir2/

        gs://bucket1/dir2/:
        gs://bucket1/dir2/subdir3/
        """
    )
    self.assertEqual(output, expected_output)

    self.assertEqual(client.list_objects.mock_calls, [
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix=query_prefix),
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix=self.dir1.prefix),
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix=self.dir2.prefix)
    ])
  def test_execute_with_all_versions_displays_generation(self, client):
    """All versions flag should add generation to URL."""
    client.get_bucket.side_effect = [self.bucket1]
    client.list_objects.side_effect = [self.bucket1_top_level_resources]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/'), all_versions=True)
    task.execute()

    output = self.GetOutput()
    expected_output = textwrap.dedent(
        """\
        gs://bucket1/object1#1
        gs://bucket1/dir1/
        gs://bucket1/dir2/
        """
    )
    self.assertEqual(output, expected_output)
  def test_execute_lists_object_url_with_recursive_flag_properly(
      self, client):
    """Should list all contents matching flag recursively with formatting."""
    client.get_object_metadata.side_effect = api_errors.NotFoundError
    client.list_objects.side_effect = [[self.dir2], self.bucket1_dir2_resources,
                                       self.bucket1_dir2_subdir3_resources]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/dir2'),
        recursion_flag=True)
    task.execute()

    output = self.GetOutput()
    expected_output = textwrap.dedent(
        """\
        gs://bucket1/dir2/:

        gs://bucket1/dir2/subdir3/:
        gs://bucket1/dir2/subdir3/object5
        """
    )
    self.assertEqual(output, expected_output)
    client.get_object_metadata.assert_called_once_with(
        self.bucket1.name, 'dir2', None, cloud_api.FieldsScope.SHORT)
    self.assertEqual(client.list_objects.mock_calls, [
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix='dir2'),
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix=self.dir2.prefix),
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix=self.subdir3.prefix)
    ])
Example #25
0
    def Run(self, args):
        """Command execution logic."""
        if args.path:
            storage_urls = [
                storage_url.storage_url_from_string(path) for path in args.path
            ]
            for url in storage_urls:
                if not isinstance(url, storage_url.CloudUrl):
                    raise errors.InvalidUrlError(
                        'Ls only works for cloud URLs.'
                        ' Error for: {}'.format(url.url_string))
        else:
            storage_urls = [storage_url.CloudUrl(cloud_api.DEFAULT_PROVIDER)]

        tasks = [
            cloud_list_task.CloudListTask(url, recursion_flag=args.recursive)
            for url in storage_urls
        ]
        task_executor.ExecuteTasks(tasks)
  def test_full_display_detail_prints_nothing_for_no_matches(self, client):
    """Test nothing is shown for no prefix match."""
    client.get_bucket.side_effect = [self.bucket1]
    client.list_objects.side_effect = [[]]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/'),
        display_detail=cloud_list_task.DisplayDetail.FULL)
    task.execute()

    output = self.GetOutput()
    expected_output = '\n'
    self.assertEqual(output, expected_output)

    client.get_bucket.assert_called_once_with(
        self.bucket1.name, cloud_api.FieldsScope.FULL)
    client.list_objects.assert_called_once_with(
        all_versions=False, bucket_name=self.bucket1.name,
        delimiter='/', fields_scope=cloud_api.FieldsScope.FULL, prefix=None)
  def test_execute_lists_provider_with_wildcards_properly(
      self, query_url, client):
    """Test if all buckets top-level contents are shown, even if '**'."""
    client.list_buckets.side_effect = [self.bucket_resources]
    client.list_objects.side_effect = [
        self.bucket1_top_level_resources, self.bucket2_top_level_resources
    ]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string(query_url))
    task.execute()

    output = self.GetOutput()
    expected_output = textwrap.dedent(
        """\
        gs://bucket1:
        gs://bucket1/object1
        gs://bucket1/dir1/
        gs://bucket1/dir2/

        gs://bucket2:
        gs://bucket2/dir_object
        gs://bucket2/dir_object/
        """
    )
    self.assertEqual(output, expected_output)

    client.list_buckets.assert_called_once_with(cloud_api.FieldsScope.SHORT)
    self.assertEqual(client.list_objects.mock_calls, [
        mock.call(
            all_versions=False,
            bucket_name=self.bucket1.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix=None),
        mock.call(
            all_versions=False,
            bucket_name=self.bucket2.name,
            delimiter='/',
            fields_scope=cloud_api.FieldsScope.SHORT,
            prefix=None)
    ])
  def test_full_display_detail_prints_objects_properly(self, client):
    """Test objects are shown with formatted metadata."""
    object1 = gcs_resource_reference.GcsObjectResource(
        storage_url.storage_url_from_string('gs://bucket1/object1'),
        metadata=self.messages.Object(name='o'))
    client.get_bucket.side_effect = [self.bucket1]
    client.list_objects.side_effect = [[object1, self.dir1, self.dir2]]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/'),
        display_detail=cloud_list_task.DisplayDetail.FULL)
    task.execute()

    output = self.GetOutput()
    expected_output = textwrap.dedent(
        """\
        [
        {
          "url": "gs://bucket1/object1",
          "type": "cloud_object",
          "metadata": {
            "name": "o"
          }
        },
        {
          "url": "gs://bucket1/dir1/",
          "type": "prefix"
        },
        {
          "url": "gs://bucket1/dir2/",
          "type": "prefix"
        }
        ]
        """
    )
    self.assertEqual(output, expected_output)

    client.get_bucket.assert_called_once_with(
        self.bucket1.name, cloud_api.FieldsScope.FULL)
    client.list_objects.assert_called_once_with(
        all_versions=False, bucket_name=self.bucket1.name,
        delimiter='/', fields_scope=cloud_api.FieldsScope.FULL, prefix=None)
  def test_execute_raises_error_if_no_object_matches(self, client):
    """No objects or prefixes match."""
    client.get_object_metadata.side_effect = api_errors.NotFoundError
    client.list_objects.side_effect = [[]]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/potato'))

    with self.assertRaisesRegex(errors.InvalidUrlError,
                                'One or more URLs matched no objects.'):
      task.execute()

    client.get_object_metadata.assert_called_once_with(
        self.bucket1.name, 'potato', None, cloud_api.FieldsScope.SHORT)
    client.list_objects.assert_called_once_with(
        all_versions=False,
        bucket_name=self.bucket1.name,
        delimiter='/',
        fields_scope=cloud_api.FieldsScope.SHORT,
        prefix='potato')
  def test_long_display_detail_prints_object_details_with_no_size(self, client):
    """Zero-size object metadata line is shown, and prefixes are aligned."""
    client.get_bucket.side_effect = [self.bucket1]
    client.list_objects.side_effect = [self.bucket1_top_level_resources]

    task = cloud_list_task.CloudListTask(
        storage_url.storage_url_from_string('gs://bucket1/'),
        display_detail=cloud_list_task.DisplayDetail.LONG)
    task.execute()

    output = self.GetOutput()
    expected_output = textwrap.dedent(
        """\
                 0  1111-01-01T00:00:00Z  gs://bucket1/object1
                                          gs://bucket1/dir1/
                                          gs://bucket1/dir2/
        TOTAL: 1 objects, 0 bytes (0B)
        """
    )
    self.assertEqual(output, expected_output)