This framework allows testing components without loading them into the server.
It's achieved by using the "minimal chassis" library to create a test harness to test a component and a service defined by it.
The architecture is as follows:
- The gunit test executable defines a special gmock test suite class that sets up the test harness during its construction.
 
- the main method initializes the gmock test framework and runs it.
 
The test harness consists of:
- a locally defined test harness "component" in the executable that implements mock test services that the component-under-test requires.
 
- machinery to init the minimal chassis, to load the harness component and the component under test and to fetch a reference to the service under test into a test suite member variable for the tests to use.
 
Component testing Howto
Imagine we have a component called "foo" that requires service a bar and implements a service called foo_svc. The files for this are below:
The foo files
include/mysql/components/services/service_foo.h
 
#define END_SERVICE_DEFINITION(name)
A macro to end the last Service definition started with the BEGIN_SERVICE_DEFINITION macro.
Definition: service.h:91
 
#define BEGIN_SERVICE_DEFINITION(name)
Declares a new Service.
Definition: service.h:86
 
#define DECLARE_BOOL_METHOD(name, args)
Declares a method that returns bool as a part of the Service definition.
Definition: service.h:112
 
 include/mysql/components/services/service_bar.h
components/foo/component_foo.cc
 
  return service_bar->mtd_bar(param);
}
 
  svc_foo_mtd_foo
 
 
 
 
Kerberos Client Authentication nullptr
Definition: auth_kerberos_client_plugin.cc:247
 
Specifies macros to define Components.
 
#define END_COMPONENT_REQUIRES()
A macro to end the last declaration started with the BEGIN_COMPONENT_REQUIRES.
Definition: component_implementation.h:386
 
#define PROVIDES_SERVICE(component, service)
Declare a Service Implementation provided by a Component.
Definition: component_implementation.h:194
 
#define BEGIN_COMPONENT_REQUIRES(name)
A macro to specify requirements of the component.
Definition: component_implementation.h:223
 
#define REQUIRES_SERVICE(service)
Adds a Service requirement with a pointer to placeholder to the list of components.
Definition: component_implementation.h:305
 
#define REQUIRES_SERVICE_PLACEHOLDER(service)
Create a service placeholder, based on the service name.
Definition: component_implementation.h:280
 
#define BEGIN_COMPONENT_METADATA(name)
A macro to specify metadata of the component.
Definition: component_implementation.h:397
 
#define END_COMPONENT_METADATA()
A macro to end the last declaration started with the BEGIN_COMPONENT_METADATA.
Definition: component_implementation.h:412
 
#define DECLARE_COMPONENT(source_name, name)
Declares a component.
Definition: component_implementation.h:165
 
#define END_COMPONENT_PROVIDES()
A macro to end the last declaration started with the BEGIN_COMPONENT_PROVIDES.
Definition: component_implementation.h:204
 
#define METADATA(key, value)
Adds a Service requirement with a pointer to placeholder to the list of components.
Definition: component_implementation.h:406
 
#define END_DECLARE_COMPONENT()
A macro to end the last declaration of a Component.
Definition: component_implementation.h:173
 
#define BEGIN_COMPONENT_PROVIDES(name)
Creates a service implementation list that are provided by specified component.
Definition: component_implementation.h:183
 
Specifies macros to define Service Implementations.
 
#define BEGIN_SERVICE_IMPLEMENTATION(component, service)
Declares a Service Implementation.
Definition: service_implementation.h:62
 
#define END_SERVICE_IMPLEMENTATION()
A macro to end the last declaration of a Service Implementation.
Definition: service_implementation.h:67
 
#define DEFINE_BOOL_METHOD(name, args)
A short macro to define method that returns bool, which is the most common case.
Definition: service_implementation.h:88
 
 
Build a gunit test
Since component_foo requires service_bar we need to mock service_bar.
Thus we build a mock implementation as follows:
components/libminchassis/gunit_harness/include/mock/service_bar_empty.cc
#include "mysql/components/services/service_bar.h"
 
namespace service_bar_spc {
    return false;
  }
}
 
 Now we will proceed to building a test harness "component" to embed in our test.
We will copy the template from components/libminchassis/gunit_harness/harness_component into our gunit directory components/foo/gunit and modify it as follows:
components/foo/gunit/test_harness_component.h
 
========== FILLME: Test Harness component 
name goes here ======
 
#define HARNESS_COMPONENT_NAME foo_harness
===============================================================
 
#define COMPONENT_REF(name)
Defines a reference to the specified Component data info structure.
Definition: component_implementation.h:462
 
case opt name
Definition: sslopt-case.h:29
 
Carries information on the specific Component, all Service Implementations it provides,...
Definition: dynamic_loader.h:263
 
 components/foo/gunit/test_harness_component.cc
#include "test_harness_component.h"
 
================ FILLME: Service 
mock includes go here ================
 
#include "components/libminchassis/gunit_harness/include/mock/service_bar_empty.cc"
===============================================================
 
#define STRINGIFY(x) #x
 
================ Component declaration related stuff ================
 
================ FILLME: Service 
mock refs go here ================
 
===================================================================
 
 
Definition: ha_mock.cc:144
 
#define STRINGIFY(s)
Definition: utils_string.h:576
 
 Now we can go ahead and implement our test driver:
components/foo/gunit/test_foo.cc
#include <gtest/gtest.h>
#include "mysql/components/services/mysql_foo.h"
#include "test_harness_component.h"
 
namespace foo_test {
 
  const char component[] = "component_foo";
  const char service[] = "service_foo";
 
  using FooTest =
 
  TEST_F(FooTest, ComponentLoaded) {
    ASSERT_NE(m_test_svc, nullptr);
    ASSERT_TRUE(m_test_svc->is_valid());
  }
 
  TEST_F(FooTest, CallFoo) {
     ASSERT_FALSE((*m_test_svc)->mtd_foo(12));
  }
}
 
int main(
int argc, 
char *argv[]) {
 
  ::testing::InitGoogleTest(&argc, argv);
  int ret = RUN_ALL_TESTS();
}
Implements a Gmock Test suite class to test a component.
Definition: test_harness_suite.h:55
 
int main(int argc, char **argv)
Definition: mysqlcheck.cc:521
 
#define SERVICE_TYPE(name)
Generates the standard Service type name.
Definition: service.h:76
 
And finally: here is the CMakeFiles.txt used for the harness component.
components/foo/gunit/CMakeLists.txt
  RETURN()
ENDIF()
 
MYSQL_ADD_EXECUTABLE(test_foo-t
  test_foo.cc
  test_harness_component.cc
  LINK_LIBRARIES gtest ${CMAKE_DL_LIBS} minchassis
                 OpenSSL::SSL OpenSSL::Crypto
  SYSTEM_INCLUDE_DIRECTORIES ${GMOCK_INCLUDE_DIRS}
  ADD_TEST test_foo-t
  COMPONENT Test)
@ IF
Definition: sql_yacc.h:283
 
 - See also
 - TestHarnessSuite_templ