summaryrefslogtreecommitdiff
path: root/chromeos/streams/fake_stream.h
blob: 2f8567d6eb4a2672416162ad25a9d2a90bfa5115 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Copyright 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef LIBCHROMEOS_CHROMEOS_STREAMS_FAKE_STREAM_H_
#define LIBCHROMEOS_CHROMEOS_STREAMS_FAKE_STREAM_H_

#include <queue>
#include <string>

#include <base/callback_forward.h>
#include <base/macros.h>
#include <base/time/clock.h>
#include <base/time/time.h>
#include <chromeos/secure_blob.h>
#include <chromeos/streams/stream.h>

namespace chromeos {

// 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 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);

  // 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, chromeos::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, chromeos::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 chromeos::Blob& GetFlushedOutputData() const;
  std::string GetFlushedOutputDataAsString() const;

  // Overrides from chromeos::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 WaitForData(AccessMode mode,
                   const base::Callback<void(AccessMode)>& callback,
                   ErrorPtr* error) override;
  bool WaitForDataBlocking(AccessMode in_mode,
                           base::TimeDelta timeout,
                           AccessMode* out_mode,
                           ErrorPtr* error) override;

 private:
  // Input data packet to be placed on the read queue.
  struct InputDataPacket {
    chromeos::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
    chromeos::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_;
  chromeos::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_;
  chromeos::Blob output_buffer_;
  chromeos::Blob expected_output_data_;
  size_t max_output_buffer_size_{0};
  bool report_write_error_{false};
  chromeos::Blob all_output_data_;

  DISALLOW_COPY_AND_ASSIGN(FakeStream);
};

}  // namespace chromeos

#endif  // LIBCHROMEOS_CHROMEOS_STREAMS_FAKE_STREAM_H_