| // Copyright 2015 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef LIBBRILLO_BRILLO_STREAMS_FAKE_STREAM_H_ | |
| #define LIBBRILLO_BRILLO_STREAMS_FAKE_STREAM_H_ | |
| #include <queue> | |
| #include <string> | |
| #include <base/functional/callback_forward.h> | |
| #include <base/time/clock.h> | |
| #include <base/time/time.h> | |
| #include <brillo/brillo_export.h> | |
| #include <brillo/secure_blob.h> | |
| #include <brillo/streams/stream.h> | |
| namespace brillo { | |
| // Fake stream implementation for testing. | |
| // This class allows to provide data for the stream in tests that can be later | |
| // read through the Stream interface. Also, data written into the stream can be | |
| // later inspected and verified. | |
| // | |
| // NOTE: This class provides a fake implementation for streams with separate | |
| // input and output channels. That is, read and write operations do not affect | |
| // each other. Also, the stream implementation is sequential only (no seeking). | |
| // Good examples of a use case for fake stream are: | |
| // - read-only sequential streams (file, memory, pipe, ...) | |
| // - write-only sequential streams (same as above) | |
| // - independent channel read-write streams (sockets, ...) | |
| // | |
| // For more complex read/write stream test scenarios using a real MemoryStream | |
| // or temporary FileStream is probably a better choice. | |
| class BRILLO_EXPORT FakeStream : public Stream { | |
| public: | |
| // Construct a new instance of the fake stream. | |
| // mode - expected read/write mode supported by the stream. | |
| // clock - the clock to use to get the current time. | |
| FakeStream(Stream::AccessMode mode, base::Clock* clock); | |
| FakeStream(const FakeStream&) = delete; | |
| FakeStream& operator=(const FakeStream&) = delete; | |
| // Add data packets to the read queue of the stream. | |
| // Optional |delay| indicates that the data packet should be delayed. | |
| void AddReadPacketData(base::TimeDelta delay, const void* data, size_t size); | |
| void AddReadPacketData(base::TimeDelta delay, brillo::Blob data); | |
| void AddReadPacketString(base::TimeDelta delay, const std::string& data); | |
| // Schedule a read error by adding a special error packet to the queue. | |
| void QueueReadError(base::TimeDelta delay); | |
| void QueueReadErrorWithMessage(base::TimeDelta delay, | |
| const std::string& message); | |
| // Resets read queue and clears any input data buffers. | |
| void ClearReadQueue(); | |
| // Add expectations for output data packets to be written by the stream. | |
| // Optional |delay| indicates that the initial write operation for the data in | |
| // the packet should be delayed. | |
| // ExpectWritePacketSize just limits the size of output packet while | |
| // ExpectWritePacketData also validates that the data matches that of |data|. | |
| void ExpectWritePacketSize(base::TimeDelta delay, size_t data_size); | |
| void ExpectWritePacketData(base::TimeDelta delay, | |
| const void* data, | |
| size_t size); | |
| void ExpectWritePacketData(base::TimeDelta delay, brillo::Blob data); | |
| void ExpectWritePacketString(base::TimeDelta delay, const std::string& data); | |
| // Schedule a write error by adding a special error packet to the queue. | |
| void QueueWriteError(base::TimeDelta delay); | |
| void QueueWriteErrorWithMessage(base::TimeDelta delay, | |
| const std::string& message); | |
| // Resets write queue and clears any output data buffers. | |
| void ClearWriteQueue(); | |
| // Returns the output data accumulated so far by all complete write packets, | |
| // or explicitly flushed. | |
| const brillo::Blob& GetFlushedOutputData() const; | |
| std::string GetFlushedOutputDataAsString() const; | |
| // Overrides from brillo::Stream. | |
| bool IsOpen() const override { return is_open_; } | |
| bool CanRead() const override; | |
| bool CanWrite() const override; | |
| bool CanSeek() const override { return false; } | |
| bool CanGetSize() const override { return false; } | |
| uint64_t GetSize() const override { return 0; } | |
| bool SetSizeBlocking(uint64_t size, ErrorPtr* error) override; | |
| uint64_t GetRemainingSize() const override { return 0; } | |
| uint64_t GetPosition() const override { return 0; } | |
| bool Seek(int64_t offset, | |
| Whence whence, | |
| uint64_t* new_position, | |
| ErrorPtr* error) override; | |
| bool ReadNonBlocking(void* buffer, | |
| size_t size_to_read, | |
| size_t* size_read, | |
| bool* end_of_stream, | |
| ErrorPtr* error) override; | |
| bool WriteNonBlocking(const void* buffer, | |
| size_t size_to_write, | |
| size_t* size_written, | |
| ErrorPtr* error) override; | |
| bool FlushBlocking(ErrorPtr* error) override; | |
| bool CloseBlocking(ErrorPtr* error) override; | |
| bool WaitForDataRead(base::OnceClosure callback, ErrorPtr* error) override; | |
| bool WaitForDataReadBlocking(base::TimeDelta timeout, | |
| ErrorPtr* error) override; | |
| bool WaitForDataWrite(base::OnceClosure callback, ErrorPtr* error) override; | |
| bool WaitForDataWriteBlocking(base::TimeDelta timeout, | |
| ErrorPtr* error) override; | |
| private: | |
| // Input data packet to be placed on the read queue. | |
| struct InputDataPacket { | |
| brillo::Blob data; // Data to be read. | |
| base::TimeDelta delay_before; // Possible delay for the first read. | |
| bool read_error{false}; // Set to true if this packet generates an error. | |
| }; | |
| // Output data packet to be placed on the write queue. | |
| struct OutputDataPacket { | |
| size_t expected_size{0}; // Output packet size | |
| brillo::Blob data; // Possible data to verify the output with. | |
| base::TimeDelta delay_before; // Possible delay for the first write. | |
| bool write_error{false}; // Set to true if this packet generates an error. | |
| }; | |
| // Check if there is any pending read data in the input buffer. | |
| bool IsReadBufferEmpty() const; | |
| // Pops the next read packet from the queue and sets its data into the | |
| // internal input buffer. | |
| bool PopReadPacket(); | |
| // Check if the output buffer is full. | |
| bool IsWriteBufferFull() const; | |
| // Moves the current full output buffer into |all_output_data_|, clears the | |
| // buffer, and pops the information about the next expected output packet | |
| // from the write queue. | |
| bool PopWritePacket(); | |
| bool is_open_{true}; | |
| Stream::AccessMode mode_; | |
| base::Clock* clock_; | |
| // Internal data for read operations. | |
| std::queue<InputDataPacket> incoming_queue_; | |
| base::Time delay_input_until_; | |
| brillo::Blob input_buffer_; | |
| size_t input_ptr_{0}; | |
| bool report_read_error_{false}; | |
| // Internal data for write operations. | |
| std::queue<OutputDataPacket> outgoing_queue_; | |
| base::Time delay_output_until_; | |
| brillo::Blob output_buffer_; | |
| brillo::Blob expected_output_data_; | |
| size_t max_output_buffer_size_{0}; | |
| bool report_write_error_{false}; | |
| brillo::Blob all_output_data_; | |
| }; | |
| } // namespace brillo | |
| #endif // LIBBRILLO_BRILLO_STREAMS_FAKE_STREAM_H_ |