diff options
| author | Patrick Venture <venture@google.com> | 2019-06-27 12:09:52 -0700 |
|---|---|---|
| committer | Patrick Venture <venture@google.com> | 2019-06-28 08:23:43 -0700 |
| commit | cf9b2195a3509b7481cbe564b0fc290c9bfc1475 (patch) | |
| tree | 58786be59d2759ee9f77d21ae77f37acd8780bbd /tools | |
| parent | a29216eccb47ab8d0fa50c78184dcfdd598f7725 (diff) | |
| download | phosphor-ipmi-flash-cf9b2195a3509b7481cbe564b0fc290c9bfc1475.tar.gz phosphor-ipmi-flash-cf9b2195a3509b7481cbe564b0fc290c9bfc1475.zip | |
tools: add progress implementation
Signed-off-by: Patrick Venture <venture@google.com>
Change-Id: I9da1674d6cbc688efc7bab0e033788d6ee4694f7
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/Makefile.am | 3 | ||||
| -rw-r--r-- | tools/bt.cpp | 10 | ||||
| -rw-r--r-- | tools/bt.hpp | 6 | ||||
| -rw-r--r-- | tools/interface.hpp | 1 | ||||
| -rw-r--r-- | tools/lpc.cpp | 10 | ||||
| -rw-r--r-- | tools/lpc.hpp | 6 | ||||
| -rw-r--r-- | tools/main.cpp | 9 | ||||
| -rw-r--r-- | tools/p2a.cpp | 10 | ||||
| -rw-r--r-- | tools/p2a.hpp | 6 | ||||
| -rw-r--r-- | tools/progress.cpp | 39 | ||||
| -rw-r--r-- | tools/progress.hpp | 38 | ||||
| -rw-r--r-- | tools/test/internal_sys_mock.hpp | 3 | ||||
| -rw-r--r-- | tools/test/progress_mock.hpp | 19 | ||||
| -rw-r--r-- | tools/test/tools_bt_unittest.cpp | 9 | ||||
| -rw-r--r-- | tools/test/tools_lpc_unittest.cpp | 11 |
15 files changed, 169 insertions, 11 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am index 086fba8..14d9618 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -21,7 +21,8 @@ libupdater_la_SOURCES = \ lpc.cpp \ io.cpp \ pci.cpp \ - p2a.cpp + p2a.cpp \ + progress.cpp libupdater_la_LIBADD = $(top_builddir)/libfirmware_common.la SUBDIRS = . test diff --git a/tools/bt.cpp b/tools/bt.cpp index 9e77688..d1e4dc7 100644 --- a/tools/bt.cpp +++ b/tools/bt.cpp @@ -16,6 +16,15 @@ bool BtDataHandler::sendContents(const std::string& input, return false; } + std::int64_t fileSize = sys->getSize(input.c_str()); + if (fileSize == 0) + { + std::fprintf(stderr, "Zero-length file, or other file access error\n"); + return false; + } + + progress->start(fileSize); + try { static constexpr int btBufferLen = 50; @@ -33,6 +42,7 @@ bool BtDataHandler::sendContents(const std::string& input, &readBuffer[bytesRead]); blob->writeBytes(session, offset, buffer); offset += bytesRead; + progress->updateProgress(bytesRead); } } while (bytesRead > 0); } diff --git a/tools/bt.hpp b/tools/bt.hpp index 729f74d..16605fd 100644 --- a/tools/bt.hpp +++ b/tools/bt.hpp @@ -2,6 +2,7 @@ #include "interface.hpp" #include "internal/sys.hpp" +#include "progress.hpp" #include <ipmiblob/blob_interface.hpp> @@ -11,10 +12,10 @@ namespace host_tool class BtDataHandler : public DataInterface { public: - BtDataHandler(ipmiblob::BlobInterface* blob, + BtDataHandler(ipmiblob::BlobInterface* blob, ProgressInterface* progress, const internal::Sys* sys = &internal::sys_impl) : blob(blob), - sys(sys){}; + progress(progress), sys(sys){}; bool sendContents(const std::string& input, std::uint16_t session) override; ipmi_flash::FirmwareFlags::UpdateFlags supportedType() const override @@ -24,6 +25,7 @@ class BtDataHandler : public DataInterface private: ipmiblob::BlobInterface* blob; + ProgressInterface* progress; const internal::Sys* sys; }; diff --git a/tools/interface.hpp b/tools/interface.hpp index 2c993bf..c613f0e 100644 --- a/tools/interface.hpp +++ b/tools/interface.hpp @@ -1,6 +1,7 @@ #pragma once #include "flags.hpp" +#include "progress.hpp" #include <cstdint> #include <string> diff --git a/tools/lpc.cpp b/tools/lpc.cpp index 7dbfaf3..3616085 100644 --- a/tools/lpc.cpp +++ b/tools/lpc.cpp @@ -103,6 +103,15 @@ bool LpcDataHandler::sendContents(const std::string& input, return false; } + std::int64_t fileSize = sys->getSize(input.c_str()); + if (fileSize == 0) + { + std::fprintf(stderr, "Zero-length file, or other file access error\n"); + return false; + } + + progress->start(fileSize); + /* For Nuvoton the maximum is 4K */ auto readBuffer = std::make_unique<std::uint8_t[]>(host_lpc_buf.length); if (nullptr == readBuffer) @@ -140,6 +149,7 @@ bool LpcDataHandler::sendContents(const std::string& input, /* This doesn't return anything on success. */ blob->writeBytes(session, offset, chunkBytes); offset += bytesRead; + progress->updateProgress(bytesRead); } } while (bytesRead > 0); } diff --git a/tools/lpc.hpp b/tools/lpc.hpp index 2c3a723..17367bb 100644 --- a/tools/lpc.hpp +++ b/tools/lpc.hpp @@ -3,6 +3,7 @@ #include "interface.hpp" #include "internal/sys.hpp" #include "io.hpp" +#include "progress.hpp" #include <cstdint> #include <ipmiblob/blob_interface.hpp> @@ -23,9 +24,11 @@ class LpcDataHandler : public DataInterface public: LpcDataHandler(ipmiblob::BlobInterface* blob, HostIoInterface* io, std::uint32_t address, std::uint32_t length, + ProgressInterface* progress, const internal::Sys* sys = &internal::sys_impl) : blob(blob), - io(io), address(address), length(length), sys(sys){}; + io(io), address(address), length(length), progress(progress), + sys(sys){}; bool sendContents(const std::string& input, std::uint16_t session) override; ipmi_flash::FirmwareFlags::UpdateFlags supportedType() const override @@ -38,6 +41,7 @@ class LpcDataHandler : public DataInterface HostIoInterface* io; std::uint32_t address; std::uint32_t length; + ProgressInterface* progress; const internal::Sys* sys; }; diff --git a/tools/main.cpp b/tools/main.cpp index c9e76c0..746e679 100644 --- a/tools/main.cpp +++ b/tools/main.cpp @@ -19,6 +19,7 @@ #include "lpc.hpp" #include "p2a.hpp" #include "pci.hpp" +#include "progress.hpp" #include "tool_errors.hpp" #include "updater.hpp" @@ -207,13 +208,15 @@ int main(int argc, char* argv[]) ipmiblob::BlobHandler blob(std::move(ipmi)); host_tool::DevMemDevice devmem; host_tool::PciUtilImpl pci; + host_tool::ProgressStdoutIndicator progress; std::unique_ptr<host_tool::DataInterface> handler; /* Input has already been validated in this case. */ if (interface == IPMIBT) { - handler = std::make_unique<host_tool::BtDataHandler>(&blob); + handler = + std::make_unique<host_tool::BtDataHandler>(&blob, &progress); } else if (interface == IPMILPC) { @@ -223,12 +226,12 @@ int main(int argc, char* argv[]) exit(EXIT_FAILURE); } handler = std::make_unique<host_tool::LpcDataHandler>( - &blob, &devmem, hostAddress, hostLength); + &blob, &devmem, hostAddress, hostLength, &progress); } else if (interface == IPMIPCI) { handler = std::make_unique<host_tool::P2aDataHandler>( - &blob, &devmem, &pci); + &blob, &devmem, &pci, &progress); } if (!handler) diff --git a/tools/p2a.cpp b/tools/p2a.cpp index 66fc62e..0ac5eb3 100644 --- a/tools/p2a.cpp +++ b/tools/p2a.cpp @@ -111,6 +111,15 @@ bool P2aDataHandler::sendContents(const std::string& input, return false; } + std::int64_t fileSize = sys->getSize(input.c_str()); + if (fileSize == 0) + { + std::fprintf(stderr, "Zero-length file, or other file access error\n"); + return false; + } + + progress->start(fileSize); + const std::uint32_t p2aLength = aspeedP2aOffset; auto readBuffer = std::make_unique<std::uint8_t[]>(p2aLength); @@ -152,6 +161,7 @@ bool P2aDataHandler::sendContents(const std::string& input, /* This doesn't return anything on success. */ blob->writeBytes(session, offset, chunkBytes); offset += bytesRead; + progress->updateProgress(bytesRead); } } while (bytesRead > 0); } diff --git a/tools/p2a.hpp b/tools/p2a.hpp index c84f12d..d1a303e 100644 --- a/tools/p2a.hpp +++ b/tools/p2a.hpp @@ -4,6 +4,7 @@ #include "internal/sys.hpp" #include "io.hpp" #include "pci.hpp" +#include "progress.hpp" #include <cstdint> #include <ipmiblob/blob_interface.hpp> @@ -22,10 +23,10 @@ class P2aDataHandler : public DataInterface { public: P2aDataHandler(ipmiblob::BlobInterface* blob, HostIoInterface* io, - PciUtilInterface* pci, + PciUtilInterface* pci, ProgressInterface* progress, const internal::Sys* sys = &internal::sys_impl) : blob(blob), - io(io), pci(pci), sys(sys) + io(io), pci(pci), progress(progress), sys(sys) { } @@ -39,6 +40,7 @@ class P2aDataHandler : public DataInterface ipmiblob::BlobInterface* blob; HostIoInterface* io; PciUtilInterface* pci; + ProgressInterface* progress; const internal::Sys* sys; }; diff --git a/tools/progress.cpp b/tools/progress.cpp new file mode 100644 index 0000000..a395ca3 --- /dev/null +++ b/tools/progress.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2019 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "progress.hpp" + +#include <cstdio> + +namespace host_tool +{ + +void ProgressStdoutIndicator::updateProgress(std::int64_t bytes) +{ + /* Print progress update. */ + currentBytes += bytes; + std::fprintf(stdout, "\rProgress: %.2f%%", + 100.0 * currentBytes / totalBytes); + std::fflush(stdout); +} + +void ProgressStdoutIndicator::start(std::int64_t bytes) +{ + totalBytes = bytes; + currentBytes = 0; +} + +} // namespace host_tool diff --git a/tools/progress.hpp b/tools/progress.hpp new file mode 100644 index 0000000..f884d62 --- /dev/null +++ b/tools/progress.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include <cstdint> + +namespace host_tool +{ + +class ProgressInterface +{ + public: + virtual ~ProgressInterface() = default; + + /** Update the progress by X bytes. This will inform any listening + * interfaces (just write to stdout mostly), and tick off as time passed. + */ + virtual void updateProgress(std::int64_t bytes) = 0; + virtual void start(std::int64_t bytes) = 0; +}; + +/** + * @brief A progress indicator that writes to stdout. It deliberately + * overwrites the same line when it's used, so it's advised to not interject + * other non-error messages. + */ +class ProgressStdoutIndicator : public ProgressInterface +{ + public: + ProgressStdoutIndicator() = default; + + void updateProgress(std::int64_t bytes) override; + void start(std::int64_t bytes) override; + + private: + std::int64_t totalBytes = 0; + std::int64_t currentBytes = 0; +}; + +} // namespace host_tool diff --git a/tools/test/internal_sys_mock.hpp b/tools/test/internal_sys_mock.hpp index fc98561..06aa023 100644 --- a/tools/test/internal_sys_mock.hpp +++ b/tools/test/internal_sys_mock.hpp @@ -4,6 +4,8 @@ #include <unistd.h> +#include <cstdint> + #include <gmock/gmock.h> namespace internal @@ -22,6 +24,7 @@ class InternalSysMock : public Sys MOCK_CONST_METHOD0(getpagesize, int()); MOCK_CONST_METHOD3(ioctl, int(int, unsigned long, void*)); MOCK_CONST_METHOD3(poll, int(struct pollfd*, nfds_t, int)); + MOCK_CONST_METHOD1(getSize, std::int64_t(const char*)); }; } // namespace internal diff --git a/tools/test/progress_mock.hpp b/tools/test/progress_mock.hpp new file mode 100644 index 0000000..80c0af1 --- /dev/null +++ b/tools/test/progress_mock.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "progress.hpp" + +#include <cstdint> + +#include <gmock/gmock.h> + +namespace host_tool +{ + +class ProgressMock : public ProgressInterface +{ + public: + MOCK_METHOD1(updateProgress, void(std::int64_t)); + MOCK_METHOD1(start, void(std::int64_t)); +}; + +} // namespace host_tool diff --git a/tools/test/tools_bt_unittest.cpp b/tools/test/tools_bt_unittest.cpp index 1a364d3..cca0b34 100644 --- a/tools/test/tools_bt_unittest.cpp +++ b/tools/test/tools_bt_unittest.cpp @@ -1,5 +1,6 @@ #include "bt.hpp" #include "internal_sys_mock.hpp" +#include "progress_mock.hpp" #include <cstring> #include <ipmiblob/test/blob_interface_mock.hpp> @@ -8,6 +9,8 @@ namespace host_tool { +namespace +{ using ::testing::_; using ::testing::ContainerEq; @@ -23,14 +26,17 @@ TEST(BtHandlerTest, verifySendsFileContents) */ internal::InternalSysMock sysMock; ipmiblob::BlobInterfaceMock blobMock; + ProgressMock progMock; - BtDataHandler handler(&blobMock, &sysMock); + BtDataHandler handler(&blobMock, &progMock, &sysMock); std::string filePath = "/asdf"; int fd = 1; std::uint16_t session = 0xbeef; std::vector<std::uint8_t> bytes = {'1', '2', '3', '4'}; + const int fakeFileSize = 100; EXPECT_CALL(sysMock, open(Eq(filePath), _)).WillOnce(Return(fd)); + EXPECT_CALL(sysMock, getSize(Eq(filePath))).WillOnce(Return(fakeFileSize)); EXPECT_CALL(sysMock, read(fd, NotNull(), _)) .WillOnce(Invoke([&](int fd, void* buf, std::size_t count) { EXPECT_TRUE(count > bytes.size()); @@ -45,4 +51,5 @@ TEST(BtHandlerTest, verifySendsFileContents) EXPECT_TRUE(handler.sendContents(filePath, session)); } +} // namespace } // namespace host_tool diff --git a/tools/test/tools_lpc_unittest.cpp b/tools/test/tools_lpc_unittest.cpp index 84a81eb..9e417ed 100644 --- a/tools/test/tools_lpc_unittest.cpp +++ b/tools/test/tools_lpc_unittest.cpp @@ -1,6 +1,7 @@ #include "internal_sys_mock.hpp" #include "io_mock.hpp" #include "lpc.hpp" +#include "progress_mock.hpp" #include <cstring> #include <ipmiblob/test/blob_interface_mock.hpp> @@ -9,6 +10,8 @@ namespace host_tool { +namespace +{ using ::testing::_; using ::testing::ContainerEq; @@ -23,14 +26,17 @@ TEST(LpcHandleTest, verifySendsFileContents) internal::InternalSysMock sysMock; ipmiblob::BlobInterfaceMock blobMock; HostIoInterfaceMock ioMock; + ProgressMock progMock; const std::uint32_t address = 0xfedc1000; const std::uint32_t length = 0x1000; - LpcDataHandler handler(&blobMock, &ioMock, address, length, &sysMock); + LpcDataHandler handler(&blobMock, &ioMock, address, length, &progMock, + &sysMock); std::uint16_t session = 0xbeef; std::string filePath = "/asdf"; int fileDescriptor = 5; + const int fakeFileSize = 100; LpcRegion host_lpc_buf; host_lpc_buf.address = address; @@ -45,6 +51,8 @@ TEST(LpcHandleTest, verifySendsFileContents) EXPECT_CALL(sysMock, open(StrEq(filePath.c_str()), _)) .WillOnce(Return(fileDescriptor)); + EXPECT_CALL(sysMock, getSize(StrEq(filePath.c_str()))) + .WillOnce(Return(fakeFileSize)); EXPECT_CALL(sysMock, read(_, NotNull(), Gt(data.size()))) .WillOnce(Invoke([&data](int, void* buf, std::size_t) { std::memcpy(buf, data.data(), data.size()); @@ -66,4 +74,5 @@ TEST(LpcHandleTest, verifySendsFileContents) EXPECT_TRUE(handler.sendContents(filePath, session)); } +} // namespace } // namespace host_tool |

