|
|
|
@ -1,78 +1,156 @@
|
|
|
|
|
package foundation.pEp.jniadapter.test.jni135;
|
|
|
|
|
|
|
|
|
|
import foundation.pEp.jniadapter.Blob;
|
|
|
|
|
import foundation.pEp.jniadapter.Engine;
|
|
|
|
|
import foundation.pEp.jniadapter.Message;
|
|
|
|
|
import foundation.pEp.jniadapter.decrypt_message_Return;
|
|
|
|
|
import foundation.pEp.jniadapter.test.utils.CTXBase;
|
|
|
|
|
import foundation.pEp.jniadapter.*;
|
|
|
|
|
import foundation.pEp.jniadapter.test.utils.AdapterTestUtils;
|
|
|
|
|
import foundation.pEp.jniadapter.test.utils.model.Role;
|
|
|
|
|
import foundation.pEp.jniadapter.test.utils.model.TestModel;
|
|
|
|
|
import foundation.pEp.jniadapter.test.utils.model.TestNode;
|
|
|
|
|
import foundation.pEp.jniadapter.test.utils.model.pEpTestIdentity;
|
|
|
|
|
import foundation.pEp.pitytest.AbstractTestContext;
|
|
|
|
|
import foundation.pEp.pitytest.TestSuite;
|
|
|
|
|
import foundation.pEp.pitytest.TestUnit;
|
|
|
|
|
import foundation.pEp.pitytest.utils.TestUtils;
|
|
|
|
|
|
|
|
|
|
import java.lang.ref.WeakReference;
|
|
|
|
|
import java.util.Vector;
|
|
|
|
|
|
|
|
|
|
import static foundation.pEp.pitytest.TestLogger.log;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Test for JNI-135 - Heavy memory consumption - memory leaks
|
|
|
|
|
relates to:
|
|
|
|
|
* JNI-148 - Mem-mgmt: Defined behaviour of Message.close()
|
|
|
|
|
* JNI-160 - Mem-mgmt: Resource Instrumentation for class Message
|
|
|
|
|
|
|
|
|
|
We are simply encrypting and decrypting in a cycles with 2 own identities alice and bob.
|
|
|
|
|
The idea is that you fire up your mem-monitoring tool of choice and convince yourself about the
|
|
|
|
|
reality of the amount leaked memory in relation to the number of cycles.
|
|
|
|
|
|
|
|
|
|
Since JNI-160, this test also prints the result of Message.getInstanceCount(). Please see ticket for more details.
|
|
|
|
|
|
|
|
|
|
This test suite proofs 3 things:
|
|
|
|
|
* If you ignore mem-mgmt, you WILL leak memory
|
|
|
|
|
* If you do mem-mgmt right, you DONT leak memory
|
|
|
|
|
* If you lost all references to an unreleased message obj, it will be unreleasable forever.
|
|
|
|
|
|
|
|
|
|
To experiment with this, you can run a single test only and make use of the options:
|
|
|
|
|
* repeatCount - how many iterations/cycles
|
|
|
|
|
* msgSizeMB - attachement size of one message
|
|
|
|
|
* EncFormat - the encryption format
|
|
|
|
|
|
|
|
|
|
To run a single test only, comment out the last line:
|
|
|
|
|
"TestSuite.getDefault().run();"
|
|
|
|
|
|
|
|
|
|
and run the TestUnit directly using TestUnit.run():
|
|
|
|
|
|
|
|
|
|
new TestUnit<ctxtype>("bla", new ctxType(), ctx -> {
|
|
|
|
|
// code
|
|
|
|
|
}).run();
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// FOR TEST CONFIG DO NOT TWEAK HERE, THESE ARE DEFAULTS
|
|
|
|
|
class Jni135TestContext extends AbstractTestContext {
|
|
|
|
|
// Model
|
|
|
|
|
public TestModel<pEpTestIdentity, TestNode<pEpTestIdentity>> model = new TestModel(pEpTestIdentity::new, TestNode::new);
|
|
|
|
|
|
|
|
|
|
// Basic
|
|
|
|
|
public Engine engine;
|
|
|
|
|
|
|
|
|
|
// Identities
|
|
|
|
|
public Identity alice;
|
|
|
|
|
public Identity bob;
|
|
|
|
|
|
|
|
|
|
// Test config defaults
|
|
|
|
|
public int repeatCount = 2000;
|
|
|
|
|
public int msgSizeMB = 1;
|
|
|
|
|
public Message.EncFormat encFormat = Message.EncFormat.PEPEncInlineEA;
|
|
|
|
|
|
|
|
|
|
public Jni135TestContext init() throws Throwable {
|
|
|
|
|
engine = new Engine();
|
|
|
|
|
// fetch data for the idents
|
|
|
|
|
alice = model.getIdent(Role.ALICE).pEpIdent;
|
|
|
|
|
bob = model.getIdent(Role.BOB).pEpIdent;
|
|
|
|
|
|
|
|
|
|
// create keys etc..
|
|
|
|
|
alice = engine.myself(alice);
|
|
|
|
|
bob = engine.myself(bob);
|
|
|
|
|
|
|
|
|
|
class Jni135TestContext extends CTXBase {
|
|
|
|
|
@Override
|
|
|
|
|
public CTXBase init() throws Throwable {
|
|
|
|
|
super.init();
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class TestAlice {
|
|
|
|
|
public static void gc() {
|
|
|
|
|
// log("gc start");
|
|
|
|
|
Object obj = new Object();
|
|
|
|
|
WeakReference ref = new WeakReference<Object>(obj);
|
|
|
|
|
obj = null;
|
|
|
|
|
while (ref.get() != null) {
|
|
|
|
|
System.gc();
|
|
|
|
|
public static void proofLeakNonLeak(Jni135TestContext ctx, boolean wannaLeak) {
|
|
|
|
|
int cycles = 0;
|
|
|
|
|
while (cycles < ctx.repeatCount) {
|
|
|
|
|
Message msg1Plain = AdapterTestUtils.makeNewTestMessage(ctx.alice, ctx.bob, Message.Direction.Outgoing);
|
|
|
|
|
Blob bigBlob = AdapterTestUtils.makeNewTestBlob(ctx.msgSizeMB * 1024 * 1024, "atti1", "text/plain");
|
|
|
|
|
Vector<Blob> atts = new Vector<Blob>();
|
|
|
|
|
atts.add(bigBlob);
|
|
|
|
|
msg1Plain.setAttachments(atts);
|
|
|
|
|
|
|
|
|
|
Message msg1Enc = ctx.engine.encrypt_message(msg1Plain, null, ctx.encFormat);
|
|
|
|
|
decrypt_message_Return decRet = ctx.engine.decrypt_message(msg1Enc, null, 0);
|
|
|
|
|
assert decRet != null : "could not decrypt message";
|
|
|
|
|
|
|
|
|
|
if (!wannaLeak) {
|
|
|
|
|
decRet.dst.close();
|
|
|
|
|
msg1Enc.close();
|
|
|
|
|
msg1Plain.close();
|
|
|
|
|
log("cycle nr: " + cycles++ + " / Message.getInstanceCount(): " + Message.getInstanceCount());
|
|
|
|
|
assert Message.getInstanceCount() == 0 : "Leaking messages";
|
|
|
|
|
} else {
|
|
|
|
|
log("cycle nr: " + cycles++ + " / Message.getInstanceCount(): " + Message.getInstanceCount());
|
|
|
|
|
assert Message.getInstanceCount() > 0 : "We should be leaking messages, actually";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// log("gc end");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
|
|
|
// TestUtils.readKey();
|
|
|
|
|
TestSuite.getDefault().setVerbose(true);
|
|
|
|
|
TestSuite.getDefault().setTestColor(TestUtils.TermColor.GREEN);
|
|
|
|
|
CTXBase jni135Ctx = new Jni135TestContext();
|
|
|
|
|
|
|
|
|
|
Engine.setDebugLogEnabled(false);
|
|
|
|
|
|
|
|
|
|
new TestUnit<CTXBase>("setDir() == getDir() ", new Jni135TestContext(), ctx -> {
|
|
|
|
|
ctx.alice = ctx.engine.myself(ctx.alice);
|
|
|
|
|
ctx.bob = ctx.engine.myself(ctx.bob);
|
|
|
|
|
|
|
|
|
|
int cycles = 0;
|
|
|
|
|
while (true) {
|
|
|
|
|
Message msg1Plain = AdapterTestUtils.makeNewTestMessage(ctx.alice, ctx.bob, Message.Direction.Outgoing);
|
|
|
|
|
Blob bigBlob = AdapterTestUtils.makeNewTestBlob(10000000, "atti1", "text/plain");
|
|
|
|
|
Vector<Blob> atts = new Vector<Blob>();
|
|
|
|
|
atts.add(bigBlob);
|
|
|
|
|
msg1Plain.setAttachments(atts);
|
|
|
|
|
|
|
|
|
|
if (false) {
|
|
|
|
|
Message msg1Enc = ctx.engine.encrypt_message(msg1Plain, null, Message.EncFormat.PEP);
|
|
|
|
|
decrypt_message_Return decRet = ctx.engine.decrypt_message(msg1Enc, null, 0);
|
|
|
|
|
|
|
|
|
|
assert decRet != null : "could not decrypt message";
|
|
|
|
|
// decRet.dst.close();
|
|
|
|
|
// msg1Enc.close();
|
|
|
|
|
// gc();
|
|
|
|
|
// msg1Plain.close();
|
|
|
|
|
}
|
|
|
|
|
log("cycles: " + cycles++);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}).run();
|
|
|
|
|
{
|
|
|
|
|
Jni135TestContext ctxDontLeak = new Jni135TestContext();
|
|
|
|
|
// Config
|
|
|
|
|
ctxDontLeak.repeatCount = 3;
|
|
|
|
|
ctxDontLeak.msgSizeMB = 1;
|
|
|
|
|
|
|
|
|
|
new TestUnit<Jni135TestContext>("Proof leaking messages ", ctxDontLeak, ctx -> {
|
|
|
|
|
proofLeakNonLeak(ctx, false);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
Jni135TestContext ctxDoLeak = new Jni135TestContext();
|
|
|
|
|
// Config
|
|
|
|
|
ctxDoLeak.repeatCount = 3;
|
|
|
|
|
ctxDoLeak.msgSizeMB = 1;
|
|
|
|
|
|
|
|
|
|
new TestUnit<Jni135TestContext>("Proof NOT leaking messages ", ctxDoLeak, ctx -> {
|
|
|
|
|
proofLeakNonLeak(ctx, true);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TestSuite.getDefault().run();
|
|
|
|
|
{
|
|
|
|
|
Jni135TestContext ctxLostRefs = new Jni135TestContext();
|
|
|
|
|
// Config
|
|
|
|
|
ctxLostRefs.repeatCount = 3;
|
|
|
|
|
ctxLostRefs.msgSizeMB = 1;
|
|
|
|
|
|
|
|
|
|
new TestUnit<Jni135TestContext>("Lost refs cant be recovered", ctxLostRefs, ctx -> {
|
|
|
|
|
try {
|
|
|
|
|
proofLeakNonLeak(ctx, false);
|
|
|
|
|
assert false : "Lost references to message objects should never be recoverable";
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
}
|
|
|
|
|
// To run one individual test only
|
|
|
|
|
})//.run(); // comment this in
|
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
// AND
|
|
|
|
|
TestSuite.getDefault().run(); // comment this out
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|