domingo, 17 de septiembre de 2017

Including a Jenkins link in the crashlytics report

I've been implementing some mobile application automatic tests using appium (appium.io). We also use Jenkins (https://jenkikns.io) as continuous integration tool. We compile and test the applications as Jenkins jobs. The apps include crashlytics (https://try.crashlytics.com/) to send a report everytime the application crashes. We are thinking it would be good to know the crash report was generated by a jenkins job and have a link to the offending job, so we can access all the logs that are stored as Jenkins artifacts. This how we do it. First we obtain the job url via Jenkins environment variables. This is the python code:

jenkins_url = os.environ ("JENKINS_URL") + "/job/" + os.environ ("JOB_NAME") + \
          "/" + os.environ ("BUILD_NUMBER")
Then we instruct appium to pass this url as an environment varaible to the application as desired capabilities. iOS

args = { "args": [], "env" : { "JENKINS_URL": jenkins_url }}
desired_caps["processArguments"] = json.dumps (args)
Android

desired_caps ["optionalIntentArguments"] = '--es "android.intent.extra.JENKINS_URL" ' +  '"' + \
        jenkins_url + '"'
Then, we read the value of the variable inside application code and set it as a crashlytics key. swift (iOS):

       NSString *jenkinsUrl = environment  [@"JENKINS_URL"];
       if  (jenkinsUrl) {
            [CrashlyticsKit setObjectValue:jenkinsUrl forKey:@"JENKINS_URL"];
       }
Java (android):

Intent intent = getIntent ();
String jenkins_url = intent.getStringExtra ("android.intent.extra.JENKINS_URL");

if (jenkins_url != null) {
    Crashlytics.setString ("JENKINS_URL", jenkins_url);
}

viernes, 10 de febrero de 2017

Using two irtrans USB devices in one Ubuntu PC.

IRTrans is a little USB device to capture and send IR commands (like a remote control).

The irtrans USB device documentation states that "Individual control of multiple external transmitters is not possible". The reason for that is the provided irtrans server (irserver64) listen to two predefined ports (21000 for the irtrans protocol and 8765 for the lirc protocol). When the second server tries to bind to any of these ports it fails because the ports are already taken.

There is a workaround for this problem using docker containers. The simple idea is, we launch two servers in two separated containers and we configure these with a different IP address.

The first thing we need to do is to install docker in our Ubuntu computer. See here how to do that.

The we need to create our container. In an empty directory we copy:
  •  the irserver64 file. 
  •  the remotes/ directory, containing a number of files with the keypresses of the remotes we want to simulate. 
  • a file called Dockerfile with the following content: 


FROM ubuntu:16.04

RUN mkdir /irtrans
RUN mkdir /irtrans/remotes

COPY irserver64 /irtrans
COPY remotes/file.rem /irtrans/remotes

WORKDIR /irtrans
ENTRYPOINT ["./irserver64"]
From this directory we can compile our container with (irtrans.1 is an arbitrary name we give to our container):

dockebuild -t irtrans.1 .
Then we need to create our docker network.

docker network create --subnet=172.18.0.0/16 mynet123=
And now we can run two containers in different ip addresses. Remember to give the container access to the serial port:

docker run --net mynet123 --ip 172.18.0.22 --device=/dev/ttyUSB0 irtrans.1 /dev/ttyUSB0
docker run --net mynet123 --ip 172.18.0.23 --device=/dev/ttyUSB2 irtrans.1 /dev/ttyUSB2

domingo, 8 de enero de 2017

Qtest + google mock

The problem we are trying to solve is using google mocks with qtest. Since we don't use google test we need to replace the default event listener so we can fail the test with qt macros. We overwrite the OnTestPartResult. Then we create a macro to initialize all our tests the same way. unittest.h:
/**
 * \file
 * \brief Generic definitions for unit tests.
 */

#ifndef __UNIT_TESTS_H__
#define __UNIT_TESTS_H__

#include 
#include "gmock/gmock.h"

namespace unittests {

/**
 * \brief A class to replace qtest default event listener. 
 * 
 * The relevant thing here is the OnTestPartResult method. We need to change it
 * to fail the tests, at qtest level, when the expectations fail.
 *
 * This function gets called when we call the destructor of the mocks or the
 * ::testing::Mock::VerifyAndClearExpectations function.
 */
class GoogleTestEventListener : public ::testing::EmptyTestEventListener {
   virtual void OnTestStart(const ::testing::TestInfo&) {
   }

   virtual void OnTestPartResult(const ::testing::TestPartResult& test_part_result) {
        if (test_part_result.failed()) {
            QFAIL(
                QString("mock objects failed with '%1' at %2:%3")
                    .arg(QString(test_part_result.summary()))
                    .arg(test_part_result.file_name())
                    .arg(test_part_result.line_number())
                    .toLatin1().constData()
            );
        }
   }

   // Called after a test ends.
   virtual void OnTestEnd(const ::testing::TestInfo&) {
   }
};

} // namespace unittests

/**
 * \def INIT_GOOGLE_MOCKS (argc, argv)
 * \brief A macro that defines the unit test initialization. 
 *
 * We define the initialization process in one place.
 * This only really needed when using google mocks expectations.i.e. if your
 * test uses EXPECT_CALL.
 */
#define INIT_GOOGLE_MOCKS(argc, argv) { \
      ::testing::InitGoogleTest (&(argc), (argv)); \
      ::testing::TestEventListeners& listeners = ::testing::UnitTest::GetInstance()->listeners();  \
      delete listeners.Release(listeners.default_result_printer());\
      listeners.Append(new unittests::GoogleTestEventListener); }

#endif // __UNIT_TESTS_H__
And now an example on how to use it. First we have a class called classToTest. classToTest.h:
#ifndef __CLASS_TO_TEST__
#define __CLASS_TO_TEST__

#include "dependency.h"

class ClassToTest 
{
public:
    ClassToTest (Dependency *dep);
    ~ClassToTest ();

    int function1 (int param);
private:
    Dependency * _dependency;
};

#endif //__CLASS_TO_TEST__
classToTest.cpp:
#include "classToTest.h"

ClassToTest::ClassToTest (Dependency *dep)
{
    _dependency = dep;
}

ClassToTest::~ClassToTest ()
{
}

int ClassToTest::function1 (int param)
{
    return (_dependency->getValue (param));
}
The class uses the following dependency. dependency.h:
#ifndef __DEPENDENCY_H__
#define __DEPENDENCY_H__

class Dependency 
{
public:
    virtual int getValue (int inValue) = 0;

};

#endif // __DEPENDENCY_H__
This is how the test looks like: MyTest.h:
#ifndef __SECOND_TEST_H__
#define __SECOND_TEST_H__

#include 

class MyTest: public QObject
{
    Q_OBJECT
private slots:
    void test1 ();
};

#endif //__SECOND_TEST_H__
MyTest.cpp:
#include "classToTest.h"
#include "unittests.h"
#include "MyTest.h"
#include "gmock/gmock.h"

class MockDependency: public Dependency 
{
public:
    MOCK_METHOD1 (getValue, int (int inValue));
};

void MyTest::test1 ()
{
    MockDependency dep;

    EXPECT_CALL (dep, getValue (13))
        .Times (1)
        .WillOnce(::testing::Return(7));

    ClassToTest C (&dep);

    QCOMPARE (C.function1 (13), 7);
}

int main (int argc, char **argv)
{
    INIT_GOOGLE_MOCKS (argc, argv);

    MyTest *theTest = new MyTest ();
    return (QTest::qExec (theTest, argc, argv));
    delete theTest;
}
Finally, I've included the cmake/ctest script in case you want to compile the example. CMakeLists.txt:
cmake_minimum_required (VERSION 2.8.11)

enable_testing ()
project (ppral CXX)

add_subdirectory (googletest-master/googlemock)

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)

find_package (Qt5Core REQUIRED)
find_package (Qt5Test REQUIRED)

# Add the include directories for the Qt 5 Widgets module to
# the compile lines.
include_directories(${Qt5Core_INCLUDE_DIRS} )
include_directories(googletest-master/googlemock/include)
include_directories(googletest-master/googletest/include)
# Add compiler flags for building executables (-fPIE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS} ")

qt5_wrap_cpp (classToTest.cpp classToTest.h Dependecy.h unittests.h
 MyTest.h MyTest.cpp)

add_executable (MyTest classToTest.cpp classToTest.h MyTest.h
    MyTest.cpp unittests.h dependency.h)
target_link_libraries (MyTest ${Qt5Core_LIBRARIES} ${Qt5Test_LIBRARIES} 
    gmock gtest)
add_test (NAME MyTest COMMAND MyTest)