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