[problem] The platform abstraction has features that should be tested.
[cause] Current tests of the dali-adaptor project use a stubbed platform
abstraction.
[solution] Make a new TCT test app that calls PlatformAbstraction
functions connected to a full platform abstraction underneath.
Single test case that loads 1000 images and checks that they all
complete.
Change-Id: Ibe5f89ebd469719ad798436dfb3cc784f0cf73f0
Signed-off-by: Andrew Cox <andrew.cox@partner.samsung.com>
Signed-off-by: Adeel Kazmi <adeel.kazmi@samsung.com>
--- /dev/null
+% Dali Adaptor Automated Testing
+
+Automated tests for the dali-adaptor project. These tests are callable from the
+TCT testing framework.
+
+There are currently three executables built, each of which has its own source
+directory and contains several test cases. These are:
+
+* `src/dali-adaptor`
+ Uses a mocked platform abstraction, so doesn't test the abstraction
+ implementations themselves.
+ This currently tests the timer and key presses only.
+* `src/dali-adaptor-internal`
+ Tests some internal components of the abstraction implementations without
+ attempting to have a live or mocked platform abstraction in place.
+ This is the correct place for test cases which can test code in dali-adaptor
+ in isolation.
+ Currently tied to the SLP platform abstraction directly.
+ Noteworthy test cases:
+ * `utc-Dali-GifLoader.cpp`: Runs the gif loader syncronously and checks
+ that the laoded bitmap matches a reference buffer on a pixel by pixel
+ basis.
+ * `utc-Dali-CommandLineOptions.cpp`: Tests whether commandline options of
+ Dali are stripped out of various inputs.
+* `src/dali-platform-abstraction`
+ Uses a real live platform abstraction so can be used to test features
+ exposed through the `Dali::Integration::PlatformAbstraction` abstract
+ interface.
+ Intended to test complex interactions operate correctly.
+ For example:
+ * Cancelation of a subset of a large number of in-flight
+ requests.
+ * Correct reporting of successful and failed requests when large numbers
+ of valid and invalid requests are issued in rapid sequence.
+
+If a loader for an image type is added to the platform abstractions, a test case
+should be added to `src/dali-adaptor-internal`, styled after
+`utc-Dali-GifLoader.cpp`. An image of that type should also be added to the
+ existing image test cases in `src/dali-platform-abstraction`.
+
+If a new commandline option is added to Dali, `utc-Dali-CommandLineOptions.cpp`
+should be expanded with it.
+
+Building
+========
+
+Use the script `build.sh` in the root of `automated-tests/`.
+To build all three test executables, run the script without arguments:
+
+ ./build.sh
+
+To build just one executable, pass its name to the build script:
+
+ ./build.sh dali-adaptor
+
+ ./build.sh dali-adaptor-internal
+
+ ./build.sh dali-platform-abstraction
+
+Running
+=======
+
+Use the `execute.sh` script. To execute the tests in all three executables, run the script with no arguments:
+
+ ./execute.sh
+
+To run just one executable, pass its name to the script:
+
+ ./execute.sh dali-adaptor
+
+ ./execute.sh dali-adaptor-internal
+
+ ./execute.sh dali-platform-abstraction
+
+To view the results of a test run, execute the following line:
+
+ firefox --new-window summary.xml
--- /dev/null
+% Images for Dali Adaptor Automated Testing
+
+Images used in automated tests for the dali-adaptor project.
+These images include broken files to test error handling as well as valid
+images.
+
+Truncated files are an interesting case and are a plausible consequence of IO
+errors such as network disconnection during downloading of an image by an
+application.
+Some image codecs can sometimes deliver a partial image for such a truncated
+file.
+It is thus a policy decision for us whether to return an image like this to the
+application, to show some junk to the user, or suppress it as a failed load,
+and these tests should demonstrate that that policy is applied for all relevant
+formats.
+
+
Version: 0.1
Release: 0
Group: Development/Tools
-License: Apache License, Version 2.0, Samsung Properietary
+License: Apache License, Version 2.0
Source0: %{name}-%{version}.tar.gz
Requires: dali-adaptor
Requires: dali
BuildRequires: dali-integration-devel
BuildRequires: pkgconfig(dali-core)
BuildRequires: pkgconfig(dali)
+BuildRequires: boost-devel
BuildRequires: libxml2-devel
BuildRequires: cmake
+BuildRequires: pkgconfig(utilX)
+BuildRequires: pkgconfig(ecore)
%description
Core API unit TC (%{name})
--- /dev/null
+%define MODULE_NAME dali-platform-abstraction
+%define MODULE_LIBNAME dali-platform-abstraction
+Name: core-%{MODULE_NAME}-tests
+Summary: Core API unit TC (%{name})
+Version: 0.1
+Release: 0
+Group: Development/Tools
+License: Apache License, Version 2.0
+Source0: %{name}-%{version}.tar.gz
+Requires: dali-adaptor
+Requires: dali
+BuildRequires: dali-integration-devel
+BuildRequires: pkgconfig(dali-core)
+BuildRequires: pkgconfig(dali)
+BuildRequires: boost-devel
+BuildRequires: libxml2-devel
+BuildRequires: cmake
+
+
+%description
+Core API unit TC (%{name})
+
+%prep
+%setup -q
+
+%build
+
+%define PREFIX "%{_libdir}/%{name}"
+
+export LDFLAGS+="-Wl,--rpath=%{PREFIX} -Wl,--as-needed"
+cd automated-tests
+cmake . -DMODULE="%{MODULE_NAME}" -DCMAKE_INSTALL_PREFIX=%{_prefix}
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+cd automated-tests
+%make_install
+mkdir -p %{buildroot}/opt/usr/share/license
+cp %{_builddir}/%{name}-%{version}/LICENSE %{buildroot}/opt/usr/share/license/%{name}
+mkdir -p %{buildroot}/tmp/
+cp %{_builddir}/%{name}-%{version}/automated-tests/scripts/add_all_smack_rule.sh %{buildroot}/tmp/
+cp %{_builddir}/%{name}-%{version}/automated-tests/scripts/all_smack.rule %{buildroot}/tmp/
+
+%post
+
+%postun
+
+
+%files
+/opt/usr/bin/*
+/opt/usr/share/license/%{name}
+/tmp/add_all_smack_rule.sh
+/tmp/all_smack.rule
--- /dev/null
+SET(PKG_NAME "dali-platform-abstraction")
+
+SET(EXEC_NAME "tct-${PKG_NAME}-core")
+SET(RPM_NAME "core-${PKG_NAME}-tests")
+
+SET(CAPI_LIB "dali-platform-abstraction")
+
+SET(TC_SOURCES
+ utc-image-loading.cpp
+)
+
+LIST(APPEND TC_SOURCES
+ resource-collector.cpp
+ ../dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.cpp
+ tct-dali-platform-abstraction-core.cpp
+)
+
+PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
+ dali-core
+ dali
+)
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -ggdb --coverage -Wall -Werror=return-type" )
+
+# Shouldn't have to do this!
+# But CMake's new auto-escape quote policy doesn't work right.
+CMAKE_POLICY(SET CMP0005 OLD)
+ADD_DEFINITIONS(-DTEST_IMAGE_DIR=\"\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../images\\\"\" )
+
+FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
+ SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
+ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS})
+
+INCLUDE_DIRECTORIES(
+ ${${CAPI_LIB}_INCLUDE_DIRS}
+ ../dali-adaptor/dali-test-suite-utils
+ ../../../adaptors/tizen
+ ../../../platform-abstractions/slp
+ ../../../
+ /usr/include/freetype2
+)
+
+ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp ${TC_SOURCES})
+TARGET_LINK_LIBRARIES(${EXEC_NAME}
+ ${${CAPI_LIB}_LIBRARIES}
+)
+
+INSTALL(PROGRAMS ${EXEC_NAME}
+ DESTINATION ${BIN_DIR}/${EXEC_NAME}
+)
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "resource-collector.h"
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Platform
+{
+using namespace Dali::Integration;
+
+ResourceCollector::ResourceCollector() :
+ mGrandTotalCompletions(0)
+{
+}
+
+ResourceCollector::~ResourceCollector() {}
+
+void ResourceCollector::LoadResponse( Dali::Integration::ResourceId id, Dali::Integration::ResourceTypeId type, Dali::Integration::ResourcePointer resource, Dali::Integration::LoadStatus status )
+{
+ if( status == RESOURCE_COMPLETELY_LOADED )
+ {
+ DALI_ASSERT_DEBUG( mCompletionCounts.find(id) == mCompletionCounts.end() && "A resource can only complete once." );
+ mCompletionStatuses[id] = true;
+ ++mCompletionCounts[id];
+ ++mSuccessCounts[id];
+ mCompletionSequence.push_back( id );
+ ++mGrandTotalCompletions;
+ }
+}
+
+void ResourceCollector::LoadFailed( Dali::Integration::ResourceId id, Dali::Integration::ResourceFailure failure )
+{
+ mCompletionStatuses[id] = false;
+ ++mFailureCounts[id];
+ mCompletionSequence.push_back( id );
+ ++mGrandTotalCompletions;
+}
+
+
+} /* namespace Platform */
+} /* namespace Internal */
+} /* namespace Dali */
--- /dev/null
+#ifndef __DALI_ADAPTOR_TCT_RESOURCE_COLLECTOR_H_
+#define __DALI_ADAPTOR_TCT_RESOURCE_COLLECTOR_H_
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <dali/dali.h>
+#include <dali/integration-api/resource-cache.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Platform
+{
+ /** Stores true for success and false for a failure for each completed
+ * resource id.*/
+ typedef std::map<Integration::ResourceId, bool> ResourceStatusMap;
+ /** Stores an integer counter for a resource ID, e.g., to count the number of
+ * times a load or a fail is reported.*/
+ typedef std::map<Integration::ResourceId, unsigned> ResourceCounterMap;
+ /** Used to track the order in which a sequence of requests is completed.*/
+ typedef std::vector<Integration::ResourceId> ResourceSequence;
+
+/**
+ * @brief Used for platform testing to record the result of resource requests
+ * initiated by tests.
+ */
+class ResourceCollector : public Integration::ResourceCache
+{
+public:
+
+ ResourceCollector();
+ virtual ~ResourceCollector();
+
+ virtual void LoadResponse(Dali::Integration::ResourceId id, Dali::Integration::ResourceTypeId type, Dali::Integration::ResourcePointer resource, Dali::Integration::LoadStatus status);
+
+ virtual void SaveComplete(Dali::Integration::ResourceId id, Dali::Integration::ResourceTypeId type) {}
+
+ virtual void LoadFailed(Dali::Integration::ResourceId id, Dali::Integration::ResourceFailure failure);
+
+ virtual void SaveFailed(Dali::Integration::ResourceId id, Dali::Integration::ResourceFailure failure) {}
+
+ // Data:
+ /** Record of the status of each completed resource. */
+ ResourceStatusMap mCompletionStatuses;
+ /** Record of how many times each resource completed (every value should be 1,
+ * else we are broken). */
+ ResourceCounterMap mCompletionCounts;
+ /** Record of how many times each resource succeeded (every value should be 0 or
+ * 1, else we are broken). */
+ ResourceCounterMap mSuccessCounts;
+ /** Record of how many times each resource failed (every value should be 0 or 1,
+ * else we are broken).
+ * Only resource IDs that correspond to deliberately unloadable resources
+ * should have counts other than 0. */
+ ResourceCounterMap mFailureCounts;
+ /** Remember the order of request completions so request priority can be tested. */
+ ResourceSequence mCompletionSequence;
+ /** Count of all successes and failures.*/
+ unsigned mGrandTotalCompletions;
+
+};
+
+} /* namespace Platform */
+} /* namespace Internal */
+} /* namespace Dali */
+
+#endif /* __DALI_ADAPTOR_TCT_RESOURCE_COLLECTOR_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include "tct-dali-platform-abstraction-core.h"
+
+int main(int argc, const char *argv[])
+{
+ int result = -1;
+ int i;
+
+ if (argc != 2) {
+ printf("Usage: %s <testcase name>\n", argv[0]);
+ return 2;
+ }
+
+ for (i = 0; tc_array[i].name; i++) {
+ if (!strcmp(argv[1], tc_array[i].name)) {
+ if (tc_array[i].startup)
+ tc_array[i].startup();
+
+ result = tc_array[i].function();
+
+ if (tc_array[i].cleanup)
+ tc_array[i].cleanup();
+
+ return result;
+ }
+ }
+
+ printf("Unknown testcase name: \"%s\"\n", argv[1]);
+ return 2;
+}
--- /dev/null
+#ifndef __TCT_DALI_PLATFORM_ABSTRACTION_CORE_H__
+#define __TCT_DALI_PLATFORM_ABSTRACTION_CORE_H__
+
+#include "testcase.h"
+
+extern void utc_dali_loading_startup(void);
+extern void utc_dali_loading_cleanup(void);
+
+extern int UtcDaliLoadCompletion(void);
+
+testcase tc_array[] = {
+ {"UtcDaliLoadCompletion", UtcDaliLoadCompletion, utc_dali_loading_startup, utc_dali_loading_cleanup},
+ {NULL, NULL}
+};
+
+#endif // __TCT_DALI_PLATFORM_ABSTRACTION_CORE_H__
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <dali/dali.h>
+#include <dali-test-suite-utils.h>
+#include "slp-platform-abstraction.h"
+#include "resource-collector.h"
+
+using namespace Dali;
+using namespace Dali::Integration;
+using namespace Dali::Internal::Platform;
+
+namespace
+{
+/**
+ * The number of loads issued in test cases is a multiple of this. The higher it
+ * is, the more the tests stress the system but the longer they take to run.
+ * A value of 1000 is enough to make load tests take tens of seconds each
+ * on desktop. */
+const unsigned NUM_LOAD_GROUPS_TO_ISSUE = 200;
+/** The number of times to ask for resource load status. */
+const unsigned MAX_NUM_RESOURCE_TRIES = 5;
+
+/** Images that should load without issue. */
+const char* const VALID_IMAGES[] = {
+ TEST_IMAGE_DIR "/frac.jpg",
+ TEST_IMAGE_DIR "/frac.24.bmp",
+ TEST_IMAGE_DIR "/frac.png",
+ TEST_IMAGE_DIR "/interlaced.gif",
+ TEST_IMAGE_DIR "/pattern.gif"
+};
+const unsigned NUM_VALID_IMAGES = 5u;
+
+
+///@ToDo: Add valid ktx, ico, and wbmp image examples.
+
+/** Live platform abstraction recreated for each test case. */
+Integration::PlatformAbstraction * gAbstraction = 0;
+
+} // anon namespace
+
+void utc_dali_loading_startup(void)
+{
+ test_return_value = TET_UNDEF;
+ gAbstraction = CreatePlatformAbstraction();
+}
+
+void utc_dali_loading_cleanup(void)
+{
+ delete gAbstraction;
+ gAbstraction = 0;
+
+ test_return_value = TET_PASS;
+}
+
+// Positive test case for loading. Load lots and be sure it has succeeded.
+int UtcDaliLoadCompletion(void)
+{
+ tet_printf("Running load completion test \n");
+
+ DALI_ASSERT_ALWAYS( gAbstraction != 0 );
+
+ // Start a bunch of loads that should work:
+
+ const Dali::ImageAttributes attributes;
+ const Dali::Integration::BitmapResourceType bitmapResourceType( attributes );
+ Dali::Integration::LoadResourcePriority priority = Dali::Integration::LoadPriorityNormal;
+ unsigned loadsLaunched = 0;
+
+ for( unsigned loadGroup = 0; loadGroup < NUM_LOAD_GROUPS_TO_ISSUE; ++loadGroup )
+ {
+ for( unsigned validImage = 0; validImage < NUM_VALID_IMAGES; ++validImage )
+ {
+ gAbstraction->LoadResource( ResourceRequest( loadGroup * NUM_VALID_IMAGES + validImage + 1, bitmapResourceType, VALID_IMAGES[validImage], priority ) );
+ }
+ loadsLaunched += NUM_VALID_IMAGES;
+ }
+
+ // Drain the completed loads:
+
+ Dali::Internal::Platform::ResourceCollector resourceSink;
+
+ for( unsigned i = 0; i < MAX_NUM_RESOURCE_TRIES && resourceSink.mGrandTotalCompletions < loadsLaunched; ++i )
+ {
+ sleep( 1 );
+ gAbstraction->GetResources( resourceSink );
+ }
+
+ // Check the loads completed as expected:
+
+ tet_printf( "Issued Loads: %u, Completed Loads: %u, Successful Loads: %u, Failed Loads: %u \n", loadsLaunched, resourceSink.mGrandTotalCompletions, unsigned(resourceSink.mSuccessCounts.size()), unsigned(resourceSink.mFailureCounts.size()) );
+ DALI_TEST_CHECK( loadsLaunched == resourceSink.mGrandTotalCompletions );
+ DALI_TEST_CHECK( loadsLaunched == resourceSink.mSuccessCounts.size() );
+ DALI_TEST_CHECK( 0 == resourceSink.mFailureCounts.size() );
+
+ // Check that each success was reported exactly once:
+ for(ResourceCounterMap::const_iterator it = resourceSink.mSuccessCounts.begin(), end = resourceSink.mSuccessCounts.end(); it != end; ++it )
+ {
+ DALI_TEST_CHECK( it->second == 1u );
+ }
+
+ END_TEST;
+}
+
namespace
{
-const char * const IDLE_PRIORITY_ENVIRONMENT_VARIABLE_NAME = "DALI_RESOURCE_THREAD_IDLE_PRIORITY";
+const char * const IDLE_PRIORITY_ENVIRONMENT_VARIABLE_NAME = "DALI_RESOURCE_THREAD_IDLE_PRIORITY"; ///@Todo Move this to somewhere that other environment variables are declared and document it there.
} // unnamed namespace
ResourceThreadBase::ResourceThreadBase(ResourceLoader& resourceLoader)
struct sched_param sp;
sp.sched_priority = 0;
sched_setscheduler(0, SCHED_IDLE, &sp);
+ ///@ToDo: change to the corresponding Pthreads call, not this POSIX.1-2001 one with a Linux-specific argument (SCHED_IDLE): int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param);, as specified in the docs for sched_setscheduler(): http://man7.org/linux/man-pages/man2/sched_setscheduler.2.html
}
InstallLogging();