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 42namespace 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. 46void PrintTo(const Extent& extent, ::std::ostream* os); 47void PrintTo(const ErrorCode& error_code, ::std::ostream* os); 48 49namespace test_utils { 50 51// 300 byte pseudo-random string. Not null terminated. 52// This does not gzip compress well. 53extern 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. 57bool WriteFileVector(const std::string& path, const brillo::Blob& data); 58bool 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. 65bool BindToUnusedLoopDevice(const std::string& filename, 66 bool writable, 67 std::string* out_lo_dev_name); 68bool UnbindLoopDevice(const std::string& lo_dev_name); 69 70// Returns true iff a == b 71bool ExpectVectorsEq(const brillo::Blob& a, const brillo::Blob& b); 72 73inline int System(const std::string& cmd) { 74 return system(cmd.c_str()); 75} 76 77inline int Symlink(const std::string& oldpath, const std::string& newpath) { 78 return symlink(oldpath.c_str(), newpath.c_str()); 79} 80 81inline int Chmod(const std::string& path, mode_t mode) { 82 return chmod(path.c_str(), mode); 83} 84 85inline int Mkdir(const std::string& path, mode_t mode) { 86 return mkdir(path.c_str(), mode); 87} 88 89inline 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. 94std::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. 99bool IsXAttrSupported(const base::FilePath& dir_path); 100 101void FillWithData(brillo::Blob* buffer); 102 103// Creates an empty ext image. 104void 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. 110void CreateExtImageAtPath(const std::string& path, 111 std::vector<std::string>* out_paths); 112 113// Class to unmount FS when object goes out of scope 114class 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 131class 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 168class 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 184class 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. 202base::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 209class NoneType; 210 211template<typename T> 212class ObjectFeederAction; 213 214template<typename T> 215class 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. 223template<typename T> 224class 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 245template<typename T> 246class ObjectCollectorAction; 247 248template<typename T> 249class 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. 257template<typename T> 258class 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