From f387cd34ec00ca0a66201cfd44373ab2008a0da8 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 11 Jan 2016 20:43:42 +0000 Subject: WIP MythFS inodes --- mythfs/etc/icebox.config | 2 +- mythfs/service/Jamfile.jam | 7 +- mythfs/service/inodes/abstractDynamicDirectory.cpp | 22 ++++++ mythfs/service/inodes/abstractDynamicDirectory.h | 18 +++++ mythfs/service/inodes/allDirectory.cpp | 20 +++++ mythfs/service/inodes/allDirectory.h | 22 ++++++ mythfs/service/inodes/byDateDirectory.h | 16 ++++ mythfs/service/inodes/byTitleDirectory.h | 15 ++++ mythfs/service/inodes/file.h | 15 ++++ mythfs/service/inodes/groupingDirectory.h | 17 +++++ mythfs/service/inodes/node.cpp | 23 ++++++ mythfs/service/inodes/node.h | 27 +++++++ mythfs/service/inodes/staticDirectory.cpp | 34 +++++++++ mythfs/service/inodes/staticDirectory.h | 19 +++++ mythfs/service/inodes/symlink.cpp | 25 ++++++ mythfs/service/inodes/symlink.h | 22 ++++++ mythfs/service/main.cpp | 24 +++--- mythfs/service/openDirectory.cpp | 22 ++++++ mythfs/service/openDirectory.h | 20 +++++ mythfs/service/recordingsVolume.cpp | 36 +++++++-- mythfs/service/recordingsVolume.h | 8 +- mythfs/service/util.h | 31 ++++++++ mythfs/unittests/fixtures/schema-min.sql | 89 ++++++++++++++++++++++ mythfs/unittests/mockDefs.cpp | 9 ++- mythfs/unittests/mockDefs.h | 2 +- mythfs/unittests/testMain.cpp | 60 +++++++++++++++ mythfs/util.h | 33 ++++++++ 27 files changed, 612 insertions(+), 26 deletions(-) create mode 100644 mythfs/service/inodes/abstractDynamicDirectory.cpp create mode 100644 mythfs/service/inodes/abstractDynamicDirectory.h create mode 100644 mythfs/service/inodes/allDirectory.cpp create mode 100644 mythfs/service/inodes/allDirectory.h create mode 100644 mythfs/service/inodes/byDateDirectory.h create mode 100644 mythfs/service/inodes/byTitleDirectory.h create mode 100644 mythfs/service/inodes/file.h create mode 100644 mythfs/service/inodes/groupingDirectory.h create mode 100644 mythfs/service/inodes/node.cpp create mode 100644 mythfs/service/inodes/node.h create mode 100644 mythfs/service/inodes/staticDirectory.cpp create mode 100644 mythfs/service/inodes/staticDirectory.h create mode 100644 mythfs/service/inodes/symlink.cpp create mode 100644 mythfs/service/inodes/symlink.h create mode 100644 mythfs/service/openDirectory.cpp create mode 100644 mythfs/service/openDirectory.h create mode 100644 mythfs/service/util.h create mode 100644 mythfs/unittests/fixtures/schema-min.sql create mode 100644 mythfs/util.h diff --git a/mythfs/etc/icebox.config b/mythfs/etc/icebox.config index f7ee191..30fe04b 100644 --- a/mythfs/etc/icebox.config +++ b/mythfs/etc/icebox.config @@ -1 +1 @@ -IceBox.Service.MythFS=mythfs:createIceTrayService --MythFS.ThreadPool.Size=2 --MythFS.ThreadPool.SizeMax=10 --mythconverg.Database.ConnectionString="server=mysql user=mythtv database=mythconverg password=mythpass" --GentooBrowseAPI.Endpoints="tcp -p 4001" +IceBox.Service.MythFS=mythfs:createIceTrayService --MythFS.ThreadPool.Size=2 --MythFS.ThreadPool.SizeMax=10 --MythFS.Database.ConnectionString="server=mysql;user=mythtv;database=mythconverg;password=mythpass" --MythFS.Endpoints="tcp -p 4001" diff --git a/mythfs/service/Jamfile.jam b/mythfs/service/Jamfile.jam index 7dc26cb..2a209e1 100644 --- a/mythfs/service/Jamfile.jam +++ b/mythfs/service/Jamfile.jam @@ -1,13 +1,15 @@ import icetray ; +import package ; lib mythfs : - [ glob *.cpp *.ice sql/*.sql ] + [ glob *.cpp inodes/*.cpp *.ice sql/*.sql ] : yes ..//netfsComms ..//adhocutil ..//dbppcore ..//boost_system + ..//boost_filesystem ..//boost_date_time ..//Ice ..//IceBox @@ -18,9 +20,12 @@ lib mythfs : ..//slicer-db ../..//glibmm MythFS + . : : . ..//netfsComms ..//icetray ; +package.install install : : : mythfs ; + diff --git a/mythfs/service/inodes/abstractDynamicDirectory.cpp b/mythfs/service/inodes/abstractDynamicDirectory.cpp new file mode 100644 index 0000000..0a703db --- /dev/null +++ b/mythfs/service/inodes/abstractDynamicDirectory.cpp @@ -0,0 +1,22 @@ +#include "abstractDynamicDirectory.h" +#include +#include + +namespace MythFS { + NetFS::Attr + AbstractDynamicDirectory::getattr() const + { + return { + 0, 0, + S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH | S_IFDIR, + 1, "root", "root", 0, 0, 0, 0, 0, 0, 0 + }; + } + + Node::PointerType + AbstractDynamicDirectory::getChild(const std::string &) const + { + throw ::NetFS::SystemError(EINVAL); + } +} + diff --git a/mythfs/service/inodes/abstractDynamicDirectory.h b/mythfs/service/inodes/abstractDynamicDirectory.h new file mode 100644 index 0000000..0d62931 --- /dev/null +++ b/mythfs/service/inodes/abstractDynamicDirectory.h @@ -0,0 +1,18 @@ +#ifndef MYTHFS_ABSTRACTDYNAMICDIRECTORY_H +#define MYTHFS_ABSTRACTDYNAMICDIRECTORY_H + +#include "node.h" + +namespace MythFS { + class AbstractDynamicDirectory : public Node { + public: + NetFS::Attr getattr() const override; + + protected: + virtual PointerType getChild(const std::string &) const override = 0; + virtual NetFS::NameList getContents() const override = 0; + }; +} + +#endif + diff --git a/mythfs/service/inodes/allDirectory.cpp b/mythfs/service/inodes/allDirectory.cpp new file mode 100644 index 0000000..d61b8b9 --- /dev/null +++ b/mythfs/service/inodes/allDirectory.cpp @@ -0,0 +1,20 @@ +#include "allDirectory.h" +#include +#include "symlink.h" + +namespace MythFS { + AllDirectory::AllDirectory(const DBPrx & d) : db(d) { } + + NetFS::NameList + AllDirectory::getContents() const + { + return db->getRecorded() / &Recorded::basename; + } + + Node::PointerType + AllDirectory::getChild(const std::string & path) const + { + return new Symlink("/var/store/mythrecordings/" + path); + } +} + diff --git a/mythfs/service/inodes/allDirectory.h b/mythfs/service/inodes/allDirectory.h new file mode 100644 index 0000000..67165ef --- /dev/null +++ b/mythfs/service/inodes/allDirectory.h @@ -0,0 +1,22 @@ +#ifndef MYTHFS_ALLDIRECTORY_H +#define MYTHFS_ALLDIRECTORY_H + +#include "abstractDynamicDirectory.h" +#include "myth-db.h" + +namespace MythFS { + class AllDirectory : public AbstractDynamicDirectory { + public: + AllDirectory(const DBPrx &); + + protected: + NetFS::NameList getContents() const override; + PointerType getChild(const std::string &) const override; + + private: + DBPrx db; + }; +} + +#endif + diff --git a/mythfs/service/inodes/byDateDirectory.h b/mythfs/service/inodes/byDateDirectory.h new file mode 100644 index 0000000..945a9d0 --- /dev/null +++ b/mythfs/service/inodes/byDateDirectory.h @@ -0,0 +1,16 @@ +#ifndef MYTHFS_BYTITLEDIRECTORY_H +#define MYTHFS_BYTITLEDIRECTORY_H + +#include "groupingDirectory.h" + +namespace MythFS { + class ByDateDirectory : public GroupingDirectory { + + protected: + virtual std::string attribute(const MythFS::RecordedPtr &) const; + }; +} + +#endif + + diff --git a/mythfs/service/inodes/byTitleDirectory.h b/mythfs/service/inodes/byTitleDirectory.h new file mode 100644 index 0000000..e9883d1 --- /dev/null +++ b/mythfs/service/inodes/byTitleDirectory.h @@ -0,0 +1,15 @@ +#ifndef MYTHFS_BYTITLEDIRECTORY_H +#define MYTHFS_BYTITLEDIRECTORY_H + +#include "groupingDirectory.h" + +namespace MythFS { + class ByTitleDirectory : public GroupingDirectory { + + protected: + virtual std::string attribute(const MythFS::RecordedPtr &) const; + }; +} + +#endif + diff --git a/mythfs/service/inodes/file.h b/mythfs/service/inodes/file.h new file mode 100644 index 0000000..e71a343 --- /dev/null +++ b/mythfs/service/inodes/file.h @@ -0,0 +1,15 @@ +#ifndef MYTHFS_FILE_H +#define MYTHFS_FILE_H + +#include "node.h" + +namespace MythFS { + class File : public Node { + public: + NetFS::Attr getattr() const override; + PointerType getChild(const std::string &) const override; + }; +} + +#endif + diff --git a/mythfs/service/inodes/groupingDirectory.h b/mythfs/service/inodes/groupingDirectory.h new file mode 100644 index 0000000..82b3c0c --- /dev/null +++ b/mythfs/service/inodes/groupingDirectory.h @@ -0,0 +1,17 @@ +#ifndef MYTHFS_GROUPINGDIRECTORY_H +#define MYTHFS_GROUPINGDIRECTORY_H + +#include "abstractDynamicDirectory.h" + +namespace MythFS { + template + class GroupingDirectory : public AbstractDynamicDirectory { + public: + protected: + virtual T attribute(const MythFS::RecordedPtr &) const = 0; + NetFS::NameList getContents() const override; + }; +} + +#endif + diff --git a/mythfs/service/inodes/node.cpp b/mythfs/service/inodes/node.cpp new file mode 100644 index 0000000..19e4fd3 --- /dev/null +++ b/mythfs/service/inodes/node.cpp @@ -0,0 +1,23 @@ +#include "node.h" +#include + +namespace MythFS { + Node::PointerType + Node::getChild(const std::string &) const + { + throw ::NetFS::SystemError(ENOTDIR); + } + + std::string + Node::readlink() const + { + throw ::NetFS::SystemError(EINVAL); + } + + NetFS::NameList + Node::getContents() const + { + throw NetFS::SystemError(ENOTDIR); + } +} + diff --git a/mythfs/service/inodes/node.h b/mythfs/service/inodes/node.h new file mode 100644 index 0000000..b88e403 --- /dev/null +++ b/mythfs/service/inodes/node.h @@ -0,0 +1,27 @@ +#ifndef MYTHFS_NODE_H +#define MYTHFS_NODE_H + +#include +#include +#include +#include +#include + +namespace MythFS { + class Node; + + typedef std::map> Contents; + + class Node : public virtual Ice::Object { + public: + typedef IceUtil::Handle PointerType; + + virtual NetFS::Attr getattr() const = 0; + virtual std::string readlink() const; + virtual PointerType getChild(const std::string &) const; + virtual NetFS::NameList getContents() const; + }; +} + +#endif + diff --git a/mythfs/service/inodes/staticDirectory.cpp b/mythfs/service/inodes/staticDirectory.cpp new file mode 100644 index 0000000..31cc4fa --- /dev/null +++ b/mythfs/service/inodes/staticDirectory.cpp @@ -0,0 +1,34 @@ +#include "staticDirectory.h" +#include +#include +#include +#include + +namespace MythFS { + NetFS::Attr + StaticDirectory::getattr() const + { + return { + 0, 0, + S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH | S_IFDIR, + 1, "root", "root", 0, 0, 0, 0, 0, 0, 0}; + } + + class NoSuchFileOrDirectory : public ::NetFS::SystemError { + public: + NoSuchFileOrDirectory(const std::string &) : ::NetFS::SystemError(ENOENT) {} + }; + + Node::PointerType + StaticDirectory::getChild(const std::string & path) const + { + return AdHoc::safeMapLookup(contents, path); + } + + NetFS::NameList + StaticDirectory::getContents() const + { + return contents / &Contents::value_type::first; + } +} + diff --git a/mythfs/service/inodes/staticDirectory.h b/mythfs/service/inodes/staticDirectory.h new file mode 100644 index 0000000..0ebb585 --- /dev/null +++ b/mythfs/service/inodes/staticDirectory.h @@ -0,0 +1,19 @@ +#ifndef MYTHFS_STATICDIRECTORY_H +#define MYTHFS_STATICDIRECTORY_H + +#include "node.h" + +namespace MythFS { + class StaticDirectory : public Node { + public: + NetFS::Attr getattr() const override; + PointerType getChild(const std::string &) const override; + NetFS::NameList getContents() const override; + + protected: + Contents contents; + }; +} + +#endif + diff --git a/mythfs/service/inodes/symlink.cpp b/mythfs/service/inodes/symlink.cpp new file mode 100644 index 0000000..8dcc0df --- /dev/null +++ b/mythfs/service/inodes/symlink.cpp @@ -0,0 +1,25 @@ +#include "symlink.h" +#include + +namespace MythFS { + Symlink::Symlink(const std::string & t) : + target(t) + { + + } + + NetFS::Attr + Symlink::getattr() const + { + return { + 0, 0, + S_IRUSR | S_IRGRP | S_IROTH | S_IFLNK, + 1,"root","root",0,0,0,0,0,0,0}; + } + + std::string + Symlink::readlink() const + { + return target; + } +} diff --git a/mythfs/service/inodes/symlink.h b/mythfs/service/inodes/symlink.h new file mode 100644 index 0000000..227d2bd --- /dev/null +++ b/mythfs/service/inodes/symlink.h @@ -0,0 +1,22 @@ +#ifndef MYTHFS_SYMLINK_H +#define MYTHFS_SYMLINK_H + +#include +#include "node.h" + +namespace MythFS { + class Symlink : public Node { + public: + Symlink(const std::string &); + + NetFS::Attr getattr() const override; + std::string readlink() const override; + + private: + const std::string target; + + }; +} + +#endif + diff --git a/mythfs/service/main.cpp b/mythfs/service/main.cpp index 145cf71..6aafc7a 100644 --- a/mythfs/service/main.cpp +++ b/mythfs/service/main.cpp @@ -5,16 +5,18 @@ #include "recordingsVolume.h" #include "dbimpl.h" -class Api : public IceTray::Service { - public: - void addObjects(const std::string &, const Ice::CommunicatorPtr & ic, const Ice::StringSeq &, const Ice::ObjectAdapterPtr & adp) override - { - auto db = getConnectionPool(ic, "mysql", "mythconverg"); - adp->add(new MythFS::Service(), ic->stringToIdentity("service")); - adp->add(new MythFS::DBImpl(db), ic->stringToIdentity("db")); - adp->add(new MythFS::RecordingsVolume(), ic->stringToIdentity("recordings")); - } -}; +namespace MythFS { + class Api : public IceTray::Service { + public: + void addObjects(const std::string &, const Ice::CommunicatorPtr & ic, const Ice::StringSeq &, const Ice::ObjectAdapterPtr & adp) override + { + auto dbpool = getConnectionPool(ic, "mysql", "MythFS"); + adp->add(new MythFS::Service(), ic->stringToIdentity("Service")); + auto dbservice = DBPrx::uncheckedCast(adp->add(new DBImpl(dbpool), ic->stringToIdentity("DB"))); + adp->add(new RecordingsVolume(dbservice), ic->stringToIdentity("recordings")); + } + }; -NAMEDFACTORY("default", Api, IceTray::ServiceFactory); + NAMEDFACTORY("default", MythFS::Api, IceTray::ServiceFactory); +} diff --git a/mythfs/service/openDirectory.cpp b/mythfs/service/openDirectory.cpp new file mode 100644 index 0000000..42a3e59 --- /dev/null +++ b/mythfs/service/openDirectory.cpp @@ -0,0 +1,22 @@ +#include "openDirectory.h" +#include + +namespace MythFS { + OpenDirectory::OpenDirectory(Node::PointerType d) : + directory(d) + { + } + + ::NetFS::NameList + OpenDirectory::readdir(const Ice::Current &) + { + return directory->getContents(); + } + + void + OpenDirectory::close(const Ice::Current & ic) + { + ic.adapter->remove(ic.id); + } +} + diff --git a/mythfs/service/openDirectory.h b/mythfs/service/openDirectory.h new file mode 100644 index 0000000..40215f5 --- /dev/null +++ b/mythfs/service/openDirectory.h @@ -0,0 +1,20 @@ +#ifndef MYTHFS_OPENDIRECTORY_H +#define MYTHFS_OPENDIRECTORY_H + +#include +#include "inodes/node.h" + +namespace MythFS { + class OpenDirectory : public ::NetFS::Directory { + public: + OpenDirectory(Node::PointerType); + + ::NetFS::NameList readdir(const Ice::Current &) override; + void close(const Ice::Current &) override; + private: + Node::PointerType directory; + }; +} + +#endif + diff --git a/mythfs/service/recordingsVolume.cpp b/mythfs/service/recordingsVolume.cpp index cfebe46..f5bf07b 100644 --- a/mythfs/service/recordingsVolume.cpp +++ b/mythfs/service/recordingsVolume.cpp @@ -1,10 +1,21 @@ #include "recordingsVolume.h" +#include +#include + +#include +#include "inodes/allDirectory.h" +#include "openDirectory.h" namespace MythFS { + RecordingsVolume::RecordingsVolume(DBPrx db) + { + contents.insert({ "all", new AllDirectory(db) }); + } + NetFS::DirectoryPrx - RecordingsVolume::opendir(const NetFS::ReqEnv &, const std::string &, const Ice::Current&) + RecordingsVolume::opendir(const NetFS::ReqEnv &, const std::string & p, const Ice::Current & ic) { - return NULL; + return ::NetFS::DirectoryPrx::uncheckedCast(ic.adapter->addWithUUID(new OpenDirectory(resolvePath(p)))); } void RecordingsVolume::mkdir(const NetFS::ReqEnv &, const std::string &, Ice::Int, const Ice::Current&) { @@ -48,12 +59,12 @@ namespace MythFS { Ice::Int RecordingsVolume::access(const NetFS::ReqEnv &, const std::string &, Ice::Int, const Ice::Current&) { - throw ::NetFS::SystemError(ENOSYS); + return 0; } - NetFS::Attr RecordingsVolume::getattr(const NetFS::ReqEnv &, const std::string &, const Ice::Current&) + NetFS::Attr RecordingsVolume::getattr(const NetFS::ReqEnv &, const std::string & path, const Ice::Current&) { - throw ::NetFS::SystemError(ENOSYS); + return resolvePath(path)->getattr(); } void RecordingsVolume::mknod(const NetFS::ReqEnv &, const std::string &, Ice::Int, Ice::Int, const Ice::Current&) @@ -76,9 +87,9 @@ namespace MythFS { throw ::NetFS::SystemError(ENOSYS); } - std::string RecordingsVolume::readlink(const NetFS::ReqEnv &, const std::string &, const Ice::Current&) + std::string RecordingsVolume::readlink(const NetFS::ReqEnv &, const std::string & path, const Ice::Current&) { - throw ::NetFS::SystemError(ENOSYS); + return resolvePath(path)->readlink(); } void RecordingsVolume::chmod(const NetFS::ReqEnv &, const std::string &, Ice::Int, const Ice::Current&) @@ -99,5 +110,16 @@ namespace MythFS { void RecordingsVolume::disconnect(const Ice::Current&) { } + + Node::PointerType + RecordingsVolume::resolvePath(const std::string & p) + { + Node::PointerType d = this; + boost::filesystem::path path(p.substr(1)); + for (const auto & e : path) { + d = d->getChild(e.string()); + } + return d; + } } diff --git a/mythfs/service/recordingsVolume.h b/mythfs/service/recordingsVolume.h index 65357ca..4bf227d 100644 --- a/mythfs/service/recordingsVolume.h +++ b/mythfs/service/recordingsVolume.h @@ -2,10 +2,14 @@ #define MYTHFS_RECORDINGS_VOLUME_H #include +#include "inodes/staticDirectory.h" +#include namespace MythFS { - class RecordingsVolume : public ::NetFS::Volume { + class RecordingsVolume : public ::NetFS::Volume, public StaticDirectory { public: + RecordingsVolume(DBPrx); + virtual NetFS::DirectoryPrx opendir(const NetFS::ReqEnv &, const std::string & path, const Ice::Current&) override; virtual void mkdir(const NetFS::ReqEnv &, const std::string & path, Ice::Int id, const Ice::Current&) override; @@ -34,6 +38,8 @@ namespace MythFS { virtual void disconnect(const Ice::Current&) override; + private: + Node::PointerType resolvePath(const std::string &); }; } diff --git a/mythfs/service/util.h b/mythfs/service/util.h new file mode 100644 index 0000000..5e42b34 --- /dev/null +++ b/mythfs/service/util.h @@ -0,0 +1,31 @@ +#ifndef MYTHFS_UTIL_H +#define MYTHFS_UTIL_H + +#include + +template +std::vector::type> +operator/(const T & input, MT T::value_type::element_type::* m) +{ + std::vector::type> result; + result.reserve(input.size()); + for (const auto & i : input) { + result.push_back(i.get()->*m); + } + return result; +} + +template +std::vector::type> +operator/(const T & input, MT T::value_type::* m) +{ + std::vector::type> result; + result.reserve(input.size()); + for (const auto & i : input) { + result.push_back(i.*m); + } + return result; +} + +#endif + diff --git a/mythfs/unittests/fixtures/schema-min.sql b/mythfs/unittests/fixtures/schema-min.sql new file mode 100644 index 0000000..ebf90d9 --- /dev/null +++ b/mythfs/unittests/fixtures/schema-min.sql @@ -0,0 +1,89 @@ +-- MySQL dump 10.13 Distrib 5.6.28, for Linux (x86_64) +-- +-- Host: defiant Database: mythconverg +-- ------------------------------------------------------ +-- Server version 5.6.27-log + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `recorded` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `recorded` ( + `chanid` int(10) unsigned NOT NULL DEFAULT '0', + `starttime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `endtime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `title` varchar(128) NOT NULL DEFAULT '', + `subtitle` varchar(128) NOT NULL DEFAULT '', + `description` varchar(16000) NOT NULL DEFAULT '', + `season` smallint(5) NOT NULL, + `episode` smallint(5) NOT NULL, + `category` varchar(64) NOT NULL DEFAULT '', + `hostname` varchar(64) NOT NULL DEFAULT '', + `bookmark` tinyint(1) NOT NULL DEFAULT '0', + `editing` int(10) unsigned NOT NULL DEFAULT '0', + `cutlist` tinyint(1) NOT NULL DEFAULT '0', + `autoexpire` int(11) NOT NULL DEFAULT '0', + `commflagged` int(10) unsigned NOT NULL DEFAULT '0', + `recgroup` varchar(32) NOT NULL DEFAULT 'Default', + `recordid` int(11) DEFAULT NULL, + `seriesid` varchar(64) DEFAULT NULL, + `programid` varchar(64) DEFAULT NULL, + `inetref` varchar(40) NOT NULL, + `lastmodified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `filesize` bigint(20) NOT NULL DEFAULT '0', + `stars` float NOT NULL DEFAULT '0', + `previouslyshown` tinyint(1) DEFAULT '0', + `originalairdate` date DEFAULT NULL, + `preserve` tinyint(1) NOT NULL DEFAULT '0', + `findid` int(11) NOT NULL DEFAULT '0', + `deletepending` tinyint(1) NOT NULL DEFAULT '0', + `transcoder` int(11) NOT NULL DEFAULT '0', + `timestretch` float NOT NULL DEFAULT '1', + `recpriority` int(11) NOT NULL DEFAULT '0', + `basename` varchar(255) NOT NULL, + `progstart` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `progend` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `playgroup` varchar(32) NOT NULL DEFAULT 'Default', + `profile` varchar(32) NOT NULL DEFAULT '', + `duplicate` tinyint(1) NOT NULL DEFAULT '0', + `transcoded` tinyint(1) NOT NULL DEFAULT '0', + `watched` tinyint(4) NOT NULL DEFAULT '0', + `storagegroup` varchar(32) NOT NULL DEFAULT 'Default', + `bookmarkupdate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + PRIMARY KEY (`chanid`,`starttime`), + UNIQUE KEY `uni_recorded_basename` (`basename`), + KEY `endtime` (`endtime`), + KEY `seriesid` (`seriesid`), + KEY `programid` (`programid`), + KEY `title` (`title`), + KEY `recordid` (`recordid`), + KEY `deletepending` (`deletepending`,`lastmodified`), + KEY `recgroup` (`recgroup`,`endtime`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2015-12-24 5:08:30 + diff --git a/mythfs/unittests/mockDefs.cpp b/mythfs/unittests/mockDefs.cpp index 68dec08..ba233c3 100644 --- a/mythfs/unittests/mockDefs.cpp +++ b/mythfs/unittests/mockDefs.cpp @@ -2,16 +2,17 @@ #include Service::Service() : - MySQL::Mock("mythconverg", { - rootDir / "fixtures" / "schema.sql", + MySQL::Mock("MythFS", { + //rootDir / "fixtures" / "schema.sql", + rootDir / "fixtures" / "schema-min.sql", rootDir / "fixtures" / "data.sql" }) { } TestClient::TestClient() : - db(getProxy("db")), - s(getProxy("service")) + db(getProxy("DB")), + s(getProxy("Service")) { } diff --git a/mythfs/unittests/mockDefs.h b/mythfs/unittests/mockDefs.h index 0b6248c..b1975e9 100644 --- a/mythfs/unittests/mockDefs.h +++ b/mythfs/unittests/mockDefs.h @@ -7,7 +7,7 @@ #include #include -class DLL_PUBLIC Service : public IceTray::DryIce, MySQL::Mock { +class DLL_PUBLIC Service : MySQL::Mock, public IceTray::DryIce { public: Service(); }; diff --git a/mythfs/unittests/testMain.cpp b/mythfs/unittests/testMain.cpp index 8c18647..5451630 100644 --- a/mythfs/unittests/testMain.cpp +++ b/mythfs/unittests/testMain.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include "mockDefs.h" BOOST_GLOBAL_FIXTURE(Service); @@ -37,3 +39,61 @@ BOOST_AUTO_TEST_CASE( getRecorded ) BOOST_AUTO_TEST_SUITE_END(); +class RecordingsTest : public TestClient { + public: + RecordingsTest() : + rv(s->connect("recordings", std::string())) + { + re.user = "root"; + re.grp = "root"; + } + ~RecordingsTest() + { + rv->disconnect(); + } + + protected: + ::NetFS::ReqEnv re; + ::NetFS::VolumePrx rv; +}; + +BOOST_FIXTURE_TEST_SUITE(rt, RecordingsTest) + +BOOST_AUTO_TEST_CASE( statRoot ) +{ + auto a = rv->getattr(re, "/"); + BOOST_REQUIRE(S_ISDIR(a.mode)); +} + +BOOST_AUTO_TEST_CASE( listRoot ) +{ + auto d = rv->opendir(re, "/"); + auto ls = d->readdir(); + BOOST_REQUIRE_EQUAL(1, ls.size()); + BOOST_REQUIRE_EQUAL("all", ls.front()); + d->close(); +} + +BOOST_AUTO_TEST_CASE( statAll ) +{ + auto a = rv->getattr(re, "/all"); + BOOST_REQUIRE(S_ISDIR(a.mode)); +} + +BOOST_AUTO_TEST_CASE( listAll ) +{ + auto d = rv->opendir(re, "/all"); + auto ls = d->readdir(); + BOOST_REQUIRE_EQUAL(11, ls.size()); + BOOST_REQUIRE_EQUAL("1001_20151220233900.mpg", ls.front()); + BOOST_REQUIRE_EQUAL("1303_20151202205900.mpg", ls.back()); + d->close(); + + auto a = rv->getattr(re, "/all/1001_20151220233900.mpg"); + BOOST_REQUIRE(S_ISLNK(a.mode)); + auto l = rv->readlink(re, "/all/1001_20151220233900.mpg"); + BOOST_REQUIRE_EQUAL("/var/store/mythrecordings/1001_20151220233900.mpg", l); +} + +BOOST_AUTO_TEST_SUITE_END(); + diff --git a/mythfs/util.h b/mythfs/util.h new file mode 100644 index 0000000..3d7ea35 --- /dev/null +++ b/mythfs/util.h @@ -0,0 +1,33 @@ +#ifndef MYTHFS_UTIL_H +#define MYTHFS_UTIL_H + +template +std::vector +operator/(const T & input, MT T::value_type::* m) +{ + std::vector result; + /* + result.reserve(input.size()); + for (const auto & i : input) { + result.push_back(i.*m); + } + */ + return result; +} + +/* +template +std::vector +operator/(const T & input, MT T::value_type::element_type::* m) +{ + std::vector result; + result.reserve(input.size()); + for (const auto & i : input) { + result.push_back(i.get()->*m); + } + return result; +} +*/ + +#endif + -- cgit v1.2.3