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 43namespace 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. 47void PrintTo(const Extent& extent, ::std::ostream* os); 48void PrintTo(const ErrorCode& error_code, ::std::ostream* os); 49 50namespace test_utils { 51 52// 300 byte pseudo-random string. Not null terminated. 53// This does not gzip compress well. 54extern 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. 58bool WriteFileVector(const std::string& path, const brillo::Blob& data); 59bool 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. 66bool BindToUnusedLoopDevice(const std::string& filename, 67 bool writable, 68 std::string* out_lo_dev_name); 69bool UnbindLoopDevice(const std::string& lo_dev_name); 70 71// Returns true iff a == b 72bool ExpectVectorsEq(const brillo::Blob& a, const brillo::Blob& b); 73 74inline int System(const std::string& cmd) { 75 return system(cmd.c_str()); 76} 77 78inline int Symlink(const std::string& oldpath, const std::string& newpath) { 79 return symlink(oldpath.c_str(), newpath.c_str()); 80} 81 82inline int Chmod(const std::string& path, mode_t mode) { 83 return chmod(path.c_str(), mode); 84} 85 86inline int Mkdir(const std::string& path, mode_t mode) { 87 return mkdir(path.c_str(), mode); 88} 89 90inline 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. 95std::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. 100bool IsXAttrSupported(const base::FilePath& dir_path); 101 102void FillWithData(brillo::Blob* buffer); 103 104// Class to unmount FS when object goes out of scope 105class 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 122class 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 159class 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 175class 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. 193base::FilePath GetBuildArtifactsPath(); 194// Returns the path of the build artifact specified in |relative_path|. 195std::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 202class NoneType; 203 204template<typename T> 205class ObjectFeederAction; 206 207template<typename T> 208class 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. 216template<typename T> 217class 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 238template<typename T> 239class ObjectCollectorAction; 240 241template<typename T> 242class 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. 250template<typename T> 251class 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