1 /* Copyright (c) 2013, 2021, Oracle and/or its affiliates.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
22 
23 // First include (the generated) my_config.h, to get correct platform defines.
24 #include "my_config.h"
25 #include <gtest/gtest.h>
26 #include <gmock/gmock.h>
27 
28 // Ignore test on windows, as we are mocking away a unix function, see below.
29 #ifndef _WIN32
30 namespace mysys_my_pwrite_unittest {
31 
32 using ::testing::_;
33 using ::testing::InSequence;
34 using ::testing::Return;
35 using ::testing::ReturnPointee;
36 using ::testing::SetErrnoAndReturn;
37 
38 class MockWrite
39 {
40 public:
~MockWrite()41   virtual ~MockWrite() {}
42   MOCK_METHOD4(mockwrite, ssize_t(int, const void *, size_t, off_t));
43   MOCK_METHOD3(mockseek, off_t(int, off_t, int));
44 };
45 
46 MockWrite *mockfs= NULL;
47 
48 // We need to mock away pwrite(2), do it with a macro:
49 #define pwrite(fd, buf, count, offset) mockfs->mockwrite(fd, buf, count, offset)
50 #define lseek(fd, offset, whence) mockfs->mockseek(fd, offset, whence)
51 
52 /*
53   Include the source file, which will give us
54   mysys_my_pwrite_unittest::my_pwrite() for testing.
55 */
56 #include "../../mysys/my_pread.c"
57 
58 #undef pwrite
59 #undef lseek
60 
61 class MysysMyPWriteTest : public ::testing::Test
62 {
SetUp()63   virtual void SetUp()
64   {
65     mockfs= new MockWrite;
66     m_offset= 0;
67     EXPECT_CALL(*mockfs, mockseek(_, m_offset, _))
68       .WillRepeatedly(ReturnPointee(&m_offset));
69   }
TearDown()70   virtual void TearDown()
71   {
72     delete mockfs;
73     mockfs= NULL;
74   }
75 public:
76   my_off_t m_offset;
77 };
78 
79 
80 // Test of normal case: write OK
TEST_F(MysysMyPWriteTest,MyPWriteOK)81 TEST_F(MysysMyPWriteTest, MyPWriteOK)
82 {
83   uchar buf[4096];
84   InSequence s;
85   EXPECT_CALL(*mockfs, mockwrite(_, _, 4096, _))
86     .Times(1)
87     .WillOnce(Return(4096));
88 
89   const size_t result= my_pwrite(42, buf, 4096, m_offset, 0);
90   EXPECT_EQ(4096U, result);
91 }
92 
93 
94 // Test of normal case: write OK with MY_NABP
TEST_F(MysysMyPWriteTest,MyPWriteOKNABP)95 TEST_F(MysysMyPWriteTest, MyPWriteOKNABP)
96 {
97   uchar buf[4096];
98   InSequence s;
99   EXPECT_CALL(*mockfs, mockwrite(_, _, 4096, _))
100     .Times(1)
101     .WillOnce(Return(4096));
102 
103   const size_t result= my_pwrite(42, buf, 4096, m_offset, MYF(MY_NABP));
104   EXPECT_EQ(0U, result);
105 }
106 
107 
108 // Test of disk full: write not OK
TEST_F(MysysMyPWriteTest,MyPWriteFail)109 TEST_F(MysysMyPWriteTest, MyPWriteFail)
110 {
111   uchar buf[4096];
112   InSequence s;
113   EXPECT_CALL(*mockfs, mockwrite(_, _, 4096, _))
114     .Times(1)
115     .WillOnce(SetErrnoAndReturn(ENOSPC, -1));
116 
117   const size_t result= my_pwrite(42, buf, 4096, m_offset, 0);
118   EXPECT_EQ(MY_FILE_ERROR, result);
119 }
120 
121 
122 // Test of disk full: write not OK, with MY_NABP
TEST_F(MysysMyPWriteTest,MyPWriteFailNABP)123 TEST_F(MysysMyPWriteTest, MyPWriteFailNABP)
124 {
125   uchar buf[4096];
126   InSequence s;
127   EXPECT_CALL(*mockfs, mockwrite(_, _, 4096, _))
128     .Times(1)
129     .WillOnce(SetErrnoAndReturn(ENOSPC, -1));
130 
131   const size_t result= my_pwrite(42, buf, 4096, m_offset, MYF(MY_NABP));
132   EXPECT_EQ(MY_FILE_ERROR, result);
133 }
134 
135 
136 // Test of disk full after partial write.
TEST_F(MysysMyPWriteTest,MyPWrite8192)137 TEST_F(MysysMyPWriteTest, MyPWrite8192)
138 {
139   uchar buf[8192];
140   InSequence s;
141   // Expect call to write 8192 bytes, return 4096.
142   EXPECT_CALL(*mockfs, mockwrite(_, _, 8192, _))
143     .Times(1)
144     .WillOnce(Return(4096));
145   // Expect second call to write remaining 4096 bytes, return disk full.
146   EXPECT_CALL(*mockfs, mockwrite(_, _, 4096, _))
147     .Times(1)
148     .WillOnce(SetErrnoAndReturn(ENOSPC, -1));
149 
150   const size_t result= my_pwrite(42, buf, 8192, m_offset, 0);
151   EXPECT_EQ(4096U, result);
152 }
153 
154 
155 // Test of disk full after partial write.
TEST_F(MysysMyPWriteTest,MyPWrite8192NABP)156 TEST_F(MysysMyPWriteTest, MyPWrite8192NABP)
157 {
158   uchar buf[8192];
159   InSequence s;
160   // Expect call to write 8192 bytes, return 4096.
161   EXPECT_CALL(*mockfs, mockwrite(_, _, 8192, _))
162     .Times(1)
163     .WillOnce(Return(4096));
164   // Expect second call to write remaining 4096 bytes, return disk full.
165   EXPECT_CALL(*mockfs, mockwrite(_, _, 4096, _))
166     .Times(1)
167     .WillOnce(SetErrnoAndReturn(ENOSPC, -1));
168 
169   const size_t result= my_pwrite(42, buf, 8192, m_offset, MYF(MY_NABP));
170   EXPECT_EQ(MY_FILE_ERROR, result);
171 }
172 
173 
174 // Test of partial write, followed by interrupt, followed by successful write.
TEST_F(MysysMyPWriteTest,MyPWrite8192Interrupt)175 TEST_F(MysysMyPWriteTest, MyPWrite8192Interrupt)
176 {
177   uchar buf[8192];
178   InSequence s;
179   // Expect call to write 8192 bytes, return 4096.
180   EXPECT_CALL(*mockfs, mockwrite(_, _, 8192, _))
181     .Times(1)
182     .WillOnce(Return(4096));
183   // Expect second call to write remaining 4096 bytes, return interrupt.
184   EXPECT_CALL(*mockfs, mockwrite(_, _, 4096, _))
185     .Times(1)
186     .WillOnce(SetErrnoAndReturn(EINTR, -1));
187   // Expect third call to write remaining 4096 bytes, return 4096.
188   EXPECT_CALL(*mockfs, mockwrite(_, _, 4096, _))
189     .Times(1)
190     .WillOnce(Return(4096));
191 
192   const size_t result= my_pwrite(42, buf, 8192, m_offset, 0);
193   EXPECT_EQ(8192U, result);
194 }
195 
196 
197 // Test of partial write, followed by interrupt, followed by successful write.
TEST_F(MysysMyPWriteTest,MyPWrite8192InterruptNABP)198 TEST_F(MysysMyPWriteTest, MyPWrite8192InterruptNABP)
199 {
200   uchar buf[8192];
201   InSequence s;
202   // Expect call to write 8192 bytes, return 4096.
203   EXPECT_CALL(*mockfs, mockwrite(_, _, 8192, _))
204     .Times(1)
205     .WillOnce(Return(4096));
206   // Expect second call to write remaining 4096 bytes, return interrupt.
207   EXPECT_CALL(*mockfs, mockwrite(_, _, 4096, _))
208     .Times(1)
209     .WillOnce(SetErrnoAndReturn(EINTR, -1));
210   // Expect third call to write remaining 4096 bytes, return 4096.
211   EXPECT_CALL(*mockfs, mockwrite(_, _, 4096, _))
212     .Times(1)
213     .WillOnce(Return(4096));
214 
215   const size_t result= my_pwrite(42, buf, 8192, m_offset, MYF(MY_NABP));
216   EXPECT_EQ(0U, result);
217 }
218 
219 
220 // Test of partial write, followed successful write.
TEST_F(MysysMyPWriteTest,MyPWrite400)221 TEST_F(MysysMyPWriteTest, MyPWrite400)
222 {
223   uchar buf[400];
224   InSequence s;
225   EXPECT_CALL(*mockfs, mockwrite(_, _, 400, _))
226     .Times(1)
227     .WillOnce(Return(200));
228   EXPECT_CALL(*mockfs, mockwrite(_, _, 200, _))
229     .Times(1)
230     .WillOnce(Return(200));
231 
232   const size_t result= my_pwrite(42, buf, 400, m_offset, 0);
233   EXPECT_EQ(400U, result);
234 }
235 
236 
237 // Test of partial write, followed successful write.
TEST_F(MysysMyPWriteTest,MyPWrite400NABP)238 TEST_F(MysysMyPWriteTest, MyPWrite400NABP)
239 {
240   uchar buf[400];
241   InSequence s;
242   EXPECT_CALL(*mockfs, mockwrite(_, _, 400, _))
243     .Times(1)
244     .WillOnce(Return(200));
245   EXPECT_CALL(*mockfs, mockwrite(_, _, 200, _))
246     .Times(1)
247     .WillOnce(Return(200));
248 
249   const size_t result= my_pwrite(42, buf, 400, m_offset, MYF(MY_NABP));
250   EXPECT_EQ(0U, result);
251 }
252 
253 
254 // Test of partial write, followed by failure, followed successful write.
TEST_F(MysysMyPWriteTest,MyPWrite300)255 TEST_F(MysysMyPWriteTest, MyPWrite300)
256 {
257   uchar buf[300];
258   InSequence s;
259   EXPECT_CALL(*mockfs, mockwrite(_, _, 300, _))
260     .Times(1)
261     .WillOnce(Return(100));
262   EXPECT_CALL(*mockfs, mockwrite(_, _, 200, _))
263     .Times(1)
264     .WillOnce(SetErrnoAndReturn(EAGAIN, 0));
265   EXPECT_CALL(*mockfs, mockwrite(_, _, 200, _))
266     .Times(1)
267     .WillOnce(Return(200));
268 
269   const size_t result= my_pwrite(42, buf, 300, m_offset, 0);
270   EXPECT_EQ(300U, result);
271 }
272 
273 }
274 #endif
275