Add initial integration test famework and IMAP client session tests
This commit is contained in:
parent
3b3e0b03d1
commit
cddbb28a43
4 changed files with 283 additions and 3 deletions
53
test/README.md
Normal file
53
test/README.md
Normal 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.
|
||||||
99
test/integration/imap/client-session.vala
Normal file
99
test/integration/imap/client-session.vala
Normal 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -87,6 +87,12 @@ geary_test_client_sources = [
|
||||||
geary_resources
|
geary_resources
|
||||||
]
|
]
|
||||||
|
|
||||||
|
geary_test_integration_sources = [
|
||||||
|
'test-integration.vala',
|
||||||
|
|
||||||
|
'integration/imap/client-session.vala',
|
||||||
|
]
|
||||||
|
|
||||||
geary_test_lib_dependencies = [
|
geary_test_lib_dependencies = [
|
||||||
gee,
|
gee,
|
||||||
gio,
|
gio,
|
||||||
|
|
@ -103,7 +109,7 @@ geary_test_client_dependencies = [
|
||||||
]
|
]
|
||||||
geary_test_client_dependencies += geary_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,
|
geary_test_lib_sources,
|
||||||
dependencies: geary_test_lib_dependencies,
|
dependencies: geary_test_lib_dependencies,
|
||||||
include_directories: config_h_dir,
|
include_directories: config_h_dir,
|
||||||
|
|
@ -111,7 +117,7 @@ geary_test_lib = static_library('geary-test-lib',
|
||||||
c_args: geary_c_options,
|
c_args: geary_c_options,
|
||||||
)
|
)
|
||||||
|
|
||||||
geary_test_engine_bin = executable('geary-test-engine',
|
geary_test_engine_bin = executable('test-engine',
|
||||||
geary_test_engine_sources,
|
geary_test_engine_sources,
|
||||||
link_with: geary_test_lib,
|
link_with: geary_test_lib,
|
||||||
dependencies: geary_test_engine_dependencies,
|
dependencies: geary_test_engine_dependencies,
|
||||||
|
|
@ -120,7 +126,7 @@ geary_test_engine_bin = executable('geary-test-engine',
|
||||||
c_args: geary_c_options,
|
c_args: geary_c_options,
|
||||||
)
|
)
|
||||||
|
|
||||||
geary_test_client_bin = executable('geary-test-client',
|
geary_test_client_bin = executable('test-client',
|
||||||
geary_test_client_sources,
|
geary_test_client_sources,
|
||||||
dependencies: geary_test_client_dependencies,
|
dependencies: geary_test_client_dependencies,
|
||||||
link_with: geary_test_lib,
|
link_with: geary_test_lib,
|
||||||
|
|
@ -129,5 +135,20 @@ geary_test_client_bin = executable('geary-test-client',
|
||||||
c_args: geary_c_options,
|
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('engine-tests', geary_test_engine_bin)
|
||||||
test('client-tests', geary_test_client_bin)
|
test('client-tests', geary_test_client_bin)
|
||||||
|
|
|
||||||
107
test/test-integration.vala
Normal file
107
test/test-integration.vala
Normal 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()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue