From f31ff1177eec7ffa0ea6375b77d78d69559f9c88 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 30 Dec 2014 19:52:21 +0000 Subject: Big commit comprising mostly of changes to the DB structure to unify recorded event details into events, lots of new unit tests --- p2pvr/daemon/Jamfile.jam | 2 +- p2pvr/daemon/events.cpp | 101 ++++++++++++++++++ p2pvr/daemon/maintenance/events.cpp | 6 ++ p2pvr/daemon/recorder.cpp | 11 +- p2pvr/daemon/recorder.h | 4 +- p2pvr/daemon/recordings.cpp | 21 ++-- p2pvr/daemon/schedules.cpp | 61 +++++------ p2pvr/daemon/schedules.h | 5 +- p2pvr/daemon/si.cpp | 49 +++++---- p2pvr/daemon/si.h | 13 +-- p2pvr/daemon/sql/Maint_pruneEvents.sql | 4 + p2pvr/daemon/sql/Recordings_getAll.sql | 4 +- p2pvr/daemon/sql/Recordings_insert.sql | 4 +- p2pvr/daemon/sql/SI_eventById.sql | 10 +- p2pvr/daemon/sql/SI_eventByUid.sql | 30 ++++++ p2pvr/daemon/sql/SI_eventSearch.sql | 5 +- p2pvr/daemon/sql/SI_eventsInRange.sql | 8 +- p2pvr/daemon/sql/SI_eventsInSchedule.sql | 11 +- p2pvr/daemon/sql/SI_eventsInSchedules.sql | 11 +- p2pvr/daemon/sql/SI_eventsOnNow.sql | 8 +- p2pvr/daemon/sql/SI_serviceNextUsed.sql | 9 +- p2pvr/daemon/sql/Schedules_GetCandidates.sql | 19 ++-- p2pvr/daemon/sql/Schedules_insert.sql | 2 +- p2pvr/daemon/sql/Schedules_scheduledToRecord.sql | 5 +- p2pvr/daemon/sql/Schedules_selectAll.sql | 2 +- p2pvr/daemon/sql/Schedules_selectById.sql | 3 +- p2pvr/daemon/sql/Schedules_update.sql | 2 +- p2pvr/daemon/unittests/Jamfile.jam | 60 ++++++++++- p2pvr/daemon/unittests/mockDevices.cpp | 29 +++++ p2pvr/daemon/unittests/mockDevices.h | 16 +++ p2pvr/daemon/unittests/mockRecorder.cpp | 8 ++ p2pvr/daemon/unittests/mockRecorder.h | 12 +++ p2pvr/daemon/unittests/mockScheduler.cpp | 36 +++++++ p2pvr/daemon/unittests/mockScheduler.h | 17 +++ p2pvr/daemon/unittests/testMaint.cpp | 128 +++++++++++------------ p2pvr/daemon/unittests/testRecordings.cpp | 74 +++++++++++++ p2pvr/daemon/unittests/testSched.cpp | 102 ++++++++++++++++++ p2pvr/daemon/unittests/testSi.cpp | 105 +++++++++++++++++++ p2pvr/daemon/unittests/testp2ice.cpp | 37 +++++-- p2pvr/datasources/schema.sql | 104 ++++++++++-------- p2pvr/devices/mockTuner.cpp | 10 +- p2pvr/devices/mockTuner.h | 5 +- p2pvr/ice/common.ice | 4 +- p2pvr/ice/commonHelpers.cpp | 2 +- p2pvr/ice/commonHelpers.h | 12 +++ p2pvr/ice/p2pvr.ice | 40 +++---- p2pvr/lib/containerCreator.h | 3 + p2pvr/lib/dvbsiHelpers/event.cpp | 48 ++++----- p2pvr/lib/p2pvrHelpers/schedule.cpp | 6 +- 49 files changed, 968 insertions(+), 300 deletions(-) create mode 100644 p2pvr/daemon/events.cpp create mode 100644 p2pvr/daemon/sql/Maint_pruneEvents.sql create mode 100644 p2pvr/daemon/sql/SI_eventByUid.sql create mode 100644 p2pvr/daemon/unittests/mockDevices.cpp create mode 100644 p2pvr/daemon/unittests/mockDevices.h create mode 100644 p2pvr/daemon/unittests/mockRecorder.cpp create mode 100644 p2pvr/daemon/unittests/mockRecorder.h create mode 100644 p2pvr/daemon/unittests/mockScheduler.cpp create mode 100644 p2pvr/daemon/unittests/mockScheduler.h create mode 100644 p2pvr/daemon/unittests/testRecordings.cpp create mode 100644 p2pvr/daemon/unittests/testSched.cpp create mode 100644 p2pvr/daemon/unittests/testSi.cpp diff --git a/p2pvr/daemon/Jamfile.jam b/p2pvr/daemon/Jamfile.jam index ac3ed58..d9894d3 100644 --- a/p2pvr/daemon/Jamfile.jam +++ b/p2pvr/daemon/Jamfile.jam @@ -11,7 +11,7 @@ cpp-pch pch : pch.hpp : lib p2pvrdaemon : pch - [ glob-tree *.cpp *.sql : dummy* test*.cpp ] + [ glob-tree *.cpp *.sql : dummy* test*.cpp mock*.cpp ] : ../ice//p2pvrice ../lib//p2pvrlib diff --git a/p2pvr/daemon/events.cpp b/p2pvr/daemon/events.cpp new file mode 100644 index 0000000..676b2b3 --- /dev/null +++ b/p2pvr/daemon/events.cpp @@ -0,0 +1,101 @@ +#include +#include "containerCreator.h" +#include +#include + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("eventUid", false); + cc("serviceId", true); + cc("eventId", true); + cc("title", false); + cc("titleLang", false); + cc("subtitle", false); + cc("description", false); + cc("descriptionLang", false); + cc("videoAspect", false); + cc("videoFrameRate", false); + cc("videoHd", false); + cc("audioChannels", false); + cc("audioLanguage", false); + cc("subtitleLanguage", false); + cc("category", false); + cc("subCategory", false); + cc("userCategory", false); + cc("dvbRating", false); + cc("startTime", false); + cc("stopTime", false); + cc("episode", false); + cc("episodes", false); + cc("year", false); + cc("flags", false); + cc("season", false); + cc("current", false); +} + +template<> +void +BindColumns(RowState & rs, const P2PVR::EventPtr & e) +{ + rs.fields[0] << e->ServiceId; + rs.fields[1] << e->EventId; + rs.fields[2] << e->Title; + rs.fields[3] << e->TitleLang; + rs.fields[4] << e->Subtitle; + rs.fields[5] << e->Description; + rs.fields[6] << e->DescriptionLang; + rs.fields[7] << e->VideoAspect; + rs.fields[8] << e->VideoFrameRate; + rs.fields[9] << e->VideoHD; + rs.fields[10] << e->AudioChannels; + rs.fields[11] << e->AudioLanguage; + rs.fields[12] << e->SubtitleLanguage; + rs.fields[13] << e->Category; + rs.fields[14] << e->SubCategory; + rs.fields[15] << e->UserCategory; + rs.fields[16] << e->DvbRating; + rs.fields[17] << e->StartTime; + rs.fields[18] << e->StopTime; + rs.fields[19] << e->Episode; + rs.fields[20] << e->Episodes; + rs.fields[21] << e->Year; + rs.fields[22] << e->Flags; + rs.fields[23] << e->Season; + rs.fields[24] << e->EventUid; + rs.fields[25] << e->Current; +} + +template<> +void +UnbindColumns(RowState & rs, const P2PVR::EventPtr & e) +{ + rs.fields[0] >> e->ServiceId; + rs.fields[1] >> e->EventId; + rs.fields[2] >> e->Title; + rs.fields[3] >> e->TitleLang; + rs.fields[4] >> e->Subtitle; + rs.fields[5] >> e->Description; + rs.fields[6] >> e->DescriptionLang; + rs.fields[7] >> e->VideoAspect; + rs.fields[8] >> e->VideoFrameRate; + rs.fields[9] >> e->VideoHD; + rs.fields[10] >> e->AudioChannels; + rs.fields[11] >> e->AudioLanguage; + rs.fields[12] >> e->SubtitleLanguage; + rs.fields[13] >> e->Category; + rs.fields[14] >> e->SubCategory; + rs.fields[15] >> e->UserCategory; + rs.fields[16] >> e->DvbRating; + rs.fields[17] >> e->StartTime; + rs.fields[18] >> e->StopTime; + rs.fields[19] >> e->Episode; + rs.fields[20] >> e->Episodes; + rs.fields[21] >> e->Year; + rs.fields[22] >> e->Flags; + rs.fields[23] >> e->Season; + rs.fields[24] >> e->EventUid; + rs.fields[25] >> e->Current; +} + diff --git a/p2pvr/daemon/maintenance/events.cpp b/p2pvr/daemon/maintenance/events.cpp index 648be0b..f075a32 100644 --- a/p2pvr/daemon/maintenance/events.cpp +++ b/p2pvr/daemon/maintenance/events.cpp @@ -9,6 +9,9 @@ #include #include #include +#include + +ResourceString(Maint_pruneEvents, sql_Maint_pruneEvents); class SiEventsHandler : public SiEpgParser { public: @@ -81,8 +84,11 @@ Maintenance::UpdateEvents(short type, const Ice::Current & ice) SqlMergeTask mergeEvents("postgres", "events"); CreateColumns(boost::bind(SqlMergeColumnsInserter, &mergeEvents, _1, _2)); mergeEvents.sources.insert(new SiEventsMerger(type, ice)); + mergeEvents.insteadOfDelete = new DynamicSql::SqlText("SET current = false"); + mergeEvents.updateWhere = new DynamicSql::SqlText("a.current"); mergeEvents.loadComplete(this); mergeEvents.execute(NULL); + Modify(Maint_pruneEvents).second->execute(); tx.Commit(); Logger()->messagebf(LOG_INFO, "%s: Updated events", __PRETTY_FUNCTION__); diff --git a/p2pvr/daemon/recorder.cpp b/p2pvr/daemon/recorder.cpp index 6cd0b5f..35aeba8 100644 --- a/p2pvr/daemon/recorder.cpp +++ b/p2pvr/daemon/recorder.cpp @@ -39,13 +39,13 @@ Recorder::RefreshSchedules(const Ice::Current &) auto si = P2PVR::SIPrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("SI"))); BOOST_FOREACH(const auto & s, schedules->GetScheduledToRecord()) { if (std::find_if(currentRecordings.begin(), currentRecordings.end(), [&s](const CurrentPtr & c) { - return s->ScheduleId == c->schedule->ScheduleId && s->ServiceId == c->event->ServiceId && s->EventId == c->event->EventId;; + return s->ScheduleId == c->schedule->ScheduleId && s->EventUid == c->event->EventUid; }) != currentRecordings.end()) { continue; } auto schedule = schedules->GetSchedule(s->ScheduleId); - auto service = si->GetService(s->ServiceId); - auto event = si->GetEvent(s->ServiceId, s->EventId); + auto event = si->GetEvents({ s->EventUid }).front(); + auto service = si->GetService(event->ServiceId); auto startIn = std::max((*event->StartTime - *schedule->Early - boost::posix_time::second_clock::universal_time()).total_seconds(), 0); IceUtil::TimerTaskPtr startTimer = new BindTimerTask(boost::bind(&Recorder::StartRecording, this, schedule, service, event)); @@ -56,7 +56,7 @@ Recorder::RefreshSchedules(const Ice::Current &) } void -Recorder::StartRecording(P2PVR::SchedulePtr schedule, DVBSI::ServicePtr service, DVBSI::EventPtr event) +Recorder::StartRecording(P2PVR::SchedulePtr schedule, DVBSI::ServicePtr service, P2PVR::EventPtr event) { std::lock_guard g(lock); auto storage = P2PVR::StoragePrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("Storage"))); @@ -79,8 +79,7 @@ Recorder::StartRecording(P2PVR::SchedulePtr schedule, DVBSI::ServicePtr service, event->Title, event->StartTime, event->StopTime, service->Name ? *service->Name : "", service->ServiceId); - recordings->NewRecording(new P2PVR::Recording(0, storage->ice_toString(), id, schedule->ScheduleId, event->Title, event->Subtitle, - event->Description, event->StartTime, *(*event->StopTime - *event->StartTime))); + recordings->NewRecording(new P2PVR::Recording(0, storage->ice_toString(), id, schedule->ScheduleId, event->EventUid)); auto newCurrent = CurrentPtr(new Current({muxer, store, ss, schedule, service, event, IceUtil::TimerTaskPtr()})); currentRecordings.insert(newCurrent); diff --git a/p2pvr/daemon/recorder.h b/p2pvr/daemon/recorder.h index 78c604b..6680801 100644 --- a/p2pvr/daemon/recorder.h +++ b/p2pvr/daemon/recorder.h @@ -19,7 +19,7 @@ class Recorder : public P2PVR::Recorder { ServiceStreamerPtr stream; P2PVR::SchedulePtr schedule; DVBSI::ServicePtr service; - DVBSI::EventPtr event; + P2PVR::EventPtr event; IceUtil::TimerTaskPtr stopTimer; }; typedef boost::shared_ptr CurrentPtr; @@ -33,7 +33,7 @@ class Recorder : public P2PVR::Recorder { private: void StartRecordings(); - void StartRecording(P2PVR::SchedulePtr schedule, DVBSI::ServicePtr service, DVBSI::EventPtr event); + void StartRecording(P2PVR::SchedulePtr schedule, DVBSI::ServicePtr service, P2PVR::EventPtr event); void StopRecording(CurrentPtr); Ice::ObjectAdapterPtr adapter; diff --git a/p2pvr/daemon/recordings.cpp b/p2pvr/daemon/recordings.cpp index 73cf77d..ceb89ba 100644 --- a/p2pvr/daemon/recordings.cpp +++ b/p2pvr/daemon/recordings.cpp @@ -19,11 +19,7 @@ CreateColumns(const ColumnCreator & cc) cc("storageaddress", false); cc("guid", false); cc("scheduleid", false); - cc("title", false); - cc("subtitle", false); - cc("description", false); - cc("starttime", false); - cc("duration", false); + cc("eventuid", false); } template<> @@ -34,11 +30,7 @@ UnbindColumns(RowState & rs, const P2PVR::RecordingPtr & r) rs.fields[1] >> r->StorageAddress; rs.fields[2] >> r->Guid; rs.fields[3] >> r->ScheduleId; - rs.fields[4] >> r->Title; - rs.fields[5] >> r->Subtitle; - rs.fields[6] >> r->Description; - rs.fields[7] >> r->StartTime; - rs.fields[8] >> r->Duration; + rs.fields[4] >> r->EventUid; } int @@ -46,8 +38,7 @@ Recordings::NewRecording(const P2PVR::RecordingPtr & r, const Ice::Current &) { Logger()->messagebf(LOG_INFO, "%s: Creating new recording %s at %s", __PRETTY_FUNCTION__, r->Guid, r->StorageAddress); TxHelper tx(this); - auto insert = Modify(Recording_Insert, - r->StorageAddress, r->Guid, r->ScheduleId, r->Title, r->Subtitle, r->Description, r->StartTime, r->Duration); + auto insert = Modify(Recording_Insert, r->StorageAddress, r->Guid, r->ScheduleId, r->EventUid); insert.second->execute(); r->RecordingId = SelectScalar(Recording_InsertNewId); Logger()->messagebf(LOG_INFO, "%s: Created recording Id: %d", __PRETTY_FUNCTION__, r->RecordingId); @@ -65,8 +56,10 @@ Recordings::DeleteRecording(int id, const Ice::Current & ice) std::string addr = recordingStorages.second / "storageaddress"; std::string guid = recordingStorages.second / "guid"; auto storage = P2PVR::StoragePrx::checkedCast(ic->stringToProxy(addr)); - storage->Delete(guid); - Logger()->messagebf(LOG_DEBUG, "%s: Delete %s from StorageAddress %s", __PRETTY_FUNCTION__, guid, addr); + if (storage) { + storage->Delete(guid); + Logger()->messagebf(LOG_DEBUG, "%s: Delete %s from StorageAddress %s", __PRETTY_FUNCTION__, guid, addr); + } } Modify(Recording_Delete, id).second->execute(); } diff --git a/p2pvr/daemon/schedules.cpp b/p2pvr/daemon/schedules.cpp index dab3917..b97924d 100644 --- a/p2pvr/daemon/schedules.cpp +++ b/p2pvr/daemon/schedules.cpp @@ -31,8 +31,7 @@ END_OPTIONS() class ScheduleCandidate { public: std::string What; - int ServiceId; - int EventId; + int EventUid; int TransportStreamId; datetime StartTime; datetime StopTime; @@ -51,16 +50,14 @@ enum RecordStatuses { class Record { public: Record() { }; - Record(int s, int e, RecordStatuses rs, int sc) : - ServiceId(s), - EventId(e), + Record(int e, RecordStatuses rs, int sc) : + EventUid(e), RecordStatus(rs), ScheduleId(sc) { } - int ServiceId; - int EventId; + int EventUid; RecordStatuses RecordStatus; int ScheduleId; }; @@ -71,8 +68,7 @@ template<> void CreateColumns(const ColumnCreator & cc) { - cc("serviceid", true); - cc("eventid", true); + cc("eventuid", true); cc("scheduleid", true); } @@ -80,9 +76,8 @@ template<> void UnbindColumns(RowState & rs, P2PVR::ScheduledToRecordPtr const & s) { - rs.fields[0] >> s->ServiceId; - rs.fields[1] >> s->EventId; - rs.fields[2] >> s->ScheduleId; + rs.fields[0] >> s->EventUid; + rs.fields[1] >> s->ScheduleId; } template<> @@ -91,7 +86,7 @@ CreateColumns(const ColumnCreator & cc) { cc("what", true); cc("serviceid", false); - cc("eventid", false); + cc("eventuid", false); cc("transportstreamid", false); cc("starttime", false); cc("stoptime", false); @@ -104,13 +99,12 @@ void UnbindColumns(RowState & rs, ScheduleCandidatePtr const & s) { rs.fields[0] >> s->What; - rs.fields[1] >> s->ServiceId; - rs.fields[2] >> s->EventId; - rs.fields[3] >> s->TransportStreamId; - rs.fields[4] >> s->StartTime; - rs.fields[5] >> s->StopTime; - rs.fields[6] >> s->Priority; - rs.fields[7] >> s->ScheduleId; + rs.fields[1] >> s->EventUid; + rs.fields[2] >> s->TransportStreamId; + rs.fields[3] >> s->StartTime; + rs.fields[4] >> s->StopTime; + rs.fields[5] >> s->Priority; + rs.fields[6] >> s->ScheduleId; } template<> @@ -119,7 +113,7 @@ CreateColumns(const ColumnCreator & cc) { cc("scheduleid", true); cc("serviceid", false); - cc("eventid", false); + cc("eventuid", false); cc("title", false); cc("search", false); cc("priority", false); @@ -134,7 +128,7 @@ UnbindColumns(RowState & rs, P2PVR::SchedulePtr const & s) { rs.fields[0] >> s->ScheduleId; rs.fields[1] >> s->ServiceId; - rs.fields[2] >> s->EventId; + rs.fields[2] >> s->EventUid; rs.fields[3] >> s->Title; rs.fields[4] >> s->Search; rs.fields[5] >> s->Priority; @@ -147,8 +141,7 @@ template<> void CreateColumns(const ColumnCreator & cc) { - cc("serviceid", true); - cc("eventid", true); + cc("eventuid", true); cc("recordstatus", false); cc("scheduleid", false); } @@ -157,16 +150,14 @@ template<> void BindColumns(RowState & rs, RecordPtr const & s) { - rs.fields[0] << s->ServiceId; - rs.fields[1] << s->EventId; - rs.fields[2] << (int)s->RecordStatus; - rs.fields[3] << s->ScheduleId; + rs.fields[0] << s->EventUid; + rs.fields[1] << (int)s->RecordStatus; + rs.fields[2] << s->ScheduleId; } -Showing::Showing(unsigned int s, unsigned int e, unsigned int t, unsigned int sc, datetime start, datetime stop, int p, const Episode * ep) : +Showing::Showing(unsigned int e, unsigned int t, unsigned int sc, datetime start, datetime stop, int p, const Episode * ep) : episode(ep), - serviceId(s), - eventId(e), + eventUid(e), priority(p), scheduleId(sc), transportStreamId(t), @@ -338,7 +329,7 @@ Schedules::DoReschedule(const Ice::Current & ice) cur = new Episode(c->What); scheduleList.push_back(cur); } - ShowingPtr s = new Showing(c->ServiceId, c->EventId, c->TransportStreamId, c->ScheduleId, + ShowingPtr s = new Showing(c->EventUid, c->TransportStreamId, c->ScheduleId, c->StartTime, c->StopTime, c->Priority, cur.get()); minPriority = std::min(minPriority, s->priority); cur->showings.push_back(s); @@ -408,7 +399,7 @@ Schedules::DoReschedule(const Ice::Current & ice) } BOOST_FOREACH(const auto & i, c->showings) { if (i) { - records.push_back(RecordPtr(new Record(i->serviceId, i->eventId, + records.push_back(RecordPtr(new Record(i->eventUid, found ? selected.find(i) != selected.end() ? Record_WillRecordThisShowing : Record_WillRecordOtherShowing : Record_CannotRecordAnyShowing, i->scheduleId))); @@ -470,11 +461,11 @@ Schedules::UpdateSchedule(const P2PVR::SchedulePtr & s, const Ice::Current & ice { TxHelper tx(this); if (s->ScheduleId == 0) { - Modify(Schedules_insert, s->ServiceId, s->EventId, s->Title, s->Search, s->Priority, s->Early, s->Late, s->Repeats).second->execute(); + Modify(Schedules_insert, s->ServiceId, s->EventUid, s->Title, s->Search, s->Priority, s->Early, s->Late, s->Repeats).second->execute(); s->ScheduleId = SelectScalar(Schedules_insertNewId); } else { - Modify(Schedules_update, s->ServiceId, s->EventId, s->Title, s->Search, s->Priority, s->Early, s->Late, s->Repeats, s->ScheduleId).second->execute(); + Modify(Schedules_update, s->ServiceId, s->EventUid, s->Title, s->Search, s->Priority, s->Early, s->Late, s->Repeats, s->ScheduleId).second->execute(); } DoReschedule(ice); return s->ScheduleId; diff --git a/p2pvr/daemon/schedules.h b/p2pvr/daemon/schedules.h index f7075dd..2ff9e0f 100644 --- a/p2pvr/daemon/schedules.h +++ b/p2pvr/daemon/schedules.h @@ -11,11 +11,10 @@ class Episode; class Showing : public IntrusivePtrBase { public: - Showing(unsigned int s, unsigned int e, unsigned int t, unsigned int sc, datetime start, datetime stop, int p, const Episode * ep); + Showing(unsigned int e, unsigned int t, unsigned int sc, datetime start, datetime stop, int p, const Episode * ep); // Record what? const Episode * episode; - const unsigned int serviceId; - const unsigned int eventId; + const unsigned int eventUid; int priority; const unsigned int scheduleId; // Requires diff --git a/p2pvr/daemon/si.cpp b/p2pvr/daemon/si.cpp index 571c6b0..0c5162e 100644 --- a/p2pvr/daemon/si.cpp +++ b/p2pvr/daemon/si.cpp @@ -9,6 +9,7 @@ ResourceString(SI_serviceNextUsed, sql_SI_serviceNextUsed); ResourceString(SI_servicesSelectAll, sql_SI_servicesSelectAll); ResourceString(SI_servicesSelectById, sql_SI_servicesSelectById); +ResourceString(SI_eventByUid, sql_SI_eventByUid); ResourceString(SI_eventById, sql_SI_eventById); ResourceString(SI_eventsOnNow, sql_SI_eventsOnNow); ResourceString(SI_eventsInSchedule, sql_SI_eventsInSchedule); @@ -100,57 +101,69 @@ SI::GetService(int id, const Ice::Current&) return rtn.front(); } -DVBSI::EventPtr +P2PVR::Events +SI::GetEvents(const P2PVR::IntSequence & eventUids, const Ice::Current &) +{ + P2PVR::Events rtn; + SqlContainerCreator cc(rtn); + BOOST_FOREACH(const auto & uid, eventUids){ + cc.populate(Select(SI_eventByUid, uid).second); + } + if (rtn.size() != eventUids.size()) throw P2PVR::NotFound(); + return rtn; +} + +P2PVR::EventPtr SI::GetEvent(int serviceId, int eventId, const Ice::Current &) { - DVBSI::Events rtn; - SqlContainerCreator cc(rtn); + P2PVR::Events rtn; + SqlContainerCreator cc(rtn); cc.populate(Select(SI_eventById, serviceId, eventId).second); if (rtn.empty()) throw P2PVR::NotFound(); return rtn.front(); } -DVBSI::Events +P2PVR::Events SI::EventsOnNow(const Ice::Current &) { - DVBSI::Events rtn; - SqlContainerCreator cc(rtn); + P2PVR::Events rtn; + SqlContainerCreator cc(rtn); cc.populate(Select(SI_eventsOnNow).second); return rtn; } -DVBSI::Events +P2PVR::Events SI::EventsInRange(const Common::DateTime & from, const Common::DateTime & to, const Ice::Current &) { - DVBSI::Events rtn; - SqlContainerCreator cc(rtn); + P2PVR::Events rtn; + SqlContainerCreator cc(rtn); cc.populate(Select(SI_eventsInRange, from, to).second); return rtn; } -DVBSI::Events +P2PVR::Events SI::EventSearch(const IceUtil::Optional & keywords, const IceUtil::Optional & serviceId, const IceUtil::Optional & from, const IceUtil::Optional & to, const Ice::Current &) { - DVBSI::Events rtn; - SqlContainerCreator cc(rtn); + P2PVR::Events rtn; + SqlContainerCreator cc(rtn); cc.populate(Select(SI_eventSearch, from, to, serviceId, serviceId, keywords, keywords, keywords, keywords).second); return rtn; } -DVBSI::Events +P2PVR::Events SI::EventsInSchedules(const Ice::Current &) { - DVBSI::Events rtn; - SqlContainerCreator cc(rtn); + P2PVR::Events rtn; + SqlContainerCreator cc(rtn); cc.populate(Select(SI_eventsInSchedules).second); return rtn; } -DVBSI::Events +P2PVR::Events SI::EventsInSchedule(int scheduleId, const Ice::Current &) { - DVBSI::Events rtn; - SqlContainerCreator cc(rtn); + P2PVR::Events rtn; + SqlContainerCreator cc(rtn); cc.populate(Select(SI_eventsInSchedule, scheduleId).second); return rtn; } diff --git a/p2pvr/daemon/si.h b/p2pvr/daemon/si.h index dd48d77..21b78e1 100644 --- a/p2pvr/daemon/si.h +++ b/p2pvr/daemon/si.h @@ -14,12 +14,13 @@ class SI : public P2PVR::SI, public DatabaseClient { DVBSI::ServiceList GetServices(const Ice::Current &); DVBSI::ServicePtr GetService(int id, const Ice::Current &); - DVBSI::EventPtr GetEvent(int serviceId, int eventId, const Ice::Current &); - DVBSI::Events EventsOnNow(const Ice::Current &); - DVBSI::Events EventsInSchedules(const Ice::Current &); - DVBSI::Events EventsInSchedule(int scheduleId, const Ice::Current &); - DVBSI::Events EventsInRange(const Common::DateTime &, const Common::DateTime &, const Ice::Current &); - DVBSI::Events EventSearch(const IceUtil::Optional & keywords, const IceUtil::Optional & serviceId, const IceUtil::Optional & from, const IceUtil::Optional & to, const Ice::Current &); + P2PVR::Events GetEvents(const P2PVR::IntSequence & eventUids, const Ice::Current &); + P2PVR::EventPtr GetEvent(int serviceId, int eventId, const Ice::Current &); + P2PVR::Events EventsOnNow(const Ice::Current &); + P2PVR::Events EventsInSchedules(const Ice::Current &); + P2PVR::Events EventsInSchedule(int scheduleId, const Ice::Current &); + P2PVR::Events EventsInRange(const Common::DateTime &, const Common::DateTime &, const Ice::Current &); + P2PVR::Events EventSearch(const IceUtil::Optional & keywords, const IceUtil::Optional & serviceId, const IceUtil::Optional & from, const IceUtil::Optional & to, const Ice::Current &); }; #endif diff --git a/p2pvr/daemon/sql/Maint_pruneEvents.sql b/p2pvr/daemon/sql/Maint_pruneEvents.sql new file mode 100644 index 0000000..b6f1d1b --- /dev/null +++ b/p2pvr/daemon/sql/Maint_pruneEvents.sql @@ -0,0 +1,4 @@ +DELETE FROM events e +WHERE e.eventuid NOT IN (SELECT eventuid FROM recorded) +AND e.eventuid NOT IN (SELECT eventuid FROM recordings) +AND NOT current diff --git a/p2pvr/daemon/sql/Recordings_getAll.sql b/p2pvr/daemon/sql/Recordings_getAll.sql index c0a096c..3c3ff51 100644 --- a/p2pvr/daemon/sql/Recordings_getAll.sql +++ b/p2pvr/daemon/sql/Recordings_getAll.sql @@ -1,3 +1,3 @@ -SELECT recordingId, storageAddress, guid, scheduleId, title, subtitle, description, startTime, duration +SELECT recordingId, storageAddress, guid, scheduleId, eventUid FROM recordings r -ORDER BY startTime, title, subtitle +ORDER BY recordingId diff --git a/p2pvr/daemon/sql/Recordings_insert.sql b/p2pvr/daemon/sql/Recordings_insert.sql index dfe2ccc..ba0b9e2 100644 --- a/p2pvr/daemon/sql/Recordings_insert.sql +++ b/p2pvr/daemon/sql/Recordings_insert.sql @@ -1,2 +1,2 @@ -INSERT INTO recordings(storageAddress, guid, scheduleId, title, subtitle, description, startTime, duration) -VALUES(?, ?, ?, ?, ?, ?, ?, ?) +INSERT INTO recordings(storageAddress, guid, scheduleId, eventUid) +VALUES(?, ?, ?, ?) diff --git a/p2pvr/daemon/sql/SI_eventById.sql b/p2pvr/daemon/sql/SI_eventById.sql index f0e028d..b751ad6 100644 --- a/p2pvr/daemon/sql/SI_eventById.sql +++ b/p2pvr/daemon/sql/SI_eventById.sql @@ -1,4 +1,5 @@ -select e.serviceid, +select + e.serviceid, e.eventid, e.title, e.titlelang, @@ -21,8 +22,11 @@ select e.serviceid, e.episodes, e.year, e.flags, - e.season + e.season, + e.eventuid, + e.current from events e -where serviceid = ? +where serviceid = ? and eventid = ? +and current diff --git a/p2pvr/daemon/sql/SI_eventByUid.sql b/p2pvr/daemon/sql/SI_eventByUid.sql new file mode 100644 index 0000000..1d559ec --- /dev/null +++ b/p2pvr/daemon/sql/SI_eventByUid.sql @@ -0,0 +1,30 @@ +select + e.serviceid, + e.eventid, + e.title, + e.titlelang, + e.subtitle, + e.description, + e.descriptionlang, + e.videoaspect, + e.videoframerate, + e.videohd, + e.audiochannels, + e.audiolanguage, + e.subtitlelanguage, + e.category, + e.subcategory, + e.usercategory, + e.dvbrating, + e.starttime, + e.stoptime, + e.episode, + e.episodes, + e.year, + e.flags, + e.season, + e.eventuid, + e.current +from events e +where eventuid = ? + diff --git a/p2pvr/daemon/sql/SI_eventSearch.sql b/p2pvr/daemon/sql/SI_eventSearch.sql index 7ff0cf7..ffbe93f 100644 --- a/p2pvr/daemon/sql/SI_eventSearch.sql +++ b/p2pvr/daemon/sql/SI_eventSearch.sql @@ -22,11 +22,14 @@ select e.episodes, e.year, e.flags, - e.season + e.season, + e.eventuid, + e.current from events e where tsrange(?, ?, '[)') && tsrange(e.starttime, e.stoptime) and (e.serviceId = ? or ?::int is null) and (event_tsvector(e) @@ plainto_tsquery(?) or ?::text is null) +and current order by max(ts_rank(event_tsvector(e), plainto_tsquery(?))) over(partition by title) desc, max(ts_rank(event_tsvector(e), plainto_tsquery(?))) over(partition by title, subtitle, description) desc, diff --git a/p2pvr/daemon/sql/SI_eventsInRange.sql b/p2pvr/daemon/sql/SI_eventsInRange.sql index 0a2d6de..1d0eb17 100644 --- a/p2pvr/daemon/sql/SI_eventsInRange.sql +++ b/p2pvr/daemon/sql/SI_eventsInRange.sql @@ -1,4 +1,5 @@ -select e.serviceid, +select + e.serviceid, e.eventid, e.title, e.titlelang, @@ -21,8 +22,11 @@ select e.serviceid, e.episodes, e.year, e.flags, - e.season + e.season, + e.eventuid, + e.current from events e where tsrange(?, ?, '[)') && tsrange(e.starttime, e.stoptime) +and current order by e.serviceid, e.starttime diff --git a/p2pvr/daemon/sql/SI_eventsInSchedule.sql b/p2pvr/daemon/sql/SI_eventsInSchedule.sql index 3f919a5..72ae26e 100644 --- a/p2pvr/daemon/sql/SI_eventsInSchedule.sql +++ b/p2pvr/daemon/sql/SI_eventsInSchedule.sql @@ -1,4 +1,5 @@ -select e.serviceid, +select + e.serviceid, e.eventid, e.title, e.titlelang, @@ -21,10 +22,12 @@ select e.serviceid, e.episodes, e.year, e.flags, - e.season + e.season, + e.eventuid, + e.current from events e, record r -where e.serviceid = r.serviceid -and e.eventid = r.eventid +where e.eventuid = r.eventuid and r.scheduleid = ? +and e.current order by e.serviceid, e.starttime diff --git a/p2pvr/daemon/sql/SI_eventsInSchedules.sql b/p2pvr/daemon/sql/SI_eventsInSchedules.sql index bd4637a..880b28a 100644 --- a/p2pvr/daemon/sql/SI_eventsInSchedules.sql +++ b/p2pvr/daemon/sql/SI_eventsInSchedules.sql @@ -1,4 +1,5 @@ -select e.serviceid, +select + e.serviceid, e.eventid, e.title, e.titlelang, @@ -21,9 +22,11 @@ select e.serviceid, e.episodes, e.year, e.flags, - e.season + e.season, + e.eventuid, + e.current from events e, record r -where e.serviceid = r.serviceid -and e.eventid = r.eventid +where e.eventuid = r.eventuid +and current order by e.serviceid, e.starttime diff --git a/p2pvr/daemon/sql/SI_eventsOnNow.sql b/p2pvr/daemon/sql/SI_eventsOnNow.sql index 36760b4..391e8de 100644 --- a/p2pvr/daemon/sql/SI_eventsOnNow.sql +++ b/p2pvr/daemon/sql/SI_eventsOnNow.sql @@ -1,4 +1,5 @@ -select e.serviceid, +select + e.serviceid, e.eventid, e.title, e.titlelang, @@ -21,7 +22,10 @@ select e.serviceid, e.episodes, e.year, e.flags, - e.season + e.season, + e.eventuid, + e.current from events e where now()::timestamp without time zone <@ tsrange(e.starttime, e.stoptime) +and current order by e.serviceid diff --git a/p2pvr/daemon/sql/SI_serviceNextUsed.sql b/p2pvr/daemon/sql/SI_serviceNextUsed.sql index 8e906ad..1bf2053 100644 --- a/p2pvr/daemon/sql/SI_serviceNextUsed.sql +++ b/p2pvr/daemon/sql/SI_serviceNextUsed.sql @@ -1,12 +1,11 @@ SELECT dd.* FROM delivery_dvbt dd, services s - LEFT OUTER JOIN record r - ON r.serviceid = s.serviceid - AND r.recordstatus = 0 LEFT OUTER JOIN events e - ON r.eventid = e.eventid - AND r.serviceid = e.serviceid + ON s.serviceid = e.serviceid AND e.starttime > NOW() + LEFT OUTER JOIN record r + ON r.eventuid = e.eventuid + AND r.recordstatus = 0 WHERE dd.transportstreamid = s.transportstreamid ORDER BY e.starttime, s.serviceid LIMIT 1 diff --git a/p2pvr/daemon/sql/Schedules_GetCandidates.sql b/p2pvr/daemon/sql/Schedules_GetCandidates.sql index 8e8b15e..0bb7bd8 100644 --- a/p2pvr/daemon/sql/Schedules_GetCandidates.sql +++ b/p2pvr/daemon/sql/Schedules_GetCandidates.sql @@ -1,25 +1,26 @@ -select what, serviceid, eventid, transportstreamid, +select what, eventuid, transportstreamid, starttime - early starttime, stoptime + late stoptime, priority, scheduleid from ( - select (e.title, e.subtitle, e.description)::text what, e.serviceid, e.eventid, sv.transportstreamid, + select (e.title, e.subtitle, e.description)::text what, e.eventuid, sv.transportstreamid, e.starttime, e.stoptime - interval '1 second' stoptime, s.early, s.late, s.scheduleid, s.priority, - rank() over(partition by e.serviceid, e.eventid, sv.serviceid order by s.priority desc, s.scheduleid) schedulerank + rank() over(partition by e.eventuid, sv.serviceid order by s.priority desc, s.scheduleid) schedulerank from services sv, events e, schedules s where (s.serviceid is null or s.serviceid = e.serviceid) and (s.title is null or lower(s.title) = lower(e.title)) - and (s.eventid is null or s.eventid = e.eventid) + and (s.eventuid is null or s.eventuid = e.eventuid) and (s.search is null or event_tsvector(e) @@ plainto_tsquery(s.search)) and sv.serviceid = e.serviceid and e.stoptime > now() and not exists ( select 1 - from recorded r - where lower(e.title) = lower(r.title) - and coalesce(lower(e.subtitle), '') = coalesce(lower(r.subtitle), '') - and ts_rank(to_tsvector(e.description), plainto_tsquery(r.description)) + - ts_rank(to_tsvector(r.description), plainto_tsquery(e.description)) > 1)) e + from recorded r, events re + where r.eventuid = re.eventuid + and lower(e.title) = lower(re.title) + and coalesce(lower(e.subtitle), '') = coalesce(lower(re.subtitle), '') + and ts_rank(to_tsvector(e.description), plainto_tsquery(re.description)) + + ts_rank(to_tsvector(re.description), plainto_tsquery(e.description)) > 1)) e where e.schedulerank = 1 order by e.priority desc, e.what, e.transportstreamid, e.starttime diff --git a/p2pvr/daemon/sql/Schedules_insert.sql b/p2pvr/daemon/sql/Schedules_insert.sql index 100e78b..70c95bd 100644 --- a/p2pvr/daemon/sql/Schedules_insert.sql +++ b/p2pvr/daemon/sql/Schedules_insert.sql @@ -1,2 +1,2 @@ -INSERT INTO schedules(serviceId, eventId, title, search, priority, early, late, repeats) +INSERT INTO schedules(serviceId, eventUid, title, search, priority, early, late, repeats) VALUES(?, ?, ?, ?, ?, ?, ?, ?) diff --git a/p2pvr/daemon/sql/Schedules_scheduledToRecord.sql b/p2pvr/daemon/sql/Schedules_scheduledToRecord.sql index 3874c37..09e9b4c 100644 --- a/p2pvr/daemon/sql/Schedules_scheduledToRecord.sql +++ b/p2pvr/daemon/sql/Schedules_scheduledToRecord.sql @@ -1,8 +1,7 @@ -SELECT r.serviceid, r.eventid, r.scheduleid +SELECT e.serviceid, e.eventid, r.scheduleid FROM record r, events e, schedules s WHERE recordstatus = 0 -AND r.serviceid = e.serviceid -AND r.eventid = e.eventid +AND r.eventuid = e.eventuid AND r.scheduleid = s.scheduleid AND e.stoptime + s.late > NOW() ORDER BY e.starttime, e.serviceid diff --git a/p2pvr/daemon/sql/Schedules_selectAll.sql b/p2pvr/daemon/sql/Schedules_selectAll.sql index e9e500e..56778a9 100644 --- a/p2pvr/daemon/sql/Schedules_selectAll.sql +++ b/p2pvr/daemon/sql/Schedules_selectAll.sql @@ -1,3 +1,3 @@ -SELECT scheduleid, serviceid, eventid, title, search, priority, early, late, repeats +SELECT scheduleid, serviceid, eventuid, title, search, priority, early, late, repeats FROM schedules ORDER BY scheduleId diff --git a/p2pvr/daemon/sql/Schedules_selectById.sql b/p2pvr/daemon/sql/Schedules_selectById.sql index 4990418..291398c 100644 --- a/p2pvr/daemon/sql/Schedules_selectById.sql +++ b/p2pvr/daemon/sql/Schedules_selectById.sql @@ -1,5 +1,4 @@ -SELECT scheduleid, serviceid, eventid, title, search, priority, early, late, repeats +SELECT scheduleid, serviceid, eventuid, title, search, priority, early, late, repeats FROM schedules WHERE scheduleid = ? -ORDER BY scheduleId diff --git a/p2pvr/daemon/sql/Schedules_update.sql b/p2pvr/daemon/sql/Schedules_update.sql index 56c9531..cf3ce49 100644 --- a/p2pvr/daemon/sql/Schedules_update.sql +++ b/p2pvr/daemon/sql/Schedules_update.sql @@ -1,6 +1,6 @@ UPDATE schedules SET serviceId = ?, - eventId = ?, + eventUid = ?, title = ?, search = ?, priority = ?, diff --git a/p2pvr/daemon/unittests/Jamfile.jam b/p2pvr/daemon/unittests/Jamfile.jam index d0d704d..e41b164 100644 --- a/p2pvr/daemon/unittests/Jamfile.jam +++ b/p2pvr/daemon/unittests/Jamfile.jam @@ -16,6 +16,7 @@ unit-test testp2ice : ../..//p2ice ../..//p2ut ../../ice//p2pvrice + ../../lib//p2pvrlib ../../p2comp//p2pvrp2comp boost_system boost_filesystem @@ -24,7 +25,7 @@ unit-test testp2ice : ; unit-test testMaint : - testMaint.cpp + testMaint.cpp mockDevices.cpp mockScheduler.cpp : BOOST_TEST_DYN_LINK ../..//p2common @@ -43,4 +44,61 @@ unit-test testMaint : ROOT=\"$(me)\" ; +unit-test testRecordings : + testRecordings.cpp + : + BOOST_TEST_DYN_LINK + ../..//p2common + ../..//p2basics + ../..//p2lib + ../..//p2ice + ../..//p2xml + ../..//p2ut + ..//p2pvrdaemon + IceUtil + Ice + boost_system + boost_filesystem + ../..//boost_utf + ROOT=\"$(me)\" + ; + +unit-test testSi : + testSi.cpp + : + BOOST_TEST_DYN_LINK + ../..//p2common + ../..//p2basics + ../..//p2lib + ../..//p2ice + ../..//p2xml + ../..//p2ut + ..//p2pvrdaemon + IceUtil + Ice + boost_system + boost_filesystem + ../..//boost_utf + ROOT=\"$(me)\" + ; + +unit-test testSched : + testSched.cpp mockDevices.cpp mockRecorder.cpp + : + BOOST_TEST_DYN_LINK + ../..//p2common + ../..//p2basics + ../..//p2lib + ../..//p2ice + ../..//p2xml + ../..//p2ut + ..//p2pvrdaemon + IceUtil + Ice + boost_system + boost_filesystem + ../../devices//p2pvrMockTuner + ../..//boost_utf + ROOT=\"$(me)\" + ; diff --git a/p2pvr/daemon/unittests/mockDevices.cpp b/p2pvr/daemon/unittests/mockDevices.cpp new file mode 100644 index 0000000..7c3dc2c --- /dev/null +++ b/p2pvr/daemon/unittests/mockDevices.cpp @@ -0,0 +1,29 @@ +#include "mockDevices.h" +#include +#include + +P2PVR::TunerPrx MockDevices::GetTunerSpecific(const DVBSI::DeliveryPtr&, const Ice::Current & ice) +{ + return P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new MockTuner())); +} + +P2PVR::TunerPrx MockDevices::GetTunerAny(Ice::Short, const DVBSI::DeliveryPtr&, const Ice::Current & ice) +{ + return P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new MockTuner())); +} + +P2PVR::PrivateTunerPrx MockDevices::GetPrivateTuner(Ice::Short, const Ice::Current & ice) +{ + return P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new MockTuner())); +} + +void MockDevices::ReleaseTuner(const P2PVR::TunerPrx & tuner, const Ice::Current & ice) +{ + ice.adapter->remove(tuner->ice_getIdentity()); +} + +Ice::Int MockDevices::TunerCount(const Ice::Current&) +{ + return 1; +} + diff --git a/p2pvr/daemon/unittests/mockDevices.h b/p2pvr/daemon/unittests/mockDevices.h new file mode 100644 index 0000000..59d1b50 --- /dev/null +++ b/p2pvr/daemon/unittests/mockDevices.h @@ -0,0 +1,16 @@ +#ifndef P2PVR_MOCKS_DEVICES_H +#define P2PVR_MOCKS_DEVICES_H + +#include + +class MockDevices : public P2PVR::Devices { + public: + P2PVR::TunerPrx GetTunerSpecific(const DVBSI::DeliveryPtr&, const Ice::Current & ice) override; + P2PVR::TunerPrx GetTunerAny(Ice::Short, const DVBSI::DeliveryPtr&, const Ice::Current & ice) override; + P2PVR::PrivateTunerPrx GetPrivateTuner(Ice::Short, const Ice::Current & ice) override; + void ReleaseTuner(const P2PVR::TunerPrx & tuner, const Ice::Current & ice) override; + Ice::Int TunerCount(const Ice::Current&) override; +}; + +#endif + diff --git a/p2pvr/daemon/unittests/mockRecorder.cpp b/p2pvr/daemon/unittests/mockRecorder.cpp new file mode 100644 index 0000000..0796aba --- /dev/null +++ b/p2pvr/daemon/unittests/mockRecorder.cpp @@ -0,0 +1,8 @@ +#include "mockRecorder.h" + +void +MockRecorder::RefreshSchedules(const Ice::Current &) +{ + +} + diff --git a/p2pvr/daemon/unittests/mockRecorder.h b/p2pvr/daemon/unittests/mockRecorder.h new file mode 100644 index 0000000..85f747b --- /dev/null +++ b/p2pvr/daemon/unittests/mockRecorder.h @@ -0,0 +1,12 @@ +#ifndef P2PVR_MOCKS_RECORDER_H +#define P2PVR_MOCKS_RECORDER_H + +#include + +class MockRecorder : public P2PVR::Recorder { + public: + void RefreshSchedules(const Ice::Current &) override; +}; + +#endif + diff --git a/p2pvr/daemon/unittests/mockScheduler.cpp b/p2pvr/daemon/unittests/mockScheduler.cpp new file mode 100644 index 0000000..2677df7 --- /dev/null +++ b/p2pvr/daemon/unittests/mockScheduler.cpp @@ -0,0 +1,36 @@ +#include "mockScheduler.h" + +void +MockScheduler::DoReschedule(const::Ice::Current &) +{ +} + +void +MockScheduler::DeleteSchedule(Ice::Int, const Ice::Current &) +{ +} + +P2PVR::SchedulePtr +MockScheduler::GetSchedule(::Ice::Int, const::Ice::Current &) +{ + return P2PVR::SchedulePtr(); +} + +P2PVR::ScheduleList +MockScheduler::GetSchedules(const::Ice::Current &) +{ + return P2PVR::ScheduleList(); +} + +P2PVR::ScheduledToRecordList +MockScheduler::GetScheduledToRecord(const::Ice::Current &) +{ + return P2PVR::ScheduledToRecordList(); +} + +Ice::Int +MockScheduler::UpdateSchedule(const::P2PVR::SchedulePtr &, const::Ice::Current &) +{ + return 0; +} + diff --git a/p2pvr/daemon/unittests/mockScheduler.h b/p2pvr/daemon/unittests/mockScheduler.h new file mode 100644 index 0000000..9176bb6 --- /dev/null +++ b/p2pvr/daemon/unittests/mockScheduler.h @@ -0,0 +1,17 @@ +#ifndef P2PVR_MOCKS_SCHEDULER_H +#define P2PVR_MOCKS_SCHEDULER_H + +#include + +class MockScheduler : public P2PVR::Schedules { + public: + void DoReschedule(const ::Ice::Current&) override; + void DeleteSchedule(Ice::Int, const Ice::Current&) override; + P2PVR::SchedulePtr GetSchedule(::Ice::Int, const ::Ice::Current&) override; + P2PVR::ScheduleList GetSchedules(const ::Ice::Current&) override; + P2PVR::ScheduledToRecordList GetScheduledToRecord(const ::Ice::Current&) override; + Ice::Int UpdateSchedule(const ::P2PVR::SchedulePtr&, const ::Ice::Current&) override; +}; + +#endif + diff --git a/p2pvr/daemon/unittests/testMaint.cpp b/p2pvr/daemon/unittests/testMaint.cpp index 139284c..10f365e 100644 --- a/p2pvr/daemon/unittests/testMaint.cpp +++ b/p2pvr/daemon/unittests/testMaint.cpp @@ -7,100 +7,90 @@ #include #include #include +#include "mockDevices.h" +#include "mockScheduler.h" #include +#include #include +#include -#define XSTR(s) STR(s) -#define STR(s) #s -const auto bindir = boost::filesystem::canonical("/proc/self/exe").parent_path(); -const auto componentdir = bindir.parent_path() / "component"; -const boost::filesystem::path root(XSTR(ROOT)); - -class MockDevices : public P2PVR::Devices { +class Core { public: - P2PVR::TunerPrx GetTunerSpecific(const DVBSI::DeliveryPtr&, const Ice::Current & ice) override - { - return P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new MockTuner())); - } - P2PVR::TunerPrx GetTunerAny(Ice::Short, const DVBSI::DeliveryPtr&, const Ice::Current & ice) override - { - return P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new MockTuner())); - } - P2PVR::PrivateTunerPrx GetPrivateTuner(Ice::Short, const Ice::Current & ice) override - { - return P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new MockTuner())); - } - void ReleaseTuner(const P2PVR::TunerPrx & tuner, const Ice::Current & ice) override + Core() { - ice.adapter->remove(tuner->ice_getIdentity()); + int paramCount = 0; + ic = Ice::initialize(paramCount, NULL); + auto adapter = ic->createObjectAdapterWithEndpoints("Adp", "tcp -p 12000"); + TestOptionsSource::LoadTestOptions({ + { "common.datasourceRoot", (RootDir / "datasources").string() }, + }); + adapter->add(new MockDevices(), ic->stringToIdentity("GlobalDevices")); + adapter->add(new MockScheduler(), ic->stringToIdentity("Schedules")); + adapter->add(new SI(), ic->stringToIdentity("SI")); + adapter->add(new Recordings(), ic->stringToIdentity("Recordings")); + adapter->add(new Maintenance(adapter, NULL), ic->stringToIdentity("Maintenance")); + adapter->activate(); + + r = P2PVR::RecordingsPrx::checkedCast(ic->stringToProxy("Recordings")); + BOOST_REQUIRE(r); + r->ice_ping(); + + s = P2PVR::SIPrx::checkedCast(ic->stringToProxy("SI")); + BOOST_REQUIRE(s); + s->ice_ping(); + + m = P2PVR::MaintenancePrx::checkedCast(ic->stringToProxy("Maintenance")); + BOOST_REQUIRE(m); + m->ice_ping(); } - Ice::Int TunerCount(const Ice::Current&) override + + ~Core() { - return 1; + ic->destroy(); } -}; -class MockScheduler : public P2PVR::Schedules { - public: - void DoReschedule(const ::Ice::Current&) { } - void DeleteSchedule(Ice::Int, const Ice::Current&) { } - P2PVR::SchedulePtr GetSchedule(::Ice::Int, const ::Ice::Current&) { return P2PVR::SchedulePtr(); } - P2PVR::ScheduleList GetSchedules(const ::Ice::Current&) { return P2PVR::ScheduleList(); } - P2PVR::ScheduledToRecordList GetScheduledToRecord(const ::Ice::Current&) { return P2PVR::ScheduledToRecordList(); } - Ice::Int UpdateSchedule(const ::P2PVR::SchedulePtr&, const ::Ice::Current&) { return 0; } + P2PVR::MaintenancePrx m; + P2PVR::RecordingsPrx r; + P2PVR::SIPrx s; + + private: + Ice::CommunicatorPtr ic; }; -static -Ice::CommunicatorPtr -standardConfig() -{ - int paramCount = 0; - Ice::CommunicatorPtr ic = Ice::initialize(paramCount, NULL); - auto adapter = ic->createObjectAdapterWithEndpoints("Adp", "tcp -p 12000"); - TestOptionsSource::LoadTestOptions({ - { "common.datasourceRoot", (root / "datasources").string() }, - }); - adapter->add(new MockDevices(), ic->stringToIdentity("GlobalDevices")); - adapter->add(new MockScheduler(), ic->stringToIdentity("Schedules")); - adapter->add(new SI(), ic->stringToIdentity("SI")); - adapter->add(new Maintenance(adapter, NULL), ic->stringToIdentity("Maintenance")); - adapter->activate(); - return ic; -} +BOOST_FIXTURE_TEST_SUITE( MaintCore, Core ) BOOST_AUTO_TEST_CASE( update_network ) { - auto ic = standardConfig(); - ScopeObject _([&ic]{ ic->destroy(); }); - - auto m = P2PVR::MaintenancePrx::checkedCast(ic->stringToProxy("Maintenance")); - BOOST_REQUIRE(m); - m->ice_ping(); - m->UpdateNetwork(FE_OFDM); } BOOST_AUTO_TEST_CASE( update_services ) { - auto ic = standardConfig(); - ScopeObject _([&ic]{ ic->destroy(); }); - - auto m = P2PVR::MaintenancePrx::checkedCast(ic->stringToProxy("Maintenance")); - BOOST_REQUIRE(m); - m->ice_ping(); - m->UpdateServices(FE_OFDM); } BOOST_AUTO_TEST_CASE( update_events ) { - auto ic = standardConfig(); - ScopeObject _([&ic]{ ic->destroy(); }); + BOOST_CHECKPOINT("Get existing recordings"); + auto recs = r->GetRecordings(); - auto m = P2PVR::MaintenancePrx::checkedCast(ic->stringToProxy("Maintenance")); - BOOST_REQUIRE(m); - m->ice_ping(); - + BOOST_CHECKPOINT("Delete existing recordings"); + BOOST_FOREACH(const auto & rec, recs) { + r->DeleteRecording(rec->RecordingId); + } + + BOOST_CHECKPOINT("Write first events"); + MockTuner::SetEventsSet(0); m->UpdateEvents(FE_OFDM); + BOOST_REQUIRE(s->GetEvent(14448, 27052)); + BOOST_REQUIRE_THROW(s->GetEvent(15856, 3591), P2PVR::NotFound); + + BOOST_CHECKPOINT("Write second events"); + MockTuner::SetEventsSet(1); + m->UpdateEvents(FE_OFDM); + BOOST_REQUIRE_THROW(s->GetEvent(14448, 27052), P2PVR::NotFound); + BOOST_REQUIRE(s->GetEvent(15856, 3591)); } +BOOST_AUTO_TEST_SUITE_END() + diff --git a/p2pvr/daemon/unittests/testRecordings.cpp b/p2pvr/daemon/unittests/testRecordings.cpp new file mode 100644 index 0000000..adfc231 --- /dev/null +++ b/p2pvr/daemon/unittests/testRecordings.cpp @@ -0,0 +1,74 @@ +#define BOOST_TEST_MODULE Recordings +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Core { + public: + Core() + { + int paramCount = 0; + ic = Ice::initialize(paramCount, NULL); + auto adapter = ic->createObjectAdapterWithEndpoints("Adp", "tcp -p 12001"); + TestOptionsSource::LoadTestOptions({ + { "common.datasourceRoot", (RootDir / "datasources").string() }, + }); + adapter->add(new Recordings(), ic->stringToIdentity("Recordings")); + adapter->add(new SI(), ic->stringToIdentity("SI")); + adapter->activate(); + + r = P2PVR::RecordingsPrx::checkedCast(ic->stringToProxy("Recordings")); + BOOST_REQUIRE(r); + r->ice_ping(); + + si = P2PVR::SIPrx::checkedCast(ic->stringToProxy("SI")); + BOOST_REQUIRE(si); + si->ice_ping(); + } + + ~Core() + { + ic->destroy(); + } + + P2PVR::SIPrx si; + P2PVR::RecordingsPrx r; + + private: + Ice::CommunicatorPtr ic; +}; + +BOOST_FIXTURE_TEST_SUITE( RecCore, Core ) + +BOOST_AUTO_TEST_CASE( recordings_get ) +{ + r->GetRecordings(); +} + +BOOST_AUTO_TEST_CASE( recordings_addAndDelete ) +{ + auto event = si->GetEvent(5696, 40124); + BOOST_REQUIRE(event); + BOOST_MESSAGE(event->Title); + + auto guid = boost::lexical_cast(boost::uuids::random_generator()()); + auto rec = P2PVR::RecordingPtr(new P2PVR::Recording(0, "", guid, 0, event->EventUid)); + auto id = r->NewRecording(rec); + r->GetRecordings(); + r->DeleteRecording(id); +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/p2pvr/daemon/unittests/testSched.cpp b/p2pvr/daemon/unittests/testSched.cpp new file mode 100644 index 0000000..9a6134b --- /dev/null +++ b/p2pvr/daemon/unittests/testSched.cpp @@ -0,0 +1,102 @@ +#define BOOST_TEST_MODULE Scheduler +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mockDevices.h" +#include "mockRecorder.h" +#include +#include +#include +#include +#include + +class Core { + public: + Core() + { + int paramCount = 0; + ic = Ice::initialize(paramCount, NULL); + auto adapter = ic->createObjectAdapterWithEndpoints("Adp", "tcp -p 12003"); + TestOptionsSource::LoadTestOptions({ + { "common.datasourceRoot", (RootDir / "datasources").string() }, + }); + adapter->add(new Schedules(), ic->stringToIdentity("Schedules")); + adapter->add(new MockDevices(), ic->stringToIdentity("GlobalDevices")); + adapter->add(new MockRecorder(), ic->stringToIdentity("Recorder")); + adapter->activate(); + + sc = P2PVR::SchedulesPrx::checkedCast(ic->stringToProxy("Schedules")); + BOOST_REQUIRE(sc); + sc->ice_ping(); + } + + ~Core() + { + ic->destroy(); + } + + P2PVR::SchedulesPrx sc; + + private: + Ice::CommunicatorPtr ic; +}; + +BOOST_FIXTURE_TEST_SUITE( ScCore, Core ) + +BOOST_AUTO_TEST_CASE( sc_getSchedules ) +{ + sc->GetSchedules(); +} + +BOOST_AUTO_TEST_CASE( sc_doReschedule ) +{ + sc->DoReschedule(); +} + +BOOST_AUTO_TEST_CASE( sc_getScheduled ) +{ + sc->GetScheduledToRecord(); +} + +BOOST_AUTO_TEST_CASE( sc_crud ) +{ + P2PVR::SchedulePtr schedule = new P2PVR::Schedule(); + schedule->Search = "Top Gear"; + + auto id = sc->UpdateSchedule(schedule); + BOOST_REQUIRE(id > 0); + schedule->ScheduleId = id; + + auto fetched = sc->GetSchedule(id); + BOOST_REQUIRE_EQUAL(schedule->ScheduleId, fetched->ScheduleId); + BOOST_REQUIRE_EQUAL(*schedule->Search, *fetched->Search); + BOOST_REQUIRE_EQUAL(schedule->Priority, fetched->Priority); + BOOST_REQUIRE_EQUAL(schedule->Repeats, fetched->Repeats); + BOOST_REQUIRE_EQUAL(schedule->Early, fetched->Early); + BOOST_REQUIRE_EQUAL(schedule->Late, fetched->Late); + + schedule->Search = "Top Gear Special"; + schedule->Early.Minutes = 5; + schedule->Late.Minutes = 15; + auto updatedId = sc->UpdateSchedule(schedule); + + fetched = sc->GetSchedule(id); + BOOST_REQUIRE_EQUAL(updatedId, id); + BOOST_REQUIRE_EQUAL(schedule->ScheduleId, fetched->ScheduleId); + BOOST_REQUIRE_EQUAL(*schedule->Search, *fetched->Search); + BOOST_REQUIRE_EQUAL(schedule->Priority, fetched->Priority); + BOOST_REQUIRE_EQUAL(schedule->Repeats, fetched->Repeats); + BOOST_REQUIRE_EQUAL(schedule->Early, fetched->Early); + BOOST_REQUIRE_EQUAL(schedule->Late, fetched->Late); + + sc->DeleteSchedule(fetched->ScheduleId); +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/p2pvr/daemon/unittests/testSi.cpp b/p2pvr/daemon/unittests/testSi.cpp new file mode 100644 index 0000000..d191b38 --- /dev/null +++ b/p2pvr/daemon/unittests/testSi.cpp @@ -0,0 +1,105 @@ +#define BOOST_TEST_MODULE SI +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Core { + public: + Core() + { + int paramCount = 0; + ic = Ice::initialize(paramCount, NULL); + auto adapter = ic->createObjectAdapterWithEndpoints("Adp", "tcp -p 12002"); + TestOptionsSource::LoadTestOptions({ + { "common.datasourceRoot", (RootDir / "datasources").string() }, + }); + adapter->add(new SI(), ic->stringToIdentity("SI")); + adapter->activate(); + + si = P2PVR::SIPrx::checkedCast(ic->stringToProxy("SI")); + BOOST_REQUIRE(si); + si->ice_ping(); + } + + ~Core() + { + ic->destroy(); + } + + P2PVR::SIPrx si; + + private: + Ice::CommunicatorPtr ic; +}; + +BOOST_FIXTURE_TEST_SUITE( SiCore, Core ) + +BOOST_AUTO_TEST_CASE ( si_getEvents ) +{ + // Get an event known to exist so we can use its uid + auto event = si->GetEvent(23968, 4378); + BOOST_REQUIRE(event); + + auto events = si->GetEvents({ event->EventUid }); + BOOST_REQUIRE_EQUAL(events.size(), 1); + BOOST_REQUIRE_EQUAL(events.front()->ServiceId, 23968); + BOOST_REQUIRE_EQUAL(events.front()->EventId, 4378); +} + +BOOST_AUTO_TEST_CASE ( si_getEvents_missing ) +{ + BOOST_REQUIRE_THROW(si->GetEvents({ 0 }), P2PVR::NotFound); +} + +BOOST_AUTO_TEST_CASE( si_getEvent ) +{ + auto event = si->GetEvent(23968, 4378); + BOOST_REQUIRE(event); + BOOST_REQUIRE_EQUAL(event->Title, "Timothy Goes to School"); + BOOST_REQUIRE_EQUAL(event->Current, true); +} + +BOOST_AUTO_TEST_CASE( si_getEventsOnNow ) +{ + si->EventsOnNow(); +} + +BOOST_AUTO_TEST_CASE( si_getEventsInSched ) +{ + si->EventsInSchedule(0); +} + +BOOST_AUTO_TEST_CASE( si_getEventsInScheds ) +{ + si->EventsInSchedules(); +} + +BOOST_AUTO_TEST_CASE( si_getEventsInRange ) +{ + si->EventsInRange(Common::DateTime {2014, 12, 19, 3, 0}, Common::DateTime {2014, 12, 20, 3, 0}); +} + +BOOST_AUTO_TEST_CASE( si_getEventSearch ) +{ + si->EventSearch("Top Gear", IceUtil::Optional< ::Ice::Int >(), + IceUtil::Optional(), IceUtil::Optional()); + si->EventSearch("Top Gear", 22272, + IceUtil::Optional(), IceUtil::Optional()); + si->EventSearch("Top Gear", 22272, + Common::DateTime {2014, 12, 19, 3, 0}, IceUtil::Optional()); + si->EventSearch("Top Gear", 22272, + Common::DateTime {2014, 12, 19, 3, 0}, Common::DateTime {2014, 12, 20, 3, 0}); +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/p2pvr/daemon/unittests/testp2ice.cpp b/p2pvr/daemon/unittests/testp2ice.cpp index 9f9e9a8..23fcbdc 100644 --- a/p2pvr/daemon/unittests/testp2ice.cpp +++ b/p2pvr/daemon/unittests/testp2ice.cpp @@ -2,18 +2,37 @@ #include #include #include +#include +#include -#define XSTR(s) STR(s) -#define STR(s) #s -const auto bindir = boost::filesystem::canonical("/proc/self/exe").parent_path(); -const boost::filesystem::path variant = bindir.leaf(); -const boost::filesystem::path compiler = bindir.parent_path().leaf(); -const boost::filesystem::path root = boost::filesystem::path(XSTR(ROOT)).parent_path().parent_path(); +const boost::filesystem::path variant = BinDir.leaf(); +const boost::filesystem::path compiler = BinDir.parent_path().leaf(); +const boost::filesystem::path root = RootDir.parent_path().parent_path(); const boost::filesystem::path iceroot = root / "ice"; +static +void +commonTests() +{ + BOOST_REQUIRE(ElementLoader::getFor("p2pvrrecordingstream")); + BOOST_REQUIRE(ElementLoader::getFor("p2pvrservicestream")); + BOOST_REQUIRE(ElementLoader::getFor("P2PVR-SI-GetEvent")); +} + +static +void +unloadTests() +{ + BOOST_REQUIRE_THROW(ElementLoader::getFor("P2PVR-SI-GetEvent"), NotSupported); + // Known issue, these *should* unload, but for some reason, don't. + BOOST_WARN_THROW(ElementLoader::getFor("p2pvrrecordingstream"), NotSupported); + BOOST_WARN_THROW(ElementLoader::getFor("p2pvrservicestream"), NotSupported); +} BOOST_AUTO_TEST_CASE( compile_client_clientOnly ) { + TestOptionsSource::LoadTestOptions({ }); + const std::string tmpdir = "/tmp/ut/p2pvr.slice"; BOOST_TEST_CHECKPOINT("Clean up"); boost::filesystem::remove_all(tmpdir); @@ -23,13 +42,15 @@ BOOST_AUTO_TEST_CASE( compile_client_clientOnly ) { "ice.compile.tmpdir", tmpdir }, { "ice.client.slicerclient", (iceroot / "common.ice").string() }, { "library", (root / "ice" / "bin" / compiler / variant / "slicer-yes" / "libp2pvrice.so").string() }, + { "library", (root / "dvb" / "bin" / compiler / variant / "libp2pvrdvb.so").string() }, + { "library", (root / "lib" / "bin" / compiler / variant / "libp2pvrlib.so").string() }, { "library", (root / "p2comp" / "bin" / compiler / variant / "libp2pvrp2comp.so").string() }, { "ice.client.slicerclient", (iceroot / "dvbsi.ice").string() }, { "ice.client.slicerclient", (iceroot / "dvb.ice").string() }, { "ice.client.slicerclient", (iceroot / "p2pvr.ice").string() }, }); - //commonTests(); + commonTests(); TestOptionsSource::LoadTestOptions({ }); - //unloadTests(); + unloadTests(); } diff --git a/p2pvr/datasources/schema.sql b/p2pvr/datasources/schema.sql index 393325d..5e0612f 100644 --- a/p2pvr/datasources/schema.sql +++ b/p2pvr/datasources/schema.sql @@ -57,7 +57,9 @@ CREATE TABLE events ( episodes smallint, year smallint, flags text, - season integer + season integer, + eventuid integer NOT NULL, + current boolean DEFAULT true NOT NULL ); @@ -127,6 +129,25 @@ CREATE TABLE delivery_dvbt ( ); +-- +-- Name: events_eventuid_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE events_eventuid_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: events_eventuid_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE events_eventuid_seq OWNED BY events.eventuid; + + -- -- Name: networks; Type: TABLE; Schema: public; Owner: -; Tablespace: -- @@ -142,8 +163,7 @@ CREATE TABLE networks ( -- CREATE TABLE record ( - serviceid integer NOT NULL, - eventid integer NOT NULL, + eventuid integer NOT NULL, recordstatus integer NOT NULL, recordingstatus integer DEFAULT 0 NOT NULL, scheduleid integer NOT NULL @@ -157,11 +177,7 @@ CREATE TABLE record ( CREATE TABLE recorded ( recordedid integer NOT NULL, scheduleid integer, - title text, - subtitle text, - description text, - starttime timestamp without time zone NOT NULL, - duration interval NOT NULL + eventuid integer NOT NULL ); @@ -193,11 +209,7 @@ CREATE TABLE recordings ( storageaddress text NOT NULL, guid text NOT NULL, scheduleid integer NOT NULL, - title text, - subtitle text, - description text, - starttime timestamp without time zone NOT NULL, - duration interval NOT NULL + eventuid integer NOT NULL ); @@ -227,7 +239,7 @@ ALTER SEQUENCE recordings_recordingid_seq OWNED BY recordings.recordingid; CREATE TABLE schedules ( scheduleid integer NOT NULL, serviceid integer, - eventid integer, + eventuid integer, title text, search text, priority integer DEFAULT 0 NOT NULL, @@ -270,7 +282,7 @@ CREATE TABLE services ( eitschedule boolean, eitpresentfollowing boolean, freecamode boolean, - transportstreamid integer NOT NULL + transportstreamid integer ); @@ -285,6 +297,13 @@ CREATE TABLE transportstreams ( ); +-- +-- Name: eventuid; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY events ALTER COLUMN eventuid SET DEFAULT nextval('events_eventuid_seq'::regclass); + + -- -- Name: recordedid; Type: DEFAULT; Schema: public; Owner: - -- @@ -335,7 +354,7 @@ ALTER TABLE ONLY delivery_dvbt -- ALTER TABLE ONLY events - ADD CONSTRAINT pk_events PRIMARY KEY (serviceid, eventid); + ADD CONSTRAINT pk_events PRIMARY KEY (eventuid); -- @@ -367,7 +386,7 @@ ALTER TABLE ONLY recordings -- ALTER TABLE ONLY record - ADD CONSTRAINT pk_records PRIMARY KEY (serviceid, eventid); + ADD CONSTRAINT pk_records PRIMARY KEY (eventuid); -- @@ -422,20 +441,6 @@ CREATE INDEX idx_events_timerange ON events USING gist (tsrange(starttime, stopt CREATE INDEX idx_recorded_schedule ON recorded USING btree (scheduleid); --- --- Name: idx_recorded_starttime; Type: INDEX; Schema: public; Owner: -; Tablespace: --- - -CREATE INDEX idx_recorded_starttime ON recorded USING btree (starttime); - - --- --- Name: idx_recorded_title; Type: INDEX; Schema: public; Owner: -; Tablespace: --- - -CREATE INDEX idx_recorded_title ON recorded USING btree (title); - - -- -- Name: idx_recordings_schedule; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -444,17 +449,10 @@ CREATE INDEX idx_recordings_schedule ON recordings USING btree (scheduleid); -- --- Name: idx_recordings_starttime; Type: INDEX; Schema: public; Owner: -; Tablespace: --- - -CREATE INDEX idx_recordings_starttime ON recordings USING btree (starttime); - - --- --- Name: idx_recordings_title; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: uni_events_serviceevent; Type: INDEX; Schema: public; Owner: -; Tablespace: -- -CREATE INDEX idx_recordings_title ON recordings USING btree (title); +CREATE UNIQUE INDEX uni_events_serviceevent ON events USING btree (serviceid, eventid) WHERE current; -- @@ -488,6 +486,22 @@ ALTER TABLE ONLY delivery_dvbt ADD CONSTRAINT fk_delivery_dvbt_transportstream FOREIGN KEY (transportstreamid) REFERENCES transportstreams(transportstreamid) ON UPDATE CASCADE ON DELETE CASCADE; +-- +-- Name: fk_record_eventuid; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY record + ADD CONSTRAINT fk_record_eventuid FOREIGN KEY (eventuid) REFERENCES events(eventuid) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- Name: fk_recorded_eventuid; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY recorded + ADD CONSTRAINT fk_recorded_eventuid FOREIGN KEY (eventuid) REFERENCES events(eventuid) ON UPDATE CASCADE; + + -- -- Name: fk_recorded_schedule; Type: FK CONSTRAINT; Schema: public; Owner: - -- @@ -497,11 +511,11 @@ ALTER TABLE ONLY recorded -- --- Name: fk_records_event; Type: FK CONSTRAINT; Schema: public; Owner: - +-- Name: fk_recordings_eventuid; Type: FK CONSTRAINT; Schema: public; Owner: - -- -ALTER TABLE ONLY record - ADD CONSTRAINT fk_records_event FOREIGN KEY (serviceid, eventid) REFERENCES events(serviceid, eventid) ON UPDATE CASCADE ON DELETE CASCADE; +ALTER TABLE ONLY recordings + ADD CONSTRAINT fk_recordings_eventuid FOREIGN KEY (eventuid) REFERENCES events(eventuid) ON UPDATE CASCADE; -- @@ -517,7 +531,7 @@ ALTER TABLE ONLY record -- ALTER TABLE ONLY schedules - ADD CONSTRAINT fk_schedule_event FOREIGN KEY (serviceid, eventid) REFERENCES events(serviceid, eventid) ON DELETE CASCADE; + ADD CONSTRAINT fk_schedule_event FOREIGN KEY (eventuid) REFERENCES events(eventuid) ON UPDATE CASCADE ON DELETE CASCADE; -- @@ -533,7 +547,7 @@ ALTER TABLE ONLY schedules -- ALTER TABLE ONLY services - ADD CONSTRAINT fk_services_transportstreams FOREIGN KEY (transportstreamid) REFERENCES transportstreams(transportstreamid) ON UPDATE CASCADE ON DELETE CASCADE; + ADD CONSTRAINT fk_services_transportstreams FOREIGN KEY (transportstreamid) REFERENCES transportstreams(transportstreamid) ON UPDATE CASCADE ON DELETE SET NULL; -- diff --git a/p2pvr/devices/mockTuner.cpp b/p2pvr/devices/mockTuner.cpp index 335ddec..b89d533 100644 --- a/p2pvr/devices/mockTuner.cpp +++ b/p2pvr/devices/mockTuner.cpp @@ -23,6 +23,14 @@ ResourceFile(services); ResourceFile(events1); ResourceFile(events2); +int MockTuner::eventSet = 0; + +void +MockTuner::SetEventsSet(int n) +{ + eventSet = n; +} + void MockTuner::TuneTo(const DVBSI::DeliveryPtr &, const Ice::Current&) { } @@ -98,7 +106,7 @@ void MockTuner::SendProgramAssociationTable(const P2PVR::RawDataClientPrx &, con void MockTuner::SendEventInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) { - DecompressAndSendPackets(events1, client, ice); + DecompressAndSendPackets(eventSet == 0 ? events1 : events2, client, ice); } int MockTuner::StartSendingTS(const P2PVR::PacketIds &, const P2PVR::RawDataClientPrx &, const Ice::Current &) diff --git a/p2pvr/devices/mockTuner.h b/p2pvr/devices/mockTuner.h index 220b535..31d12cb 100644 --- a/p2pvr/devices/mockTuner.h +++ b/p2pvr/devices/mockTuner.h @@ -6,7 +6,6 @@ class MockTuner : public P2PVR::PrivateTuner { public: - void TuneTo(const DVBSI::DeliveryPtr &, const Ice::Current&); int GetStatus(const Ice::Current&); @@ -24,8 +23,12 @@ class MockTuner : public P2PVR::PrivateTuner { Ice::Long GetLastUsedTime(const Ice::Current&); + static void SetEventsSet(int n); + protected: void DecompressAndSendPackets(const Ice::ByteSeq &, const P2PVR::RawDataClientPrx &, const Ice::Current&) const; + + static int eventSet; }; #endif diff --git a/p2pvr/ice/common.ice b/p2pvr/ice/common.ice index 14ca155..c4be4ce 100644 --- a/p2pvr/ice/common.ice +++ b/p2pvr/ice/common.ice @@ -11,8 +11,8 @@ module Common { }; struct Duration { - short Hour; - short Minute; + short Hours = 0; + short Minutes = 0; }; }; diff --git a/p2pvr/ice/commonHelpers.cpp b/p2pvr/ice/commonHelpers.cpp index 46c7fad..6ad120b 100644 --- a/p2pvr/ice/commonHelpers.cpp +++ b/p2pvr/ice/commonHelpers.cpp @@ -12,7 +12,7 @@ namespace Common { boost::posix_time::time_duration operator*(const Common::Duration & d) { - return boost::posix_time::time_duration(d.Hour, d.Minute, 0); + return boost::posix_time::time_duration(d.Hours, d.Minutes, 0); } } diff --git a/p2pvr/ice/commonHelpers.h b/p2pvr/ice/commonHelpers.h index cc3cac1..3f7e57d 100644 --- a/p2pvr/ice/commonHelpers.h +++ b/p2pvr/ice/commonHelpers.h @@ -18,6 +18,18 @@ namespace Common { << ":" << std::setw(2) << std::setfill('0') << dt.Minute; return o; } + + template + std::basic_ostream & + operator<<(std::basic_ostream & o, const Common::Duration & d) + { + if (d.Hours) { + o << d.Hours << "hrs "; + } + o << d.Minutes << "min"; + return o; + } + boost::posix_time::ptime operator*(const Common::DateTime &); boost::posix_time::time_duration operator*(const Common::Duration &); } diff --git a/p2pvr/ice/p2pvr.ice b/p2pvr/ice/p2pvr.ice index eb4ebbf..7f58539 100644 --- a/p2pvr/ice/p2pvr.ice +++ b/p2pvr/ice/p2pvr.ice @@ -6,6 +6,13 @@ #include "dvbsi.ice" module P2PVR { + ["project2:type"] + class Event extends DVBSI::Event { + int EventUid; + bool Current = true; + }; + sequence Events; + ["project2:type"] exception NotFound { }; @@ -15,27 +22,23 @@ module P2PVR { int RecordingId; string StorageAddress; string Guid; - optional(1) int ScheduleId; - string Title; - optional(2) string Subtitle; - optional(3) string Description; - Common::DateTime StartTime; - Common::Duration Duration; + int ScheduleId; + int EventUid; }; sequence RecordingList; // Something that defines what we would like to record. ["project2:type"] class Schedule { - int ScheduleId; + int ScheduleId = 0; optional(1) int ServiceId; - optional(2) int EventId; + optional(2) int EventUid; optional(3) string Title; optional(4) string Search; - int Priority; + int Priority = 0; Common::Duration Early; Common::Duration Late; - bool Repeats; + bool Repeats = false; }; sequence ScheduleList; @@ -43,8 +46,7 @@ module P2PVR { ["project2:type"] class ScheduledToRecord { int ScheduleId; - int ServiceId; - int EventId; + int EventUid; }; sequence ScheduledToRecordList; @@ -93,6 +95,7 @@ module P2PVR { }; sequence Deliveries; + sequence IntSequence; interface SI { // Get delivery methods idempotent Deliveries GetAllDeliveries(short type); @@ -105,18 +108,19 @@ module P2PVR { ["project2:rows"] idempotent DVBSI::Service GetService(int id) throws NotFound; // Get events + idempotent Events GetEvents(IntSequence eventUids) throws NotFound; ["project2:rows"] - idempotent DVBSI::Event GetEvent(int serviceId, int eventId) throws NotFound; + idempotent Event GetEvent(int serviceId, int eventId) throws NotFound; ["project2:rows"] - idempotent DVBSI::Events EventsOnNow(); + idempotent Events EventsOnNow(); ["project2:rows"] - idempotent DVBSI::Events EventsInSchedules(); + idempotent Events EventsInSchedules(); ["project2:rows"] - idempotent DVBSI::Events EventsInSchedule(int scheduleId); + idempotent Events EventsInSchedule(int scheduleId); ["project2:rows"] - idempotent DVBSI::Events EventsInRange(Common::DateTime from, Common::DateTime to); + idempotent Events EventsInRange(Common::DateTime from, Common::DateTime to); ["project2:rows"] - idempotent DVBSI::Events EventSearch(optional(1) string keywords, optional(2) int serviceId, optional(3) Common::DateTime from, optional(4) Common::DateTime to); + idempotent Events EventSearch(optional(1) string keywords, optional(2) int serviceId, optional(3) Common::DateTime from, optional(4) Common::DateTime to); }; interface Recorder { diff --git a/p2pvr/lib/containerCreator.h b/p2pvr/lib/containerCreator.h index 9804d9b..289ac9e 100644 --- a/p2pvr/lib/containerCreator.h +++ b/p2pvr/lib/containerCreator.h @@ -19,6 +19,9 @@ class ContainerCreator { auto v = P(new V); container.push_back(v); ObjectRowState

rs; + if (rs.fields.size() != columnCount) { + throw std::runtime_error("Incorrent column count"); + } for (unsigned int c = 0; c < columnCount; c++) { rs.fields[c] = get(c); } diff --git a/p2pvr/lib/dvbsiHelpers/event.cpp b/p2pvr/lib/dvbsiHelpers/event.cpp index ca072df..4bca135 100644 --- a/p2pvr/lib/dvbsiHelpers/event.cpp +++ b/p2pvr/lib/dvbsiHelpers/event.cpp @@ -6,30 +6,30 @@ template<> void CreateColumns(const ColumnCreator & cc) { - cc("serviceId", true); - cc("eventId", true); - cc("title", false); - cc("titleLang", false); - cc("subtitle", false); - cc("description", false); - cc("descriptionLang", false); - cc("videoAspect", false); - cc("videoFrameRate", false); - cc("videoHd", false); - cc("audioChannels", false); - cc("audioLanguage", false); - cc("subtitleLanguage", false); - cc("category", false); - cc("subCategory", false); - cc("userCategory", false); - cc("dvbRating", false); - cc("startTime", false); - cc("stopTime", false); - cc("episode", false); - cc("episodes", false); - cc("year", false); - cc("flags", false); - cc("season", false); + cc("serviceId", true); + cc("eventId", true); + cc("title", false); + cc("titleLang", false); + cc("subtitle", false); + cc("description", false); + cc("descriptionLang", false); + cc("videoAspect", false); + cc("videoFrameRate", false); + cc("videoHd", false); + cc("audioChannels", false); + cc("audioLanguage", false); + cc("subtitleLanguage", false); + cc("category", false); + cc("subCategory", false); + cc("userCategory", false); + cc("dvbRating", false); + cc("startTime", false); + cc("stopTime", false); + cc("episode", false); + cc("episodes", false); + cc("year", false); + cc("flags", false); + cc("season", false); } template<> diff --git a/p2pvr/lib/p2pvrHelpers/schedule.cpp b/p2pvr/lib/p2pvrHelpers/schedule.cpp index f8abc1e..91815e9 100644 --- a/p2pvr/lib/p2pvrHelpers/schedule.cpp +++ b/p2pvr/lib/p2pvrHelpers/schedule.cpp @@ -9,7 +9,7 @@ CreateColumns(const ColumnCreator & cc) { cc("scheduleid", true); cc("serviceid", true); - cc("eventid", false); + cc("eventuid", false); cc("title", false); cc("search", false); cc("priority", false); @@ -24,7 +24,7 @@ BindColumns(RowState & rs, const P2PVR::SchedulePtr & s) { rs.fields[0] << s->ScheduleId; rs.fields[1] << s->ServiceId; - rs.fields[2] << s->EventId; + rs.fields[2] << s->EventUid; rs.fields[3] << s->Title; rs.fields[4] << s->Search; rs.fields[5] << s->Priority; @@ -39,7 +39,7 @@ UnbindColumns(RowState & rs, P2PVR::SchedulePtr const & s) { rs.fields[0] >> s->ScheduleId; rs.fields[1] >> s->ServiceId; - rs.fields[2] >> s->EventId; + rs.fields[2] >> s->EventUid; rs.fields[3] >> s->Title; rs.fields[4] >> s->Search; rs.fields[5] >> s->Priority; -- cgit v1.2.3