geary/test/engine/imap-engine/account-processor-test.vala
Michael Gratton 2030b2dec7 test: Break out engine mock objects into their own name-space
Engine mocks don't need to be in the `Geary` namespace, and including
them there makes it difficult to use them in client tests, so put them
all in their own name-space and corresponding directory.
2020-08-13 19:51:33 +10:00

184 lines
5 KiB
Vala

/*
* Copyright 2017 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.
*/
errordomain AccountProcessorTestError {
TEST;
}
public class Geary.ImapEngine.AccountProcessorTest : TestCase {
public class TestOperation : AccountOperation {
public bool throw_error = false;
public bool wait_for_cancel = false;
public bool execute_called = false;
private Nonblocking.Spinlock spinlock = new Nonblocking.Spinlock();
internal TestOperation(Geary.Account account) {
base(account);
}
public override async void execute(Cancellable cancellable)
throws Error {
this.execute_called = true;
if (this.wait_for_cancel) {
yield this.spinlock.wait_async(cancellable);
}
if (this.throw_error) {
throw new AccountProcessorTestError.TEST("Failed");
}
}
}
public class OtherOperation : TestOperation {
internal OtherOperation(Geary.Account account) {
base(account);
}
}
private AccountProcessor? processor = null;
private Geary.Account? account = null;
private Geary.AccountInformation? info = null;
private uint succeeded;
private uint failed;
private uint completed;
public AccountProcessorTest() {
base("Geary.ImapEngine.AccountProcessorTest");
add_test("success", success);
add_test("failure", failure);
add_test("duplicate", duplicate);
add_test("stop", stop);
}
public override void set_up() {
this.info = new Geary.AccountInformation(
"test-info",
ServiceProvider.OTHER,
new Mock.CredentialsMediator(),
new RFC822.MailboxAddress(null, "test1@example.com")
);
this.account = new Mock.Account(this.info);
this.processor = new AccountProcessor();
this.succeeded = 0;
this.failed = 0;
this.completed = 0;
}
public override void tear_down() {
this.processor.stop();
this.processor = null;
this.account = null;
this.info = null;
this.succeeded = 0;
this.failed = 0;
this.completed = 0;
}
public void success() throws Error {
TestOperation op = setup_operation(new TestOperation(this.account));
this.processor.enqueue(op);
assert(this.processor.waiting == 1);
execute_all();
assert(op.execute_called);
assert(this.succeeded == 1);
assert(this.failed == 0);
assert(this.completed == 1);
}
public void failure() throws Error {
TestOperation op = setup_operation(new TestOperation(this.account));
op.throw_error = true;
AccountOperation? error_op = null;
Error? error = null;
this.processor.operation_error.connect((proc, op, err) => {
error_op = op;
error = err;
});
this.processor.enqueue(op);
execute_all();
assert(this.succeeded == 0);
assert(this.failed == 1);
assert(this.completed == 1);
assert(error_op == op);
assert(error is AccountProcessorTestError.TEST);
}
public void duplicate() throws Error {
TestOperation op1 = setup_operation(new TestOperation(this.account));
TestOperation op2 = setup_operation(new TestOperation(this.account));
TestOperation op3 = setup_operation(new OtherOperation(this.account));
this.processor.enqueue(op1);
this.processor.enqueue(op2);
assert(this.processor.waiting == 1);
this.processor.enqueue(op3);
assert(this.processor.waiting == 2);
}
public void stop() throws Error {
TestOperation op1 = setup_operation(new TestOperation(this.account));
op1.wait_for_cancel = true;
TestOperation op2 = setup_operation(new OtherOperation(this.account));
this.processor.enqueue(op1);
this.processor.enqueue(op2);
while (!this.processor.is_executing) {
this.main_loop.iteration(true);
}
this.processor.stop();
while (this.main_loop.pending()) {
this.main_loop.iteration(true);
}
assert(!this.processor.is_executing);
assert(this.processor.waiting == 0);
assert(this.succeeded == 0);
assert(this.failed == 1);
assert(this.completed == 1);
}
private TestOperation setup_operation(TestOperation op) {
op.succeeded.connect(() => {
this.succeeded++;
});
op.failed.connect(() => {
this.failed++;
});
op.completed.connect(() => {
this.completed++;
});
return op;
}
private void execute_all() {
while (this.processor.is_executing || this.processor.waiting > 0) {
this.main_loop.iteration(true);
}
}
}