Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adsk Contrib - Harden test temp folder handling #2019

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 72 additions & 26 deletions tests/cpu/OCIOZArchive_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,80 @@ namespace OCIO = OCIO_NAMESPACE;

namespace
{
struct FileCreationGuard
{
explicit FileCreationGuard(unsigned lineNo)
{
OCIO_CHECK_NO_THROW_FROM(m_filename = OCIO::Platform::CreateTempFilename(""), lineNo);
}
~FileCreationGuard()
struct FileCreationGuard
{
// Even if not strictly required on most OSes, perform the cleanup.
std::remove(m_filename.c_str());
}
explicit FileCreationGuard(unsigned lineNo)
{
try
{
m_filename = OCIO::Platform::CreateTempFilename("");
}
catch (...)
{
std::ostringstream ss;
ss << "Temp file creation for line " << lineNo << " failed. Test will fail.";
throw OCIO::Exception(ss.str().c_str());
}

if(!m_filename.empty())
{
m_isCreated = true;
}
}
~FileCreationGuard()
{
// Even if not strictly required on most OSes, perform the cleanup.
if (m_isCreated)
{
std::remove(m_filename.c_str());
}

m_isCreated = false;
}

std::string m_filename;
};
std::string m_filename;
bool m_isCreated = false;
};

struct DirectoryCreationGuard
{
explicit DirectoryCreationGuard(const std::string name, unsigned lineNo)
{
OCIO_CHECK_NO_THROW_FROM(
m_directoryPath = OCIO::CreateTemporaryDirectory(name), lineNo
);
}
~DirectoryCreationGuard()
struct DirectoryCreationGuard
{
// Even if not strictly required on most OSes, perform the cleanup.
OCIO::RemoveTemporaryDirectory(m_directoryPath);
}
explicit DirectoryCreationGuard(const std::string name, unsigned lineNo)
{
try
{
m_directoryPath = OCIO::CreateTemporaryDirectory(name);
}
catch (...)
{
std::ostringstream ss;
ss << "Temp folder creation for name '" << name << "' for line " << lineNo << " failed. Test will fail.";
throw OCIO::Exception(ss.str().c_str());
}

if (!m_directoryPath.empty())
{
m_isCreated = true;
}
}
~DirectoryCreationGuard()
{
// Even if not strictly required on most OSes, perform the cleanup.
if (m_isCreated && !m_directoryPath.empty())
{
OCIO::RemoveTemporaryDirectory(m_directoryPath);
}

m_isCreated = false;
}

bool created() const
{
return m_isCreated;
}

std::string m_directoryPath;
};
std::string m_directoryPath;
bool m_isCreated = false;
};
} //anon.


Expand Down Expand Up @@ -524,6 +567,9 @@ OCIO_ADD_TEST(OCIOZArchive, extract_config_and_compare_to_original)

// 2 - Extract the OCIOZ archive to temporary directory.
DirectoryCreationGuard dGuard("context_test1", __LINE__);

OCIO_REQUIRE_ASSERT(dGuard.created()); // Don't continue if the temp folder creation failed.

OCIO_CHECK_NO_THROW(OCIO::ExtractOCIOZArchive(
archivePath.c_str(), dGuard.m_directoryPath.c_str()
));
Expand Down
111 changes: 63 additions & 48 deletions tests/cpu/UnitTestUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,107 +71,122 @@ ConstProcessorRcPtr GetFileTransformProcessor(const std::string & fileName)
return config->getProcessor(fileTransform);
}

namespace
{
constexpr const char* TempDirMagicPrefix = "OCIOTestTemp_";
}

std::string CreateTemporaryDirectory(const std::string & name)
{
std::string extended_name = TempDirMagicPrefix + name;

int nError = 0;

#if defined(_WIN32)
std::string sPath = GetEnvVariable("TEMP");
static const std::string directory = pystring::os::path::join(sPath, name);
char cPath[MAX_PATH];
DWORD len = GetTempPathA(MAX_PATH, cPath);
if( len>MAX_PATH || len==0 )
{
throw Exception("Temp path could not be determined.");
}

static const std::string directory = pystring::os::path::join(cPath, extended_name);
nError = _mkdir(directory.c_str());
#else
std::string sPath = "/tmp";
const std::string directory = pystring::os::path::join(sPath, name);
const std::string directory = pystring::os::path::join(sPath, extended_name);
nError = mkdir(directory.c_str(), 0777);
#endif

if (nError != 0)
{
std::ostringstream error;
error << "Could not create a temporary directory." << " Make sure that the directory do "
<< "not already exist or sufficient permissions are set";
error << "Could not create a temporary directory '" << directory << "'. Make sure that the directory do "
"not already exist or sufficient permissions are set";
throw Exception(error.str().c_str());
}

return directory;
}

#if defined(_WIN32)
void removeDirectory(const wchar_t* directoryPath)
void RemoveTemporaryDirectory(const std::string & sDirectoryPath)
{
std::wstring search_path = std::wstring(directoryPath) + Platform::filenameToUTF("/*.*");
std::wstring s_p = std::wstring(directoryPath) + Platform::filenameToUTF("/");
WIN32_FIND_DATA fd;
HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd);
if(sDirectoryPath.empty())
{
throw Exception("removeDirectory() is called with empty path.");
}

// Sanity check: don't delete the folder if we haven't created it.
if(std::string::npos == sDirectoryPath.find(TempDirMagicPrefix))
{
std::ostringstream error;
error << "removeDirectory() tries to delete folder '"<< sDirectoryPath << "' which was not created by the unit tests.";
throw Exception(error.str().c_str());
}

#if defined(_WIN32)
std::string search_pattern = sDirectoryPath + ("/*.*");
std::string cur_path = sDirectoryPath + "/";

WIN32_FIND_DATAA fd;
HANDLE hFind = FindFirstFileA(search_pattern.c_str(), &fd);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// Ignore "." and ".." directory.
if (wcscmp(fd.cFileName, Platform::filenameToUTF(".").c_str()) != 0 &&
wcscmp(fd.cFileName, Platform::filenameToUTF("..").c_str()) != 0)
if ( strcmp(fd.cFileName, ".") && strcmp(fd.cFileName, "..") )
{
removeDirectory((wchar_t*)(s_p + fd.cFileName).c_str());
RemoveTemporaryDirectory(cur_path + fd.cFileName);
}
}
else
{
DeleteFile((s_p + fd.cFileName).c_str());
DeleteFileA((cur_path + fd.cFileName).c_str());
}
} while (::FindNextFile(hFind, &fd));
} while (FindNextFileA(hFind, &fd));

::FindClose(hFind);
_wrmdir(directoryPath);
FindClose(hFind);
RemoveDirectoryA(sDirectoryPath.c_str());
}
}
#else
void removeDirectory(const char * directoryPath)
{
struct dirent *entry = NULL;
DIR *dir = NULL;
dir = opendir(directoryPath);
while((entry = readdir(dir)))
{
DIR *sub_dir = NULL;
FILE *file = NULL;
struct dirent* entry = NULL;
DIR* dir = NULL;
dir = opendir(sDirectoryPath.c_str());
while ((entry = readdir(dir)))
{
DIR* sub_dir = NULL;
FILE* file = NULL;

std::string absPath;
// Ignore "." and ".." directory.
if (!StringUtils::Compare(".", entry->d_name) &&
!StringUtils::Compare("..", entry->d_name))
{
absPath = pystring::os::path::join(directoryPath, entry->d_name);
absPath = pystring::os::path::join(sDirectoryPath, entry->d_name);
sub_dir = opendir(absPath.c_str());
if(sub_dir)
{
if (sub_dir)
{
closedir(sub_dir);
removeDirectory(absPath.c_str());
}
else
{
RemoveTemporaryDirectory(absPath);
}
else
{
file = fopen(absPath.c_str(), "r");
if(file)
{
if (file)
{
fclose(file);
remove(absPath.c_str());
}
}
}
}
}
}
remove(directoryPath);
remove(sDirectoryPath.c_str());
closedir(dir);
}
#endif

void RemoveTemporaryDirectory(const std::string & directoryPath)
{
#if defined(_WIN32)
removeDirectory(Platform::filenameToUTF(directoryPath).c_str());
#else
removeDirectory(directoryPath.c_str());
#endif
}

} // namespace OCIO_NAMESPACE
Loading