@@ -311,6 +311,8 @@ class AwsS3ClientWrapperImpl : public AwsS3ClientWrapper {
311311
312312namespace  test  {
313313//  An wrapper that mimicks S3 operations in local storage. Used for test.
314+ //  There are a lot of string copies between std::string and Aws::String
315+ //  unfortunately. However, since it's used for tests only, it's probably fine.
314316class  TestS3ClientWrapper  : public  AwsS3ClientWrapper  {
315317 public: 
316318  TestS3ClientWrapper (Env* base_env) : base_env_(base_env) {
@@ -326,28 +328,32 @@ class TestS3ClientWrapper : public AwsS3ClientWrapper {
326328    auto  bucket = ToStdString (request.GetBucket ());
327329    auto  prefix = ToStdString (request.GetPrefix ());
328330    auto  dir = getLocalPath (request.GetBucket (), request.GetPrefix ());
331+ 
332+     //  If this directory is not found, just ignore and return nothing.
329333    bool  is_dir{false };
330334    {
331335      Status st = base_env_->IsDirectory (dir, &is_dir);
332336      if  (!st.ok () || !is_dir) {
333337        return  ListObjectsOutcome (ListObjectsResult ());
334338      }
335339    }
340+ 
336341    std::vector<std::string> children;
337342    base_env_->GetChildren (dir, &children);
338343
339344    ListObjectsResult res;
340345    Aws::Vector<Object> contents;
341346    for  (const  auto & c : children) {
347+       //  Ignore these 2 special directories.
342348      if  (c == " ." " .." 
343349        continue ;
344350      }
345-       Object o;
346351      std::string x = prefix + c;
352+       Object o;
347353      o.SetKey (ToAwsString (x));
348354      contents.emplace_back (std::move (o));
349355    }
350-     res.SetContents (contents);
356+     res.SetContents (std::move ( contents) );
351357
352358    ListObjectsOutcome outcome (res);
353359    return  outcome;
@@ -407,7 +413,7 @@ class TestS3ClientWrapper : public AwsS3ClientWrapper {
407413    std::vector<char > scratch;
408414    scratch.reserve (file_size);
409415    Slice buffer;
410-     fromFile->Read (5000 , &buffer, scratch.data ());
416+     fromFile->Read (file_size , &buffer, scratch.data ());
411417    toFile->Append (buffer);
412418
413419    CopyObjectResult res;
@@ -441,6 +447,8 @@ class TestS3ClientWrapper : public AwsS3ClientWrapper {
441447    fromFile->Read (file_size, &buffer, scratch.data ());
442448
443449    if  (request.RangeHasBeenSet ()) {
450+       //  Range is a string in this format: "bytes=start-end".
451+       //  start and end are inclusive.
444452      auto  range = request.GetRange ();
445453      int  start = 0 ;
446454      int  end = 0 ;
@@ -467,6 +475,7 @@ class TestS3ClientWrapper : public AwsS3ClientWrapper {
467475
468476  virtual  std::shared_ptr<Aws::Transfer::TransferHandle> DownloadFile (
469477      const  Aws::String&, const  Aws::String&, const  Aws::String&) override  {
478+     //  Don't support AWS Transfer Manager for now.
470479    return  nullptr ;
471480  }
472481
@@ -479,10 +488,11 @@ class TestS3ClientWrapper : public AwsS3ClientWrapper {
479488    if  (stream) {
480489      ss << stream->rdbuf ();
481490    }
482-     std::string buffer = ToStdString (ss.str ());
491+ 
492+     //  First, create the actual file.
483493    {
494+       std::string buffer = ToStdString (ss.str ());
484495      auto  to = getLocalPath (request.GetBucket (), request.GetKey ());
485- 
486496      auto  parent_path = getParentPath (to);
487497      createDirRecursively (parent_path);
488498
@@ -493,9 +503,12 @@ class TestS3ClientWrapper : public AwsS3ClientWrapper {
493503        f->Append (buffer);
494504      }
495505
506+       //  Even if this is an empty file, we still want to create it.
496507      f->Sync ();
497508    }
498509
510+     //  If metadata is set on this file, create the metadata file.
511+     //  The metadata is stored in a separate directory.
499512    if  (request.MetadataHasBeenSet ()) {
500513      auto  to = getMetadataLocalPath (request.GetBucket (), request.GetKey ());
501514      auto  parent_path = getParentPath (to);
@@ -504,7 +517,7 @@ class TestS3ClientWrapper : public AwsS3ClientWrapper {
504517      std::unique_ptr<WritableFile> f;
505518      base_env_->NewWritableFile (to, &f, EnvOptions ());
506519
507-       std::string metadata = buildMetadata (request.GetMetadata ());
520+       std::string metadata = serializeMetadata (request.GetMetadata ());
508521      f->Append (metadata);
509522    }
510523
@@ -515,6 +528,7 @@ class TestS3ClientWrapper : public AwsS3ClientWrapper {
515528  virtual  std::shared_ptr<Aws::Transfer::TransferHandle> UploadFile (
516529      const  Aws::String&, const  Aws::String&, const  Aws::String&,
517530      uint64_t ) override  {
531+     //  Don't support AWS Transfer Manager for now.
518532    return  nullptr ;
519533  }
520534
@@ -544,6 +558,13 @@ class TestS3ClientWrapper : public AwsS3ClientWrapper {
544558    auto  metadataPath =
545559        getMetadataLocalPath (request.GetBucket (), request.GetKey ());
546560    if  (base_env_->FileExists (metadataPath).ok ()) {
561+       //  Metadata is stored in the following format
562+       //  ```
563+       //  key1
564+       //  value1
565+       //  key2
566+       //  value2
567+       //  ```
547568      std::ifstream metadataFile (metadataPath);
548569      std::string line;
549570      Aws::String key;
@@ -587,17 +608,20 @@ class TestS3ClientWrapper : public AwsS3ClientWrapper {
587608    return  root_dir_ + " /.metadata/" " /" 
588609  }
589610
611+   //  Given an S3 location, return actual directory on local disk.
590612  std::string getLocalPath (const  Aws::String& bucket,
591613                           const  Aws::String& prefix) {
592614    return  getLocalPathStr (ToStdString (bucket), ToStdString (prefix));
593615  }
594616
617+   //  Given an S3 location, return the metadata directory on local disk.
595618  std::string getMetadataLocalPath (const  Aws::String& bucket,
596619                                   const  Aws::String& prefix) {
597620    return  getMetadataLocalPathStr (ToStdString (bucket), ToStdString (prefix));
598621  }
599622
600-   std::string buildMetadata (
623+   //  Serialize metadata information in order to store on disk.
624+   std::string serializeMetadata (
601625      const  Aws::Map<Aws::String, Aws::String>& metadata) {
602626    Aws::StringStream ss;
603627    for  (const  auto & kv : metadata) {
@@ -606,18 +630,21 @@ class TestS3ClientWrapper : public AwsS3ClientWrapper {
606630    return  ToStdString (ss.str ());
607631  }
608632
633+   //  Recurisvely delete the directory.
609634  void  destroyDir (const  std::string& dir) {
610635    std::string cmd = " rm -rf " 
611636    int  rc = system (cmd.c_str ());
612637    (void )rc;
613638  }
614639
640+   //  Recursively create the directory and any missing component in the path.
615641  void  createDirRecursively (const  std::string& dir) {
616642    std::string cmd = " mkdir -p " 
617643    int  rc = system (cmd.c_str ());
618644    (void )rc;
619645  }
620646
647+   //  Given /a/b/c, return /a/b/
621648  std::string getParentPath (const  std::string& path) {
622649    auto  parts = StringSplit (path, ' /' 
623650    if  (parts.empty ()) {
0 commit comments