Add initial integration test famework and IMAP client session tests

This commit is contained in:
Michael Gratton 2019-03-31 01:42:08 +11:00
parent 3b3e0b03d1
commit cddbb28a43
4 changed files with 283 additions and 3 deletions

53
test/README.md Normal file
View file

@ -0,0 +1,53 @@
Automated Test Infrastructure
=============================
Geary currently supports three types of automated tests:
* Engine unit tests
* Client (GTK and JavaScript) unit tests
* Server integration tests
Unit tests
----------
Unit tests test individual functions, in general avoid doing any I/O
so they are fast, and can be run automatically.
The engine and client unit tests are hooked up to the Meson build, so
you can use Meson's test infrastructure to build and run them. These
are run automatically as part of the Gitlab CI process and if you use
the development Makefile, you can execute them locally by simply
calling:
make test
The engine tests can be run headless (i.e. without an X11 or Wayland
session), but the client tests require a functioning display since
they execute GTK code.
Integration tests
-----------------
Integration tests run Geary's network code against actual servers, to
ensure that the code also works in the real world.
The integration tests are built by default, but not currently hooked
up to Meson and are not automatically run by Gitlab CI, since they
require multiple working servers, network connection to the servers,
and login credentials.
You can run them manually however against any server you have a test
account on, using the following form:
build/test/test-integration PROTOCOL PROVIDER [HOSTNAME] LOGIN PASSWORD
For example, to test against GMail's IMAP service:
build/test/test-integration imap gmail test@gmail.com p455w04d
If `PROVIDER` is `other`, then `HOSTNAME` is required.
The easiest way to test against a number of different servers at the
moment is to create a test account for each, then write a shell script
or similar to execute the tests against each in turn.

View file

@ -0,0 +1,99 @@
/*
* Copyright 2019 Michael Gratton <mike@vee.net>
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
*/
class Integration.Imap.ClientSession : TestCase {
private Configuration config;
private Geary.Imap.ClientSession? session;
public ClientSession(Configuration config) {
base("Integration.Imap.ClientSession");
this.config = config;
add_test("session_connect", session_connect);
add_test("login_password_invalid", login_password_invalid);
if (config.provider == GMAIL ||
config.provider == OUTLOOK) {
add_test("login_oauth2_invalid", login_oauth2_invalid);
}
add_test("initiate_session", initiate_session);
}
public override void set_up() {
this.session = new Geary.Imap.ClientSession(
this.config.target
);
}
public override void tear_down() throws GLib.Error {
if (this.session.get_protocol_state(null) != UNCONNECTED) {
this.session.disconnect_async.begin(null, async_complete_full);
this.session.disconnect_async.end(async_result());
}
this.session = null;
}
public void session_connect() throws GLib.Error {
this.session.connect_async.begin(null, async_complete_full);
this.session.connect_async.end(async_result());
this.session.disconnect_async.begin(null, async_complete_full);
this.session.disconnect_async.end(async_result());
}
public void login_password_invalid() throws GLib.Error {
do_connect();
Geary.Credentials password_creds = new Geary.Credentials(
PASSWORD, "automated-integration-test", "password"
);
this.session.login_async.begin(
password_creds, null, async_complete_full
);
try {
this.session.login_async.end(async_result());
assert_not_reached();
} catch (Geary.ImapError.UNAUTHENTICATED err) {
// All good
}
}
public void login_oauth2_invalid() throws GLib.Error {
do_connect();
Geary.Credentials oauth2_creds = new Geary.Credentials(
OAUTH2, "automated-integration-test", "password"
);
this.session.login_async.begin(
oauth2_creds, null, async_complete_full
);
try {
this.session.login_async.end(async_result());
assert_not_reached();
} catch (Geary.ImapError.UNAUTHENTICATED err) {
// All good
}
}
public void initiate_session() throws GLib.Error {
do_connect();
this.session.initiate_session_async.begin(
this.config.credentials, null, async_complete_full
);
this.session.initiate_session_async.end(async_result());
}
private void do_connect() throws GLib.Error {
this.session.connect_async.begin(null, async_complete_full);
this.session.connect_async.end(async_result());
}
}

View file

@ -87,6 +87,12 @@ geary_test_client_sources = [
geary_resources
]
geary_test_integration_sources = [
'test-integration.vala',
'integration/imap/client-session.vala',
]
geary_test_lib_dependencies = [
gee,
gio,
@ -103,7 +109,7 @@ geary_test_client_dependencies = [
]
geary_test_client_dependencies += geary_client_dependencies
geary_test_lib = static_library('geary-test-lib',
geary_test_lib = static_library('test-lib',
geary_test_lib_sources,
dependencies: geary_test_lib_dependencies,
include_directories: config_h_dir,
@ -111,7 +117,7 @@ geary_test_lib = static_library('geary-test-lib',
c_args: geary_c_options,
)
geary_test_engine_bin = executable('geary-test-engine',
geary_test_engine_bin = executable('test-engine',
geary_test_engine_sources,
link_with: geary_test_lib,
dependencies: geary_test_engine_dependencies,
@ -120,7 +126,7 @@ geary_test_engine_bin = executable('geary-test-engine',
c_args: geary_c_options,
)
geary_test_client_bin = executable('geary-test-client',
geary_test_client_bin = executable('test-client',
geary_test_client_sources,
dependencies: geary_test_client_dependencies,
link_with: geary_test_lib,
@ -129,5 +135,20 @@ geary_test_client_bin = executable('geary-test-client',
c_args: geary_c_options,
)
geary_test_integration_bin = executable('test-integration',
geary_test_integration_sources,
dependencies: [
geary_engine_dep,
gee,
gio,
gmime,
webkit2gtk,
],
link_with: geary_test_lib,
include_directories: config_h_dir,
vala_args: geary_vala_options,
c_args: geary_c_options,
)
test('engine-tests', geary_test_engine_bin)
test('client-tests', geary_test_client_bin)

107
test/test-integration.vala Normal file
View file

@ -0,0 +1,107 @@
/*
* Copyright 2019 Michael Gratton <mike@vee.net>
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
*/
private const int TIMEOUT = 5;
public struct Integration.Configuration {
Geary.Protocol type;
Geary.ServiceProvider provider;
Geary.ServiceInformation service;
Geary.Endpoint target;
Geary.Credentials credentials;
}
int main(string[] args) {
/*
* Initialise all the things.
*/
Test.init(ref args);
Geary.RFC822.init();
Geary.HTML.init();
Geary.Logging.init();
Geary.Logging.log_to(stderr);
GLib.Log.set_default_handler(Geary.Logging.default_handler);
Integration.Configuration config = load_config(args);
/*
* Hook up all tests into appropriate suites
*/
TestSuite integration = new TestSuite("integration");
switch (config.type) {
case IMAP:
integration.add_suite(
new Integration.Imap.ClientSession(config).get_suite()
);
break;
}
/*
* Run the tests
*/
TestSuite root = TestSuite.get_root();
root.add_suite(integration);
MainLoop loop = new MainLoop();
int ret = -1;
Idle.add(() => {
ret = Test.run();
loop.quit();
return false;
});
loop.run();
return ret;
}
private Integration.Configuration load_config(string[] args) {
int i = 1;
try {
Geary.Protocol type = Geary.Protocol.for_value(args[i++]);
Geary.ServiceProvider provider = Geary.ServiceProvider.for_value(
args[i++]
);
Geary.ServiceInformation service = new Geary.ServiceInformation(
type, provider
);
if (provider == OTHER) {
service.host = args[i++];
service.port = service.get_default_port();
}
Geary.Credentials credentials = new Geary.Credentials(
PASSWORD, args[i++], args[i++]
);
provider.set_service_defaults(service);
Geary.Endpoint target = new Geary.Endpoint(
new NetworkAddress(service.host, service.port),
service.transport_security,
TIMEOUT
);
return { type, provider, service, target, credentials };
} catch (GLib.Error err) {
error(
"Error loading config: %s",
(new Geary.ErrorContext(err)).format_full_error()
);
}
}