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