Browse Source

HUE-4417 [aws] Switch from s3 to s3a to enable direct save to S3

Jenny Kim 9 years ago
parent
commit
2560694271

+ 2 - 2
apps/filebrowser/src/filebrowser/forms.py

@@ -23,7 +23,7 @@ from django.contrib.auth.models import User, Group
 from django.forms import FileField, CharField, BooleanField, Textarea
 from django.forms.formsets import formset_factory, BaseFormSet
 
-from aws.s3 import S3_ROOT, normpath as s3_normpath
+from aws.s3 import S3A_ROOT, normpath as s3_normpath
 from desktop.lib import i18n
 from hadoop.fs import normpath
 from filebrowser.lib import rwx
@@ -62,7 +62,7 @@ class PathField(CharField):
 
   def clean(self, value):
     cleaned_path = CharField.clean(self, value)
-    if value.lower().startswith(S3_ROOT):
+    if value.lower().startswith(S3A_ROOT):
       cleaned_path = s3_normpath(cleaned_path)
     else:
       cleaned_path = normpath(cleaned_path)

+ 1 - 1
apps/filebrowser/src/filebrowser/templates/fb_components.mako

@@ -22,7 +22,7 @@ from django.utils.translation import ugettext as _
 <%def name="breadcrumbs(path, breadcrumbs, from_listdir=False)">
     % if from_listdir:
       <ul class="nav nav-pills hueBreadcrumbBar">
-        %if path.lower().find('s3://') != 0:
+        %if path.lower().find('s3a://') != 0:
         <li><a href="${url('filebrowser.views.view', path=urlencode(path))}?default_to_home" class="homeLink"><i class="fa fa-home"></i> ${_('Home')}</a></li>
         %endif
         <li>

+ 4 - 4
apps/filebrowser/src/filebrowser/templates/listdir_components.mako

@@ -779,7 +779,7 @@ from django.utils.translation import ugettext as _
           mtime: file.mtime
         },
         isBucket: ko.pureComputed(function(){
-          return file.path.toLowerCase().indexOf('s3://') == 0 && file.path.substr(5).indexOf('/') == -1
+          return file.path.toLowerCase().indexOf('s3a://') == 0 && file.path.substr(5).indexOf('/') == -1
         }),
         selected: ko.observable(false),
         highlighted: ko.observable(file.highlighted || false),
@@ -972,11 +972,11 @@ from django.utils.translation import ugettext as _
       });
 
       self.isS3 = ko.pureComputed(function () {
-        return self.currentPath().toLowerCase().indexOf('s3://') === 0;
+        return self.currentPath().toLowerCase().indexOf('s3a://') === 0;
       });
 
       self.isS3Root = ko.pureComputed(function () {
-        return self.isS3() && self.currentPath().toLowerCase() === 's3://';
+        return self.isS3() && self.currentPath().toLowerCase() === 's3a://';
       });
 
       self.inTrash = ko.computed(function() {
@@ -1746,7 +1746,7 @@ from django.utils.translation import ugettext as _
               }
             }
           };
-          if (ops.path.toLowerCase() !== 's3://') {
+          if (ops.path.toLowerCase() !== 's3a://') {
             _dropzone = new Dropzone(document.body, options);
 
             _dropzone.on('queuecomplete', function () {

+ 1 - 1
apps/filebrowser/src/filebrowser/views_test.py

@@ -1057,4 +1057,4 @@ def test_location_to_url():
   assert_equal(prefix + '/var/lib/hadoop-hdfs', location_to_url('/var/lib/hadoop-hdfs', False))
   assert_equal(prefix + '/var/lib/hadoop-hdfs', location_to_url('hdfs://localhost:8020/var/lib/hadoop-hdfs'))
   assert_equal(prefix + '/', location_to_url('hdfs://localhost:8020'))
-  assert_equal(prefix + 's3%3A//bucket/key', location_to_url('s3://bucket/key'))
+  assert_equal(prefix + 's3a%3A//bucket/key', location_to_url('s3a://bucket/key'))

+ 5 - 5
desktop/core/src/desktop/lib/fs/fs_test.py

@@ -24,11 +24,11 @@ from desktop.lib import fs
 def test_splitpath():
   s = fs.splitpath
 
-  eq_(s('s3://'), ['s3://'])
-  eq_(s('s3://bucket'), ['s3://', 'bucket'])
-  eq_(s('s3://bucket/key'), ['s3://', 'bucket', 'key'])
-  eq_(s('s3://bucket/key/'), ['s3://', 'bucket', 'key'])
-  eq_(s('s3://bucket/bar/foo'), ['s3://', 'bucket', 'bar', 'foo'])
+  eq_(s('s3a://'), ['s3a://'])
+  eq_(s('s3a://bucket'), ['s3a://', 'bucket'])
+  eq_(s('s3a://bucket/key'), ['s3a://', 'bucket', 'key'])
+  eq_(s('s3a://bucket/key/'), ['s3a://', 'bucket', 'key'])
+  eq_(s('s3a://bucket/bar/foo'), ['s3a://', 'bucket', 'bar', 'foo'])
 
   eq_(s('/'), ['/'])
   eq_(s('/dir'), ['/', 'dir'])

+ 16 - 16
desktop/core/src/desktop/lib/fs/proxyfs_test.py

@@ -30,10 +30,10 @@ def test_fs_selection():
     raise SkipTest("Skips until HUE-2947 is resolved")
 
   s3fs, hdfs = MagicMock(), MagicMock()
-  proxy_fs = ProxyFS({'s3': s3fs, 'hdfs': hdfs}, 'hdfs')
+  proxy_fs = ProxyFS({'s3a': s3fs, 'hdfs': hdfs}, 'hdfs')
 
-  proxy_fs.isdir('s3://bucket/key')
-  s3fs.isdir.assert_called_once_with('s3://bucket/key')
+  proxy_fs.isdir('s3a://bucket/key')
+  s3fs.isdir.assert_called_once_with('s3a://bucket/key')
   assert_false(hdfs.isdir.called)
 
   proxy_fs.isfile('hdfs://localhost:42/user/alice/file')
@@ -51,11 +51,11 @@ def test_fs_selection():
 # TODO: remove after HUE-2947 is resolved
 def test__get_fs():
   s3fs, hdfs = 'fake_s3', 'fake_hdfs'
-  proxy_fs = ProxyFS({'s3': s3fs, 'hdfs': hdfs}, 'hdfs')
+  proxy_fs = ProxyFS({'s3a': s3fs, 'hdfs': hdfs}, 'hdfs')
   f = proxy_fs._get_fs
 
-  eq_(f('s3://bucket'), s3fs)
-  eq_(f('S3://bucket/key'), s3fs)
+  eq_(f('s3a://bucket'), s3fs)
+  eq_(f('S3A://bucket/key'), s3fs)
   eq_(f('hdfs://path'), hdfs)
   eq_(f('/tmp'), hdfs)
 
@@ -69,14 +69,14 @@ def test_multi_fs_selection():
   except ImportError:
     raise SkipTest("Skips until HUE-2947 is resolved")
   s3fs, hdfs = MagicMock(), MagicMock()
-  proxy_fs = ProxyFS({'s3': s3fs, 'hdfs': hdfs}, 'hdfs')
+  proxy_fs = ProxyFS({'s3a': s3fs, 'hdfs': hdfs}, 'hdfs')
 
-  proxy_fs.copy('s3://bucket1/key', 's3://bucket2/key')
-  s3fs.copy.assert_called_once_with('s3://bucket1/key', 's3://bucket2/key')
+  proxy_fs.copy('s3a://bucket1/key', 's3a://bucket2/key')
+  s3fs.copy.assert_called_once_with('s3a://bucket1/key', 's3a://bucket2/key')
   assert_false(hdfs.copy.called)
 
-  proxy_fs.copyfile('s3://bucket/key', 'key2')
-  s3fs.copyfile.assert_called_once_with('s3://bucket/key', 'key2')
+  proxy_fs.copyfile('s3a://bucket/key', 'key2')
+  s3fs.copyfile.assert_called_once_with('s3a://bucket/key', 'key2')
   assert_false(hdfs.copyfile.called)
 
   proxy_fs.rename('/tmp/file', 'shmile')
@@ -84,17 +84,17 @@ def test_multi_fs_selection():
   assert_false(s3fs.rename.called)
 
   # Will be addressed in HUE-2934
-  assert_raises(NotImplementedError, proxy_fs.copy_remote_dir, 's3://bucket/key', '/tmp/dir')
+  assert_raises(NotImplementedError, proxy_fs.copy_remote_dir, 's3a://bucket/key', '/tmp/dir')
 
 
 # TODO: remove after HUE-2947 is resolved
 def test__get_fs_pair():
   s3fs, hdfs = 'fake_s3', 'fake_hdfs'
-  proxy_fs = ProxyFS({'s3': s3fs, 'hdfs': hdfs}, 'hdfs')
+  proxy_fs = ProxyFS({'s3a': s3fs, 'hdfs': hdfs}, 'hdfs')
   f = proxy_fs._get_fs_pair
 
-  eq_(f('s3://bucket1/key', 's3://bucket2/key'), (s3fs, s3fs))
-  eq_(f('s3://bucket/key', 'key2'), (s3fs, s3fs))
+  eq_(f('s3a://bucket1/key', 's3a://bucket2/key'), (s3fs, s3fs))
+  eq_(f('s3a://bucket/key', 'key2'), (s3fs, s3fs))
   eq_(f('/tmp/file', 'shmile'), (hdfs, hdfs))
 
   assert_raises(IOError, f, 'ftp://host', 'key2')
@@ -102,4 +102,4 @@ def test__get_fs_pair():
 
 
 def test_constructor_given_invalid_arguments():
-  assert_raises(ValueError, ProxyFS, {'s3': {}}, 'hdfs')
+  assert_raises(ValueError, ProxyFS, {'s3a': {}}, 'hdfs')

+ 6 - 6
desktop/core/src/desktop/static/desktop/js/jquery.filechooser.js

@@ -147,10 +147,10 @@
           self.options.fsSelected = fs;
           var storedPath = $.totalStorage(STORAGE_PREFIX + self.options.user + self.options.fsSelected);
           if (storedPath !== null) {
-            if (fs === 's3' && storedPath.toLowerCase().indexOf('s3') === -1) {
-              self.navigateTo('S3://');
+            if (fs === 's3a' && storedPath.toLowerCase().indexOf('s3a') === -1) {
+              self.navigateTo('S3A://');
             }
-            else if (fs !== 's3' && storedPath.toLowerCase().indexOf('s3') > -1) {
+            else if (fs !== 's3a' && storedPath.toLowerCase().indexOf('s3a') > -1) {
               self.navigateTo('');
             }
             else {
@@ -158,7 +158,7 @@
             }
           }
           else {
-            self.navigateTo(fs === 's3' ? 'S3://' : '');
+            self.navigateTo(fs === 's3a' ? 'S3A://' : '');
           }
         });
         $li.appendTo($ul);
@@ -261,7 +261,7 @@
 
             if (file.type == "dir") {
               _flink.attr("href", "javascript:void(0)").text(" " + (file.name != "" ? file.name : "..")).appendTo(_f);
-              if (file.path.toLowerCase().indexOf('s3://') == 0 && file.path.substr(5).indexOf('/') == -1) {
+              if (file.path.toLowerCase().indexOf('s3a://') == 0 && file.path.substr(5).indexOf('/') == -1) {
                 $("<i class='fa fa-cloud'></i>").prependTo(_flink);
               }
               else {
@@ -375,7 +375,7 @@
         _parent.options.onError();
       }
       if (e.status === 404 || e.status === 500) {
-        _parent.navigateTo(_parent.options.errorRedirectPath != "" ? _parent.options.errorRedirectPath : (_parent.options.fsSelected === 's3' ? 'S3://' : '/?default_to_home'));
+        _parent.navigateTo(_parent.options.errorRedirectPath != "" ? _parent.options.errorRedirectPath : (_parent.options.fsSelected === 's3a' ? 'S3A://' : '/?default_to_home'));
       }
       else {
         console.error(e);

+ 1 - 1
desktop/core/src/desktop/static/desktop/js/jquery.hdfstree.js

@@ -286,7 +286,7 @@
 
     if (_this.options.isS3){
       _paths.shift();
-      _paths[0] = 's3://';
+      _paths[0] = 's3a://';
     }
 
     showHdfsLeaf({

+ 2 - 2
desktop/core/src/desktop/templates/common_header.mako

@@ -439,7 +439,7 @@ if USE_NEW_EDITOR.get():
             <li><a href="/${apps['filebrowser'].display_name}">
               <i class="fa fa-fw fa-file" style="vertical-align: middle"></i>${_('HDFS Browser')}</a>
             </li>
-            <li><a href="/${apps['filebrowser'].display_name}/view=S3://">
+            <li><a href="/${apps['filebrowser'].display_name}/view=S3A://">
               <i class="fa fa-fw fa-cloud" style="vertical-align: middle"></i>${_('S3 Browser')}</a>
             </li>
           </ul>
@@ -452,7 +452,7 @@ if USE_NEW_EDITOR.get():
       </li>
       <li class="hideMoreThan1380">
         % if is_s3_enabled():
-          <a title="${_('S3 Browser')}" rel="navigator-tooltip" href="/${apps['filebrowser'].display_name}/view=S3://">
+          <a title="${_('S3 Browser')}" rel="navigator-tooltip" href="/${apps['filebrowser'].display_name}/view=S3A://">
             <i class="fa fa-cloud"></i>
           </a>
         % endif

+ 10 - 10
desktop/libs/aws/src/aws/s3/__init__.py

@@ -35,7 +35,7 @@ ERRNO_MAP = {
 }
 DEFAULT_ERRNO = errno.EINVAL
 
-S3_PATH_RE = re.compile('^/*[sS]3[a]?://([^/]+)(/(.*?([^/]+)?/?))?$')
+S3_PATH_RE = re.compile('^/*[sS]3[aA]?://([^/]+)(/(.*?([^/]+)?/?))?$')
 S3_ROOT = 's3://'
 S3A_ROOT = 's3a://'
 
@@ -73,19 +73,19 @@ def parse_uri(uri):
 
 def is_root(uri):
   """
-  Check if URI is S3 root (S3://)
+  Check if URI is S3 root (S3A://)
   """
-  return uri.lower() == S3_ROOT
+  return uri.lower() == S3A_ROOT
 
 
 def abspath(cd, uri):
   """
   Returns absolute URI, examples:
 
-  abspath('s3://bucket/key', key2') == 's3://bucket/key/key2'
-  abspath('s3://bucket/key', 's3://bucket2/key2') == 's3://bucket2/key2'
+  abspath('s3a://bucket/key', key2') == 's3a://bucket/key/key2'
+  abspath('s3a://bucket/key', 's3a://bucket2/key2') == 'sa://bucket2/key2'
   """
-  if cd.lower().startswith(S3_ROOT):
+  if cd.lower().startswith(S3A_ROOT):
     uri = join(cd, uri)
   else:
     uri = normpath(join(cd, uri))
@@ -100,19 +100,19 @@ def join(*comp_list):
       return '/' if is_root(uri) else uri
   joined = posixpath.join(*map(_prep, comp_list))
   if joined and joined[0] == '/':
-    joined = 's3:/%s' % joined
+    joined = 's3a:/%s' % joined
   return joined
 
 
 def normpath(path):
   """
-  Return normalized path but ignore leading S3_ROOT prefix if it exists
+  Return normalized path but ignore leading S3A_ROOT prefix if it exists
   """
-  if path.lower().startswith(S3_ROOT):
+  if path.lower().startswith(S3A_ROOT):
     if is_root(path):
       normalized = path
     else:
-      normalized = '%s%s' % (S3_ROOT, fs_normpath(path[len(S3_ROOT):]))
+      normalized = '%s%s' % (S3A_ROOT, fs_normpath(path[len(S3A_ROOT):]))
   else:
     normalized = fs_normpath(path)
   return normalized

+ 17 - 17
desktop/libs/aws/src/aws/s3/s3_test.py

@@ -24,38 +24,38 @@ from aws import s3
 def test_parse_uri():
   p = s3.parse_uri
 
-  eq_(('bucket', 'folder/key', 'key'), p('s3://bucket/folder/key'))
-  eq_(('bucket', 'folder/key/', 'key'), p('s3://bucket/folder/key/'))
-  eq_(('bucket', 'folder/key/', 'key'), p('S3://bucket/folder/key/'))
-  eq_(('bucket', '', ''), p('s3://bucket'))
-  eq_(('bucket', '', ''), p('s3://bucket/'))
+  eq_(('bucket', 'folder/key', 'key'), p('s3a://bucket/folder/key'))
+  eq_(('bucket', 'folder/key/', 'key'), p('s3a://bucket/folder/key/'))
+  eq_(('bucket', 'folder/key/', 'key'), p('S3A://bucket/folder/key/'))
+  eq_(('bucket', '', ''), p('s3a://bucket'))
+  eq_(('bucket', '', ''), p('s3a://bucket/'))
 
   assert_raises(ValueError, p, '/local/path')
   assert_raises(ValueError, p, 'ftp://ancient/archive')
-  assert_raises(ValueError, p, 's3:/missed/slash')
-  assert_raises(ValueError, p, 's3://')
+  assert_raises(ValueError, p, 's3a:/missed/slash')
+  assert_raises(ValueError, p, 's3a://')
 
 
 def test_join():
   j = s3.join
-  eq_("s3://b", j("s3://", "b"))
-  eq_("s3://b/f", j("s3://b", "f"))
-  eq_("s3://b/f1/f2", j("s3://b", "f1", "f2"))
-  eq_("s3://b/f1/f2/../f3", j("s3://b/f1/f2", "../f3"))
+  eq_("s3a://b", j("s3a://", "b"))
+  eq_("s3a://b/f", j("s3a://b", "f"))
+  eq_("s3a://b/f1/f2", j("s3a://b", "f1", "f2"))
+  eq_("s3a://b/f1/f2/../f3", j("s3a://b/f1/f2", "../f3"))
 
 
 def test_abspath():
   a = s3.abspath
-  eq_('s3://a/b/c/d', a('s3://a/b/c', 'd'))
-  eq_('s3://a/b/c/d', a('/a/b/c', 'd'))
+  eq_('s3a://a/b/c/d', a('s3a://a/b/c', 'd'))
+  eq_('s3a://a/b/c/d', a('/a/b/c', 'd'))
 
 
 def test_is_root():
   i = s3.is_root
-  eq_(True, i('s3://'))
-  eq_(True, i('S3://'))
-  eq_(False, i('s3:/'))
-  eq_(False, i('s3://bucket'))
+  eq_(True, i('s3a://'))
+  eq_(True, i('S3A://'))
+  eq_(False, i('s3a:/'))
+  eq_(False, i('s3a://bucket'))
   eq_(False, i('/local/path'))
 
 

+ 3 - 3
desktop/libs/aws/src/aws/s3/s3fs.py

@@ -31,7 +31,7 @@ from boto.s3.prefix import Prefix
 from django.utils.translation import ugettext as _
 
 from aws import s3
-from aws.s3 import normpath, s3file, translate_s3_error, S3_ROOT
+from aws.s3 import normpath, s3file, translate_s3_error, S3A_ROOT
 from aws.s3.s3stat import S3Stat
 
 
@@ -160,9 +160,9 @@ class S3FileSystem(object):
     if not s3.is_root(parent_dir):
       bucket_name, key_name, basename = s3.parse_uri(path)
       if not basename:  # bucket is top-level so return root
-        parent_dir = S3_ROOT
+        parent_dir = S3A_ROOT
       else:
-        bucket_path = '%s%s' % (S3_ROOT, bucket_name)
+        bucket_path = '%s%s' % (S3A_ROOT, bucket_name)
         key_path = '/'.join(key_name.split('/')[:-1])
         parent_dir = s3.abspath(bucket_path, key_path)
     return parent_dir

+ 8 - 8
desktop/libs/aws/src/aws/s3/s3fs_test.py

@@ -95,10 +95,10 @@ class S3FSTest(S3TestBase):
     assert_true(self.fs.exists(dir_path))
     assert_true(self.fs.exists(file_path))
 
-    assert_true(self.fs.exists('s3://%s' % self.bucket_name))
-    assert_true(self.fs.exists('s3://'))
+    assert_true(self.fs.exists('s3a://%s' % self.bucket_name))
+    assert_true(self.fs.exists('s3a://'))
     fake_bucket = 'fake%s' % generate_id(8, string.ascii_lowercase + string.digits)
-    assert_false(self.fs.exists('s3://%s' % fake_bucket))
+    assert_false(self.fs.exists('s3a://%s' % fake_bucket))
 
 
   def test_stats(self):
@@ -106,13 +106,13 @@ class S3FSTest(S3TestBase):
     not_exists = self.get_test_path('does_not_exist')
     assert_raises(IOError, self.fs.stats, not_exists)
 
-    root_stat = self.fs.stats('s3://')
+    root_stat = self.fs.stats('s3a://')
     eq_(True, root_stat.isDir)
-    eq_('s3://', root_stat.path)
+    eq_('s3a://', root_stat.path)
 
-    bucket_stat = self.fs.stats('s3://%s' % self.bucket_name)
+    bucket_stat = self.fs.stats('s3a://%s' % self.bucket_name)
     eq_(True, bucket_stat.isDir)
-    eq_('s3://%s' % self.bucket_name, bucket_stat.path)
+    eq_('s3a://%s' % self.bucket_name, bucket_stat.path)
 
 
   def test_copyfile(self):
@@ -242,7 +242,7 @@ class S3FSTest(S3TestBase):
 
 
   def test_listing_buckets(self):
-    buckets = self.fs.listdir('s3://')
+    buckets = self.fs.listdir('s3a://')
     assert_true(len(buckets) > 0)
 
 

+ 4 - 4
desktop/libs/aws/src/aws/s3/s3stat.py

@@ -68,16 +68,16 @@ class S3Stat(object):
 
   @classmethod
   def from_bucket(cls, bucket):
-    return cls(bucket.name, 's3://%s' % bucket.name, True, 0, None)
+    return cls(bucket.name, 's3a://%s' % bucket.name, True, 0, None)
 
   @classmethod
   def from_key(cls, key, is_dir=False):
     if key.name:
       name = posixpath.basename(key.name[:-1] if key.name[-1] == '/' else key.name)
-      path = 's3://%s/%s' % (key.bucket.name, key.name)
+      path = 's3a://%s/%s' % (key.bucket.name, key.name)
     else:
       name = ''
-      path = 's3://%s' % key.bucket.name
+      path = 's3a://%s' % key.bucket.name
 
     size = key.size or 0
 
@@ -92,7 +92,7 @@ class S3Stat(object):
 
   @classmethod
   def for_s3_root(cls):
-    return cls('S3', 's3://', True, 0, None)
+    return cls('S3A', 's3a://', True, 0, None)
 
   def to_json_dict(self):
     """

+ 7 - 7
desktop/libs/aws/src/aws/s3/s3stat_test.py

@@ -23,7 +23,7 @@ from aws.s3.s3stat import S3Stat
 
 
 def test_derivable_properties():
-  s = S3Stat('foo', 's3://bar/foo', False, 40, 1424983327)
+  s = S3Stat('foo', 's3a://bar/foo', False, 40, 1424983327)
   eq_('FILE', s.type)
   eq_(0666 | stat.S_IFREG, s.mode)
   eq_('', s.user)
@@ -31,7 +31,7 @@ def test_derivable_properties():
   eq_(1424983327, s.atime)
   eq_(False, s.aclBit)
 
-  s = S3Stat('bar', 's3://bar', True, 0, 1424983327)
+  s = S3Stat('bar', 's3a://bar', True, 0, 1424983327)
   eq_('DIRECTORY', s.type)
   eq_(0777 | stat.S_IFDIR, s.mode)
 
@@ -40,7 +40,7 @@ def test_from_bucket():
   s = S3Stat.from_bucket(FakeBucket('boo'))
   eq_('DIRECTORY', s.type)
   eq_('boo', s.name)
-  eq_('s3://boo', s.path)
+  eq_('s3a://boo', s.path)
   eq_(0, s.size)
   eq_(None, s.atime)
 
@@ -50,7 +50,7 @@ def test_from_key():
   s = S3Stat.from_key(key)
   eq_('FILE', s.type)
   eq_('foo', s.name)
-  eq_('s3://bar/foo', s.path)
+  eq_('s3a://bar/foo', s.path)
   eq_(42, s.size)
   eq_(1424983327, s.mtime)
 
@@ -59,14 +59,14 @@ def test_from_key():
   s = S3Stat.from_key(key, is_dir=True)
   eq_('DIRECTORY', s.type)
   eq_(0, s.size)
-  eq_(0, s.atime)
+  eq_(None, s.atime)
 
 
 def test_for_s3_root():
   s = S3Stat.for_s3_root()
   eq_('DIRECTORY', s.type)
-  eq_('S3', s.name)
-  eq_('s3://', s.path)
+  eq_('S3A', s.name)
+  eq_('s3a://', s.path)
   eq_(0, s.size)
   eq_(None, s.atime)
 

+ 1 - 1
desktop/libs/aws/src/aws/s3/s3test_utils.py

@@ -69,7 +69,7 @@ class S3TestBase(unittest.TestCase):
 
   @classmethod
   def get_test_path(cls, path=None):
-    base_path = join('s3://', cls.bucket_name, cls.path_prefix)
+    base_path = join('s3a://', cls.bucket_name, cls.path_prefix)
     if path:
       return join(base_path, path)
     return base_path