Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
@@ -0,0 +1,78 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
# Created by Christian Fröbel, SLSE, 2017-06-19
|
||||
#
|
||||
|
||||
SET(SRCS_static
|
||||
ava_test_server.h
|
||||
ava_test_server.cpp
|
||||
)
|
||||
|
||||
#
|
||||
# Static lib just to hold the AvaTestServer as it is needed for the
|
||||
# stand-alone executable as well as for the unit tests.
|
||||
#
|
||||
NGL_ADD_LIBRARY(WS AAR SV avaTestServer_static STATIC ${SRCS_static})
|
||||
NGL_TARGET_LINK_LIBRARIES(avaTestServer_static
|
||||
PUBLIC
|
||||
Qt5::Core
|
||||
Qt5::Network
|
||||
)
|
||||
|
||||
SET(SRCS
|
||||
ava_test_server_main.cpp
|
||||
)
|
||||
|
||||
NGL_ADD_EXECUTABLE(WS AAR SV NO_TRANSLATION avaTestServer ${SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(avaTestServer
|
||||
avaTestServer_static
|
||||
Qt5::Core
|
||||
)
|
||||
|
||||
IF(BUILD_TESTING)
|
||||
SET(SRCS
|
||||
main.cpp
|
||||
ava_comm_double.h
|
||||
parse_line_test.h
|
||||
parse_line_test.cpp
|
||||
ava_comm_test.h
|
||||
ava_comm_test.cpp
|
||||
ava_control_test.h
|
||||
ava_control_test.cpp
|
||||
av_helper_test.h
|
||||
av_helper_test.cpp
|
||||
asset_assignment_manager_test.h
|
||||
asset_assignment_manager_test.cpp
|
||||
audio_video_handler_impl_test.h
|
||||
audio_video_handler_impl_test.cpp
|
||||
choose_stream_test.h
|
||||
choose_stream_test.cpp
|
||||
avs_command_queue_test.h
|
||||
avs_command_queue_test.cpp
|
||||
ava_timeline_test.h
|
||||
ava_timeline_test.cpp
|
||||
rt_state_test.h
|
||||
rt_state_test.cpp
|
||||
list_response_collector_test.h
|
||||
list_response_collector_test.cpp
|
||||
)
|
||||
|
||||
IF(TARGET svcAvmCommon)
|
||||
ADD_EXECUTABLE(avmTests ${SRCS})
|
||||
TARGET_LINK_LIBRARIES(avmTests
|
||||
Qt5::Core
|
||||
Qt5::Network
|
||||
Qt5::Test
|
||||
svcAvmCommon
|
||||
svcIsmCommon
|
||||
avaTestServer_static
|
||||
nglcoreapplication
|
||||
NGLLogger
|
||||
Boost::boost
|
||||
)
|
||||
ADD_TEST(NAME avmTests COMMAND $<TARGET_FILE:avmTests>)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
+595
@@ -0,0 +1,595 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AssetAssignmentManager
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-12-01
|
||||
*/
|
||||
|
||||
#include "asset_assignment_manager_test.h"
|
||||
#include <AudioVideoManagement/asset_assignment_manager.h>
|
||||
#include <AudioVideoManagement/exercise.h>
|
||||
#include <AudioVideoManagement/asset.h>
|
||||
#include <AudioVideoManagement/mounting_point.h>
|
||||
#include <InfrastructureManagement/ism.hpp>
|
||||
#include <LtsUtilsCore/data_modification_enum.h>
|
||||
#include <QString>
|
||||
#include <QSignalSpy>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <random>
|
||||
|
||||
using namespace AudioVideoManagement;
|
||||
using namespace InfrastructureManagement;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
const int EXERCISE_42 = 42;
|
||||
const int EXERCISE_35 = 35;
|
||||
|
||||
MainStructureElement createBuilding()
|
||||
{
|
||||
static int mseId = 0;
|
||||
static int seId = 0;
|
||||
MainStructureElement building;
|
||||
building.id(++mseId);
|
||||
building.name("Building");
|
||||
building.structureElementId(++seId);
|
||||
building.properties("{}");
|
||||
|
||||
StructureElement mountingPoint;
|
||||
mountingPoint.id(++seId);
|
||||
mountingPoint.name("MP_OUT0001");
|
||||
mountingPoint.displayName("Outdoor Camera 1");
|
||||
mountingPoint.mainStructureElementId(building.id());
|
||||
mountingPoint.structureElementTypeId(StructureElementType::MountingPoint);
|
||||
mountingPoint.mountingPointTypeId(MountingPointType::OutdoorCamera);
|
||||
mountingPoint.properties("{}");
|
||||
building.elements().push_back(mountingPoint);
|
||||
|
||||
return building;
|
||||
}
|
||||
|
||||
InstrumentationAsset createAsset()
|
||||
{
|
||||
static int id = 0;
|
||||
|
||||
InstrumentationAsset asset;
|
||||
asset.id(++id);
|
||||
asset.name(QStringLiteral("CAM_UBEOCE000%1").arg(id).toUtf8().constData());
|
||||
asset.mountingPointTypeId(MountingPointType::OutdoorCamera);
|
||||
|
||||
return asset;
|
||||
}
|
||||
|
||||
MountingPointAsset createMount(InstrumentationAsset &asset, const StructureElement &mountingPoint)
|
||||
{
|
||||
static int id = 0;
|
||||
MountingPointAsset mount;
|
||||
mount.id(++id);
|
||||
mount.assetId(asset.id());
|
||||
mount.structureElementId(mountingPoint.id());
|
||||
|
||||
asset.assetStateId(InstrumentationAssetState::Mounted);
|
||||
|
||||
return mount;
|
||||
}
|
||||
|
||||
void unmount(InstrumentationAsset &asset)
|
||||
{
|
||||
asset.assetStateId(InstrumentationAssetState::Unmounted);
|
||||
}
|
||||
|
||||
void assign(MainStructureElement &building, int exerciseId)
|
||||
{
|
||||
building.properties(QStringLiteral("{\"available_in_exercise\": [%1]}").arg(exerciseId).toUtf8().constData());
|
||||
}
|
||||
|
||||
void unassign(MainStructureElement &building)
|
||||
{
|
||||
building.properties("{}");
|
||||
}
|
||||
|
||||
void assign(InstrumentationAsset &asset, int exerciseId)
|
||||
{
|
||||
Q_ASSERT(asset.assetStateId() == InstrumentationAssetState::Mounted);
|
||||
std::vector<int> exercises{exerciseId};
|
||||
asset.availableInExercise(exercises);
|
||||
}
|
||||
|
||||
void unassign(InstrumentationAsset &asset)
|
||||
{
|
||||
Q_ASSERT(asset.assetStateId() == InstrumentationAssetState::Mounted);
|
||||
asset.availableInExercise().clear();
|
||||
}
|
||||
|
||||
class AssignmentSpy : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AssignmentSpy(Exercise *exercise)
|
||||
{
|
||||
connect(exercise, &Exercise::assetAssigned, this, &AssignmentSpy::assetAssigned);
|
||||
connect(exercise, &Exercise::assetUnassigned, this, &AssignmentSpy::assetUnassigned);
|
||||
}
|
||||
|
||||
bool isEmpty() const { return assignedAssets.empty() && unassignedAssets.empty(); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
assignedAssets.clear();
|
||||
unassignedAssets.clear();
|
||||
}
|
||||
|
||||
std::vector<InstrumentationAsset> assignedAssets;
|
||||
std::vector<InstrumentationAsset> unassignedAssets;
|
||||
|
||||
private slots:
|
||||
void assetAssigned(Asset *asset)
|
||||
{
|
||||
assignedAssets.push_back(asset->data());
|
||||
}
|
||||
|
||||
void assetUnassigned(Asset *asset)
|
||||
{
|
||||
unassignedAssets.push_back(asset->data());
|
||||
}
|
||||
};
|
||||
|
||||
template<class Container>
|
||||
void shuffle(Container &c)
|
||||
{
|
||||
static std::random_device randomDevice;
|
||||
static std::default_random_engine randomEngine(randomDevice());
|
||||
|
||||
std::shuffle(c.begin(), c.end(), randomEngine);
|
||||
}
|
||||
|
||||
using Notifications = std::vector<std::function<void()>>;
|
||||
|
||||
void fireRandomly(Notifications ¬ifications)
|
||||
{
|
||||
shuffle(notifications);
|
||||
std::for_each(notifications.begin(), notifications.end(), [] (const std::function<void()> &f) { f(); });
|
||||
notifications.clear();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
/**
|
||||
* Scenario where the application starts with the Asset unmounted and unassigned.
|
||||
*/
|
||||
void AssetAssignmentManagerTest::testStartUnmountedUnassigned()
|
||||
{
|
||||
AssetAssignmentManager mgr;
|
||||
Exercise *exercise = mgr.exercise(EXERCISE_42);
|
||||
AssignmentSpy spy(exercise);
|
||||
Notifications notifications;
|
||||
|
||||
MainStructureElement building = createBuilding();
|
||||
InstrumentationAsset asset1 = createAsset();
|
||||
InstrumentationAsset asset2 = createAsset();
|
||||
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMainStructureElementChanged, &mgr, building, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset2, DataModification::eAdded));
|
||||
fireRandomly(notifications);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Scenario where the application starts with the Asset mounted and assigned.
|
||||
*/
|
||||
void AssetAssignmentManagerTest::testStartMountedAssigned()
|
||||
{
|
||||
AssetAssignmentManager mgr;
|
||||
Exercise *exercise = mgr.exercise(EXERCISE_42);
|
||||
AssignmentSpy spy(exercise);
|
||||
Notifications notifications;
|
||||
|
||||
MainStructureElement building = createBuilding();
|
||||
InstrumentationAsset asset1 = createAsset();
|
||||
InstrumentationAsset asset2 = createAsset();
|
||||
MountingPointAsset mount = createMount(asset1, building.elements()[0]);
|
||||
assign(building, EXERCISE_42);
|
||||
assign(asset1, EXERCISE_42);
|
||||
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMainStructureElementChanged, &mgr, building, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset2, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMountingChanged, &mgr, mount, DataModification::eAdded));
|
||||
fireRandomly(notifications);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.assignedAssets.size() == 1);
|
||||
QVERIFY(spy.unassignedAssets.empty());
|
||||
QCOMPARE(spy.assignedAssets[0], asset1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scenario where at runtime the Asset is first mounted, then the Building is assigned.
|
||||
*/
|
||||
void AssetAssignmentManagerTest::testRuntimeMountAssign()
|
||||
{
|
||||
AssetAssignmentManager mgr;
|
||||
Exercise *exercise = mgr.exercise(EXERCISE_42);
|
||||
AssignmentSpy spy(exercise);
|
||||
Notifications notifications;
|
||||
|
||||
// create building unassigned, assets unmounted
|
||||
MainStructureElement building = createBuilding();
|
||||
InstrumentationAsset asset1 = createAsset();
|
||||
InstrumentationAsset asset2 = createAsset();
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMainStructureElementChanged, &mgr, building, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset2, DataModification::eAdded));
|
||||
fireRandomly(notifications);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.isEmpty());
|
||||
|
||||
|
||||
// create the mount, building still unassigned
|
||||
MountingPointAsset mount = createMount(asset1, building.elements()[0]);
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eModified));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMountingChanged, &mgr, mount, DataModification::eAdded));
|
||||
fireRandomly(notifications);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.isEmpty());
|
||||
|
||||
|
||||
// assign the building and the asset as it is mounted
|
||||
assign(building, EXERCISE_42);
|
||||
assign(asset1, EXERCISE_42);
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMainStructureElementChanged, &mgr, building, DataModification::eModified));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eModified));
|
||||
fireRandomly(notifications);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.assignedAssets.size() == 1);
|
||||
QVERIFY(spy.unassignedAssets.empty());
|
||||
QCOMPARE(spy.assignedAssets[0], asset1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scenario where at runtime the Building is first assigned, then the Asset is mounted.
|
||||
*/
|
||||
void AssetAssignmentManagerTest::testRuntimeAssignMount()
|
||||
{
|
||||
AssetAssignmentManager mgr;
|
||||
Exercise *exercise = mgr.exercise(EXERCISE_42);
|
||||
AssignmentSpy spy(exercise);
|
||||
Notifications notifications;
|
||||
|
||||
// create building unassigned, assets unmounted
|
||||
MainStructureElement building = createBuilding();
|
||||
InstrumentationAsset asset1 = createAsset();
|
||||
InstrumentationAsset asset2 = createAsset();
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMainStructureElementChanged, &mgr, building, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset2, DataModification::eAdded));
|
||||
fireRandomly(notifications);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.isEmpty());
|
||||
|
||||
|
||||
// assign the building, but not yet the asset as it is not mounted
|
||||
assign(building, EXERCISE_42);
|
||||
mgr.onMainStructureElementChanged(building, DataModification::eModified);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.isEmpty());
|
||||
|
||||
|
||||
// mount the asset and assign it as the building is assigned already
|
||||
MountingPointAsset mount = createMount(asset1, building.elements()[0]);
|
||||
assign(asset1, EXERCISE_42);
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMountingChanged, &mgr, mount, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eModified));
|
||||
fireRandomly(notifications);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.assignedAssets.size() == 1);
|
||||
QVERIFY(spy.unassignedAssets.empty());
|
||||
QCOMPARE(spy.assignedAssets[0], asset1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scenario where the Asset is already mounted at startup and then the Building will be assigned at runtime.
|
||||
*/
|
||||
void AssetAssignmentManagerTest::testStartMountedRuntimeAssign()
|
||||
{
|
||||
AssetAssignmentManager mgr;
|
||||
Exercise *exercise = mgr.exercise(EXERCISE_42);
|
||||
AssignmentSpy spy(exercise);
|
||||
Notifications notifications;
|
||||
|
||||
// create building unassigned and asset1 mounted
|
||||
MainStructureElement building = createBuilding();
|
||||
InstrumentationAsset asset1 = createAsset();
|
||||
InstrumentationAsset asset2 = createAsset();
|
||||
MountingPointAsset mount = createMount(asset1, building.elements()[0]);
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMainStructureElementChanged, &mgr, building, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset2, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMountingChanged, &mgr, mount, DataModification::eAdded));
|
||||
fireRandomly(notifications);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.isEmpty());
|
||||
|
||||
|
||||
// assign building and asset1 as it is mounted
|
||||
assign(building, EXERCISE_42);
|
||||
assign(asset1, EXERCISE_42);
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMainStructureElementChanged, &mgr, building, DataModification::eModified));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eModified));
|
||||
fireRandomly(notifications);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.assignedAssets.size() == 1);
|
||||
QVERIFY(spy.unassignedAssets.empty());
|
||||
QCOMPARE(spy.assignedAssets[0], asset1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scenario where the Building is already assigned at startup and the Asset will be mounted at runtime.
|
||||
*/
|
||||
void AssetAssignmentManagerTest::testStartAssignedRuntimeMount()
|
||||
{
|
||||
AssetAssignmentManager mgr;
|
||||
Exercise *exercise = mgr.exercise(EXERCISE_42);
|
||||
AssignmentSpy spy(exercise);
|
||||
Notifications notifications;
|
||||
|
||||
// create building assigned, assets unmounted
|
||||
MainStructureElement building = createBuilding();
|
||||
assign(building, EXERCISE_42);
|
||||
InstrumentationAsset asset1 = createAsset();
|
||||
InstrumentationAsset asset2 = createAsset();
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMainStructureElementChanged, &mgr, building, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset2, DataModification::eAdded));
|
||||
fireRandomly(notifications);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.isEmpty());
|
||||
|
||||
|
||||
// mount asset1 and assign it as the building is assigned already
|
||||
MountingPointAsset mount = createMount(asset1, building.elements()[0]);
|
||||
assign(asset1, EXERCISE_42);
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eModified));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMountingChanged, &mgr, mount, DataModification::eAdded));
|
||||
fireRandomly(notifications);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.assignedAssets.size() == 1);
|
||||
QVERIFY(spy.unassignedAssets.empty());
|
||||
QCOMPARE(spy.assignedAssets[0], asset1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scenario where the Asset is first umounted at runtime, then the Building is unassigned.
|
||||
*/
|
||||
void AssetAssignmentManagerTest::testRuntimeUnmountUnassign()
|
||||
{
|
||||
AssetAssignmentManager mgr;
|
||||
Exercise *exercise = mgr.exercise(EXERCISE_42);
|
||||
AssignmentSpy spy(exercise);
|
||||
Notifications notifications;
|
||||
|
||||
MainStructureElement building = createBuilding();
|
||||
InstrumentationAsset asset1 = createAsset();
|
||||
InstrumentationAsset asset2 = createAsset();
|
||||
MountingPointAsset mount = createMount(asset1, building.elements()[0]);
|
||||
assign(building, EXERCISE_42);
|
||||
assign(asset1, EXERCISE_42);
|
||||
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMainStructureElementChanged, &mgr, building, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset2, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMountingChanged, &mgr, mount, DataModification::eAdded));
|
||||
fireRandomly(notifications);
|
||||
|
||||
spy.clear();
|
||||
|
||||
|
||||
// unmount asset1 and also unassign it
|
||||
InstrumentationAsset assignedAsset = asset1;
|
||||
unassign(assignedAsset);
|
||||
unmount(assignedAsset);
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMountingChanged, &mgr, mount, DataModification::eRemoved));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, assignedAsset, DataModification::eModified));
|
||||
fireRandomly(notifications);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.assignedAssets.empty());
|
||||
QVERIFY(spy.unassignedAssets.size() == 1);
|
||||
QCOMPARE(spy.unassignedAssets[0], asset1);
|
||||
|
||||
spy.clear();
|
||||
|
||||
|
||||
// unassign the building
|
||||
unassign(building);
|
||||
mgr.onMainStructureElementChanged(building, DataModification::eModified);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Scenario where the Building is first unassigned at runtime, then the Asset is unmounted.
|
||||
*/
|
||||
void AssetAssignmentManagerTest::testRuntimeUnassignUnmount()
|
||||
{
|
||||
AssetAssignmentManager mgr;
|
||||
Exercise *exercise = mgr.exercise(EXERCISE_42);
|
||||
AssignmentSpy spy(exercise);
|
||||
Notifications notifications;
|
||||
|
||||
MainStructureElement building = createBuilding();
|
||||
InstrumentationAsset asset1 = createAsset();
|
||||
InstrumentationAsset asset2 = createAsset();
|
||||
MountingPointAsset mount = createMount(asset1, building.elements()[0]);
|
||||
assign(building, EXERCISE_42);
|
||||
assign(asset1, EXERCISE_42);
|
||||
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMainStructureElementChanged, &mgr, building, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset2, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMountingChanged, &mgr, mount, DataModification::eAdded));
|
||||
fireRandomly(notifications);
|
||||
|
||||
spy.clear();
|
||||
|
||||
|
||||
// unassign the building and also asset1
|
||||
InstrumentationAsset unassignedAsset = asset1;
|
||||
unassign(building);
|
||||
unassign(unassignedAsset);
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMainStructureElementChanged, &mgr, building, DataModification::eModified));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, unassignedAsset, DataModification::eModified));
|
||||
fireRandomly(notifications);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.assignedAssets.empty());
|
||||
QVERIFY(spy.unassignedAssets.size() == 1);
|
||||
QCOMPARE(spy.unassignedAssets[0], asset1);
|
||||
|
||||
spy.clear();
|
||||
|
||||
|
||||
// unmount the asset
|
||||
unmount(asset1);
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eModified));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMountingChanged, &mgr, mount, DataModification::eRemoved));
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Scenario where the MountingPoint (i.e. the Building) will be directly reassigned at runtime
|
||||
* while the Assets stays mounted.
|
||||
*/
|
||||
void AssetAssignmentManagerTest::testRuntimeReassign()
|
||||
{
|
||||
AssetAssignmentManager mgr;
|
||||
Notifications notifications;
|
||||
|
||||
MainStructureElement building = createBuilding();
|
||||
InstrumentationAsset asset1 = createAsset();
|
||||
InstrumentationAsset asset2 = createAsset();
|
||||
MountingPointAsset mount = createMount(asset1, building.elements()[0]);
|
||||
assign(building, EXERCISE_42);
|
||||
assign(asset1, EXERCISE_42);
|
||||
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMainStructureElementChanged, &mgr, building, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset2, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMountingChanged, &mgr, mount, DataModification::eAdded));
|
||||
fireRandomly(notifications);
|
||||
|
||||
|
||||
AssignmentSpy spy42(mgr.exercise(EXERCISE_42));
|
||||
AssignmentSpy spy35(mgr.exercise(EXERCISE_35));
|
||||
|
||||
InstrumentationAsset reassignedAsset = asset1;
|
||||
assign(building, EXERCISE_35);
|
||||
assign(reassignedAsset, EXERCISE_35);
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMainStructureElementChanged, &mgr, building, DataModification::eModified));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, reassignedAsset, DataModification::eModified));
|
||||
fireRandomly(notifications);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy42.assignedAssets.empty());
|
||||
QVERIFY(spy42.unassignedAssets.size() == 1);
|
||||
QCOMPARE(spy42.unassignedAssets[0], asset1);
|
||||
|
||||
QVERIFY(spy35.assignedAssets.size() == 1);
|
||||
QVERIFY(spy35.unassignedAssets.empty());
|
||||
QCOMPARE(spy35.assignedAssets[0], reassignedAsset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scenario that happens during shutdown of the services when an Asset is mounted and anssigned.
|
||||
* All Entities are then simply removed from DDS.
|
||||
*/
|
||||
void AssetAssignmentManagerTest::testShutdownMountedAssigned()
|
||||
{
|
||||
AssetAssignmentManager mgr;
|
||||
Exercise *exercise = mgr.exercise(EXERCISE_42);
|
||||
AssignmentSpy spy(exercise);
|
||||
Notifications notifications;
|
||||
|
||||
MainStructureElement building = createBuilding();
|
||||
InstrumentationAsset asset1 = createAsset();
|
||||
InstrumentationAsset asset2 = createAsset();
|
||||
MountingPointAsset mount = createMount(asset1, building.elements()[0]);
|
||||
assign(building, EXERCISE_42);
|
||||
assign(asset1, EXERCISE_42);
|
||||
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMainStructureElementChanged, &mgr, building, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset2, DataModification::eAdded));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMountingChanged, &mgr, mount, DataModification::eAdded));
|
||||
fireRandomly(notifications);
|
||||
|
||||
spy.clear();
|
||||
|
||||
|
||||
// remove all entities
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMainStructureElementChanged, &mgr, building, DataModification::eRemoved));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset1, DataModification::eRemoved));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onAssetChanged, &mgr, asset2, DataModification::eRemoved));
|
||||
notifications.push_back(std::bind(&AssetAssignmentManager::onMountingChanged, &mgr, mount, DataModification::eRemoved));
|
||||
fireRandomly(notifications);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.assignedAssets.empty());
|
||||
QVERIFY(spy.unassignedAssets.size() == 1);
|
||||
QCOMPARE(spy.unassignedAssets[0], asset1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Special case where an Asset will be added (alreay assigned) *and* modified (still assigned)
|
||||
* before the MountingPointAsset will be published.
|
||||
* In that case there would be two pending assigns.
|
||||
*/
|
||||
void AssetAssignmentManagerTest::testDoublePendingAssign()
|
||||
{
|
||||
AssetAssignmentManager mgr;
|
||||
Exercise *exercise = mgr.exercise(EXERCISE_42);
|
||||
AssignmentSpy spy(exercise);
|
||||
Notifications notifications;
|
||||
|
||||
MainStructureElement building = createBuilding();
|
||||
InstrumentationAsset asset1 = createAsset();
|
||||
InstrumentationAsset asset2 = createAsset();
|
||||
MountingPointAsset mount = createMount(asset1, building.elements()[0]);
|
||||
assign(building, EXERCISE_42);
|
||||
assign(asset1, EXERCISE_42);
|
||||
|
||||
mgr.onMainStructureElementChanged(building, DataModification::eAdded);
|
||||
mgr.onAssetChanged(asset1, DataModification::eAdded);
|
||||
mgr.onAssetChanged(asset2, DataModification::eAdded);
|
||||
mgr.onAssetChanged(asset1, DataModification::eModified);
|
||||
mgr.onMountingChanged(mount, DataModification::eAdded);
|
||||
|
||||
QVERIFY(!mgr.hasPending());
|
||||
QVERIFY(spy.assignedAssets.size() == 1);
|
||||
QVERIFY(spy.unassignedAssets.empty());
|
||||
QCOMPARE(spy.assignedAssets[0], asset1);
|
||||
}
|
||||
|
||||
#include "asset_assignment_manager_test.moc"
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AssetAssignmentManager
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-12-01
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QTest>
|
||||
|
||||
/**
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class AssetAssignmentManagerTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void initTestCase() {}
|
||||
void cleanupTestCase() {}
|
||||
void init() {}
|
||||
void cleanup() {}
|
||||
|
||||
void testStartUnmountedUnassigned();
|
||||
void testStartMountedAssigned();
|
||||
void testRuntimeMountAssign();
|
||||
void testRuntimeAssignMount();
|
||||
void testStartMountedRuntimeAssign();
|
||||
void testStartAssignedRuntimeMount();
|
||||
|
||||
void testRuntimeUnmountUnassign();
|
||||
void testRuntimeUnassignUnmount();
|
||||
|
||||
void testRuntimeReassign();
|
||||
|
||||
void testShutdownMountedAssigned();
|
||||
|
||||
void testDoublePendingAssign();
|
||||
};
|
||||
+602
@@ -0,0 +1,602 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AudioVideoHandlerImplTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLSE, 2018-01-09
|
||||
*/
|
||||
|
||||
#include "audio_video_handler_impl_test.h"
|
||||
#include <AudioVideoManagement/audio_video_handler_impl.h>
|
||||
#include <AudioVideoManagement/asset.h>
|
||||
#include <AudioVideoManagement/mounting_point.h>
|
||||
#include <AudioVideoManagement/exercise.h>
|
||||
#include <AudioVideoManagement/avm.hpp>
|
||||
#include <InfrastructureManagement/ism.hpp>
|
||||
#include <LtsUtilsCore/json_object.h>
|
||||
#include <QtGlobal>
|
||||
#include <boost/optional.hpp>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
|
||||
using namespace AudioVideoManagement;
|
||||
using namespace InfrastructureManagement;
|
||||
using LtsUtils::JsonObject;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
int streamCount(const Streams &streams)
|
||||
{
|
||||
if (streams.second)
|
||||
return 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
class DbMock : public AudioVideoHandlerImpl::IDbProxy
|
||||
{
|
||||
public:
|
||||
const Streams &findStreams(AssetId id) const override
|
||||
{
|
||||
auto found = m_cache.find(id);
|
||||
Q_ASSERT(found != m_cache.end());
|
||||
return found->second;
|
||||
}
|
||||
|
||||
const Streams &findStreams(Asset *asset) override
|
||||
{
|
||||
Q_ASSERT(asset);
|
||||
return findStreams(asset->data().id());
|
||||
}
|
||||
|
||||
bool isEmpty() const { return m_cache.empty(); }
|
||||
|
||||
int deviceCount() const { return m_cache.size(); }
|
||||
|
||||
int streamCount() const
|
||||
{
|
||||
int count = 0;
|
||||
for (const auto &streams: m_cache)
|
||||
count += ::streamCount(streams.second);
|
||||
return count;
|
||||
}
|
||||
|
||||
void insert(Streams &streams) override
|
||||
{
|
||||
streams.first.id = ++m_nextId;
|
||||
if (streams.second)
|
||||
streams.second->id = ++m_nextId;
|
||||
link(streams);
|
||||
auto insertResult = m_cache.insert(std::make_pair(streams.assetId(), streams));
|
||||
Q_ASSERT(insertResult.second);
|
||||
}
|
||||
|
||||
/**
|
||||
* We simply maintain the ids or give a new id to a possibly new entry.
|
||||
*/
|
||||
void update(Streams &newStreams) override
|
||||
{
|
||||
auto found = m_cache.find(newStreams.assetId());
|
||||
Q_ASSERT(found != m_cache.end());
|
||||
const Streams oldStreams = found->second;
|
||||
|
||||
newStreams.first.id = oldStreams.first.id;
|
||||
if (newStreams.second)
|
||||
{
|
||||
if (oldStreams.second)
|
||||
newStreams.second->id = oldStreams.second->id;
|
||||
else
|
||||
newStreams.second->id = ++m_nextId;
|
||||
}
|
||||
|
||||
link(newStreams);
|
||||
found->second = newStreams; // update cache
|
||||
}
|
||||
|
||||
void remove(Asset *asset) override
|
||||
{
|
||||
Q_ASSERT(asset);
|
||||
auto count = m_cache.erase(asset->data().id());
|
||||
Q_ASSERT(count == 1);
|
||||
}
|
||||
|
||||
private:
|
||||
void link(Streams& streams)
|
||||
{
|
||||
if (!streams.second)
|
||||
{
|
||||
streams.first.link = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
streams.first.link = streams.second->id;
|
||||
streams.second->link = streams.first.id;
|
||||
}
|
||||
|
||||
int m_nextId{0};
|
||||
std::map<AssetId, Streams> m_cache;
|
||||
};
|
||||
|
||||
|
||||
class DtsSpy : public AudioVideoHandlerImpl::IDtsProxy
|
||||
{
|
||||
public:
|
||||
void publish(const Stream &stream) override
|
||||
{
|
||||
m_published.push_back(stream);
|
||||
}
|
||||
|
||||
void remove(uint64_t streamId) override
|
||||
{
|
||||
m_removed.push_back(streamId);
|
||||
}
|
||||
|
||||
bool isEmpty() const { return m_published.empty() && m_removed.empty(); }
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_published.clear();
|
||||
m_removed.clear();
|
||||
}
|
||||
|
||||
std::vector<Stream> m_published;
|
||||
std::vector<uint64_t> m_removed;
|
||||
};
|
||||
|
||||
|
||||
Asset *createAsset(int id, MountingPointType mpType, const std::string &properties)
|
||||
{
|
||||
InstrumentationAsset data;
|
||||
data.id(id);
|
||||
data.name(QStringLiteral("ASSET_000%1").arg(id).toUtf8().constData());
|
||||
data.hostname(QStringLiteral("host_000%1").arg(id).toUtf8().constData());
|
||||
data.mountingPointTypeId(mpType);
|
||||
data.properties(properties);
|
||||
|
||||
return new Asset(data);
|
||||
}
|
||||
|
||||
MountingPoint *createMountingPoint(int id, MountingPointType mpType)
|
||||
{
|
||||
StructureElement data;
|
||||
data.id(id);
|
||||
data.name(QStringLiteral("MP_000%1").arg(id).toUtf8().constData());
|
||||
data.displayName(QStringLiteral("display name %1").arg(id).toUtf8().constData());
|
||||
data.structureElementTypeId(StructureElementType::MountingPoint);
|
||||
data.mountingPointTypeId(mpType);
|
||||
data.properties("{}");
|
||||
|
||||
return new MountingPoint(data);
|
||||
}
|
||||
|
||||
void setProperties(Asset *asset, const std::string &newProperties)
|
||||
{
|
||||
Q_ASSERT(asset);
|
||||
InstrumentationAsset data = asset->data();
|
||||
data.properties(newProperties);
|
||||
asset->update(data);
|
||||
}
|
||||
|
||||
void setDisplayName(MountingPoint *mp, const std::string &newDisplayName)
|
||||
{
|
||||
Q_ASSERT(mp);
|
||||
StructureElement data = mp->data();
|
||||
data.displayName(newDisplayName);
|
||||
mp->update(data);
|
||||
}
|
||||
|
||||
void setRecording(MountingPoint *mp, bool on)
|
||||
{
|
||||
Q_ASSERT(mp);
|
||||
StructureElement data = mp->data();
|
||||
if (on)
|
||||
data.properties(R"({"record": true})");
|
||||
else
|
||||
data.properties(R"({"record": false})");
|
||||
mp->update(data);
|
||||
}
|
||||
|
||||
void mount(Asset *asset, MountingPoint *mp)
|
||||
{
|
||||
Q_ASSERT(asset);
|
||||
InstrumentationAsset data = asset->data();
|
||||
data.assetStateId(InstrumentationAssetState::Mounted);
|
||||
asset->update(data);
|
||||
asset->mount(mp);
|
||||
}
|
||||
|
||||
Database::AvmDeviceConfig dcEntry(int64_t id, const std::string &context, const std::string &type, const std::string &name, const std::string &controller, const std::string &definition, int32_t link)
|
||||
{
|
||||
Database::AvmDeviceConfig dc;
|
||||
dc.id = id;
|
||||
dc.context = QString::fromStdString(context);
|
||||
dc.type = QString::fromStdString(type);
|
||||
dc.name = QString::fromStdString(name);
|
||||
dc.controller = QString::fromStdString(controller);
|
||||
dc.definition = QString::fromStdString(definition);
|
||||
dc.link = link;
|
||||
return dc;
|
||||
}
|
||||
|
||||
bool operator==(const Database::AvmDeviceConfig &lhs, const Database::AvmDeviceConfig &rhs)
|
||||
{
|
||||
if (lhs.id != rhs.id)
|
||||
return false;
|
||||
if (lhs.context != rhs.context)
|
||||
return false;
|
||||
if (lhs.type != rhs.type)
|
||||
return false;
|
||||
if (lhs.name != rhs.name)
|
||||
return false;
|
||||
if (lhs.controller != rhs.controller)
|
||||
return false;
|
||||
if (lhs.definition != rhs.definition)
|
||||
return false;
|
||||
if (lhs.link != rhs.link)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
AudioVideoHandlerImplTest::AudioVideoHandlerImplTest() = default;
|
||||
AudioVideoHandlerImplTest::~AudioVideoHandlerImplTest() = default;
|
||||
|
||||
/**
|
||||
* Create Assets and MountingPoints.
|
||||
* They will be mounted already but left in the pool exercise.
|
||||
*/
|
||||
void AudioVideoHandlerImplTest::init()
|
||||
{
|
||||
m_nextAssetId = 0;
|
||||
m_nextMpId = 0;
|
||||
m_pool.reset(new Exercise(ExerciseContext::defaultContext()));
|
||||
m_exercise.reset(new Exercise(ExerciseContext(42)));
|
||||
|
||||
m_indoorCam = createAsset(++m_nextAssetId, MountingPointType::IndoorCamera, R"({"type": "vapix"})");
|
||||
m_outdoorCam = createAsset(++m_nextAssetId, MountingPointType::OutdoorCamera, R"({"type": "vapix"})");
|
||||
m_announcementUnit = createAsset(++m_nextAssetId, MountingPointType::AnnouncementUnit, R"({"type": "vapix"})");
|
||||
|
||||
m_mpIndoor = createMountingPoint(++m_nextMpId, MountingPointType::IndoorCamera);
|
||||
m_mpOutdoor = createMountingPoint(++m_nextMpId, MountingPointType::OutdoorCamera);
|
||||
m_mpAnnouncementUnit = createMountingPoint(++m_nextMpId, MountingPointType::AnnouncementUnit);
|
||||
|
||||
mount(m_indoorCam, m_mpIndoor);
|
||||
mount(m_outdoorCam, m_mpOutdoor);
|
||||
mount(m_announcementUnit, m_mpAnnouncementUnit);
|
||||
|
||||
m_pool->add(std::unique_ptr<Asset>(m_indoorCam));
|
||||
m_pool->add(std::unique_ptr<Asset>(m_outdoorCam));
|
||||
m_pool->add(std::unique_ptr<Asset>(m_announcementUnit));
|
||||
m_pool->add(std::unique_ptr<MountingPoint>(m_mpIndoor));
|
||||
m_pool->add(std::unique_ptr<MountingPoint>(m_mpOutdoor));
|
||||
m_pool->add(std::unique_ptr<MountingPoint>(m_mpAnnouncementUnit));
|
||||
}
|
||||
|
||||
void AudioVideoHandlerImplTest::cleanup()
|
||||
{
|
||||
m_pool.reset();
|
||||
m_exercise.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a camera to an Exercise that neither has microphone nor speaker.
|
||||
*/
|
||||
void AudioVideoHandlerImplTest::testAssignCameraVideo()
|
||||
{
|
||||
DbMock dbMock;
|
||||
DtsSpy dtsSpy;
|
||||
AudioVideoHandlerImpl handler(m_exercise.get(), &dbMock, &dtsSpy);
|
||||
handler.onContextActivated();
|
||||
QVERIFY(dbMock.isEmpty());
|
||||
QVERIFY(dtsSpy.isEmpty());
|
||||
|
||||
m_pool->moveMountedTo(m_indoorCam, m_exercise.get(), boost::none);
|
||||
QCOMPARE(dbMock.deviceCount(), 1);
|
||||
QCOMPARE(dbMock.streamCount(), 1);
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_published.size()), 1);
|
||||
QVERIFY(dtsSpy.m_removed.empty());
|
||||
|
||||
// verify DB
|
||||
const Streams &streams = dbMock.findStreams(m_indoorCam->data().id());
|
||||
QVERIFY(!streams.second);
|
||||
QVERIFY(streams.first == dcEntry(1, "ex_42", "AXIS_VIDEO_CHANNEL", "av_0001", "EXCAVS01", "url=rtsp://root:root@host_0001:554;mode=1;", 0));
|
||||
|
||||
// verify DDS
|
||||
QCOMPARE(dtsSpy.m_published[0], Stream(1, "av_0001", StreamType::Video, m_mpIndoor->data().id()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a Camera to an Exercise that has a microphone.
|
||||
*/
|
||||
void AudioVideoHandlerImplTest::testAssignCameraVideoAudioIn()
|
||||
{
|
||||
testAssignCameraVideoAudio(R"({"type": "vapix", "hasMicrophone": true})", StreamType::AudioIn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a Camera to an Exercise that has a speaker.
|
||||
*/
|
||||
void AudioVideoHandlerImplTest::testAssignCameraVideoAudioOut()
|
||||
{
|
||||
testAssignCameraVideoAudio(R"({"type": "vapix", "hasSpeaker": true})", StreamType::AudioOut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a Camera to an Exercise that has both, microphone and speaker.
|
||||
*/
|
||||
void AudioVideoHandlerImplTest::testAssignCameraVideoAudioInOut()
|
||||
{
|
||||
testAssignCameraVideoAudio(R"({"type": "vapix", "hasMicrophone": true, "hasSpeaker": true})", StreamType::AudioInOut);
|
||||
}
|
||||
|
||||
void AudioVideoHandlerImplTest::testAssignCameraVideoAudio(const std::string &camProperties, StreamType expectedStreamType)
|
||||
{
|
||||
DbMock dbMock;
|
||||
DtsSpy dtsSpy;
|
||||
AudioVideoHandlerImpl handler(m_exercise.get(), &dbMock, &dtsSpy);
|
||||
|
||||
// Change the Asset's properties before activating the context.
|
||||
setProperties(m_outdoorCam, camProperties);
|
||||
handler.onContextActivated();
|
||||
|
||||
m_pool->moveMountedTo(m_outdoorCam, m_exercise.get(), boost::none);
|
||||
QCOMPARE(dbMock.deviceCount(), 1);
|
||||
QCOMPARE(dbMock.streamCount(), 2);
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_published.size()), 2);
|
||||
QVERIFY(dtsSpy.m_removed.empty());
|
||||
|
||||
// verfiy DB
|
||||
const Streams &streams = dbMock.findStreams(m_outdoorCam->data().id());
|
||||
QVERIFY(streams.second);
|
||||
QVERIFY(streams.first == dcEntry(1, "ex_42", "AXIS_VIDEO_CHANNEL", "av_0002", "EXCAVS01", "url=rtsp://root:root@host_0002:554;mode=1;", 2));
|
||||
QVERIFY(*streams.second == dcEntry(2, "ex_42", "AXIS_AUDIO_CHANNEL", "av_0002", "EXCAVS01", "url=http://root:root@host_0002:80;mode=1;", 1));
|
||||
|
||||
// verify DDS
|
||||
const Stream &videoStream = dtsSpy.m_published[0];
|
||||
QCOMPARE(videoStream, Stream(1, "av_0002", StreamType::Video, m_mpOutdoor->data().id()));
|
||||
const Stream &audioStream = dtsSpy.m_published[1];
|
||||
QCOMPARE(audioStream, Stream(2, "av_0002", expectedStreamType, m_mpOutdoor->data().id()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign an AnnouncementUnit to an exercise.
|
||||
*/
|
||||
void AudioVideoHandlerImplTest::testAssignAnnouncementUnit()
|
||||
{
|
||||
DbMock dbMock;
|
||||
DtsSpy dtsSpy;
|
||||
AudioVideoHandlerImpl handler(m_exercise.get(), &dbMock, &dtsSpy);
|
||||
handler.onContextActivated();
|
||||
|
||||
m_pool->moveMountedTo(m_announcementUnit, m_exercise.get(), boost::none);
|
||||
QCOMPARE(dbMock.deviceCount(), 1);
|
||||
QCOMPARE(dbMock.streamCount(), 1);
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_published.size()), 1);
|
||||
QVERIFY(dtsSpy.m_removed.empty());
|
||||
|
||||
// verfiy DB
|
||||
const Streams &streams = dbMock.findStreams(m_announcementUnit->data().id());
|
||||
QVERIFY(!streams.second);
|
||||
QVERIFY(streams.first == dcEntry(1, "ex_42", "AXIS_AUDIO_CHANNEL", "av_0003", "EXCAVS01", "url=http://root:root@host_0003:80;codec=aac;mode=1;", 0));
|
||||
|
||||
// verify DDS
|
||||
QCOMPARE(dtsSpy.m_published[0], Stream(1, "av_0003", StreamType::AudioOut, m_mpAnnouncementUnit->data().id()));
|
||||
}
|
||||
|
||||
/**
|
||||
* In this test we assign Assets to the Exercise *before* the Exercise gets activated.
|
||||
*/
|
||||
void AudioVideoHandlerImplTest::testAssignBeforeActivation()
|
||||
{
|
||||
DbMock dbMock;
|
||||
DtsSpy dtsSpy;
|
||||
AudioVideoHandlerImpl handler(m_exercise.get(), &dbMock, &dtsSpy);
|
||||
|
||||
m_pool->moveMountedTo(m_indoorCam, m_exercise.get(), boost::none);
|
||||
m_pool->moveMountedTo(m_outdoorCam, m_exercise.get(), boost::none);
|
||||
m_pool->moveMountedTo(m_announcementUnit, m_exercise.get(), boost::none);
|
||||
|
||||
QVERIFY(dbMock.isEmpty());
|
||||
QVERIFY(dtsSpy.isEmpty());
|
||||
|
||||
handler.onContextActivated();
|
||||
|
||||
QCOMPARE(dbMock.deviceCount(), 3);
|
||||
QCOMPARE(dbMock.streamCount(), 3);
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_published.size()), 3);
|
||||
}
|
||||
|
||||
void AudioVideoHandlerImplTest::testUnassignCameraVideo()
|
||||
{
|
||||
DbMock dbMock;
|
||||
DtsSpy dtsSpy;
|
||||
AudioVideoHandlerImpl handler(m_exercise.get(), &dbMock, &dtsSpy);
|
||||
|
||||
m_pool->moveMountedTo(m_indoorCam, m_exercise.get(), boost::none);
|
||||
handler.onContextActivated();
|
||||
QCOMPARE(dbMock.deviceCount(), 1);
|
||||
QCOMPARE(dbMock.streamCount(), 1);
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_published.size()), 1);
|
||||
QVERIFY(dtsSpy.m_removed.empty());
|
||||
|
||||
dtsSpy.reset();
|
||||
m_exercise->moveMountedTo(m_indoorCam, m_pool.get(), boost::none);
|
||||
QVERIFY(dbMock.isEmpty());
|
||||
QVERIFY(dtsSpy.m_published.empty());
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_removed.size()), 1);
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_removed[0]), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a Camera while it is assigned.
|
||||
*/
|
||||
void AudioVideoHandlerImplTest::testUpdateRemoveAssignedAsset()
|
||||
{
|
||||
DbMock dbMock;
|
||||
DtsSpy dtsSpy;
|
||||
AudioVideoHandlerImpl handler(m_exercise.get(), &dbMock, &dtsSpy);
|
||||
|
||||
m_pool->moveMountedTo(m_indoorCam, m_exercise.get(), boost::none);
|
||||
handler.onContextActivated();
|
||||
QCOMPARE(dbMock.deviceCount(), 1);
|
||||
QCOMPARE(dbMock.streamCount(), 1);
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_published.size()), 1);
|
||||
QVERIFY(dtsSpy.m_removed.empty());
|
||||
|
||||
|
||||
// add microphone to Camera => one additional audio stream
|
||||
dtsSpy.reset();
|
||||
setProperties(m_indoorCam, R"({"type": "vapix", "hasMicrophone": true})");
|
||||
QCOMPARE(dbMock.deviceCount(), 1);
|
||||
QCOMPARE(dbMock.streamCount(), 2);
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_published.size()), 2); // one updated, one new
|
||||
QVERIFY(dtsSpy.m_removed.empty());
|
||||
|
||||
// verify DB
|
||||
Streams streams = dbMock.findStreams(m_indoorCam->data().id());
|
||||
QVERIFY(streams.second);
|
||||
QVERIFY(streams.first == dcEntry(1, "ex_42", "AXIS_VIDEO_CHANNEL", "av_0001", "EXCAVS01", "url=rtsp://root:root@host_0001:554;mode=1;", 2));
|
||||
QVERIFY(*streams.second == dcEntry(2, "ex_42", "AXIS_AUDIO_CHANNEL", "av_0001", "EXCAVS01", "url=http://root:root@host_0001:80;mode=1;", 1));
|
||||
|
||||
// verify DDS
|
||||
QCOMPARE(dtsSpy.m_published[0], Stream(1, "av_0001", StreamType::Video, m_mpIndoor->data().id()));
|
||||
QCOMPARE(dtsSpy.m_published[1], Stream(2, "av_0001", StreamType::AudioIn, m_mpIndoor->data().id()));
|
||||
|
||||
|
||||
// remove microphone again => removal of audio stream
|
||||
dtsSpy.reset();
|
||||
setProperties(m_indoorCam, R"({"type": "vapix", "hasMicrophone": false})");
|
||||
QCOMPARE(dbMock.deviceCount(), 1);
|
||||
QCOMPARE(dbMock.streamCount(), 1);
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_published.size()), 1); // one updated
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_removed.size()), 1);
|
||||
|
||||
// verify DB
|
||||
streams = dbMock.findStreams(m_indoorCam->data().id());
|
||||
QVERIFY(!streams.second);
|
||||
QVERIFY(streams.first == dcEntry(1, "ex_42", "AXIS_VIDEO_CHANNEL", "av_0001", "EXCAVS01", "url=rtsp://root:root@host_0001:554;mode=1;", 0));
|
||||
|
||||
// verify DDS
|
||||
QCOMPARE(dtsSpy.m_published[0], Stream(1, "av_0001", StreamType::Video, m_mpIndoor->data().id()));
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_removed[0]), 2);
|
||||
|
||||
|
||||
// unassign the Camera
|
||||
dtsSpy.reset();
|
||||
m_exercise->moveMountedTo(m_indoorCam, m_pool.get(), boost::none);
|
||||
QCOMPARE(dbMock.deviceCount(), 0);
|
||||
QVERIFY(dtsSpy.m_published.empty());
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_removed.size()), 1);
|
||||
|
||||
// verify DDS
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_removed[0]), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the MountingPoint of an assigned Asset.
|
||||
*/
|
||||
void AudioVideoHandlerImplTest::testUpdateAssignedMountingPoint()
|
||||
{
|
||||
DbMock dbMock;
|
||||
DtsSpy dtsSpy;
|
||||
AudioVideoHandlerImpl handler(m_exercise.get(), &dbMock, &dtsSpy);
|
||||
|
||||
m_pool->moveMountedTo(m_indoorCam, m_exercise.get(), boost::none);
|
||||
handler.onContextActivated();
|
||||
QCOMPARE(dbMock.deviceCount(), 1);
|
||||
QCOMPARE(dbMock.streamCount(), 1);
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_published.size()), 1);
|
||||
QVERIFY(dtsSpy.m_removed.empty());
|
||||
|
||||
// Change the displayName of the MountingPoint.
|
||||
// We now distinguish between internal stream name and display name.
|
||||
// Updating the displayName property of a MountingPoint does not change the internal stream name.
|
||||
dtsSpy.reset();
|
||||
setDisplayName(m_mpIndoor, "updated display name");
|
||||
QCOMPARE(dbMock.deviceCount(), 1);
|
||||
QCOMPARE(dbMock.streamCount(), 1);
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_published.size()), 1);
|
||||
QVERIFY(dtsSpy.m_removed.empty());
|
||||
|
||||
// verify DB
|
||||
Streams streams = dbMock.findStreams(m_indoorCam->data().id());
|
||||
QVERIFY(!streams.second);
|
||||
QVERIFY(streams.first == dcEntry(1, "ex_42", "AXIS_VIDEO_CHANNEL", "av_0001", "EXCAVS01", "url=rtsp://root:root@host_0001:554;mode=1;", 0));
|
||||
|
||||
// verify DDS
|
||||
QCOMPARE(dtsSpy.m_published[0], Stream(1, "av_0001", StreamType::Video, m_mpIndoor->data().id()));
|
||||
|
||||
|
||||
// set recording-flag on MountingPoint
|
||||
dtsSpy.reset();
|
||||
setRecording(m_mpIndoor, true);
|
||||
QCOMPARE(dbMock.deviceCount(), 1);
|
||||
QCOMPARE(dbMock.streamCount(), 1);
|
||||
QCOMPARE(static_cast<int>(dtsSpy.m_published.size()), 1);
|
||||
QVERIFY(dtsSpy.m_removed.empty());
|
||||
|
||||
// verify DB
|
||||
streams = dbMock.findStreams(m_indoorCam->data().id());
|
||||
QVERIFY(!streams.second);
|
||||
QVERIFY(streams.first == dcEntry(1, "ex_42", "AXIS_VIDEO_CHANNEL", "av_0001", "EXCAVS01", "url=rtsp://root:root@host_0001:554;mode=1;recording=ECRS@EXCAVS01;recordcontrol=prealarm;", 0));
|
||||
|
||||
// verify DDS
|
||||
QCOMPARE(dtsSpy.m_published[0], Stream(1, "av_0001", StreamType::Video, m_mpIndoor->data().id())); // no change here
|
||||
}
|
||||
|
||||
void AudioVideoHandlerImplTest::testDeviceDefinitionCameraVideo()
|
||||
{
|
||||
QCOMPARE(AudioVideoHandlerImpl::deviceDefinitionCameraVideo("host", JsonObject::fromJson(R"({"type": "vapix"})"), JsonObject::fromJson(R"({})")),
|
||||
QStringLiteral("url=rtsp://root:root@host:554;mode=1;"));
|
||||
|
||||
QCOMPARE(AudioVideoHandlerImpl::deviceDefinitionCameraVideo("host", JsonObject::fromJson(R"({"type": "vapix", "username": "user", "password": "1234"})"), JsonObject::fromJson(R"({})")),
|
||||
QStringLiteral("url=rtsp://user:1234@host:554;mode=1;"));
|
||||
|
||||
QCOMPARE(AudioVideoHandlerImpl::deviceDefinitionCameraVideo("host", JsonObject::fromJson(R"({"type": "vapix", "port": 123})"), JsonObject::fromJson(R"({})")),
|
||||
QStringLiteral("url=rtsp://root:root@host:123;mode=1;"));
|
||||
|
||||
QCOMPARE(AudioVideoHandlerImpl::deviceDefinitionCameraVideo("host", JsonObject::fromJson(R"({"type": "vapix"})"), JsonObject::fromJson(R"({"record": true})")),
|
||||
QStringLiteral("url=rtsp://root:root@host:554;mode=1;recording=ECRS@EXCAVS01;recordcontrol=prealarm;"));
|
||||
}
|
||||
|
||||
void AudioVideoHandlerImplTest::testDeviceDefinitionCameraAudio()
|
||||
{
|
||||
QCOMPARE(AudioVideoHandlerImpl::deviceDefinitionCameraAudio("host", JsonObject::fromJson(R"({"type": "vapix"})"), JsonObject::fromJson(R"({})")),
|
||||
QStringLiteral("url=http://root:root@host:80;mode=1;"));
|
||||
|
||||
QCOMPARE(AudioVideoHandlerImpl::deviceDefinitionCameraAudio("host", JsonObject::fromJson(R"({"type": "vapix", "username": "user", "password": "1234"})"), JsonObject::fromJson(R"({})")),
|
||||
QStringLiteral("url=http://user:1234@host:80;mode=1;"));
|
||||
|
||||
QCOMPARE(AudioVideoHandlerImpl::deviceDefinitionCameraAudio("host", JsonObject::fromJson(R"({"type": "vapix", "audioPort": 88})"), JsonObject::fromJson(R"({})")),
|
||||
QStringLiteral("url=http://root:root@host:88;mode=1;"));
|
||||
|
||||
QCOMPARE(AudioVideoHandlerImpl::deviceDefinitionCameraAudio("host", JsonObject::fromJson(R"({"type": "vapix"})"), JsonObject::fromJson(R"({"record": true})")),
|
||||
QStringLiteral("url=http://root:root@host:80;mode=1;recording=ECRS@EXCAVS01;recordcontrol=prealarm;"));
|
||||
}
|
||||
|
||||
void AudioVideoHandlerImplTest::testDeviceDefinitionAnnouncementUnit()
|
||||
{
|
||||
QCOMPARE(AudioVideoHandlerImpl::deviceDefinitionAnnouncementUnit("host", JsonObject::fromJson(R"({"type": "vapix"})"), JsonObject::fromJson(R"({})")),
|
||||
QStringLiteral("url=http://root:root@host:80;codec=aac;mode=1;"));
|
||||
|
||||
QCOMPARE(AudioVideoHandlerImpl::deviceDefinitionAnnouncementUnit("host", JsonObject::fromJson(R"({"type": "vapix", "username": "user", "password": "1234"})"), JsonObject::fromJson(R"({})")),
|
||||
QStringLiteral("url=http://user:1234@host:80;codec=aac;mode=1;"));
|
||||
|
||||
QCOMPARE(AudioVideoHandlerImpl::deviceDefinitionAnnouncementUnit("host", JsonObject::fromJson(R"({"type": "vapix", "audioPort": 88})"), JsonObject::fromJson(R"({})")),
|
||||
QStringLiteral("url=http://root:root@host:88;codec=aac;mode=1;"));
|
||||
|
||||
QCOMPARE(AudioVideoHandlerImpl::deviceDefinitionAnnouncementUnit("host", JsonObject::fromJson(R"({"type": "vapix"})"), JsonObject::fromJson(R"({"record": true})")),
|
||||
QStringLiteral("url=http://root:root@host:80;codec=aac;mode=1;recording=ECRS@EXCAVS01;"));
|
||||
}
|
||||
|
||||
} // namespace AudioVideoManagement
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AudioVideoHandlerImplTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLSE, 2018-01-09
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AudioVideoManagement/avm_enums.hpp>
|
||||
#include <QTest>
|
||||
#include <memory>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class Asset;
|
||||
class MountingPoint;
|
||||
class Exercise;
|
||||
|
||||
/**
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class AudioVideoHandlerImplTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AudioVideoHandlerImplTest();
|
||||
~AudioVideoHandlerImplTest();
|
||||
|
||||
private slots:
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
void testAssignCameraVideo();
|
||||
void testAssignCameraVideoAudioIn();
|
||||
void testAssignCameraVideoAudioOut();
|
||||
void testAssignCameraVideoAudioInOut();
|
||||
void testAssignAnnouncementUnit();
|
||||
|
||||
void testAssignBeforeActivation();
|
||||
|
||||
void testUnassignCameraVideo();
|
||||
|
||||
void testUpdateRemoveAssignedAsset();
|
||||
void testUpdateAssignedMountingPoint();
|
||||
|
||||
void testDeviceDefinitionCameraVideo();
|
||||
void testDeviceDefinitionCameraAudio();
|
||||
void testDeviceDefinitionAnnouncementUnit();
|
||||
|
||||
private:
|
||||
void testAssignCameraVideoAudio(const std::string &camProperties, StreamType expectedStreamType);
|
||||
|
||||
int m_nextAssetId{0};
|
||||
int m_nextMpId{0};
|
||||
std::unique_ptr<Exercise> m_pool;
|
||||
std::unique_ptr<Exercise> m_exercise;
|
||||
Asset *m_indoorCam{nullptr};
|
||||
Asset *m_outdoorCam{nullptr};
|
||||
Asset *m_announcementUnit{nullptr};
|
||||
MountingPoint *m_mpIndoor{nullptr};
|
||||
MountingPoint *m_mpOutdoor{nullptr};
|
||||
MountingPoint *m_mpAnnouncementUnit{nullptr};
|
||||
};
|
||||
|
||||
} // namespace AudioVideoManagement
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* unit tests for av helper functions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-06-23
|
||||
*/
|
||||
|
||||
#include "av_helper_test.h"
|
||||
#include <AudioVideoManagement/av_helper.h>
|
||||
#include <QDateTime>
|
||||
#include <QByteArray>
|
||||
#include <string>
|
||||
|
||||
using namespace AudioVideoManagement;
|
||||
|
||||
void AvHelperTest::testCreateDuration()
|
||||
{
|
||||
AvaDuration duration = createDuration(QByteArray("1494829980.13"));
|
||||
AvaDuration expected{149482998013};
|
||||
QCOMPARE(duration, expected);
|
||||
}
|
||||
|
||||
void AvHelperTest::testCreateDuration_withoutDot()
|
||||
{
|
||||
AvaDuration duration = createDuration(QByteArray("1494829980"));
|
||||
AvaDuration expected{149482998000};
|
||||
QCOMPARE(duration, expected);
|
||||
}
|
||||
|
||||
void AvHelperTest::testDurationToString()
|
||||
{
|
||||
AvaDuration d{149482998013};
|
||||
QString expected = QStringLiteral("1494829980.13");
|
||||
QCOMPARE(toString(d), expected);
|
||||
|
||||
d = AvaDuration{149482998003};
|
||||
expected = QStringLiteral("1494829980.03");
|
||||
QCOMPARE(toString(d), expected);
|
||||
}
|
||||
|
||||
void AvHelperTest::testIsStreamNameValid()
|
||||
{
|
||||
QVERIFY(isStreamNameValid(std::string("G3Krs")));
|
||||
QVERIFY(isStreamNameValid(std::string("SR Ltg Krs")));
|
||||
QVERIFY(isStreamNameValid(std::string("BtlFüKrs")));
|
||||
QVERIFY(isStreamNameValid(std::string("GebVersBtl8")));
|
||||
QVERIFY(isStreamNameValid(std::string("2.231")));
|
||||
|
||||
QVERIFY(!isStreamNameValid(std::string(" G3Krs")));
|
||||
QVERIFY(!isStreamNameValid(std::string("G3Krs ")));
|
||||
QVERIFY(!isStreamNameValid(std::string("tvc/01")));
|
||||
QVERIFY(!isStreamNameValid(std::string("tvc\\01")));
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* unit tests for av helper functions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-06-23
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QTest>
|
||||
|
||||
/**
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class AvHelperTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void testCreateDuration();
|
||||
void testCreateDuration_withoutDot();
|
||||
void testDurationToString();
|
||||
void testIsStreamNameValid();
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AvaCommDouble
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLE, 2018-12-19
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AudioVideoManagement/iava_comm.h>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
/**
|
||||
* All methods with empty implementation -- we only need the signals.
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class AvaCommDouble : public IAvaComm
|
||||
{
|
||||
public:
|
||||
void forceDisconnect() override {}
|
||||
|
||||
void switchContext(int) override {}
|
||||
void setUserProfile(const QString &, const QString &, AvaAudioPrio, AvaGuiStyle) override {}
|
||||
void setTimezone(QChar) override {}
|
||||
void setVideoDialogProfile(const QString &, AvaVisibility) override {}
|
||||
void setVideoDialogGeometry(const QString &, const QRect &) override {}
|
||||
void setVideoProfile(const QString &, const QString &) override {}
|
||||
void setAnnouncementProfile(AvaSumChannel, const QString &, const QString &, const QString &) override {}
|
||||
void getStreamList(AvaStreamType, AvaStreamSource) override {}
|
||||
void chooseStream(const QString &, const QString &, bool ) override {}
|
||||
void chooseStreamOverview(const QString &, const QStringList &, bool ) override {}
|
||||
void releaseStream(const QString &, const QString &) override {}
|
||||
void queryTimeline(const QString &, const boost::optional<AvaTimePoint> & = {}, const boost::optional<AvaTimePoint> & = {}) override {}
|
||||
void setVolume(AvaVolume) override {}
|
||||
void chooseImport(const QString &, const QString &, int ) override {}
|
||||
void releaseImport(const QString &) override {}
|
||||
|
||||
void sendPreparedCommand(const QString &) override {}
|
||||
|
||||
void startStream(const QString &, const QString &, AvaSpeed) override {}
|
||||
void stopStream(const QString &, const QString &) override {}
|
||||
void pauseStream(const QString &, const QString &) override {}
|
||||
void setStreamSpeed(const QString &, const QString &, AvaSpeed) override {}
|
||||
void setAbsPosition(const QString &, const QString &, AvaTimePoint) override {}
|
||||
void positionUpdate(const QString &, const QString &, std::chrono::milliseconds) override {}
|
||||
void setPint(const QString &, const QString &, bool ) override {}
|
||||
|
||||
void getElokaList(const QString &) override {}
|
||||
void chooseEloka(const QString &, const QString &, AvaElokaMode) override {}
|
||||
void releaseEloka(const QString &) override {}
|
||||
void queryEloka(AvaQueryElokaMode) override {}
|
||||
|
||||
void setScript(const QString &, const QString &, AvaScriptSource, const QVector<AvaScriptEntry> &) override {}
|
||||
void releaseScript(const QString &, const QString &) override {}
|
||||
void startScript(const QString &, const QString &) override {}
|
||||
void stopScript(const QString &, const QString &) override {}
|
||||
void pauseScript(const QString &, const QString &) override {}
|
||||
void setAbsPositionScript(const QString &, const QString &, AvaTimePoint) override {}
|
||||
|
||||
void defineStreamNameMapping(const QString &, const QString &) override {}
|
||||
void resetStreamNameMapping() override {}
|
||||
|
||||
void keepAlive() override {}
|
||||
};
|
||||
|
||||
} // namespace AudioVideoManagement
|
||||
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AvaCommTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-06-20
|
||||
*/
|
||||
|
||||
#include "ava_comm_test.h"
|
||||
#include "ava_test_server.h"
|
||||
#include <AudioVideoManagement/ava_comm.h>
|
||||
#include <AudioVideoManagement/ava_types.h>
|
||||
#include <AudioVideoManagement/avs_dialog.h>
|
||||
#include <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
#include <QList>
|
||||
#include <QVector>
|
||||
#include <QByteArray>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
using namespace AudioVideoManagement;
|
||||
|
||||
class AvaCommTest::SignalSpy : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SignalSpy(AvaComm *signalSource)
|
||||
{
|
||||
Q_ASSERT(signalSource);
|
||||
connect(signalSource, &AvaComm::ok, this, &SignalSpy::onOk);
|
||||
connect(signalSource, &AvaComm::connected, this, &SignalSpy::onConnected);
|
||||
|
||||
connect(signalSource, &AvaComm::streamListBeginReceived, this, &SignalSpy::onStreamListBeginReceived);
|
||||
connect(signalSource, &AvaComm::timelineListBeginReceived, this, &SignalSpy::onTimelineListBeginReceived);
|
||||
connect(signalSource, &AvaComm::elokaListBeginReceived, this, &SignalSpy::onElokaListBeginReceived);
|
||||
connect(signalSource, &AvaComm::listValueReceived, this, &SignalSpy::onListValueReceived);
|
||||
connect(signalSource, &AvaComm::endOfListReceived, this, &SignalSpy::onEndOfListReceived);
|
||||
|
||||
connect(signalSource, &AvaComm::streamStateReceived, this, &SignalSpy::onStreamStateReceived);
|
||||
connect(signalSource, &AvaComm::streamInfoReceived, this, &SignalSpy::onStreamInfoReceived);
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_connected = false;
|
||||
m_ok = false;
|
||||
m_streamListBegin = false;
|
||||
m_timelineListBegin = false;
|
||||
m_elokaListBegin = false;
|
||||
m_endOfList = false;
|
||||
m_listValues.clear();
|
||||
m_streamState.reset();
|
||||
m_streamInfo.reset();
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onConnected() { m_connected = true; }
|
||||
void onOk() { m_ok = true; }
|
||||
void onStreamListBeginReceived() { m_streamListBegin = true; }
|
||||
void onTimelineListBeginReceived() { m_timelineListBegin = true; }
|
||||
void onElokaListBeginReceived() { m_elokaListBegin = true; }
|
||||
void onListValueReceived(const QVector<QByteArray> &parts) { m_listValues.append(parts); }
|
||||
void onEndOfListReceived() { m_endOfList = true; }
|
||||
|
||||
void onStreamStateReceived(const QString &dialogId, const QString &streamName, AvaStreamState streamState) { Q_UNUSED(dialogId); Q_UNUSED(streamName); m_streamState = streamState; }
|
||||
void onStreamInfoReceived(const QString &dialogId, const QString &streamName, const AvaStreamInfo &streamInfo) { Q_UNUSED(dialogId); Q_UNUSED(streamName); m_streamInfo = streamInfo; }
|
||||
|
||||
public:
|
||||
bool m_connected{false};
|
||||
bool m_ok{false};
|
||||
bool m_streamListBegin{false};
|
||||
bool m_timelineListBegin{false};
|
||||
bool m_elokaListBegin{false};
|
||||
bool m_endOfList{false};
|
||||
QVector<QVector<QByteArray>> m_listValues;
|
||||
boost::optional<AvaStreamState> m_streamState;
|
||||
boost::optional<AvaStreamInfo> m_streamInfo;
|
||||
};
|
||||
|
||||
AvaCommTest::AvaCommTest() = default;
|
||||
AvaCommTest::~AvaCommTest() = default;
|
||||
|
||||
void AvaCommTest::initTestCase()
|
||||
{
|
||||
m_fakeAvaServer.reset(new AvaTestServer);
|
||||
}
|
||||
|
||||
void AvaCommTest::cleanupTestCase()
|
||||
{
|
||||
m_fakeAvaServer.reset();
|
||||
}
|
||||
|
||||
void AvaCommTest::init()
|
||||
{
|
||||
m_avaComm.reset(new AvaComm(QStringLiteral("localhost"), 6370));
|
||||
m_spy.reset(new SignalSpy(m_avaComm.get()));
|
||||
m_avaComm->start();
|
||||
}
|
||||
|
||||
void AvaCommTest::cleanup()
|
||||
{
|
||||
m_spy.reset();
|
||||
m_avaComm.reset();
|
||||
}
|
||||
|
||||
void AvaCommTest::testSwitchContext()
|
||||
{
|
||||
const int EXERCISE = 42;
|
||||
|
||||
QTRY_VERIFY(m_spy->m_connected);
|
||||
|
||||
m_avaComm->switchContext(EXERCISE);
|
||||
QTRY_VERIFY(m_spy->m_ok);
|
||||
}
|
||||
|
||||
void AvaCommTest::testSetUserProfile()
|
||||
{
|
||||
QTRY_VERIFY(m_spy->m_connected);
|
||||
|
||||
m_avaComm->setUserProfile(QStringLiteral("ctc"), QStringLiteral("en_US"), AvaAudioPrio(1), AvaGuiStyle::Light);
|
||||
QTRY_VERIFY(m_spy->m_ok);
|
||||
}
|
||||
|
||||
void AvaCommTest::testSetVideoDialogProfile()
|
||||
{
|
||||
// The real server needs a user profile before setVideoDialogProfile can be issued.
|
||||
testSetUserProfile();
|
||||
|
||||
m_spy->reset();
|
||||
m_avaComm->setVideoDialogProfile(AvsDialog::VIDEO_1, AvaVisibility::Hidden);
|
||||
QTRY_VERIFY(m_spy->m_ok);
|
||||
}
|
||||
|
||||
void AvaCommTest::testGetStreamList()
|
||||
{
|
||||
// The real server needs a context before getStreamList actually returns some streams.
|
||||
testSwitchContext();
|
||||
|
||||
m_spy->reset();
|
||||
m_avaComm->getStreamList(AvaStreamType::Video, AvaStreamSource::Server);
|
||||
QTRY_VERIFY(m_spy->m_endOfList);
|
||||
|
||||
QVERIFY(m_spy->m_streamListBegin);
|
||||
QCOMPARE(m_spy->m_listValues.size(), 5);
|
||||
|
||||
// sample check
|
||||
const QVector<QByteArray> expected = {"2", "2", u8"Videöäü 50-5(S)"};
|
||||
QCOMPARE(m_spy->m_listValues.at(1), expected);
|
||||
}
|
||||
|
||||
void AvaCommTest::testChooseStream()
|
||||
{
|
||||
// The real server needs a context and a user profile before chooseStream can be issued.
|
||||
login();
|
||||
m_spy->reset();
|
||||
|
||||
const bool notMuted = false;
|
||||
m_avaComm->chooseStream(AvsDialog::VIDEO_1, QStringLiteral("Video 52-1(S)"), notMuted);
|
||||
QTRY_VERIFY(m_spy->m_ok);
|
||||
QTRY_VERIFY(m_spy->m_streamState && *m_spy->m_streamState == AvaStreamState::Stop);
|
||||
|
||||
QTRY_VERIFY(m_spy->m_streamInfo);
|
||||
const AvaStreamInfo& actual = *m_spy->m_streamInfo;
|
||||
QCOMPARE(actual.start, AvaTimePoint(AvaDuration{125551541486}));
|
||||
QCOMPARE(actual.end, AvaTimePoint(AvaDuration{125563407789}));
|
||||
QCOMPARE(actual.duration, AvaDuration{11866303});
|
||||
}
|
||||
|
||||
void AvaCommTest::testQueryTimeline()
|
||||
{
|
||||
// The real server needs a context and a user profile before queryTimeline can be issued.
|
||||
login();
|
||||
m_spy->reset();
|
||||
|
||||
m_avaComm->queryTimeline(QStringLiteral("Video 52-1(S)"));
|
||||
QTRY_VERIFY(m_spy->m_ok);
|
||||
QTRY_VERIFY(m_spy->m_endOfList);
|
||||
QVERIFY(m_spy->m_timelineListBegin);
|
||||
QCOMPARE(m_spy->m_listValues.size(), 2);
|
||||
|
||||
QVector<QVector<QByteArray>> expected = {{"1499415421.77-1499416659.03"}, {"1499417373.77-1499417842.06"}};
|
||||
QCOMPARE(m_spy->m_listValues, expected);
|
||||
}
|
||||
|
||||
void AvaCommTest::testGetElokaList()
|
||||
{
|
||||
// The real server needs a context before getStreamList actually returns some streams.
|
||||
testSwitchContext();
|
||||
m_spy->reset();
|
||||
|
||||
m_avaComm->getElokaList(QStringLiteral("TrSpFuKr12"));
|
||||
QTRY_VERIFY(m_spy->m_ok);
|
||||
QTRY_VERIFY(m_spy->m_endOfList);
|
||||
QVERIFY(m_spy->m_elokaListBegin);
|
||||
QCOMPARE(m_spy->m_listValues.size(), 2);
|
||||
|
||||
QVector<QVector<QByteArray>> expected = {{"ELOKA 1"}, {"Eloka 2"}};
|
||||
QCOMPARE(m_spy->m_listValues, expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Login with context and user profile.
|
||||
*/
|
||||
void AvaCommTest::login()
|
||||
{
|
||||
const int EXERCISE = 42;
|
||||
|
||||
QTRY_VERIFY(m_spy->m_connected);
|
||||
m_avaComm->switchContext(EXERCISE);
|
||||
QTRY_VERIFY(m_spy->m_ok);
|
||||
|
||||
m_spy->reset();
|
||||
m_avaComm->setUserProfile(QStringLiteral("ctc"), QStringLiteral("en_US"), AvaAudioPrio(1), AvaGuiStyle::Light);
|
||||
QTRY_VERIFY(m_spy->m_ok);
|
||||
}
|
||||
|
||||
#include "ava_comm_test.moc"
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AvaComm
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-06-20
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QTest>
|
||||
#include <memory>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class AvaComm;
|
||||
class AvaTestServer;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class AvaCommTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AvaCommTest();
|
||||
~AvaCommTest();
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
void testSwitchContext();
|
||||
void testSetUserProfile();
|
||||
void testSetVideoDialogProfile();
|
||||
void testGetStreamList();
|
||||
void testChooseStream();
|
||||
void testQueryTimeline();
|
||||
void testGetElokaList();
|
||||
|
||||
private:
|
||||
void login();
|
||||
|
||||
class SignalSpy;
|
||||
|
||||
std::unique_ptr<AudioVideoManagement::AvaTestServer> m_fakeAvaServer;
|
||||
std::unique_ptr<AudioVideoManagement::AvaComm> m_avaComm;
|
||||
std::unique_ptr<SignalSpy> m_spy;
|
||||
};
|
||||
@@ -0,0 +1,264 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AvaControl
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-06-29
|
||||
*/
|
||||
|
||||
#include "ava_control_test.h"
|
||||
#include "ava_test_server.h"
|
||||
#include <AudioVideoManagement/ava_types.h>
|
||||
#include <AudioVideoManagement/ava_comm.h>
|
||||
#include <AudioVideoManagement/ava_control.h>
|
||||
#include <AudioVideoManagement/stream_name_mapping.h>
|
||||
#include <AudioVideoManagement/avs_dialog.h>
|
||||
#include <AudioVideoManagement/list_response_collector.h>
|
||||
#include <QVector>
|
||||
#include <QtGlobal>
|
||||
#include <QDateTime>
|
||||
#include <QSignalSpy>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
using namespace AudioVideoManagement;
|
||||
|
||||
AvaControlTest::AvaControlTest() = default;
|
||||
AvaControlTest::~AvaControlTest() = default;
|
||||
|
||||
class AvaControlTest::SignalSpy : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SignalSpy(AvaControl *signalSource)
|
||||
{
|
||||
Q_ASSERT(signalSource);
|
||||
connect(signalSource->comm(), &IAvaComm::connected, this, &SignalSpy::onConnected);
|
||||
connect(signalSource, &AvaControl::chooseStreamResponse, this, &SignalSpy::onChooseStreamResponse);
|
||||
connect(signalSource, &AvaControl::getStreamListResponse, this, &SignalSpy::onGetStreamListResponse);
|
||||
connect(signalSource, &AvaControl::queryTimelineResponse, this, &SignalSpy::onQueryTimelineResponse);
|
||||
connect(signalSource, &AvaControl::getElokaListResponse, this, &SignalSpy::onGetElokaListResponse);
|
||||
connect(signalSource, &AvaControl::queryElokaResponse, this, &SignalSpy::onQueryElokaResponse);
|
||||
connect(signalSource, &AvaControl::setScriptResponse, this, &SignalSpy::onSetScriptResponse);
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_connected = false;
|
||||
m_streamInfo.clear();
|
||||
m_streamState.clear();
|
||||
m_streamList.reset();
|
||||
m_timeline.reset();
|
||||
m_elokaList.reset();
|
||||
m_queryElokaResponse.reset();
|
||||
m_scriptInfo.clear();
|
||||
m_scriptState.clear();
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onConnected() { m_connected = true; }
|
||||
void onChooseStreamResponse(const AvaStreamInfo &streamInfo, AvaStreamState streamState)
|
||||
{
|
||||
m_streamInfo.append(streamInfo);
|
||||
m_streamState.append(streamState);
|
||||
}
|
||||
|
||||
void onGetStreamListResponse(const QVector<AvaStream> &streams) { m_streamList = streams; }
|
||||
void onQueryTimelineResponse(const AvaTimeline &timeline) { m_timeline = timeline; }
|
||||
void onGetElokaListResponse(const QVector<QString> &elokaSignals) { m_elokaList = elokaSignals; }
|
||||
void onQueryElokaResponse(const QVector<AvaEloka> &eloka) { m_queryElokaResponse = eloka; }
|
||||
|
||||
void onSetScriptResponse(const AvaStreamInfo &scriptInfo, AvaStreamState scriptState)
|
||||
{
|
||||
m_scriptInfo.append(scriptInfo);
|
||||
m_scriptState.append(scriptState);
|
||||
}
|
||||
|
||||
public:
|
||||
bool m_connected{false};
|
||||
QVector<AvaStreamInfo> m_streamInfo;
|
||||
QVector<AvaStreamState> m_streamState;
|
||||
boost::optional<QVector<AvaStream>> m_streamList;
|
||||
boost::optional<AvaTimeline> m_timeline;
|
||||
boost::optional<QVector<QString>> m_elokaList;
|
||||
boost::optional<QVector<AvaEloka>> m_queryElokaResponse;
|
||||
QVector<AvaStreamInfo> m_scriptInfo;
|
||||
QVector<AvaStreamState> m_scriptState;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
const QString &DIALOG()
|
||||
{
|
||||
return AvsDialog::VIDEO_1;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
void AvaControlTest::initTestCase()
|
||||
{
|
||||
m_fakeAvaServer.reset(new AvaTestServer);
|
||||
}
|
||||
|
||||
void AvaControlTest::cleanupTestCase()
|
||||
{
|
||||
m_fakeAvaServer.reset();
|
||||
}
|
||||
|
||||
void AvaControlTest::init()
|
||||
{
|
||||
m_streamNameMapping.reset(new StreamNameMapping);
|
||||
m_avaComm.reset(new AvaComm(QStringLiteral("localhost"), 6370));
|
||||
m_avaCtrl.reset(new AvaControl(m_avaComm.get(), m_streamNameMapping.get(), std::chrono::seconds(3)));
|
||||
m_spy.reset(new SignalSpy(m_avaCtrl.get()));
|
||||
m_avaComm->start();
|
||||
}
|
||||
|
||||
void AvaControlTest::cleanup()
|
||||
{
|
||||
m_spy.reset();
|
||||
m_avaCtrl.reset();
|
||||
m_avaComm.reset();
|
||||
m_streamNameMapping.reset();
|
||||
}
|
||||
|
||||
void AvaControlTest::testChooseStream()
|
||||
{
|
||||
QTRY_VERIFY(m_spy->m_connected);
|
||||
|
||||
m_avaCtrl->chooseStream(DIALOG(), QStringLiteral("Video 52-1(S)"));
|
||||
QTRY_VERIFY(m_spy->m_streamInfo.size() == 1 && m_spy->m_streamState.size() == 1);
|
||||
QCOMPARE(m_spy->m_streamState.front(), AvaStreamState::Stop);
|
||||
QCOMPARE(m_spy->m_streamInfo.front().start, AvaTimePoint(AvaDuration{125551541486}));
|
||||
QCOMPARE(m_spy->m_streamInfo.front().end, AvaTimePoint(AvaDuration{125563407789}));
|
||||
QCOMPARE(m_spy->m_streamInfo.front().duration, AvaDuration{11866303});
|
||||
}
|
||||
|
||||
/**
|
||||
* A use case where the user quickly changes the selected stream
|
||||
* before the response of the first chooseStream was received.
|
||||
*/
|
||||
void AvaControlTest::testChooseStreamCascade()
|
||||
{
|
||||
QTRY_VERIFY(m_spy->m_connected);
|
||||
|
||||
m_avaCtrl->chooseStream(DIALOG(), QStringLiteral("Video 52-1(S)"));
|
||||
m_avaCtrl->chooseStream(DIALOG(), QStringLiteral("Video 3"));
|
||||
QTRY_VERIFY(m_spy->m_streamInfo.size() == 2 && m_spy->m_streamState.size() == 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test issuing several commands in quick succession.
|
||||
* Such a sequence could be sent during application startup.
|
||||
* AvaControl is responsible for serializing the commands:
|
||||
* the next command must not be sent before the prior command finished.
|
||||
*/
|
||||
void AvaControlTest::testInitialSequence()
|
||||
{
|
||||
QTRY_VERIFY(m_spy->m_connected);
|
||||
|
||||
const int EXERCISE = 42;
|
||||
m_avaCtrl->switchContext(EXERCISE);
|
||||
m_avaCtrl->setUserProfile(QStringLiteral("ctc"), QStringLiteral("en_US"), AvaAudioPrio(1), AvaGuiStyle::Light);
|
||||
m_avaCtrl->getStreamList(AvaStreamType::Video, AvaStreamSource::Server);
|
||||
m_avaCtrl->chooseStream(DIALOG(), QStringLiteral("Video 52-1(S)"));
|
||||
QTRY_VERIFY(m_spy->m_streamInfo.size() == 1 && m_spy->m_streamState.size() == 1);
|
||||
}
|
||||
|
||||
void AvaControlTest::testGetStreamList()
|
||||
{
|
||||
QTRY_VERIFY(m_spy->m_connected);
|
||||
|
||||
m_avaCtrl->getStreamList(AvaStreamType::Video, AvaStreamSource::Server);
|
||||
QTRY_VERIFY(m_spy->m_streamList);
|
||||
|
||||
// sample check
|
||||
const AvaStream &sample = m_spy->m_streamList->at(1);
|
||||
AvaStream expected{AvaStreamType::Video, AvaStreamSource::Server, QStringLiteral("Videöäü 50-5"), QStringLiteral("Videöäü 50-5")};
|
||||
QCOMPARE(sample.type, expected.type);
|
||||
QCOMPARE(sample.source, expected.source);
|
||||
QCOMPARE(sample.internalName, expected.internalName);
|
||||
}
|
||||
|
||||
void AvaControlTest::testQueryTimeline()
|
||||
{
|
||||
QTRY_VERIFY(m_spy->m_connected);
|
||||
|
||||
m_avaCtrl->queryTimeline(QStringLiteral("Video 52-1(S)"));
|
||||
QTRY_VERIFY(m_spy->m_timeline);
|
||||
|
||||
AvaTimeline expected
|
||||
({
|
||||
{ AvaTimePoint(AvaDuration{149941542177}), AvaTimePoint(AvaDuration{149941665903}) },
|
||||
{ AvaTimePoint(AvaDuration{149941737377}), AvaTimePoint(AvaDuration{149941784206}) }
|
||||
});
|
||||
|
||||
QCOMPARE(*m_spy->m_timeline, expected);
|
||||
}
|
||||
|
||||
void AvaControlTest::testGetElokaList()
|
||||
{
|
||||
QTRY_VERIFY(m_spy->m_connected);
|
||||
|
||||
m_avaCtrl->getElokaList(QStringLiteral("TrSpFuKr12"));
|
||||
QTRY_VERIFY(m_spy->m_elokaList);
|
||||
|
||||
QVector<QString> expected = {QStringLiteral("ELOKA 1"), QStringLiteral("Eloka 2")};
|
||||
QCOMPARE(*m_spy->m_elokaList, expected);
|
||||
}
|
||||
|
||||
void AvaControlTest::testQueryEloka()
|
||||
{
|
||||
QTRY_VERIFY(m_spy->m_connected);
|
||||
|
||||
m_avaCtrl->queryEloka(AvaQueryElokaMode::Poll);
|
||||
QTRY_VERIFY(m_spy->m_queryElokaResponse);
|
||||
|
||||
QVector<AvaEloka> expected = { {QStringLiteral("Eloka1"), QStringLiteral("Funk1"), 1, AvaTimePoint(AvaDuration{125551541400})} };
|
||||
QCOMPARE(*m_spy->m_queryElokaResponse, expected);
|
||||
}
|
||||
|
||||
void AvaControlTest::testQueryElokaStop()
|
||||
{
|
||||
QTRY_VERIFY(m_spy->m_connected);
|
||||
|
||||
QSignalSpy commandQueueEmptySpy(m_avaCtrl.get(), &AvaControl::commandQueueEmpty);
|
||||
|
||||
m_avaCtrl->queryEloka(AvaQueryElokaMode::Stop);
|
||||
|
||||
commandQueueEmptySpy.wait();
|
||||
QVERIFY(!m_spy->m_queryElokaResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* When queryEloka is used in Push-Mode, we must handle asynchronous QueryElokaLists.
|
||||
* This is what we simulate here.
|
||||
*/
|
||||
void AvaControlTest::testAsyncQueryElokaList()
|
||||
{
|
||||
QTRY_VERIFY(m_spy->m_connected);
|
||||
|
||||
boost::optional<QVector<AvaEloka>> queryElokaResponse;
|
||||
auto doneCallback = [&queryElokaResponse] (QVector<AvaEloka> &&response) { queryElokaResponse = std::move(response); };
|
||||
QueryElokaListCollector collector(m_avaComm.get(), doneCallback);
|
||||
|
||||
collector.start();
|
||||
// We use Poll here as we want to control how many responses the AvaTestServer sends.
|
||||
// Also, the Push-mode is not implemented in AvaTestServer.
|
||||
m_avaCtrl->queryEloka(AvaQueryElokaMode::Poll);
|
||||
QTRY_VERIFY(queryElokaResponse);
|
||||
|
||||
QVector<AvaEloka> expected = { {QStringLiteral("Eloka1"), QStringLiteral("Funk1"), 1, AvaTimePoint(AvaDuration{125551541400})} };
|
||||
QCOMPARE(*queryElokaResponse, expected);
|
||||
|
||||
queryElokaResponse.reset();
|
||||
collector.start();
|
||||
m_avaCtrl->queryEloka(AvaQueryElokaMode::Poll);
|
||||
QTRY_VERIFY(queryElokaResponse);
|
||||
QCOMPARE(*queryElokaResponse, expected);
|
||||
}
|
||||
|
||||
#include "ava_control_test.moc"
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AvaControl
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-06-29
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QTest>
|
||||
#include <memory>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class AvaComm;
|
||||
class AvaControl;
|
||||
class AvaTestServer;
|
||||
class StreamNameMapping;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class AvaControlTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AvaControlTest();
|
||||
~AvaControlTest();
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
void testChooseStream();
|
||||
void testChooseStreamCascade();
|
||||
void testInitialSequence();
|
||||
void testGetStreamList();
|
||||
void testQueryTimeline();
|
||||
void testGetElokaList();
|
||||
void testQueryEloka();
|
||||
void testQueryElokaStop();
|
||||
void testAsyncQueryElokaList();
|
||||
|
||||
private:
|
||||
class SignalSpy;
|
||||
|
||||
std::unique_ptr<AudioVideoManagement::AvaTestServer> m_fakeAvaServer;
|
||||
std::unique_ptr<AudioVideoManagement::StreamNameMapping> m_streamNameMapping;
|
||||
std::unique_ptr<AudioVideoManagement::AvaComm> m_avaComm;
|
||||
std::unique_ptr<AudioVideoManagement::AvaControl> m_avaCtrl;
|
||||
std::unique_ptr<SignalSpy> m_spy;
|
||||
};
|
||||
+1364
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,609 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AvaTestServer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-06-19
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtNetwork/QTcpServer>
|
||||
#include <QtNetwork/QTcpSocket>
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QDateTime>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
/**
|
||||
* Taken from ZW/ZWPR/ScrEdAV/ScrEdAVStream.{hpp,cpp}
|
||||
*/
|
||||
class ScrEdAVStream
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Get the stream category
|
||||
* @return return the stream category type.
|
||||
*/
|
||||
int getCategory() const;
|
||||
|
||||
/**
|
||||
* Get the stream duration.
|
||||
* @return QDateTime object with the stream duration
|
||||
*/
|
||||
double getDuration() const;
|
||||
|
||||
/**
|
||||
* get the stream end time.
|
||||
* @return QDateTime object with the end time.
|
||||
*/
|
||||
QDateTime getEndTime() const;
|
||||
|
||||
/**
|
||||
* get the stream name.
|
||||
* @return QString with the name of the stream.
|
||||
*/
|
||||
QString getName() const;
|
||||
|
||||
/**
|
||||
* get the stream's play time.
|
||||
* @return QDateTime object with the actual stream play time.
|
||||
*/
|
||||
QDateTime getPlayTime() const;
|
||||
|
||||
/**
|
||||
* get the signal pause handling flag.
|
||||
* @return int with the signla pause handling state.
|
||||
*/
|
||||
int getSignalPauseHandling() const;
|
||||
|
||||
/**
|
||||
* get the stream speed.
|
||||
* @return int with the stream play speed.
|
||||
*/
|
||||
int getSpeed() const;
|
||||
|
||||
/**
|
||||
* get the stream's start time.
|
||||
* @return QDateTime object with the stream start time.
|
||||
*/
|
||||
QDateTime getStartTime() const;
|
||||
|
||||
/**
|
||||
* get the stream play state.
|
||||
* @return in with the stream play state.
|
||||
*/
|
||||
int getState() const;
|
||||
|
||||
/**
|
||||
* get the stream ply mode.
|
||||
* @return int with the stream play mode
|
||||
*/
|
||||
int getStreamPlayMode() const;
|
||||
|
||||
/**
|
||||
* get the stream type.
|
||||
* @return int with the stream type.
|
||||
*/
|
||||
int getType() const;
|
||||
|
||||
/**
|
||||
* denotes the stream mute state.
|
||||
* @return true when the stream is muted, false otherwise.
|
||||
*/
|
||||
bool isMute() const;
|
||||
|
||||
/**
|
||||
* set the stream category, possible values are:
|
||||
* @li 1 ->interface
|
||||
* @li 2 ->server
|
||||
* @li 4->local
|
||||
*
|
||||
* @param newVal
|
||||
*/
|
||||
void setCategory(int newVal);
|
||||
|
||||
/**
|
||||
* set the stream's duration.
|
||||
*
|
||||
* @param newVal
|
||||
*/
|
||||
void setDuration(double newVal);
|
||||
|
||||
/**
|
||||
* set the stream's end time.
|
||||
*
|
||||
* @param newVal
|
||||
*/
|
||||
void setEndTime(const QDateTime &newVal);
|
||||
|
||||
/**
|
||||
* set the Mute state for the stream.
|
||||
*
|
||||
* @param newVal
|
||||
*/
|
||||
void setMute(bool newVal);
|
||||
|
||||
/**
|
||||
* set the stream name
|
||||
*
|
||||
* @param newVal
|
||||
*/
|
||||
void setName(const QString &newVal);
|
||||
|
||||
/**
|
||||
* set the stream's end time.
|
||||
*
|
||||
* @param newVal
|
||||
*/
|
||||
void setPlayTime(const QDateTime &newVal);
|
||||
|
||||
/**
|
||||
* set the signal pause handling flag.
|
||||
*
|
||||
* @param newVal
|
||||
*/
|
||||
void setSignalPauseHandling(int newVal);
|
||||
|
||||
/**
|
||||
* set the stream speed.
|
||||
*
|
||||
* @param newVal
|
||||
*/
|
||||
void setSpeed(int newVal);
|
||||
|
||||
/**
|
||||
* set the stream's start time.
|
||||
*
|
||||
* @param newVal
|
||||
*/
|
||||
void setStartTime(const QDateTime &newVal);
|
||||
|
||||
/**
|
||||
* set the Stream state.
|
||||
*
|
||||
* @param newVal
|
||||
*/
|
||||
void setState(int newVal);
|
||||
|
||||
/**
|
||||
* set the stream play mode.
|
||||
*
|
||||
* @param newVal
|
||||
*/
|
||||
void setStreamPlayMode(int newVal);
|
||||
|
||||
/**
|
||||
* set the stream type, 1 -> Audio, 2 -> Video
|
||||
*
|
||||
* @param newVal
|
||||
*/
|
||||
void setType(int newVal);
|
||||
|
||||
/**
|
||||
* Set the volume factor
|
||||
*/
|
||||
void setVolumeFactor(double factor) { m_VolumeFactor = factor; }
|
||||
|
||||
/**
|
||||
* Return the volume factor
|
||||
*/
|
||||
double getVolumeFactor() const { return m_VolumeFactor; }
|
||||
|
||||
double getVolume() const;
|
||||
void setVolume(double volume);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Contains the stream category, possible values are:
|
||||
* @li 1 - interface
|
||||
* @li 2 - server
|
||||
* @li 4- local
|
||||
*/
|
||||
int m_Category{1};
|
||||
/**
|
||||
* Contains the stream duration.
|
||||
*/
|
||||
double m_Duration{0};
|
||||
/**
|
||||
* Contains the stream end time.
|
||||
*/
|
||||
QDateTime m_EndTime;
|
||||
/**
|
||||
* Contains the Mute state for the stream.
|
||||
*/
|
||||
bool m_Mute{false};
|
||||
/**
|
||||
* Contains the stream name
|
||||
*/
|
||||
QString m_Name;
|
||||
/**
|
||||
* Contains the stream's actual play position time.
|
||||
*/
|
||||
QDateTime m_PlayTime;
|
||||
/**
|
||||
* Contains the signal pause handling flag.
|
||||
*/
|
||||
int m_SignalPauseHandling{1};
|
||||
/**
|
||||
* Contains the stream speed.
|
||||
*/
|
||||
int m_Speed{100};
|
||||
/**
|
||||
* Contains the stream's start time.
|
||||
*/
|
||||
QDateTime m_StartTime;
|
||||
/**
|
||||
* Contains the Stream state.
|
||||
*/
|
||||
int m_State{0};
|
||||
/**
|
||||
* Contains the stream play mode.
|
||||
*/
|
||||
int m_StreamPlayMode{0};
|
||||
/**
|
||||
* Contains the stream type
|
||||
* @li 1 - audio
|
||||
* @li 2 - video
|
||||
*/
|
||||
int m_Type{0};
|
||||
|
||||
/**
|
||||
* The volume factor for this script
|
||||
*/
|
||||
double m_VolumeFactor{50};
|
||||
};
|
||||
|
||||
|
||||
//======================================================================================================================
|
||||
|
||||
|
||||
/**
|
||||
* Taken from ZW/ZWPR/ScrEdAV/ScrEdAVScript.{hpp,cpp}
|
||||
*/
|
||||
class ScrEdAVScript
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Contains the script type. The type is one of the follwoing list:
|
||||
* @li 1 = AUDIO
|
||||
* @li 2 = VIDEO
|
||||
* @li 3 = LOCAL AUDIO
|
||||
* @li 4 = LOCAL VIDEO
|
||||
* @return returns an int with the category type.
|
||||
*/
|
||||
int getCategory() const;
|
||||
|
||||
/**
|
||||
* Gets the filesplitting parameter
|
||||
* @return returns an int with the filesplitting parameter.
|
||||
*/
|
||||
int getFileSplitting() const;
|
||||
|
||||
/**
|
||||
* get the name of the current played stream.
|
||||
* @return returns a QString with the name of the current played stream.
|
||||
*/
|
||||
QString getCurrentPlayedStream() const;
|
||||
|
||||
/**
|
||||
* get the name of export script name.
|
||||
* @return returns a QString with the name of the export script name .
|
||||
*/
|
||||
QString getExportScriptName() const;
|
||||
|
||||
/**
|
||||
* get the name of the export directory.
|
||||
* @return returns a QString of the export directory.
|
||||
*/
|
||||
QString getExportDirectory() const;
|
||||
|
||||
/**
|
||||
* Gets the scripts duration.
|
||||
* @return returns a QDateTime object with the script duration.
|
||||
*/
|
||||
double getDuration() const;
|
||||
|
||||
/**
|
||||
* gets the elapsed time in relation to the script start.
|
||||
* @return returns a QDateTime with the elapsed time in relation to the script
|
||||
* start.
|
||||
*/
|
||||
double getElapsedTime() const;
|
||||
|
||||
/**
|
||||
* get the scripts end time.
|
||||
* @return returns a QDateTime object with the scripts end time.
|
||||
*/
|
||||
QDateTime getEndTime() const;
|
||||
|
||||
/**
|
||||
* gets the script's name.
|
||||
* @return returns a QString with the scripts name.
|
||||
*/
|
||||
QString getName() const;
|
||||
|
||||
/**
|
||||
* gets the scripts start time.
|
||||
* @return returns a QDateTime object with the scripts start time.
|
||||
*/
|
||||
QDateTime getStartTime() const;
|
||||
|
||||
/**
|
||||
* gets the scripts play state. Possible states are:
|
||||
* @li 0 = STOP
|
||||
* @li 1 = START
|
||||
* @li 2 = PAUSE
|
||||
* @li 3 = Datenpfad abgebaut
|
||||
* @li 4 = Datenpfad darf nicht aufgebaut werden
|
||||
* @return returns an int with the scripts play state.
|
||||
*/
|
||||
int getState() const;
|
||||
|
||||
/**
|
||||
* Get the stream sequences.
|
||||
* @return returns a QVector which contains ScrEdAVStream objects.
|
||||
*/
|
||||
QVector<ScrEdAVStream> getStreamSequences() const;
|
||||
|
||||
/**
|
||||
* Denotes if the script is muted or not.
|
||||
* @return true when the script is muted, false otherwise.
|
||||
*/
|
||||
bool isMute() const;
|
||||
|
||||
/**
|
||||
* Contains the script type.
|
||||
*
|
||||
* @param newVal The new value for the script category. possible values are:
|
||||
* @li 1 = AUDIO
|
||||
* @li 2 = VIDEO
|
||||
* @li 3 = LOCAL AUDIO
|
||||
* @li 4 = LOCAL VIDEO
|
||||
*/
|
||||
void setCategory(int newVal);
|
||||
|
||||
/**
|
||||
* Set the name of the current played stream.
|
||||
*
|
||||
* @param newVal The name of the current played stream.
|
||||
*/
|
||||
void setCurrentPlayedStream(const QString &newVal);
|
||||
|
||||
/**
|
||||
* Set the scripts duration.
|
||||
*
|
||||
* @param newVal The new script duration value.
|
||||
*/
|
||||
void setDuration(double newVal);
|
||||
|
||||
/**
|
||||
* Set the elapsed time in relation to the script start.
|
||||
*
|
||||
* @param newVal The new vakue for the elapsed time.
|
||||
*/
|
||||
void setElapsedTime(double newVal);
|
||||
|
||||
/**
|
||||
* Set the scripts end time.
|
||||
*
|
||||
* @param newVal The new value for the end time.
|
||||
*/
|
||||
void setEndTime(const QDateTime &newVal);
|
||||
|
||||
/**
|
||||
* set the script muted or not.
|
||||
*
|
||||
* @param newVal the new value for mute.
|
||||
*/
|
||||
void setMute(bool newVal);
|
||||
|
||||
/**
|
||||
* Set the script's name.
|
||||
*
|
||||
* @param newVal The scripts new name.
|
||||
*/
|
||||
void setName(const QString &newVal);
|
||||
|
||||
/**
|
||||
* Set the scripts start time.
|
||||
*
|
||||
* @param newVal The scripts new start time.
|
||||
*/
|
||||
void setStartTime(const QDateTime &newVal);
|
||||
|
||||
/**
|
||||
* set the scripts play state.
|
||||
*
|
||||
* @param newVal set the new play state: Possible states are:
|
||||
* @li 0 = STOP
|
||||
* @li 1 = START
|
||||
* @li 2 = PAUSE
|
||||
* @li 3 = Datenpfad abgebaut
|
||||
* @li 4 = Datenpfad darf nicht aufgebaut werden
|
||||
*/
|
||||
void setState(int newVal);
|
||||
|
||||
/**
|
||||
* set the scripts play state.
|
||||
*
|
||||
* @param newVal set the new filesplitting value: Possible states are:
|
||||
* @li 0 = Dateisplitting nur bei einem Wechsel des Stream-Typs
|
||||
* @li 1 = Dateisplitting nach jeder Skriptzeile
|
||||
*/
|
||||
void setFileSplitting(int newVal);
|
||||
|
||||
/**
|
||||
* set the stream sequences.
|
||||
*
|
||||
* @param newVal set a QVector with the new stream sequences.
|
||||
*/
|
||||
void setStreamSequences(const QVector<ScrEdAVStream> &newVal);
|
||||
|
||||
/**
|
||||
* set the name of the export script.
|
||||
*
|
||||
* @param newVal name of the export script.
|
||||
*/
|
||||
void setExportScriptName(const QString &newVal);
|
||||
|
||||
|
||||
/**
|
||||
* set the directory for the export script
|
||||
*
|
||||
* @param newVal directory of the export script
|
||||
*/
|
||||
void setExportDirectory(const QString &newVal);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Contains the script type. Possible values are:
|
||||
* @li 1 = AUDIO
|
||||
* @li 2 = VIDEO
|
||||
* @li 3 = LOCAL AUDIO
|
||||
* @li 4 = LOCAL VIDEO
|
||||
*/
|
||||
int m_Category{0};
|
||||
/**
|
||||
* Contains the name of the current played stream.
|
||||
*/
|
||||
QString m_CurrentPlayedStream;
|
||||
/**
|
||||
* Contains the scripts duration.
|
||||
*/
|
||||
double m_Duration{0};
|
||||
/**
|
||||
* Contains the elapsed time in relation to the script start.
|
||||
*/
|
||||
double m_ElapsedTime{0};
|
||||
/**
|
||||
* Contains the scripts end time.
|
||||
*/
|
||||
QDateTime m_EndTime;
|
||||
/**
|
||||
* Denotes if the script is muted or not.
|
||||
*/
|
||||
bool m_Mute{false};
|
||||
/**
|
||||
* Contains the script's name.
|
||||
*/
|
||||
QString m_Name;
|
||||
/**
|
||||
* Contains the scripts start time.
|
||||
*/
|
||||
QDateTime m_StartTime;
|
||||
/**
|
||||
* Contains the play state. Possible states are:
|
||||
* @li 0 = STOP
|
||||
* @li 1 = START
|
||||
* @li 2 = PAUSE
|
||||
* @li 3 = Datenpfad abgebaut
|
||||
* @li 4 = Datenpfad darf nicht aufgebaut werden
|
||||
*/
|
||||
int m_State{0};
|
||||
/**
|
||||
* Contains the file splitting. Possible states are:
|
||||
* @li 0 = Dateisplitting nur bei einem Wechsel des Stream-Typs
|
||||
* @li 1 = Dateisplitting nach jeder Skriptzeile
|
||||
*/
|
||||
int m_FileSplitting{0};
|
||||
/**
|
||||
* Contains the stream sequences.
|
||||
*/
|
||||
QVector<ScrEdAVStream> m_StreamSequences;
|
||||
/**
|
||||
* Contains the export script name.
|
||||
*/
|
||||
QString m_ExportScriptName;
|
||||
/**
|
||||
* Contains the export directory name.
|
||||
*/
|
||||
QString m_ExportDirectory;
|
||||
};
|
||||
|
||||
|
||||
//======================================================================================================================
|
||||
|
||||
|
||||
/**
|
||||
* This class can be used in tests to replace AVS_Workstation.
|
||||
* It mocks the server side of the RCP/AVA protocol.
|
||||
*
|
||||
* Taken and adapted from ZW/ZWPR/ScrEdAV/TestApp/ScrEdAVTestServer.{hpp,cpp}
|
||||
*/
|
||||
class AvaTestServer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AvaTestServer();
|
||||
~AvaTestServer() override;
|
||||
|
||||
private:
|
||||
QTcpServer *m_Server;
|
||||
|
||||
QVector<QTcpSocket *> m_Conns;
|
||||
|
||||
QString m_SignalPause;
|
||||
|
||||
QDateTime m_Position;
|
||||
float m_AbsScriptPos;
|
||||
float m_RelScriptPos;
|
||||
|
||||
QString m_SelectedStream;
|
||||
QString m_SelectedScript;
|
||||
QString m_Outputdevice;
|
||||
|
||||
QTimer *m_PosUpdate;
|
||||
QTimer *m_ScriptPosUpdate;
|
||||
int m_PosUpdateTime;
|
||||
int m_StreamState;
|
||||
int m_ScriptState;
|
||||
int m_StreamSpeed;
|
||||
int m_PendingListReading;
|
||||
|
||||
bool m_ReversPlay;
|
||||
|
||||
bool m_Audiomute;
|
||||
bool m_PlayMode;
|
||||
|
||||
QVector<ScrEdAVStream> m_Scripts;
|
||||
ScrEdAVScript m_Script;
|
||||
ScrEdAVStream m_SelStreamFromScript;
|
||||
int m_StreamNbr;
|
||||
|
||||
|
||||
QString qDateTimeToAVTime(const QDateTime &a_qDateTime);
|
||||
QString floatToAVTime(float a_time);
|
||||
float avTimeToFloat(const QByteArray &a_avTime);
|
||||
QDateTime avTimeToQDateTime(const QString &a_avTime);
|
||||
|
||||
/** Called for every line received on a connection. */
|
||||
void processLine(const QByteArray &line);
|
||||
QList<QByteArray> parse(const QByteArray &a_byteArray, int a_i);
|
||||
void sendData(const QString &data_);
|
||||
|
||||
void replyOk();
|
||||
void replyBadArguments();
|
||||
void replyBadCommand();
|
||||
void replyCommandNotAllowed();
|
||||
|
||||
private slots:
|
||||
|
||||
void connectionIncoming();
|
||||
|
||||
void readAndAnswer();
|
||||
|
||||
void sendPosUpdate();
|
||||
void sendScriptPosUpdate();
|
||||
|
||||
void closedConnection();
|
||||
};
|
||||
|
||||
} // namespace AudioVideoManagement
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Standalone Server for mocking AVA_Workstation (RCP/AVA).
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-06-19
|
||||
*/
|
||||
|
||||
#include "ava_test_server.h"
|
||||
#include <QCoreApplication>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
AudioVideoManagement::AvaTestServer server;
|
||||
return app.exec();
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AvaTimelineTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLSE, 2018-03-28
|
||||
*/
|
||||
|
||||
#include "ava_timeline_test.h"
|
||||
#include <AudioVideoManagement/ava_types.h>
|
||||
#include <initializer_list>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace AudioVideoManagement;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/**
|
||||
* Small helper so that we can easily craeate a AvaTimeline from a list of int-pairs.
|
||||
*/
|
||||
AvaTimeline makeTimeline(std::initializer_list<std::pair<int, int>> v)
|
||||
{
|
||||
AvaTimeline timeline;
|
||||
std::for_each(v.begin(), v.end(), [&timeline] (const std::pair<int, int> &p) { timeline.append({AvaTimePoint(AvaDuration{p.first}), AvaTimePoint(AvaDuration{p.second})}); });
|
||||
return timeline;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
void AvaTimelineTest::testMergeEmpty()
|
||||
{
|
||||
const AvaTimeline timeline1 = makeTimeline({ {1, 2}, {3, 4} });
|
||||
AvaTimeline timeline2 = timeline1;
|
||||
AvaTimeline empty;
|
||||
timeline2.merge(empty);
|
||||
QCOMPARE(timeline2, timeline1);
|
||||
|
||||
empty.merge(timeline1);
|
||||
QCOMPARE(empty, timeline1);
|
||||
}
|
||||
|
||||
void AvaTimelineTest::testMergeSelf()
|
||||
{
|
||||
const AvaTimeline timeline1 = makeTimeline({ {1, 2}, {3, 4} });
|
||||
AvaTimeline timeline2 = timeline1;
|
||||
timeline2.merge(timeline2);
|
||||
QCOMPARE(timeline2, timeline1);
|
||||
}
|
||||
|
||||
void AvaTimelineTest::testMergeDisjunct()
|
||||
{
|
||||
AvaTimeline timeline1 = makeTimeline({ {1, 2} });
|
||||
AvaTimeline timeline2 = makeTimeline({ {3, 4} });
|
||||
|
||||
timeline1.merge(timeline2);
|
||||
AvaTimeline expected = makeTimeline({ {1, 2}, {3, 4}});
|
||||
QCOMPARE(timeline1, expected);
|
||||
}
|
||||
|
||||
void AvaTimelineTest::testMergeWithin()
|
||||
{
|
||||
AvaTimeline timeline1 = makeTimeline({ {1, 4} });
|
||||
AvaTimeline timeline2 = makeTimeline({ {2, 3} });
|
||||
|
||||
timeline1.merge(timeline2);
|
||||
AvaTimeline expected = makeTimeline({ {1, 4} });
|
||||
QCOMPARE(timeline1, expected);
|
||||
}
|
||||
|
||||
void AvaTimelineTest::testMergeOverlap()
|
||||
{
|
||||
AvaTimeline timeline1 = makeTimeline({ {1, 3} });
|
||||
AvaTimeline timeline2 = makeTimeline({ {2, 4} });
|
||||
|
||||
timeline1.merge(timeline2);
|
||||
AvaTimeline expected = makeTimeline({ {1, 4} });
|
||||
QCOMPARE(timeline1, expected);
|
||||
}
|
||||
|
||||
void AvaTimelineTest::testMergeEdgeOverlap()
|
||||
{
|
||||
AvaTimeline timeline1 = makeTimeline({ {1, 2} });
|
||||
AvaTimeline timeline2 = makeTimeline({ {2, 3} });
|
||||
|
||||
timeline1.merge(timeline2);
|
||||
AvaTimeline expected = makeTimeline({ {1, 3} });
|
||||
QCOMPARE(timeline1, expected);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AvaTimelineTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLSE, 2018-03-28
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QTest>
|
||||
|
||||
/**
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class AvaTimelineTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void testMergeEmpty();
|
||||
void testMergeSelf();
|
||||
void testMergeDisjunct();
|
||||
void testMergeWithin();
|
||||
void testMergeOverlap();
|
||||
void testMergeEdgeOverlap();
|
||||
};
|
||||
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AvsCommandQueueTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLSE, 2018-02-28
|
||||
*/
|
||||
|
||||
#include "avs_command_queue_test.h"
|
||||
#include <AudioVideoManagement/avs_command_queue.h>
|
||||
#include <AudioVideoManagement/icommand.h>
|
||||
#include <LtsUtilsCore/connection.h>
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
|
||||
using namespace AudioVideoManagement;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class ExecutionSpy
|
||||
{
|
||||
public:
|
||||
void executedA(int value)
|
||||
{
|
||||
++m_execCountA;
|
||||
m_lastValueA = value;
|
||||
}
|
||||
|
||||
void executedB(int value)
|
||||
{
|
||||
++m_execCountB;
|
||||
m_lastValueB = value;
|
||||
}
|
||||
|
||||
int m_execCountA{0};
|
||||
int m_lastValueA{0};
|
||||
int m_execCountB{0};
|
||||
int m_lastValueB{0};
|
||||
};
|
||||
|
||||
|
||||
class CommandA : public ICommand
|
||||
{
|
||||
public:
|
||||
CommandA(ExecutionSpy *spy, int value)
|
||||
: m_spy(spy)
|
||||
, m_value(value)
|
||||
{
|
||||
Q_ASSERT(spy);
|
||||
}
|
||||
|
||||
void send() override
|
||||
{
|
||||
m_spy->executedA(m_value);
|
||||
}
|
||||
|
||||
QString debug() const override { return QLatin1String("CommandA"); }
|
||||
|
||||
bool nullifies(ICommand *other) const override
|
||||
{
|
||||
Q_ASSERT(other);
|
||||
CommandA *other_ = dynamic_cast<CommandA*>(other);
|
||||
return other_ != nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
ExecutionSpy *m_spy;
|
||||
int m_value;
|
||||
};
|
||||
|
||||
|
||||
class CommandB : public ICommand
|
||||
{
|
||||
public:
|
||||
CommandB(ExecutionSpy *spy, int value)
|
||||
: m_spy(spy)
|
||||
, m_value(value)
|
||||
{
|
||||
Q_ASSERT(spy);
|
||||
}
|
||||
|
||||
void send() override
|
||||
{
|
||||
m_spy->executedB(m_value);
|
||||
}
|
||||
QString debug() const override { return QLatin1String("CommandB"); }
|
||||
|
||||
bool nullifies(ICommand *other) const override
|
||||
{
|
||||
Q_ASSERT(other);
|
||||
CommandB *other_ = dynamic_cast<CommandB*>(other);
|
||||
return other_ != nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
ExecutionSpy *m_spy;
|
||||
int m_value;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
void AvsCommandQueueTest::testReduceNeverDropCmdInExecution()
|
||||
{
|
||||
ExecutionSpy spy;
|
||||
|
||||
std::unique_ptr<CommandA> cmd1(new CommandA(&spy, 10));
|
||||
std::unique_ptr<CommandA> cmd2(new CommandA(&spy, 20));
|
||||
|
||||
AvsCommandQueue queue(std::chrono::seconds(3));
|
||||
queue.queue(std::move(cmd1), nullptr);
|
||||
queue.queue(std::move(cmd2), nullptr); // Does not override cmd1 as cmd1 is being executed already and thus cannot be dropped anymore.
|
||||
|
||||
QCOMPARE(spy.m_execCountA, 1);
|
||||
QCOMPARE(spy.m_lastValueA, 10);
|
||||
|
||||
queue.done();
|
||||
QCOMPARE(spy.m_execCountA, 2);
|
||||
QCOMPARE(spy.m_lastValueA, 20);
|
||||
|
||||
queue.done();
|
||||
QVERIFY(queue.isEmpty());
|
||||
}
|
||||
|
||||
void AvsCommandQueueTest::testReduce1()
|
||||
{
|
||||
ExecutionSpy spy;
|
||||
|
||||
std::unique_ptr<CommandA> cmd1(new CommandA(&spy, 10));
|
||||
std::unique_ptr<CommandA> cmd2(new CommandA(&spy, 20));
|
||||
std::unique_ptr<CommandA> cmd3(new CommandA(&spy, 30));
|
||||
|
||||
AvsCommandQueue queue(std::chrono::seconds(3));
|
||||
queue.queue(std::move(cmd1), nullptr);
|
||||
queue.queue(std::move(cmd2), nullptr);
|
||||
queue.queue(std::move(cmd3), nullptr); // causes cmd2 to be dropped
|
||||
|
||||
// Only two commands complete as one was dropped.
|
||||
queue.done();
|
||||
queue.done();
|
||||
QVERIFY(queue.isEmpty());
|
||||
|
||||
QCOMPARE(spy.m_execCountA, 2);
|
||||
QCOMPARE(spy.m_lastValueA, 30);
|
||||
}
|
||||
|
||||
void AvsCommandQueueTest::testReduce2()
|
||||
{
|
||||
ExecutionSpy spy;
|
||||
|
||||
std::unique_ptr<CommandA> cmdA1(new CommandA(&spy, 10));
|
||||
std::unique_ptr<CommandA> cmdA2(new CommandA(&spy, 20));
|
||||
std::unique_ptr<CommandA> cmdA3(new CommandA(&spy, 30));
|
||||
std::unique_ptr<CommandB> cmdB1(new CommandB(&spy, 10));
|
||||
std::unique_ptr<CommandB> cmdB2(new CommandB(&spy, 20));
|
||||
std::unique_ptr<CommandB> cmdB3(new CommandB(&spy, 30));
|
||||
|
||||
AvsCommandQueue queue(std::chrono::seconds(3));
|
||||
queue.queue(std::move(cmdA1), nullptr);
|
||||
queue.queue(std::move(cmdB1), nullptr);
|
||||
queue.queue(std::move(cmdA2), nullptr); // cmdA1 not dropped as it is being executed already
|
||||
queue.queue(std::move(cmdB2), nullptr); // causes cmdB1 to be dropped
|
||||
queue.queue(std::move(cmdA3), nullptr); // causes cmdA2 to be dropped
|
||||
queue.queue(std::move(cmdB3), nullptr); // causes cmdB2 to be dropped
|
||||
|
||||
// Only three commands complete as one was dropped.
|
||||
queue.done();
|
||||
queue.done();
|
||||
queue.done();
|
||||
QVERIFY(queue.isEmpty());
|
||||
QCOMPARE(spy.m_execCountA, 2);
|
||||
QCOMPARE(spy.m_lastValueA, 30);
|
||||
QCOMPARE(spy.m_execCountB, 1);
|
||||
QCOMPARE(spy.m_lastValueB, 30);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AvsCommandQueueTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLSE, 2018-02-28
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QTest>
|
||||
|
||||
/**
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class AvsCommandQueueTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void initTestCase() {}
|
||||
void cleanupTestCase() {}
|
||||
void init() {}
|
||||
void cleanup() {}
|
||||
|
||||
void testReduceNeverDropCmdInExecution();
|
||||
void testReduce1();
|
||||
void testReduce2();
|
||||
};
|
||||
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ChooseStreamTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLSE, 2018-01-26
|
||||
*/
|
||||
|
||||
#include "choose_stream_test.h"
|
||||
#include "ava_comm_double.h"
|
||||
#include <AudioVideoManagement/AvsCommands/choose_stream.h>
|
||||
#include <AudioVideoManagement/iava_comm.h>
|
||||
#include <AudioVideoManagement/iava_command_done_observer.h>
|
||||
|
||||
using namespace AudioVideoManagement;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class DoneObserver : public IAvaCommandDoneObserver
|
||||
{
|
||||
public:
|
||||
void done(ICommand *cmd) override { Q_UNUSED(cmd); m_done = true; }
|
||||
void done(AvaCommands::ChooseStream *cmd) override { Q_UNUSED(cmd); m_done = true; }
|
||||
void done(AvaCommands::GetStreamList *cmd) override { Q_UNUSED(cmd); m_done = true; }
|
||||
void done(AvaCommands::QueryTimeline *cmd) override { Q_UNUSED(cmd); m_done = true; }
|
||||
void done(AvaCommands::GetElokaList *cmd) override { Q_UNUSED(cmd); m_done = true; }
|
||||
void done(AvaCommands::QueryEloka *cmd) override { Q_UNUSED(cmd); m_done = true; }
|
||||
void done(AvaCommands::SetRtProfileBase *cmd) override { Q_UNUSED(cmd); m_done = true; }
|
||||
void done(AvaCommands::SetAnnouncementProfile *cmd) override { Q_UNUSED(cmd); m_done = true; }
|
||||
void done(AvaCommands::SetVideoProfile *cmd) override { Q_UNUSED(cmd); m_done = true; }
|
||||
void done(AvaCommands::SetScript *cmd) override { Q_UNUSED(cmd); m_done = true; }
|
||||
void done(AvaCommands::StartScript *cmd) override { Q_UNUSED(cmd); m_done = true; }
|
||||
|
||||
void failed(ICommand *cmd) override { Q_UNUSED(cmd); }
|
||||
void alive(ICommand *cmd) override { Q_UNUSED(cmd); }
|
||||
|
||||
bool m_done{false};
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
/**
|
||||
* Scenario when chooseStream is called when no stream is currently chosen.
|
||||
* Sample comm protocol:
|
||||
* chooseStream CAMERA_IN_AP_3 1 Video1
|
||||
* 200 OK
|
||||
* 220 "CAMERA_IN_AP_3" "Video1" 1516978925.00 1516978925.00 0.00 STREAMINFO
|
||||
* 221 "CAMERA_IN_AP_3" "Video1" 1516978924.97 STREAMPOS
|
||||
* 222 "CAMERA_IN_AP_3" "Video1" 100 STREAMSPEED
|
||||
* 223 "CAMERA_IN_AP_3" "Video1" 0 STREAMSTATE
|
||||
* 224 "CAMERA_IN_AP_3" "Video1" 1 0 STREAMMODE
|
||||
* 225 "CAMERA_IN_AP_3" "Video1" 1 STREAMAUDIOMUTE
|
||||
* 228 "CAMERA_IN_AP_3" "Video1" 1 STREAMVOLUMECHANGED
|
||||
* 225 "CAMERA_IN_AP_3" "Video1" 1 STREAMAUDIOMUTE
|
||||
* 223 "CAMERA_IN_AP_3" "Video1" 1 STREAMSTATE
|
||||
*/
|
||||
void ChooseStreamTest::testChooseFirstStream()
|
||||
{
|
||||
const QString dialog = QStringLiteral("Video1");
|
||||
const QString stream = QStringLiteral("cam1");
|
||||
AvaCommDouble avaCommDouble;
|
||||
DoneObserver observer;
|
||||
AvaCommands::ChooseStream chooseStream(&avaCommDouble, &observer, dialog, stream);
|
||||
chooseStream.send();
|
||||
|
||||
emit avaCommDouble.ok();
|
||||
emit avaCommDouble.streamInfoReceived(dialog, stream, AvaStreamInfo{AvaTimePoint{AvaDuration{151697892500}}, AvaTimePoint{AvaDuration{151697892500}}, AvaDuration{0}});
|
||||
emit avaCommDouble.streamStateReceived(dialog, stream, AvaStreamState::Stop);
|
||||
QVERIFY(!observer.m_done);
|
||||
emit avaCommDouble.streamModeReceived(dialog, stream, true, false);
|
||||
QVERIFY(observer.m_done);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scenario when chooseStream is called when a stream is currenly chosen already.
|
||||
* Sample comm protocol:
|
||||
* chooseStream CAMERA_IN_AP_1 1 Video1
|
||||
* 200 OK
|
||||
* 221 "CAMERA_IN_AP_3" "Video1" 1516978962.33 STREAMPOS
|
||||
* 223 "CAMERA_IN_AP_3" "Video1" 3 STREAMSTATE
|
||||
* 223 "CAMERA_IN_AP_3" "Video1" 3 STREAMSTATE
|
||||
* 220 "CAMERA_IN_AP_1" "Video1" 1516978962.00 1516978962.00 0.00 STREAMINFO
|
||||
* 221 "CAMERA_IN_AP_1" "Video1" 1516978962.37 STREAMPOS
|
||||
* 222 "CAMERA_IN_AP_1" "Video1" 100 STREAMSPEED
|
||||
* 223 "CAMERA_IN_AP_1" "Video1" 0 STREAMSTATE
|
||||
* 224 "CAMERA_IN_AP_1" "Video1" 1 0 STREAMMODE
|
||||
* 225 "CAMERA_IN_AP_1" "Video1" 1 STREAMAUDIOMUTE
|
||||
* 228 "CAMERA_IN_AP_1" "Video1" 1 STREAMVOLUMECHANGED
|
||||
* 225 "CAMERA_IN_AP_1" "Video1" 1 STREAMAUDIOMUTE
|
||||
* 223 "CAMERA_IN_AP_1" "Video1" 1 STREAMSTATE
|
||||
*/
|
||||
void ChooseStreamTest::testChooseSecondStream()
|
||||
{
|
||||
const QString dialog = QStringLiteral("Video1");
|
||||
const QString oldStream = QStringLiteral("cam1");
|
||||
const QString newStream = QStringLiteral("cam2");
|
||||
AvaCommDouble avaCommDouble;
|
||||
DoneObserver observer;
|
||||
AvaCommands::ChooseStream chooseStream(&avaCommDouble, &observer, dialog, newStream);
|
||||
chooseStream.send();
|
||||
|
||||
emit avaCommDouble.ok();
|
||||
emit avaCommDouble.streamStateReceived(dialog, oldStream, AvaStreamState::NotPossible);
|
||||
emit avaCommDouble.streamStateReceived(dialog, oldStream, AvaStreamState::NotPossible);
|
||||
emit avaCommDouble.streamInfoReceived(dialog, newStream, AvaStreamInfo{AvaTimePoint{AvaDuration{151697896200}}, AvaTimePoint{AvaDuration{151697896200}}, AvaDuration{0}});
|
||||
emit avaCommDouble.streamStateReceived(dialog, newStream, AvaStreamState::Stop);
|
||||
QVERIFY(!observer.m_done);
|
||||
emit avaCommDouble.streamModeReceived(dialog, newStream, true, false);
|
||||
QVERIFY(observer.m_done);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as testChooseSecondStream but we choose the same stream.
|
||||
*/
|
||||
void ChooseStreamTest::testChooseSameStream()
|
||||
{
|
||||
const QString dialog = QStringLiteral("Video1");
|
||||
const QString stream = QStringLiteral("cam1");
|
||||
AvaCommDouble avaCommDouble;
|
||||
DoneObserver observer;
|
||||
AvaCommands::ChooseStream chooseStream(&avaCommDouble, &observer, dialog, stream);
|
||||
chooseStream.send();
|
||||
|
||||
emit avaCommDouble.ok();
|
||||
emit avaCommDouble.streamStateReceived(dialog, stream, AvaStreamState::NotPossible);
|
||||
emit avaCommDouble.streamStateReceived(dialog, stream, AvaStreamState::NotPossible);
|
||||
emit avaCommDouble.streamInfoReceived(dialog, stream, AvaStreamInfo{AvaTimePoint{AvaDuration{151697896200}}, AvaTimePoint{AvaDuration{151697896200}}, AvaDuration{0}});
|
||||
emit avaCommDouble.streamStateReceived(dialog, stream, AvaStreamState::Stop);
|
||||
QVERIFY(!observer.m_done);
|
||||
emit avaCommDouble.streamModeReceived(dialog, stream, true, false);
|
||||
QVERIFY(observer.m_done);
|
||||
}
|
||||
|
||||
/**
|
||||
* Almost the same as testChooseSecondStream() but this time there are two streams
|
||||
* choosen already (using chooseStreamOverview).
|
||||
* Sample comm protocol:
|
||||
* chooseStream CAMERA_IN_AP_3 1 Video1
|
||||
* 200 OK
|
||||
* 221 "CAMERA_IN_AP_1" "Video1" 1516979047.87 STREAMPOS
|
||||
* 221 "CAMERA_IN_AP_2" "Video1" 1516979047.87 STREAMPOS
|
||||
* 223 "CAMERA_IN_AP_1" "Video1" 3 STREAMSTATE
|
||||
* 223 "CAMERA_IN_AP_2" "Video1" 3 STREAMSTATE
|
||||
* 223 "CAMERA_IN_AP_1" "Video1" 3 STREAMSTATE
|
||||
* 223 "CAMERA_IN_AP_2" "Video1" 3 STREAMSTATE
|
||||
* 220 "CAMERA_IN_AP_3" "Video1" 1516979048.00 1516979048.00 0.00 STREAMINFO
|
||||
* 221 "CAMERA_IN_AP_3" "Video1" 1516979047.92 STREAMPOS
|
||||
* 222 "CAMERA_IN_AP_3" "Video1" 100 STREAMSPEED
|
||||
* 223 "CAMERA_IN_AP_3" "Video1" 0 STREAMSTATE
|
||||
* 224 "CAMERA_IN_AP_3" "Video1" 1 0 STREAMMODE
|
||||
* 225 "CAMERA_IN_AP_3" "Video1" 1 STREAMAUDIOMUTE
|
||||
* 228 "CAMERA_IN_AP_3" "Video1" 1 STREAMVOLUMECHANGED
|
||||
* 225 "CAMERA_IN_AP_3" "Video1" 1 STREAMAUDIOMUTE
|
||||
* 223 "CAMERA_IN_AP_3" "Video1" 1 STREAMSTATE
|
||||
*/
|
||||
void ChooseStreamTest::testChooseAfterOverview()
|
||||
{
|
||||
const QString dialog = QStringLiteral("Video1");
|
||||
const QString oldStream1 = QStringLiteral("cam1");
|
||||
const QString oldStream2 = QStringLiteral("cam2");
|
||||
const QString newStream = QStringLiteral("cam3");
|
||||
AvaCommDouble avaCommDouble;
|
||||
DoneObserver observer;
|
||||
AvaCommands::ChooseStream chooseStream(&avaCommDouble, &observer, dialog, newStream);
|
||||
chooseStream.send();
|
||||
|
||||
emit avaCommDouble.streamStateReceived(dialog, oldStream1, AvaStreamState::NotPossible);
|
||||
emit avaCommDouble.streamStateReceived(dialog, oldStream2, AvaStreamState::NotPossible);
|
||||
emit avaCommDouble.streamStateReceived(dialog, oldStream1, AvaStreamState::NotPossible);
|
||||
emit avaCommDouble.streamStateReceived(dialog, oldStream2, AvaStreamState::NotPossible);
|
||||
emit avaCommDouble.streamInfoReceived(dialog, newStream, AvaStreamInfo{AvaTimePoint{AvaDuration{151697904800}}, AvaTimePoint{AvaDuration{151697904800}}, AvaDuration{0}});
|
||||
emit avaCommDouble.streamStateReceived(dialog, newStream, AvaStreamState::Stop);
|
||||
QVERIFY(!observer.m_done);
|
||||
emit avaCommDouble.streamModeReceived(dialog, newStream, true, false);
|
||||
QVERIFY(observer.m_done);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ChooseStreamTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLSE, 2018-01-26
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QTest>
|
||||
|
||||
/**
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class ChooseStreamTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void testChooseFirstStream();
|
||||
void testChooseSecondStream();
|
||||
void testChooseSameStream();
|
||||
void testChooseAfterOverview();
|
||||
};
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ListResponseCollectorTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLE, 2018-12-18
|
||||
*/
|
||||
|
||||
#include "list_response_collector_test.h"
|
||||
#include "ava_comm_double.h"
|
||||
#include <AudioVideoManagement/list_response_collector.h>
|
||||
#include <AudioVideoManagement/ava_types.h>
|
||||
#include <AudioVideoManagement/av_helper.h>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
using namespace AudioVideoManagement;
|
||||
|
||||
void ListResponseCollectorTest::test()
|
||||
{
|
||||
AvaCommDouble avaComm;
|
||||
QVector<QString> invalidNames;
|
||||
auto doneCallback = [&invalidNames] (QVector<QString> &&result) { invalidNames = std::move(result); };
|
||||
InvalidNameListCollector collector(&avaComm, doneCallback);
|
||||
|
||||
// complete sequence -- but we didn't start yet
|
||||
emit avaComm.invalidNameListBeginReceived();
|
||||
emit avaComm.listValueReceived({"stream 1"});
|
||||
emit avaComm.listValueReceived({"stream 2"});
|
||||
emit avaComm.listValueReceived({"stream 3"});
|
||||
emit avaComm.endOfListReceived();
|
||||
QVERIFY(invalidNames.isEmpty());
|
||||
|
||||
collector.start();
|
||||
emit avaComm.invalidNameListBeginReceived();
|
||||
emit avaComm.listValueReceived({"stream 1"});
|
||||
emit avaComm.listValueReceived({"stream 2"});
|
||||
emit avaComm.listValueReceived({"stream 3"});
|
||||
QVERIFY(invalidNames.isEmpty());
|
||||
emit avaComm.endOfListReceived();
|
||||
QVector<QString> expected{QString::fromUtf8("stream 1"), QString::fromUtf8("stream 2"), QString::fromUtf8("stream 3")};
|
||||
QCOMPARE(invalidNames, expected);
|
||||
}
|
||||
|
||||
void ListResponseCollectorTest::testOutOfOrder()
|
||||
{
|
||||
AvaCommDouble avaComm;
|
||||
QVector<QString> invalidNames;
|
||||
auto doneCallback = [&invalidNames] (QVector<QString> &&result) { invalidNames = std::move(result); };
|
||||
InvalidNameListCollector collector(&avaComm, doneCallback);
|
||||
|
||||
collector.start();
|
||||
|
||||
// the following signals shall be ignored as the start of the (specific) list was not yet signalled
|
||||
emit avaComm.elokaListBeginReceived();
|
||||
emit avaComm.listValueReceived({"foo", "bar"});
|
||||
emit avaComm.listValueReceived({"foo", "bar"});
|
||||
emit avaComm.endOfListReceived();
|
||||
QVERIFY(invalidNames.isEmpty());
|
||||
|
||||
emit avaComm.invalidNameListBeginReceived();
|
||||
emit avaComm.listValueReceived({"stream 1"});
|
||||
emit avaComm.listValueReceived({"stream 2"});
|
||||
emit avaComm.listValueReceived({"stream 3"});
|
||||
QVERIFY(invalidNames.isEmpty());
|
||||
emit avaComm.endOfListReceived();
|
||||
QVector<QString> expected{QString::fromUtf8("stream 1"), QString::fromUtf8("stream 2"), QString::fromUtf8("stream 3")};
|
||||
QCOMPARE(invalidNames, expected);
|
||||
}
|
||||
|
||||
void ListResponseCollectorTest::testIgnoreFollowingList()
|
||||
{
|
||||
AvaCommDouble avaComm;
|
||||
QVector<QString> invalidNames;
|
||||
auto doneCallback = [&invalidNames] (QVector<QString> &&result) { invalidNames = std::move(result); };
|
||||
InvalidNameListCollector collector(&avaComm, doneCallback);
|
||||
|
||||
collector.start();
|
||||
emit avaComm.invalidNameListBeginReceived();
|
||||
emit avaComm.listValueReceived({"stream 1"});
|
||||
emit avaComm.listValueReceived({"stream 2"});
|
||||
emit avaComm.listValueReceived({"stream 3"});
|
||||
emit avaComm.endOfListReceived();
|
||||
QCOMPARE(invalidNames.size(), 3);
|
||||
|
||||
// the following list (of the same type) shall be ignored
|
||||
invalidNames.clear();
|
||||
emit avaComm.invalidNameListBeginReceived();
|
||||
emit avaComm.listValueReceived({"another stream 1"});
|
||||
emit avaComm.listValueReceived({"another stream 2"});
|
||||
emit avaComm.endOfListReceived();
|
||||
QVERIFY(invalidNames.isEmpty());
|
||||
}
|
||||
|
||||
void ListResponseCollectorTest::testRestart()
|
||||
{
|
||||
AvaCommDouble avaComm;
|
||||
QVector<QString> invalidNames;
|
||||
auto doneCallback = [&invalidNames] (QVector<QString> &&result) { invalidNames = std::move(result); };
|
||||
InvalidNameListCollector collector(&avaComm, doneCallback);
|
||||
|
||||
collector.start();
|
||||
emit avaComm.invalidNameListBeginReceived();
|
||||
emit avaComm.listValueReceived({"stream 1"});
|
||||
emit avaComm.listValueReceived({"stream 2"});
|
||||
emit avaComm.listValueReceived({"stream 3"});
|
||||
emit avaComm.endOfListReceived();
|
||||
QCOMPARE(invalidNames.size(), 3);
|
||||
|
||||
invalidNames.clear();
|
||||
collector.start();
|
||||
emit avaComm.invalidNameListBeginReceived();
|
||||
emit avaComm.listValueReceived({"another stream 1"});
|
||||
emit avaComm.listValueReceived({"another stream 2"});
|
||||
emit avaComm.endOfListReceived();
|
||||
QVector<QString> expected{QString::fromUtf8("another stream 1"), QString::fromUtf8("another stream 2")};
|
||||
QCOMPARE(invalidNames, expected);
|
||||
}
|
||||
|
||||
void ListResponseCollectorTest::testReset()
|
||||
{
|
||||
AvaCommDouble avaComm;
|
||||
QVector<QString> invalidNames;
|
||||
auto doneCallback = [&invalidNames] (QVector<QString> &&result) { invalidNames = std::move(result); };
|
||||
InvalidNameListCollector collector(&avaComm, doneCallback);
|
||||
|
||||
collector.start();
|
||||
emit avaComm.invalidNameListBeginReceived();
|
||||
emit avaComm.listValueReceived({"stream 1"});
|
||||
emit avaComm.listValueReceived({"stream 2"});
|
||||
emit avaComm.listValueReceived({"stream 3"});
|
||||
|
||||
// restart the collector before the list is finished
|
||||
collector.reset();
|
||||
collector.start();
|
||||
|
||||
emit avaComm.invalidNameListBeginReceived();
|
||||
emit avaComm.listValueReceived({"stream 1"});
|
||||
emit avaComm.listValueReceived({"stream 2"});
|
||||
emit avaComm.endOfListReceived();
|
||||
QCOMPARE(invalidNames.size(), 2);
|
||||
}
|
||||
|
||||
void ListResponseCollectorTest::testTimeline()
|
||||
{
|
||||
AvaCommDouble avaComm;
|
||||
AvaTimeline timeline;
|
||||
auto doneCallback = [&timeline] (AvaTimeline &&result) { timeline = std::move(result); };
|
||||
auto aliveCallback = std::function<void()>{};
|
||||
const QString streamName = QStringLiteral("CAM 1");
|
||||
TimelineListCollector collector(&avaComm, streamName, doneCallback, aliveCallback);
|
||||
|
||||
collector.start();
|
||||
emit avaComm.timelineListBeginReceived(QStringLiteral("CAM 1"));
|
||||
emit avaComm.listValueReceived({"1.00-2.00"});
|
||||
emit avaComm.listValueReceived({"3.00-4.00"});
|
||||
emit avaComm.listValueReceived({"5.00-6.00"});
|
||||
QVERIFY(timeline.isEmpty());
|
||||
emit avaComm.endOfListReceived();
|
||||
|
||||
AvaTimeline expected({ {createTimePoint("1"), createTimePoint("2")}, {createTimePoint("3"), createTimePoint("4")}, {createTimePoint("5"), createTimePoint("6")} });
|
||||
QCOMPARE(timeline, expected);
|
||||
}
|
||||
|
||||
void ListResponseCollectorTest::testRestartTimeline()
|
||||
{
|
||||
AvaCommDouble avaComm;
|
||||
AvaTimeline timeline;
|
||||
auto doneCallback = [&timeline] (AvaTimeline &&result) { timeline = std::move(result); };
|
||||
auto aliveCallback = std::function<void()>{};
|
||||
const QString streamName = QStringLiteral("CAM 1");
|
||||
TimelineListCollector collector(&avaComm, streamName, doneCallback, aliveCallback);
|
||||
|
||||
collector.start();
|
||||
emit avaComm.timelineListBeginReceived(QStringLiteral("CAM 1"));
|
||||
emit avaComm.listValueReceived({"1.00-2.00"});
|
||||
emit avaComm.listValueReceived({"3.00-4.00"});
|
||||
emit avaComm.listValueReceived({"5.00-6.00"});
|
||||
emit avaComm.endOfListReceived();
|
||||
QCOMPARE(timeline.parts().size(), 3);
|
||||
|
||||
timeline.clear();
|
||||
emit avaComm.timelineListBeginReceived(QStringLiteral("CAM 1"));
|
||||
emit avaComm.listValueReceived({"1.00-2.00"});
|
||||
emit avaComm.listValueReceived({"3.00-4.00"});
|
||||
emit avaComm.endOfListReceived();
|
||||
QVERIFY(timeline.isEmpty()); // ignored as collector was not re-started yet
|
||||
|
||||
collector.start();
|
||||
emit avaComm.timelineListBeginReceived(QStringLiteral("CAM 1"));
|
||||
emit avaComm.listValueReceived({"1.00-2.00"});
|
||||
emit avaComm.listValueReceived({"3.00-4.00"});
|
||||
emit avaComm.endOfListReceived();
|
||||
|
||||
AvaTimeline expected({ {createTimePoint("1"), createTimePoint("2")}, {createTimePoint("3"), createTimePoint("4")} });
|
||||
QCOMPARE(timeline, expected);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ListResponseCollectorTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLE, 2018-12-18
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QTest>
|
||||
|
||||
/**
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class ListResponseCollectorTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void test();
|
||||
void testOutOfOrder();
|
||||
void testIgnoreFollowingList();
|
||||
void testRestart();
|
||||
void testReset();
|
||||
void testTimeline();
|
||||
void testRestartTimeline();
|
||||
};
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* unit test main
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-06-19
|
||||
*/
|
||||
|
||||
#include "parse_line_test.h"
|
||||
#include "ava_comm_test.h"
|
||||
#include "ava_control_test.h"
|
||||
#include "av_helper_test.h"
|
||||
#include "asset_assignment_manager_test.h"
|
||||
#include "audio_video_handler_impl_test.h"
|
||||
#include "choose_stream_test.h"
|
||||
#include "ava_timeline_test.h"
|
||||
#include "avs_command_queue_test.h"
|
||||
#include "rt_state_test.h"
|
||||
#include "list_response_collector_test.h"
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <QtTest/QtTest>
|
||||
#include <QCommandLineParser>
|
||||
#include <QCommandLineOption>
|
||||
#include <QStringList>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <iostream>
|
||||
|
||||
using namespace AudioVideoManagement;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
QStringList toStringList(int argc, char **argv)
|
||||
{
|
||||
QStringList options;
|
||||
options.reserve(argc);
|
||||
for (int i = 0; i < argc; ++i)
|
||||
options.append(QString::fromUtf8(argv[i]));
|
||||
return options;
|
||||
}
|
||||
|
||||
QStringList removeParsedArgs(const QStringList &args)
|
||||
{
|
||||
QStringList reducedArgs = {args.front()};
|
||||
|
||||
auto separatorPos = std::find(args.begin(), args.end(), QStringLiteral("--"));
|
||||
if (separatorPos == args.end())
|
||||
return reducedArgs;
|
||||
|
||||
++separatorPos;
|
||||
std::copy(separatorPos, args.end(), std::back_inserter(reducedArgs));
|
||||
return reducedArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the name of the test class to an instance of it.
|
||||
*/
|
||||
using TestMap = std::map<QString, std::unique_ptr<QObject>>;
|
||||
|
||||
template<class Test>
|
||||
void addTest(TestMap& tests)
|
||||
{
|
||||
std::unique_ptr<QObject> test(new Test);
|
||||
auto result = tests.insert(std::make_pair(QString::fromUtf8(test->metaObject()->className()), std::move(test)));
|
||||
Q_ASSERT(result.second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate all test classes and return them.
|
||||
* Every new test class needs to be added here.
|
||||
*/
|
||||
TestMap allTests()
|
||||
{
|
||||
TestMap tests;
|
||||
addTest<ParseLineTest>(tests);
|
||||
addTest<AvaCommTest>(tests);
|
||||
addTest<AvaControlTest>(tests);
|
||||
addTest<AvHelperTest>(tests);
|
||||
addTest<AssetAssignmentManagerTest>(tests);
|
||||
addTest<AudioVideoHandlerImplTest>(tests);
|
||||
addTest<ChooseStreamTest>(tests);
|
||||
addTest<AvsCommandQueueTest>(tests);
|
||||
addTest<AvaTimelineTest>(tests);
|
||||
addTest<RtStateTest>(tests);
|
||||
addTest<ListResponseCollectorTest>(tests);
|
||||
return tests;
|
||||
}
|
||||
|
||||
int runTests(const QStringList &selectedTests, const TestMap &allTests, const QStringList &args)
|
||||
{
|
||||
int result = 0;
|
||||
for (const QString &testName : selectedTests)
|
||||
{
|
||||
auto found = allTests.find(testName);
|
||||
if (found == allTests.end())
|
||||
{
|
||||
std::cout << "Unknown test: " << testName.toUtf8().constData() << std::endl;
|
||||
result = 1;
|
||||
continue;
|
||||
}
|
||||
QObject* test = found->second.get();
|
||||
result |= QTest::qExec(test, args);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int runAllTests(const TestMap &allTests, const QStringList &args)
|
||||
{
|
||||
QStringList allTestNames;
|
||||
allTestNames.reserve(allTests.size());
|
||||
for (const auto &test: allTests)
|
||||
allTestNames.append(test.first);
|
||||
return runTests(allTestNames, allTests, args);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int fakeArgc = 1;
|
||||
NGLCoreApplication app(fakeArgc, argv);
|
||||
app.createLogger("AVM", "log4cxx_avmTests.props");
|
||||
|
||||
// Before passing the command line arguments to QTest::qExec() we do some parsing ourselves.
|
||||
// The problem is that QTest conceptionally only allows one instance of a single test class.
|
||||
// As we want to instantiate and test more than one test class, we offer a command line option
|
||||
// to select one or more test classes to run: -t <TestClass>.
|
||||
// Other options which shall be passed to QTest::qExec() must come after -t-options and
|
||||
// an explicit '--' separator.
|
||||
QCommandLineParser parser;
|
||||
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
|
||||
QCommandLineOption selectTestOption(QStringList{QStringLiteral("t"), QStringLiteral("test")}, QStringLiteral("Test-class to run"), QStringLiteral("test"));
|
||||
parser.addOption(selectTestOption);
|
||||
|
||||
QStringList commandLineArgs = toStringList(argc, argv);
|
||||
(void) parser.parse(commandLineArgs);
|
||||
QStringList reducedCommandLineArgs = removeParsedArgs(commandLineArgs);
|
||||
if (parser.isSet(selectTestOption))
|
||||
{
|
||||
QStringList selectedTests = parser.values(selectTestOption.valueName());
|
||||
return runTests(selectedTests, allTests(), reducedCommandLineArgs);
|
||||
}
|
||||
|
||||
return runAllTests(allTests(), reducedCommandLineArgs);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ParseLineTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-06-19
|
||||
*/
|
||||
|
||||
#include "parse_line_test.h"
|
||||
#include <AudioVideoManagement/av_socket.h>
|
||||
|
||||
using namespace AudioVideoManagement;
|
||||
|
||||
/**
|
||||
* Special case that I could not cover with the data-driven approach.
|
||||
*/
|
||||
void ParseLineTest::testEmpty()
|
||||
{
|
||||
QByteArray line;
|
||||
const auto parts = AVSocket::parseLine(line);
|
||||
QCOMPARE(parts.size(), 0);
|
||||
}
|
||||
|
||||
void ParseLineTest::test()
|
||||
{
|
||||
QFETCH(QByteArray, line);
|
||||
QFETCH(QByteArray, gluedParts);
|
||||
const auto expected = gluedParts.split(';');
|
||||
const auto parts = AVSocket::parseLine(line);
|
||||
QCOMPARE(parts.size(), expected.size());
|
||||
for (int i = 0; i < expected.size(); ++i)
|
||||
QCOMPARE(parts.at(i), expected.at(i));
|
||||
}
|
||||
|
||||
void ParseLineTest::test_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("line");
|
||||
QTest::addColumn<QByteArray>("gluedParts");
|
||||
|
||||
QTest::newRow("")
|
||||
<< QByteArray("{}")
|
||||
<< QByteArray("");
|
||||
QTest::newRow("")
|
||||
<< QByteArray("218 Video1 \"\" VIDEODIALOGSTATE")
|
||||
<< QByteArray("218;Video1;;VIDEODIALOGSTATE");
|
||||
QTest::newRow("")
|
||||
<< QByteArray("218 \"Video1\" \"\" VIDEODIALOGSTATE")
|
||||
<< QByteArray("218;Video1;;VIDEODIALOGSTATE");
|
||||
QTest::newRow("")
|
||||
<< QByteArray("218 \"Video 1\" \"\" VIDEODIALOGSTATE")
|
||||
<< QByteArray("218;Video 1;;VIDEODIALOGSTATE");
|
||||
QTest::newRow("")
|
||||
<< QByteArray("218 \"Video \\\"1\\\"\" \"\" VIDEODIALOGSTATE")
|
||||
<< QByteArray("218;Video \"1\";;VIDEODIALOGSTATE");
|
||||
QTest::newRow("")
|
||||
<< QByteArray("setvideoprofile Video1 \"1 {bldg_56: {CAM_UBEICE0001} {CAM_UBEICE0002} {CAM_UBEICE0003} {CAM_UBEICE0004}}\"")
|
||||
<< QByteArray("setvideoprofile;Video1;1 {bldg_56: {CAM_UBEICE0001} {CAM_UBEICE0002} {CAM_UBEICE0003} {CAM_UBEICE0004}}");
|
||||
|
||||
QTest::newRow("")
|
||||
<< QByteArray("{hello \" world}")
|
||||
<< QByteArray("hello \" world");
|
||||
|
||||
// Was that intended?
|
||||
QTest::newRow("")
|
||||
<< QByteArray("{")
|
||||
<< QByteArray("");
|
||||
QTest::newRow("")
|
||||
<< QByteArray("\"")
|
||||
<< QByteArray("");
|
||||
|
||||
// Oops, I guess that was not intended!
|
||||
QTest::newRow("")
|
||||
<< QByteArray("setvideoprofile Video1 {bldg_56: {CAM_UBEICE0001} {CAM_UBEICE0002} {CAM_UBEICE0003} {CAM_UBEICE0004}}")
|
||||
<< QByteArray("setvideoprofile;Video1;bldg_56: {CAM_UBEICE0001;CAM_UBEICE0002;CAM_UBEICE0003;CAM_UBEICE0004;}");
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ParseLineTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-06-19
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QTest>
|
||||
|
||||
/**
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class ParseLineTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void testEmpty();
|
||||
void test();
|
||||
void test_data();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* RtStateTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLE, 2018-12-16
|
||||
*/
|
||||
|
||||
#include "rt_state_test.h"
|
||||
#include <AudioVideoManagement/rt_state.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
using namespace AudioVideoManagement;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
QVector<RtState::RadioCircuit> radioCircuits()
|
||||
{
|
||||
return {{RadioSystem::Tvc, 1, "tvc 1"}, {RadioSystem::Tvc, 2, "tvc 2"}, {RadioSystem::Cnr, 1, "cnr 1"}};
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void RtStateTest::testInitialState()
|
||||
{
|
||||
RtState rtState;
|
||||
rtState.setRadioCircuits(radioCircuits());
|
||||
|
||||
QCOMPARE(rtState.toCommand(), std::string(R"(setRtProfile "Default" "15 0 {cnr 1} 15 0 {tvc 1} 15 0 {tvc 2} " "{tvc 1} {tvc 2} {cnr 1} {} {} {} {} {} " "1 1 1 1 1 1 1 1 " 1)"));
|
||||
}
|
||||
|
||||
void RtStateTest::testVolume()
|
||||
{
|
||||
RtState rtState;
|
||||
rtState.setRadioCircuits(radioCircuits());
|
||||
|
||||
rtState.setVolume("tvc 2", AvaVolume(5));
|
||||
QCOMPARE(rtState.toCommand(), std::string(R"(setRtProfile "Default" "15 0 {cnr 1} 15 0 {tvc 1} 15 5 {tvc 2} " "{tvc 1} {tvc 2} {cnr 1} {} {} {} {} {} " "1 1 1 1 1 1 1 1 " 1)"));
|
||||
}
|
||||
|
||||
void RtStateTest::testNewProfile()
|
||||
{
|
||||
RtState rtState;
|
||||
rtState.setRadioCircuits(radioCircuits());
|
||||
rtState.setVolume("tvc 2", AvaVolume(5));
|
||||
rtState.setVolume("cnr 1", AvaVolume(-3));
|
||||
rtState.setSelection(AvaRtPos(2), "tvc 2", AvaRtButtonState::Left);
|
||||
rtState.setSelection(AvaRtPos(3), "cnr 1", AvaRtButtonState::Both);
|
||||
|
||||
rtState.setRadioCircuits({{RadioSystem::Tvc, 2, "tvc 2"}, {RadioSystem::Cnr, 1, "cnr 1"}, {RadioSystem::Cnr, 2, "cnr 2"}});
|
||||
QCOMPARE(rtState.toCommand(), std::string(R"(setRtProfile "Default" "15 -3 {cnr 1} 15 0 {cnr 2} 15 5 {tvc 2} " "{tvc 2} {cnr 1} {cnr 2} {} {} {} {} {} " "2 4 1 1 1 1 1 1 " 1)"));
|
||||
}
|
||||
|
||||
void RtStateTest::testSelection()
|
||||
{
|
||||
RtState rtState;
|
||||
rtState.setRadioCircuits(radioCircuits());
|
||||
|
||||
rtState.setSelection(AvaRtPos(1), "", AvaRtButtonState::None); // de-select
|
||||
rtState.setSelection(AvaRtPos(2), "", AvaRtButtonState::None); // de-select
|
||||
rtState.setSelection(AvaRtPos(3), "cnr 1", AvaRtButtonState::Both);
|
||||
rtState.setSelection(AvaRtPos(8), "tvc 1", AvaRtButtonState::Right);
|
||||
QCOMPARE(rtState.toCommand(), std::string(R"(setRtProfile "Default" "15 0 {cnr 1} 15 0 {tvc 1} 15 0 {tvc 2} " "{} {} {cnr 1} {} {} {} {} {tvc 1} " "1 1 4 1 1 1 1 3 " 1)"));
|
||||
}
|
||||
|
||||
void RtStateTest::testChangeName()
|
||||
{
|
||||
RtState rtState;
|
||||
rtState.setRadioCircuits(radioCircuits());
|
||||
|
||||
rtState.changeName({RadioSystem::Tvc, 2, "TVC_2"});
|
||||
QCOMPARE(rtState.toCommand(), std::string(R"(setRtProfile "Default" "15 0 {cnr 1} 15 0 {tvc 1} 15 0 {TVC_2} " "{tvc 1} {TVC_2} {cnr 1} {} {} {} {} {} " "1 1 1 1 1 1 1 1 " 1)"));
|
||||
}
|
||||
|
||||
void RtStateTest::testSumChannel()
|
||||
{
|
||||
RtState rtState;
|
||||
rtState.setRadioCircuits(radioCircuits());
|
||||
|
||||
rtState.setSumChannel(AvaSumChannel::Left);
|
||||
QCOMPARE(rtState.toCommand(), std::string(R"(setRtProfile "Default" "15 0 {cnr 1} 15 0 {tvc 1} 15 0 {tvc 2} " "{tvc 1} {tvc 2} {cnr 1} {} {} {} {} {} " "1 1 1 1 1 1 1 1 " 2)"));
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* RtStateTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLE, 2018-12-16
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QTest>
|
||||
|
||||
/**
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class RtStateTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void testInitialState();
|
||||
void testVolume();
|
||||
void testNewProfile();
|
||||
void testSelection();
|
||||
void testChangeName();
|
||||
void testSumChannel();
|
||||
};
|
||||
Reference in new issue
Block a user