YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/memenv/memenv-test.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file. See the AUTHORS file for names of contributors.
4
//
5
// The following only applies to changes made to this file as part of YugaByte development.
6
//
7
// Portions Copyright (c) YugaByte, Inc.
8
//
9
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
10
// in compliance with the License.  You may obtain a copy of the License at
11
//
12
// http://www.apache.org/licenses/LICENSE-2.0
13
//
14
// Unless required by applicable law or agreed to in writing, software distributed under the License
15
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
16
// or implied.  See the License for the specific language governing permissions and limitations
17
// under the License.
18
//
19
// Modified for yb:
20
// - use gtest
21
22
#include <memory>
23
#include <unordered_set>
24
#include <vector>
25
26
#include <glog/logging.h>
27
#include <gtest/gtest.h>
28
29
#include "yb/gutil/map-util.h"
30
31
#include "yb/util/env.h"
32
#include "yb/util/env_util.h"
33
#include "yb/util/memenv/memenv.h"
34
#include "yb/util/result.h"
35
#include "yb/util/test_macros.h"
36
37
using std::shared_ptr;
38
using std::string;
39
using std::unordered_set;
40
using std::vector;
41
42
namespace yb {
43
44
class MemEnvTest : public ::testing::Test {
45
 public:
46
  Env* env_;
47
48
  MemEnvTest()
49
9
      : env_(NewMemEnv(Env::Default())) {
50
9
  }
51
9
  ~MemEnvTest() {
52
9
    delete env_;
53
9
  }
54
};
55
56
1
TEST_F(MemEnvTest, Basics) {
57
1
  uint64_t file_size;
58
1
  std::unique_ptr<WritableFile> writable_file;
59
1
  vector<string> children;
60
61
  // Create the directory.
62
1
  ASSERT_FALSE(env_->FileExists("/dir"));
63
1
  ASSERT_OK(env_->CreateDir("/dir"));
64
1
  ASSERT_TRUE(env_->FileExists("/dir"));
65
66
  // Check that the directory is empty.
67
1
  ASSERT_TRUE(!env_->FileExists("/dir/non_existent"));
68
1
  ASSERT_FALSE(env_->GetFileSize("/dir/non_existent").ok());
69
1
  ASSERT_OK(env_->GetChildren("/dir", &children));
70
1
  ASSERT_EQ(0, children.size());
71
72
  // Create a file.
73
1
  ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file));
74
1
  writable_file.reset();
75
76
  // Check that the file exists.
77
1
  ASSERT_TRUE(env_->FileExists("/dir/f"));
78
1
  file_size = ASSERT_RESULT(env_->GetFileSize("/dir/f"));
79
1
  ASSERT_EQ(0, file_size);
80
1
  ASSERT_OK(env_->GetChildren("/dir", &children));
81
1
  ASSERT_EQ(1, children.size());
82
1
  ASSERT_EQ("f", children[0]);
83
84
  // Write to the file.
85
1
  ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file));
86
1
  ASSERT_OK(writable_file->Append("abc"));
87
1
  writable_file.reset();
88
89
  // Check for expected size.
90
1
  file_size = ASSERT_RESULT(env_->GetFileSize("/dir/f"));
91
1
  ASSERT_EQ(3, file_size);
92
93
  // Check that renaming works.
94
1
  ASSERT_TRUE(!env_->RenameFile("/dir/non_existent", "/dir/g").ok());
95
1
  ASSERT_OK(env_->RenameFile("/dir/f", "/dir/g"));
96
1
  ASSERT_TRUE(!env_->FileExists("/dir/f"));
97
1
  ASSERT_TRUE(env_->FileExists("/dir/g"));
98
1
  file_size = ASSERT_RESULT(env_->GetFileSize("/dir/g"));
99
1
  ASSERT_EQ(3, file_size);
100
101
  // Check that opening non-existent file fails.
102
1
  std::unique_ptr<SequentialFile> seq_file;
103
1
  std::unique_ptr<RandomAccessFile> rand_file;
104
1
  ASSERT_TRUE(!env_->NewSequentialFile("/dir/non_existent", &seq_file).ok());
105
1
  ASSERT_TRUE(!seq_file);
106
1
  ASSERT_TRUE(!env_->NewRandomAccessFile("/dir/non_existent", &rand_file).ok());
107
1
  ASSERT_TRUE(!rand_file);
108
109
  // Check that deleting works.
110
1
  ASSERT_TRUE(!env_->DeleteFile("/dir/non_existent").ok());
111
1
  ASSERT_OK(env_->DeleteFile("/dir/g"));
112
1
  ASSERT_TRUE(!env_->FileExists("/dir/g"));
113
1
  ASSERT_OK(env_->GetChildren("/dir", &children));
114
1
  ASSERT_EQ(0, children.size());
115
1
  ASSERT_OK(env_->DeleteDir("/dir"));
116
1
  ASSERT_FALSE(env_->FileExists("/dir"));
117
1
}
118
119
1
TEST_F(MemEnvTest, ReadWrite) {
120
1
  Slice result;
121
1
  uint8_t scratch[100];
122
123
1
  ASSERT_OK(env_->CreateDir("/dir"));
124
125
1
  {
126
1
    std::unique_ptr<WritableFile> writable_file;
127
1
    ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file));
128
1
    ASSERT_OK(writable_file->Append("hello "));
129
1
    ASSERT_OK(writable_file->Append("world"));
130
1
  }
131
132
1
  {
133
    // Read sequentially.
134
1
    std::unique_ptr<SequentialFile> seq_file;
135
1
    ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file));
136
1
    ASSERT_OK(seq_file->Read(5, &result, scratch)); // Read "hello".
137
1
    ASSERT_EQ(0, result.compare("hello"));
138
1
    ASSERT_OK(seq_file->Skip(1));
139
1
    ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Read "world".
140
1
    ASSERT_EQ(0, result.compare("world"));
141
1
    ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Try reading past EOF.
142
1
    ASSERT_EQ(0, result.size());
143
1
    ASSERT_OK(seq_file->Skip(100)); // Try to skip past end of file.
144
1
    ASSERT_OK(seq_file->Read(1000, &result, scratch));
145
1
    ASSERT_EQ(0, result.size());
146
1
  }
147
148
1
  {
149
    // Random reads.
150
1
    std::unique_ptr<RandomAccessFile> rand_file;
151
1
    ASSERT_OK(env_->NewRandomAccessFile("/dir/f", &rand_file));
152
1
    ASSERT_OK(rand_file->Read(6, 5, &result, scratch)); // Read "world".
153
1
    ASSERT_EQ(0, result.compare("world"));
154
1
    ASSERT_OK(rand_file->Read(0, 5, &result, scratch)); // Read "hello".
155
1
    ASSERT_EQ(0, result.compare("hello"));
156
1
    ASSERT_OK(rand_file->Read(10, 100, &result, scratch)); // Read "d".
157
1
    ASSERT_EQ(0, result.compare("d"));
158
159
    // Too high offset.
160
1
    ASSERT_TRUE(!rand_file->Read(1000, 5, &result, scratch).ok());
161
1
  }
162
1
}
163
164
1
TEST_F(MemEnvTest, Locks) {
165
1
  FileLock* lock;
166
167
  // These are no-ops, but we test they return success.
168
1
  ASSERT_OK(env_->LockFile("some file", &lock, false /* recursive_lock_ok */));
169
1
  ASSERT_OK(env_->UnlockFile(lock));
170
1
}
171
172
1
TEST_F(MemEnvTest, Misc) {
173
1
  string test_dir;
174
1
  ASSERT_OK(env_->GetTestDirectory(&test_dir));
175
1
  ASSERT_TRUE(!test_dir.empty());
176
177
1
  std::unique_ptr<WritableFile> writable_file;
178
1
  ASSERT_OK(env_->NewWritableFile("/a/b", &writable_file));
179
180
  // These are no-ops, but we test they return success.
181
1
  ASSERT_OK(writable_file->Sync());
182
1
  ASSERT_OK(writable_file->Flush(WritableFile::FLUSH_SYNC));
183
1
  ASSERT_OK(writable_file->Flush(WritableFile::FLUSH_ASYNC));
184
1
  ASSERT_OK(writable_file->Close());
185
1
}
186
187
1
TEST_F(MemEnvTest, LargeWrite) {
188
1
  const size_t kWriteSize = 300 * 1024;
189
1
  std::unique_ptr<uint8_t[]> scratch(new uint8_t[kWriteSize * 2]);
190
191
1
  string write_data;
192
307k
  for (size_t i = 0; i < kWriteSize; ++i) {
193
307k
    write_data.append(1, static_cast<char>(i));
194
307k
  }
195
196
1
  std::unique_ptr<WritableFile> writable_file;
197
1
  ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file));
198
1
  ASSERT_OK(writable_file->Append("foo"));
199
1
  ASSERT_OK(writable_file->Append(write_data));
200
1
  writable_file.reset();
201
202
1
  std::unique_ptr<SequentialFile> seq_file;
203
1
  Slice result;
204
1
  ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file));
205
1
  ASSERT_OK(seq_file->Read(3, &result, scratch.get())); // Read "foo".
206
1
  ASSERT_EQ(0, result.compare("foo"));
207
208
1
  size_t read = 0;
209
1
  string read_data;
210
2
  while (read < kWriteSize) {
211
1
    ASSERT_OK(seq_file->Read(kWriteSize - read, &result, scratch.get()));
212
1
    read_data.append(reinterpret_cast<const char *>(result.data()),
213
1
                     result.size());
214
1
    read += result.size();
215
1
  }
216
1
  ASSERT_TRUE(write_data == read_data);
217
1
}
218
219
1
TEST_F(MemEnvTest, Overwrite) {
220
  // File does not exist, create it.
221
1
  shared_ptr<WritableFile> writer;
222
1
  ASSERT_OK(env_util::OpenFileForWrite(env_, "some file", &writer));
223
224
  // File exists, overwrite it.
225
1
  ASSERT_OK(env_util::OpenFileForWrite(env_, "some file", &writer));
226
227
  // File exists, try to overwrite (and fail).
228
1
  WritableFileOptions opts;
229
1
  opts.mode = Env::CREATE_NON_EXISTING;
230
1
  Status s = env_util::OpenFileForWrite(opts,
231
1
                                        env_, "some file", &writer);
232
1
  ASSERT_TRUE(s.IsAlreadyPresent());
233
1
}
234
235
1
TEST_F(MemEnvTest, Reopen) {
236
1
  string first = "The quick brown fox";
237
1
  string second = "jumps over the lazy dog";
238
239
  // Create the file and write to it.
240
1
  shared_ptr<WritableFile> writer;
241
1
  ASSERT_OK(env_util::OpenFileForWrite(env_, "some file", &writer));
242
1
  ASSERT_OK(writer->Append(first));
243
1
  ASSERT_EQ(first.length(), writer->Size());
244
1
  ASSERT_OK(writer->Close());
245
246
  // Reopen it and append to it.
247
1
  WritableFileOptions reopen_opts;
248
1
  reopen_opts.mode = Env::OPEN_EXISTING;
249
1
  ASSERT_OK(env_util::OpenFileForWrite(reopen_opts,
250
1
                                       env_, "some file", &writer));
251
1
  ASSERT_EQ(first.length(), writer->Size());
252
1
  ASSERT_OK(writer->Append(second));
253
1
  ASSERT_EQ(first.length() + second.length(), writer->Size());
254
1
  ASSERT_OK(writer->Close());
255
256
  // Check that the file has both strings.
257
1
  shared_ptr<RandomAccessFile> reader;
258
1
  ASSERT_OK(env_util::OpenFileForRandom(env_, "some file", &reader));
259
1
  uint64_t size = ASSERT_RESULT(reader->Size());
260
1
  ASSERT_EQ(first.length() + second.length(), size);
261
1
  Slice s;
262
1
  std::vector<uint8_t> scratch(size);
263
1
  ASSERT_OK(env_util::ReadFully(reader.get(), 0, size, &s, scratch.data()));
264
1
  ASSERT_EQ(first + second, s.ToString());
265
1
}
266
267
1
TEST_F(MemEnvTest, TempFile) {
268
1
  string tmpl = "foo.XXXXXX";
269
1
  string bad_tmpl = "foo.YYY";
270
271
1
  string path;
272
1
  std::unique_ptr<WritableFile> file;
273
274
  // Ensure we don't accept a bad template.
275
1
  Status s = env_->NewTempWritableFile(WritableFileOptions(), bad_tmpl, &path, &file);
276
2
  ASSERT_TRUE(s.IsInvalidArgument()) << "Should not accept bad template: " << s.ToString();
277
1
  ASSERT_STR_CONTAINS(s.ToString(), "must end with the string XXXXXX");
278
279
  // Create multiple temp files, ensure no collisions.
280
1
  unordered_set<string> paths;
281
11
  for (int i = 0; i < 10; i++) {
282
10
    ASSERT_OK(env_->NewTempWritableFile(WritableFileOptions(), tmpl, &path, &file));
283
0
    VLOG(1) << "Created temporary file at path " << path;
284
20
    ASSERT_EQ(path.length(), tmpl.length()) << "Template and final path should have same length";
285
20
    ASSERT_NE(path, tmpl) << "Template and final path should differ";
286
10
    ASSERT_OK(file->Append("Hello, tempfile.\n"));
287
10
    ASSERT_OK(file->Close());
288
20
    ASSERT_FALSE(ContainsKey(paths, path)) << "Created " << path << " twice!";
289
10
    InsertOrDie(&paths, path); // Will crash if we have a duplicate.
290
10
  }
291
292
  // Delete the files we created.
293
10
  for (const string& p : paths) {
294
10
    ASSERT_OK(env_->DeleteFile(p));
295
10
  }
296
1
}
297
298
1
TEST_F(MemEnvTest, TestRWFile) {
299
  // Create the file.
300
1
  std::unique_ptr<RWFile> file;
301
1
  ASSERT_OK(env_->NewRWFile("foo", &file));
302
303
  // Append to it.
304
1
  string kTestData = "abcdefghijklmno";
305
1
  ASSERT_OK(file->Write(0, kTestData));
306
307
  // Read from it.
308
1
  Slice result;
309
1
  std::unique_ptr<uint8_t[]> scratch(new uint8_t[kTestData.length()]);
310
1
  ASSERT_OK(file->Read(0, kTestData.length(), &result, scratch.get()));
311
1
  ASSERT_EQ(result, kTestData);
312
313
  // Try to rewrite; it shouldn't work.
314
1
  ASSERT_TRUE(file->Write(0, kTestData).IsNotSupported());
315
316
  // Make sure we can't overwrite it.
317
1
  RWFileOptions opts;
318
1
  opts.mode = Env::CREATE_NON_EXISTING;
319
1
  ASSERT_TRUE(env_->NewRWFile(opts, "foo", &file).IsAlreadyPresent());
320
321
  // Reopen it without truncating the existing data.
322
1
  opts.mode = Env::OPEN_EXISTING;
323
1
  ASSERT_OK(env_->NewRWFile(opts, "foo", &file));
324
1
  ASSERT_OK(file->Read(0, kTestData.length(), &result, scratch.get()));
325
1
  ASSERT_EQ(result, kTestData);
326
1
}
327
328
}  // namespace yb