MINIFICPP-1020 - PutFile fails to create empty files

Signed-off-by: Arpad Boda <aboda@apache.org>

Approved by phrocker and bakaid on GH

This closes #637
diff --git a/extensions/standard-processors/processors/PutFile.cpp b/extensions/standard-processors/processors/PutFile.cpp
index 880577f..54b5b04 100644
--- a/extensions/standard-processors/processors/PutFile.cpp
+++ b/extensions/standard-processors/processors/PutFile.cpp
@@ -218,11 +218,24 @@
     }
   }
 
-  ReadCallback cb(tmpFile, destFile);
-  session->read(flowFile, &cb);
+  bool success = false;
 
-  logger_->log_debug("Committing %s", destFile);
-  if (cb.commit()) {
+  if (flowFile->getSize() > 0) {
+    ReadCallback cb(tmpFile, destFile);
+    session->read(flowFile, &cb);
+    logger_->log_debug("Committing %s", destFile);
+    success = cb.commit();
+  } else {
+    std::ofstream outfile(destFile);
+    if (!outfile.good()) {
+      logger_->log_error("Failed to create empty file: %s", destFile);
+    } else {
+      success = true;
+    }
+    outfile.close();
+  }
+
+  if (success) {
     session->transfer(flowFile, Success);
     return true;
   } else {
diff --git a/extensions/standard-processors/tests/unit/PutFileTests.cpp b/extensions/standard-processors/tests/unit/PutFileTests.cpp
index ebf121d..b5b43f0 100644
--- a/extensions/standard-processors/tests/unit/PutFileTests.cpp
+++ b/extensions/standard-processors/tests/unit/PutFileTests.cpp
@@ -392,3 +392,37 @@
 
   LogTestController::getInstance().reset();
 }
+
+TEST_CASE("PutFileEmptyTest", "[EmptyFilePutTest]") {
+  TestController testController;
+
+  LogTestController::getInstance().setDebug<minifi::processors::GetFile>();
+  LogTestController::getInstance().setDebug<TestPlan>();
+  LogTestController::getInstance().setDebug<minifi::processors::PutFile>();
+
+  std::shared_ptr<TestPlan> plan = testController.createPlan();
+
+  std::shared_ptr<core::Processor> getfile = plan->addProcessor("GetFile", "getfileCreate2");
+
+  std::shared_ptr<core::Processor> putfile = plan->addProcessor("PutFile", "putfile", core::Relationship("success", "description"), true);
+
+  char format[] = "/tmp/gt.XXXXXX";
+  auto dir = testController.createTempDirectory(format);
+  char format2[] = "/tmp/ft.XXXXXX";
+  auto putfiledir = testController.createTempDirectory(format2);
+
+  plan->setProperty(getfile, org::apache::nifi::minifi::processors::GetFile::Directory.getName(), dir);
+  plan->setProperty(putfile, org::apache::nifi::minifi::processors::PutFile::Directory.getName(), putfiledir);
+
+  std::ofstream of(std::string(dir) + utils::file::FileUtils::get_separator() + "tstFile.ext");
+  of.close();
+
+  plan->runNextProcessor();  // Get
+  plan->runNextProcessor();  // Put
+
+  std::ifstream is(std::string(putfiledir) + utils::file::FileUtils::get_separator() + "tstFile.ext", std::ifstream::binary);
+
+  REQUIRE(is.is_open());
+  is.seekg(0, is.end);
+  REQUIRE(is.tellg() == 0);
+}