1 // 2 // Copyright (C) 2012 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #ifndef UPDATE_ENGINE_COMMON_TEST_UTILS_H_ 18 #define UPDATE_ENGINE_COMMON_TEST_UTILS_H_ 19 20 #include <sys/stat.h> 21 #include <sys/types.h> 22 #include <unistd.h> 23 24 // Streams used for gtest's PrintTo() functions. 25 #include <iostream> // NOLINT(readability/streams) 26 #include <memory> 27 #include <set> 28 #include <string> 29 #include <vector> 30 31 #include <base/callback.h> 32 #include <base/files/file_path.h> 33 #include <gtest/gtest.h> 34 35 #include "update_engine/common/action.h" 36 #include "update_engine/common/subprocess.h" 37 #include "update_engine/common/utils.h" 38 #include "update_engine/update_metadata.pb.h" 39 40 // These are some handy functions for unittests. 41 42 namespace chromeos_update_engine { 43 44 // PrintTo() functions are used by gtest to log these objects. These PrintTo() 45 // functions must be defined in the same namespace as the first argument. 46 void PrintTo(const Extent& extent, ::std::ostream* os); 47 void PrintTo(const ErrorCode& error_code, ::std::ostream* os); 48 49 namespace test_utils { 50 51 // 300 byte pseudo-random string. Not null terminated. 52 // This does not gzip compress well. 53 extern const uint8_t kRandomString[300]; 54 55 // Writes the data passed to path. The file at path will be overwritten if it 56 // exists. Returns true on success, false otherwise. 57 bool WriteFileVector(const std::string& path, const brillo::Blob& data); 58 bool WriteFileString(const std::string& path, const std::string& data); 59 60 // Binds provided |filename| to an unused loopback device, whose name is written 61 // to the string pointed to by |out_lo_dev_name|. The new loop device will be 62 // read-only unless |writable| is set to true. Returns true on success, false 63 // otherwise (along with corresponding test failures), in which case the content 64 // of |out_lo_dev_name| is unknown. 65 bool BindToUnusedLoopDevice(const std::string& filename, 66 bool writable, 67 std::string* out_lo_dev_name); 68 bool UnbindLoopDevice(const std::string& lo_dev_name); 69 70 // Returns true iff a == b 71 bool ExpectVectorsEq(const brillo::Blob& a, const brillo::Blob& b); 72 73 inline int System(const std::string& cmd) { 74 return system(cmd.c_str()); 75 } 76 77 inline int Symlink(const std::string& oldpath, const std::string& newpath) { 78 return symlink(oldpath.c_str(), newpath.c_str()); 79 } 80 81 inline int Chmod(const std::string& path, mode_t mode) { 82 return chmod(path.c_str(), mode); 83 } 84 85 inline int Mkdir(const std::string& path, mode_t mode) { 86 return mkdir(path.c_str(), mode); 87 } 88 89 inline int Chdir(const std::string& path) { 90 return chdir(path.c_str()); 91 } 92 93 // Reads a symlink from disk. Returns empty string on failure. 94 std::string Readlink(const std::string& path); 95 96 // Checks if xattr is supported in the directory specified by 97 // |dir_path| which must be writable. Returns true if the feature is 98 // supported, false if not or if an error occurred. 99 bool IsXAttrSupported(const base::FilePath& dir_path); 100 101 void FillWithData(brillo::Blob* buffer); 102 103 // Creates an empty ext image. 104 void CreateEmptyExtImageAtPath(const std::string& path, 105 size_t size, 106 int block_size); 107 108 // Creates an ext image with some files in it. The paths creates are 109 // returned in out_paths. 110 void CreateExtImageAtPath(const std::string& path, 111 std::vector<std::string>* out_paths); 112 113 // Class to unmount FS when object goes out of scope 114 class ScopedFilesystemUnmounter { 115 public: 116 explicit ScopedFilesystemUnmounter(const std::string& mountpoint) 117 : mountpoint_(mountpoint), 118 should_unmount_(true) {} 119 ~ScopedFilesystemUnmounter() { 120 if (should_unmount_) { 121 utils::UnmountFilesystem(mountpoint_); 122 } 123 } 124 void set_should_unmount(bool unmount) { should_unmount_ = unmount; } 125 private: 126 const std::string mountpoint_; 127 bool should_unmount_; 128 DISALLOW_COPY_AND_ASSIGN(ScopedFilesystemUnmounter); 129 }; 130 131 class ScopedLoopbackDeviceBinder { 132 public: 133 ScopedLoopbackDeviceBinder(const std::string& file, 134 bool writable, 135 std::string* dev) { 136 is_bound_ = BindToUnusedLoopDevice(file, writable, &dev_); 137 EXPECT_TRUE(is_bound_); 138 139 if (is_bound_ && dev) 140 *dev = dev_; 141 } 142 143 ~ScopedLoopbackDeviceBinder() { 144 if (!is_bound_) 145 return; 146 147 for (int retry = 0; retry < 5; retry++) { 148 if (UnbindLoopDevice(dev_)) 149 return; 150 sleep(1); 151 } 152 ADD_FAILURE(); 153 } 154 155 const std::string &dev() { 156 EXPECT_TRUE(is_bound_); 157 return dev_; 158 } 159 160 bool is_bound() const { return is_bound_; } 161 162 private: 163 std::string dev_; 164 bool is_bound_; 165 DISALLOW_COPY_AND_ASSIGN(ScopedLoopbackDeviceBinder); 166 }; 167 168 class ScopedTempFile { 169 public: 170 ScopedTempFile() : ScopedTempFile("update_engine_test_temp_file.XXXXXX") {} 171 172 explicit ScopedTempFile(const std::string& pattern) { 173 EXPECT_TRUE(utils::MakeTempFile(pattern, &path_, nullptr)); 174 unlinker_.reset(new ScopedPathUnlinker(path_)); 175 } 176 177 const std::string& path() const { return path_; } 178 179 private: 180 std::string path_; 181 std::unique_ptr<ScopedPathUnlinker> unlinker_; 182 }; 183 184 class ScopedLoopMounter { 185 public: 186 explicit ScopedLoopMounter(const std::string& file_path, 187 std::string* mnt_path, 188 unsigned long flags); // NOLINT(runtime/int) 189 190 private: 191 // These objects must be destructed in the following order: 192 // ScopedFilesystemUnmounter (the file system must be unmounted first) 193 // ScopedLoopbackDeviceBinder (then the loop device can be deleted) 194 // ScopedDirRemover (then the mount point can be deleted) 195 std::unique_ptr<ScopedDirRemover> dir_remover_; 196 std::unique_ptr<ScopedLoopbackDeviceBinder> loop_binder_; 197 std::unique_ptr<ScopedFilesystemUnmounter> unmounter_; 198 }; 199 200 // Returns the path where the build artifacts are stored. This is the directory 201 // where the unittest executable is being run from. 202 base::FilePath GetBuildArtifactsPath(); 203 204 } // namespace test_utils 205 206 // Useful actions for test. These need to be defined in the 207 // chromeos_update_engine namespace. 208 209 class NoneType; 210 211 template<typename T> 212 class ObjectFeederAction; 213 214 template<typename T> 215 class ActionTraits<ObjectFeederAction<T>> { 216 public: 217 typedef T OutputObjectType; 218 typedef NoneType InputObjectType; 219 }; 220 221 // This is a simple Action class for testing. It feeds an object into 222 // another action. 223 template<typename T> 224 class ObjectFeederAction : public Action<ObjectFeederAction<T>> { 225 public: 226 typedef NoneType InputObjectType; 227 typedef T OutputObjectType; 228 void PerformAction() { 229 LOG(INFO) << "feeder running!"; 230 CHECK(this->processor_); 231 if (this->HasOutputPipe()) { 232 this->SetOutputObject(out_obj_); 233 } 234 this->processor_->ActionComplete(this, ErrorCode::kSuccess); 235 } 236 static std::string StaticType() { return "ObjectFeederAction"; } 237 std::string Type() const { return StaticType(); } 238 void set_obj(const T& out_obj) { 239 out_obj_ = out_obj; 240 } 241 private: 242 T out_obj_; 243 }; 244 245 template<typename T> 246 class ObjectCollectorAction; 247 248 template<typename T> 249 class ActionTraits<ObjectCollectorAction<T>> { 250 public: 251 typedef NoneType OutputObjectType; 252 typedef T InputObjectType; 253 }; 254 255 // This is a simple Action class for testing. It receives an object from 256 // another action. 257 template<typename T> 258 class ObjectCollectorAction : public Action<ObjectCollectorAction<T>> { 259 public: 260 typedef T InputObjectType; 261 typedef NoneType OutputObjectType; 262 void PerformAction() { 263 LOG(INFO) << "collector running!"; 264 ASSERT_TRUE(this->processor_); 265 if (this->HasInputObject()) { 266 object_ = this->GetInputObject(); 267 } 268 this->processor_->ActionComplete(this, ErrorCode::kSuccess); 269 } 270 static std::string StaticType() { return "ObjectCollectorAction"; } 271 std::string Type() const { return StaticType(); } 272 const T& object() const { return object_; } 273 private: 274 T object_; 275 }; 276 277 } // namespace chromeos_update_engine 278 279 #endif // UPDATE_ENGINE_COMMON_TEST_UTILS_H_ 280