var chai = require("chai");
var expect = chai.expect;
var assert = chai.assert;
var Web3 = require('web3');

describe.skip('Whisper Tests', function () {
    var node1 = new Web3();
    var node2 = new Web3();
    var web3 = node1;
    node1.setProvider(new web3.providers.HttpProvider('http://localhost:8645'));
    node2.setProvider(new web3.providers.HttpProvider('http://localhost:8745'));

    console.log('Node is expected: wnode-status -datadir app1 wnode -http -httpport 8645');
    console.log('Node is expected: wnode-status -datadir app2 wnode -http -httpport 8745');
    console.log('Node is expected: wnode-status -datadir wnode1 wnode -notify -injectaccounts=false -identity ./static/keys/wnodekey -firebaseauth ./static/keys/firebaseauthkey');

    // some common vars
    var topic1 = '0xdeadbeef'; // each topic 4 bytes, as hex
    var topic2 = '0xbeefdead'; // each topic 4 bytes, as hex
    var topic3 = '0xbebebebe'; // each topic 4 bytes, as hex
    var topic4 = '0xdadadada'; // each topic 4 bytes, as hex
    var identity1 = '0x04eedbaafd6adf4a9233a13e7b1c3c14461fffeba2e9054b8d456ce5f6ebeafadcbf3dce3716253fbc391277fa5a086b60b283daf61fb5b1f26895f456c2f31ae3';
    var identity2 = '0x0490161b00f2c47542d28c2e8908e77159b1720dccceb6393d7c001850122efc3b1709bcea490fd8f5634ba1a145aa0722d86b9330b0e39a8d493cb981fd459da2';

    // watchFilter makes sure that we halt the filter on first message received
    var watchFilter = function (filter, done) {
        var messageReceived = false;
        filter.watch(function (error, message) {
            if (messageReceived)  return; // avoid double calling
            messageReceived = true; // no need to watch for the filter any more
            filter.stopWatching();
            done(error, message);
        });
    };

    // makeTopic generates random topic (4 bytes, in hex)
    var makeTopic = function () {
        var min = 1;
        var max = Math.pow(16, 8);
        var randInt = Math.floor(Math.random() * (max - min + 1)) + min;
        return web3.toHex(randInt);
    };

    context('shh/5 API verification', function () {
        it('statusd node is running', function () {
            var web3 = new Web3();
            var provider = new web3.providers.HttpProvider('http://localhost:8645');
            var result = provider.send({});
            assert.equal(typeof result, 'object');
        });

        it('shh.version()', function () {
            var version = node1.shh.version();
            assert.equal(version, '0x5', 'Whisper version does not match');
        });

        it('shh.info()', function () {
            var info = node1.shh.info();
            if (info == "") {
                throw new Error('no Whisper info provided')
            }
        });

        context('symmetric key management', function () {
            var keyId = ''; // symmetric key ID (to be populated)
            var keyVal = ''; // symmetric key value (to be populated)

            it('shh.generateSymmetricKey()', function () {
                keyId = node1.shh.generateSymmetricKey();
                assert.lengthOf(keyId, 64, 'invalid keyId length');
            });

            it('shh.getSymmetricKey(keyId)', function () {
                keyVal = node1.shh.getSymmetricKey(keyId);
                assert.lengthOf(keyVal, 66, 'invalid key value length'); // 2 bytes for "0x"
            });

            it('shh.hasSymmetricKey(keyId)', function () {
                expect(node1.shh.hasSymmetricKey(keyId)).to.equal(true);
            });

            it('shh.deleteSymmetricKey(keyId)', function () {
                expect(node1.shh.hasSymmetricKey(keyId)).to.equal(true);
                node1.shh.deleteSymmetricKey(keyId);
                expect(node1.shh.hasSymmetricKey(keyId)).to.equal(false);
            });

            it('shh.addSymmetricKeyDirect(keyVal)', function () {
                keyIdOriginal = keyId;
                keyId = node1.shh.addSymmetricKeyDirect(keyVal);
                assert.notEqual(keyId, keyIdOriginal);
                assert.lengthOf(keyId, 64, 'invalid keyId length');
                expect(node1.shh.hasSymmetricKey(keyId)).to.equal(true);
            });

            it('shh.addSymmetricKeyFromPassword(password)', function () {
                var password = 'foobar';
                var keyId = node1.shh.addSymmetricKeyFromPassword(password);
                var keyVal = node1.shh.getSymmetricKey(keyId);

                assert.lengthOf(keyId, 64, 'invalid keyId length');
                expect(node1.shh.hasSymmetricKey(keyId)).to.equal(true);
                assert.equal(keyVal, '0xa582720d74d463589df14c11538189a1c07778c47e86f70bab7b5ba27e2de3cc');
            });
        });

        context('assymmetric key management', function () {
            var keyId = ''; // to be populated
            var pubKey = ''; // to be populated

            it('shh.newKeyPair()', function () {
                keyId = node1.shh.newKeyPair();
                assert.lengthOf(keyId, 64);
            });

            it('shh.hasKeyPair(id)', function () {
                expect(node1.shh.hasKeyPair(keyId)).to.equal(true);
            });

            it('shh.getPublicKey(id)', function () {
                pubKey = node1.shh.getPublicKey(keyId);
                assert.lengthOf(pubKey, 132);
            });

            it('shh.hasKeyPair(pubKey)', function () {
                expect(node1.shh.hasKeyPair(pubKey)).to.equal(true);
            });

            it('shh.getPrivateKey(id)', function () {
                var prvkey = node1.shh.getPrivateKey(keyId);
                assert.lengthOf(prvkey, 66);
            });

            it('shh.deleteKeyPair(id)', function () {
                expect(node1.shh.hasKeyPair(pubKey)).to.equal(true);
                expect(node1.shh.hasKeyPair(keyId)).to.equal(true);
                node1.shh.deleteKeyPair(keyId);
                expect(node1.shh.hasKeyPair(pubKey)).to.equal(false);
                expect(node1.shh.hasKeyPair(keyId)).to.equal(false);

                // re-create
                keyId = node1.shh.newKeyPair();
                assert.lengthOf(keyId, 64);
                pubKey = node1.shh.getPublicKey(keyId);
                assert.lengthOf(pubKey, 132);
            });

            it('shh.deleteKeyPair(pubKey)', function () {
                expect(node1.shh.hasKeyPair(pubKey)).to.equal(true);
                expect(node1.shh.hasKeyPair(keyId)).to.equal(true);
                node1.shh.deleteKeyPair(pubKey);
                expect(node1.shh.hasKeyPair(pubKey)).to.equal(false);
                expect(node1.shh.hasKeyPair(keyId)).to.equal(false);

                // re-create
                keyId = node1.shh.newKeyPair();
                assert.lengthOf(keyId, 64);
                pubKey = node1.shh.getPublicKey(keyId);
                assert.lengthOf(pubKey, 132);
            });
        });

        context('subscribe and manually get messages', function () {
            // NOTE: you can still use shh.filter to poll for messages automatically, see other examples

            var filterid1 = ''; // sym filter, to be populated
            var filterid2 = ''; // asym filter, to be populated
            var keyId = ''; // symkey, to be populated
            var uniqueTopic = makeTopic();

            var payloadBeforeSymFilter = 'sent before filter was active (symmetric)';
            var payloadAfterSymFilter = 'sent after filter was active (symmetric)';
            var payloadBeforeAsymFilter = 'sent before filter was active (asymmetric)';
            var payloadAfterAsymFilter = 'sent after filter was active (asymmetric)';

            it('shh.subscribe(filterParams) - symmetric filter', function () {
                keyId = node1.shh.generateSymmetricKey();
                assert.lengthOf(keyId, 64);

                // send message, which will be floating around *before* filter is even created
                var message = {
                    type: "sym",
                    key: keyId,
                    topic: uniqueTopic,
                    payload: payloadBeforeSymFilter
                };
                expect(node1.shh.post(message)).to.equal(null);

                // symmetric filter
                filterid1 = node1.shh.subscribe({
                    type: "sym",
                    key: keyId,
                    sig: identity1,
                    topics: [topic1, topic2, uniqueTopic]
                });
                assert.lengthOf(filterid1, 64);
            });

            it('shh.subscribe(filterParams) - asymmetric filter', function () {
                // send message, which will be floating around *before* filter is even created
                var message = {
                    type: "asym",
                    key: identity2,
                    topic: uniqueTopic,
                    payload: payloadBeforeAsymFilter
                };
                expect(node1.shh.post(message)).to.equal(null);

                // asymmetric filter
                filterid2 = node1.shh.subscribe({
                    type: "asym",
                    key: identity2,
                    sig: identity1,
                    topics: [topic1, topic2, uniqueTopic]
                });
                assert.lengthOf(filterid1, 64);
            });

            it('shh.getFloatingMessages(filterID) - symmetric filter', function () {
                // let's try to capture message that was there *before* filter is created
                var messages = node1.shh.getFloatingMessages(filterid1);
                assert.typeOf(messages, 'array');
                assert.lengthOf(messages, 1);
                assert.equal(web3.toAscii(messages[0].payload), payloadBeforeSymFilter);

                // send message, after the filter has been already installed
                var message = {
                    type: "sym",
                    key: keyId,
                    topic: uniqueTopic,
                    payload: payloadAfterSymFilter
                };
                expect(node1.shh.post(message)).to.equal(null);
            });

            it('shh.getFloatingMessages(filterID) - asymmetric filter', function () {
                // let's try to capture message that was there *before* filter is created
                var messages = node1.shh.getFloatingMessages(filterid2);
                assert.typeOf(messages, 'array');
                assert.lengthOf(messages, 1);
                assert.equal(web3.toAscii(messages[0].payload), payloadBeforeAsymFilter);

                // send message, after the filter has been already installed
                var message = {
                    type: "asym",
                    key: identity2,
                    topic: uniqueTopic,
                    payload: payloadAfterAsymFilter
                };
                expect(node1.shh.post(message)).to.equal(null);
            });

            it('shh.getNewSubscriptionMessages(filterID) - symmetric filter', function (done) {
                // allow some time for message to propagate
                setTimeout(function () {
                    // now let's try to capture new messages from our last capture
                    var messages = node1.shh.getNewSubscriptionMessages(filterid1);
                    assert.typeOf(messages, 'array');
                    assert.lengthOf(messages, 1);
                    assert.equal(web3.toAscii(messages[0].payload), payloadAfterSymFilter);

                    // no more messages should be returned
                    messages = node1.shh.getNewSubscriptionMessages(filterid1);
                    assert.typeOf(messages, 'array');
                    assert.lengthOf(messages, 0);

                    done();
                }, 200);
            });

            it('shh.getNewSubscriptionMessages(filterID) - asymmetric filter', function () {
                // allow some time for message to propagate
                setTimeout(function () {
                    // now let's try to capture new messages from our last capture
                    var messages = node1.shh.getNewSubscriptionMessages(filterid2);
                    assert.typeOf(messages, 'array');
                    assert.lengthOf(messages, 1);
                    assert.equal(web3.toAscii(messages[0].payload), payloadAfterAsymFilter);

                    // no more messages should be returned
                    messages = node1.shh.getNewSubscriptionMessages(filterid2);
                    assert.typeOf(messages, 'array');
                    assert.lengthOf(messages, 0);

                    done();
                }, 200);
            });

            it.skip('shh.unsubscribe(filterID)', function () {
                node1.shh.unsubscribe(filterid1);
                node1.shh.unsubscribe(filterid2);
            });
        });
    });

    context('symmetrically encrypted messages send/recieve', function () {
        this.timeout(0);

        var keyId = ''; // symmetric key ID (to be populated)
        var keyVal = ''; // symmetric key value (to be populated)
        var payload = 'here come the dragons';

        it('default test identity is present', function () {
            if (!node1.shh.hasKeyPair(identity1)) {
                throw new Error('identity not found in whisper: ' + identity1);
            }
        });

        it('ensure symkey exists', function () {
            keyId = node1.shh.generateSymmetricKey();
            assert.lengthOf(keyId, 64);
            expect(node1.shh.hasSymmetricKey(keyId)).to.equal(true);
        });

        it('read the generated symkey', function () {
            keyVal = node1.shh.getSymmetricKey(keyId);
            assert.lengthOf(keyVal, 66); // 2 bytes for "0x"
        });

        it('send/receive symmetrically encrypted message', function (done) {
            // start watching for messages
            watchFilter(node1.shh.filter({
                type: "sym",
                key: keyId,
                sig: identity1,
                topics: [topic1, topic2]
            }), function (err, message) {
                done(err);
            });

            // send message
            var message = {
                type: "sym",
                key: keyId,
                sig: identity1,
                topic: topic1,
                payload: web3.fromAscii(payload),
                ttl: 20,
                powTime: 2,
                powTarget: 0.001
            };
            expect(node1.shh.post(message)).to.equal(null);
        });

        it('send the minimal symmetric message possible', function (done) {
            var uniqueTopic = makeTopic();

            // start watching for messages
            watchFilter(node1.shh.filter({
                type: "sym",
                key: keyId,
                topics: [uniqueTopic]
            }), function (err, message) {
                done(err);
            });

            // send message
            var message = {
                type: "sym",
                key: keyId,
                topic: uniqueTopic
            };
            expect(node1.shh.post(message)).to.equal(null);
        });
    });

    context('message travelling from one node to another', function () {
        this.timeout(0);

        var keyId1 = ''; // symmetric key ID on node 1 (to be populated)
        var keyId2 = ''; // symmetric key ID on node 2 (to be populated)

        it('statusd node1 is running', function () {
            var web3 = new Web3();
            var provider = new web3.providers.HttpProvider('http://localhost:8645');
            var result = provider.send({});
            assert.equal(typeof result, 'object');
        });

        it('statusd node2 is running', function () {
            var web3 = new Web3();
            var provider = new web3.providers.HttpProvider('http://localhost:8745');
            var result = provider.send({});
            assert.equal(typeof result, 'object');
        });

        it('test identities injected', function () {
            if (!node1.shh.hasKeyPair(identity1)) {
                throw new Error('identity not found in whisper (node1): ' + identity1);
            }
            if (!node1.shh.hasKeyPair(identity2)) {
                throw new Error('identity not found in whisper (node1): ' + identity2);
            }
            if (!node2.shh.hasKeyPair(identity1)) {
                throw new Error('identity not found in whisper (node2): ' + identity1);
            }
            if (!node2.shh.hasKeyPair(identity2)) {
                throw new Error('identity not found in whisper (node2): ' + identity2);
            }
        });

        it('ensure symkey exists', function () {
            keyId1 = node1.shh.generateSymmetricKey();
            assert.lengthOf(keyId1, 64);
            expect(node1.shh.hasSymmetricKey(keyId1)).to.equal(true);

            // obtain key value
            var keyVal = node1.shh.getSymmetricKey(keyId1);
            assert.lengthOf(keyVal, 66); // 2 bytes of "0x"

            // share the value with the node2
            keyId2 = node2.shh.addSymmetricKeyDirect(keyVal);
            assert.lengthOf(keyId2, 64);
            expect(node2.shh.hasSymmetricKey(keyId2)).to.equal(true);
        });

        it('send symmetrically encrypted, signed message (node1 -> node2)', function (done) {
            var payload = 'send symmetrically encrypted, signed message (node1 -> node2)';
            var topic = makeTopic();
            // start watching for messages
            watchFilter(node2.shh.filter({
                type: "sym",
                sig: identity1,
                key: keyId2,
                topics: [topic]
            }), function (err, message) {
                done(err);
            });

            // send message
            var message = {
                type: "sym",
                sig: identity1,
                key: keyId1,
                topic: topic,
                payload: payload,
                ttl: 20
            };
            expect(node1.shh.post(message)).to.equal(null);
        });

        it('send asymmetrically encrypted, signed message (node1.id1 -> node2.id2)', function (done) {
            var payload = 'send asymmetrically encrypted, signed message (node1.id1 -> node2.id2)';
            var topic = makeTopic();
            // start watching for messages
            watchFilter(node2.shh.filter({
                type: "asym",
                sig: identity1,
                key: identity2
            }), function (err, message) {
                done(err);
            });

            // send message
            var message = {
                type: "asym",
                sig: identity1,
                key: identity2,
                topic: topic,
                payload: payload,
                ttl: 20
            };
            expect(node1.shh.post(message)).to.equal(null);
        });
    });

    context('push notifications', function () {
        this.timeout(5000);
        var discoveryPubKey = '0x040edb0d71a3dbe928e154fcb696ffbda359b153a90efc2b46f0043ce9f5dbe55b77b9328fd841a1db5273758624afadd5b39638d4c35b36b3a96e1a586c1b4c2a';
        var discoverServerTopic = '0x268302f3'; // DISCOVER_NOTIFICATION_SERVER
        var proposeServerTopic = '0x08e3d8c0'; // PROPOSE_NOTIFICATION_SERVER
        var acceptServerTopic = '0x04f7dea6'; // ACCEPT_NOTIFICATION_SERVER
        var ackClientSubscriptionTopic = '0x93dafe28'; // ACK_NOTIFICATION_SERVER_SUBSCRIPTION
        var sendNotificationTopic = '0x69915296'; // SEND_NOTIFICATION
        var newChatSessionTopic = '0x509579a2'; // NEW_CHAT_SESSION
        var ackNewChatSessionTopic = '0xd012aae8'; // ACK_NEW_CHAT_SESSION
        var newDeviceRegistrationTopic = '0x14621a51'; // NEW_DEVICE_REGISTRATION
        var ackDeviceRegistrationTopic = '0x424358d6'; // ACK_DEVICE_REGISTRATION
        var checkClientSessionTopic = '0x8745d931'; // CHECK_CLIENT_SESSION
        var confirmClientSessionTopic = '0xd3202c5f'; // CONFIRM_CLIENT_SESSION
        var dropClientSessionTopic = '0x3a6656bb'; // DROP_CLIENT_SESSION

        // ensures that message had payload (which is HEX-encoded JSON)
        var extractPayload = function (message) {
            expect(message).to.have.property('payload');
            return JSON.parse(web3.toAscii(message.payload));
        };

        var identity1 = ''; // pub key of device 1
        var identity2 = ''; // pub key of device 2
        var chatKeySharingTopic = makeTopic(); // topic used by device1 to send chat key to device 2

        context('prepare devices', function () {
            it('create key pair to be used as main identity on device1', function () {
                var keyId = node1.shh.newKeyPair();
                assert.lengthOf(keyId, 64);

                identity1 = node1.shh.getPublicKey(keyId);
                assert.lengthOf(identity1, 132);

                expect(node1.shh.hasKeyPair(identity1)).to.equal(true);
                expect(node1.shh.hasKeyPair(identity2)).to.equal(false);
            });

            it('create key pair to be used as main identity on device2', function () {
                var keyId = node2.shh.newKeyPair();
                assert.lengthOf(keyId, 64);

                identity2 = node2.shh.getPublicKey(keyId);
                assert.lengthOf(identity1, 132);

                expect(node2.shh.hasKeyPair(identity1)).to.equal(false);
                expect(node2.shh.hasKeyPair(identity2)).to.equal(true);
            });
        });

        context('run device1', function () {
            var serverId = ''; // accepted/selected server id
            var subscriptionKeyId = ''; // symkey provided by server, and used to configure client-server subscription
            var chatKeyId = ''; // symkey provided by server, and shared among clients so that they can trigger notifications
            var appChatId = ''; // chat id that identifies device1-device2 interaction session on RN app level


            it('start discovery by sending discovery request', function () {
                var message = {
                    type: "asym",
                    sig: identity1,
                    key: discoveryPubKey,
                    topic: discoverServerTopic,
                    ttl: 20
                };
                expect(node1.shh.post(message)).to.equal(null);
            });

            it('watch for server proposals', function (done) {
                watchFilter(node1.shh.filter({
                    type: "asym",
                    sig: discoveryPubKey,
                    key: identity1,
                    topics: [proposeServerTopic]
                }), function (err, message) {
                    if (err) return done(err);

                    // process payload
                    var payload = extractPayload(message);
                    expect(payload).to.have.property('server');
                    serverId = payload.server;

                    done();
                });
            });

            it('client accepts server', function () {
                var message = {
                    type: "asym",
                    sig: identity1,
                    key: discoveryPubKey,
                    topic: acceptServerTopic,
                    payload: '{"server": "' + serverId + '"}',
                    ttl: 20
                };
                expect(node1.shh.post(message)).to.equal(null);
            });

            it('watch for server ACK response and save provided subscription key', function (done) {
                watchFilter(node1.shh.filter({
                    type: "asym",
                    key: identity1,
                    topics: [ackClientSubscriptionTopic]
                }), function (err, message) {
                    if (err) return done(err);

                    // process payload
                    var payload = extractPayload(message);
                    expect(payload).to.have.property('server');
                    expect(payload).to.have.property('key');

                    // save subscription key
                    subscriptionKeyId = node1.shh.addSymmetricKeyDirect(payload.key);
                    assert.lengthOf(subscriptionKeyId, 64);
                    expect(node1.shh.hasSymmetricKey(subscriptionKeyId)).to.equal(true);

                    done();
                });
            });

            it('create chat session', function () {
                appChatId = makeTopic(); // globally unique chat id
                var message = {
                    type: "sym",
                    sig: identity1,
                    key: subscriptionKeyId,
                    topic: newChatSessionTopic,
                    payload: '{"chat": "' + appChatId + '"}',
                    ttl: 20
                };
                expect(node1.shh.post(message)).to.equal(null);
            });

            it('watch for server to respond with chat key', function (done) {
                watchFilter(node1.shh.filter({
                    type: "asym",
                    key: identity1,
                    topics: [ackNewChatSessionTopic]
                }), function (err, message) {
                    if (err) return done(err);

                    // process payload
                    var payload = extractPayload(message);
                    expect(payload).to.have.property('server');
                    expect(payload).to.have.property('key');

                    // save subscription key
                    chatKeyId = node1.shh.addSymmetricKeyDirect(payload.key);
                    assert.lengthOf(chatKeyId, 64);
                    expect(node1.shh.hasSymmetricKey(chatKeyId)).to.equal(true);

                    done();
                });
            });

            it('register device with a given chat', function (done) {
                // this obtained from https://status-sandbox-c1b34.firebaseapp.com/
                var deviceId = 'ca5pRJc6L8s:APA91bHpYFtpxvXx6uOayGmnNVnktA4PEEZdquCCt3fWR5ldLzSy1A37Tsbzk5Gavlmk1d_fvHRVnK7xPAhFFl-erF7O87DnIEstW6DEyhyiKZYA4dXFh6uy323f9A3uw5hEtT_kQVhT';
                var message = {
                    type: "sym",
                    sig: identity1,
                    key: chatKeyId,
                    topic: newDeviceRegistrationTopic,
                    payload: '{"device": "' + deviceId + '"}',
                    ttl: 20
                };
                expect(node1.shh.post(message)).to.equal(null);

                // watch for server server ACK
                watchFilter(node1.shh.filter({
                    type: "asym",
                    key: identity1,
                    topics: [ackDeviceRegistrationTopic]
                }), function (err, message) {
                    if (err) return done(err);

                    // process payload
                    var payload = extractPayload(message);
                    expect(payload).to.have.property('server');

                    done();
                });
            });

            it('share chat key, so that another device can send us notifications', function () {
                var chatKey = node1.shh.getSymmetricKey(chatKeyId);
                assert.lengthOf(chatKey, 66);
                var message = {
                    type: "asym",
                    sig: identity1,
                    key: identity2,
                    topic: chatKeySharingTopic,
                    payload: '{"chat": "' + appChatId + '", "key": "' + chatKey + '"}',
                    ttl: 20
                };
                expect(node1.shh.post(message)).to.equal(null);
            });
        });

        context('run device2', function () {
            var chatKeyId = '';

            it('watch for device1 to send us chat key', function (done) {
                watchFilter(node2.shh.filter({
                    type: "asym",
                    key: identity2,
                    topics: [chatKeySharingTopic]
                }), function (err, message) {
                    if (err) return done(err);

                    // process payload
                    var payload = extractPayload(message);
                    expect(payload).to.have.property('chat');
                    expect(payload).to.have.property('key');

                    // persist chat key
                    chatKeyId = node2.shh.addSymmetricKeyDirect(payload.key);
                    assert.lengthOf(chatKeyId, 64);
                    expect(node2.shh.hasSymmetricKey(chatKeyId)).to.equal(true);

                    done();
                });
            });

            it('trigger notification (from device2, on device1)', function () {
                var message = {
                    type: "sym",
                    sig: identity2,
                    key: chatKeyId,
                    topic: sendNotificationTopic,
                    payload: '{' // see https://firebase.google.com/docs/cloud-messaging/http-server-ref
                    + '"notification": {'
                    + '"title": "status.im notification",'
                    + '"body": "Hello this is test notification!",'
                    + '"icon": "https://status.im/img/logo.png",'
                    + '"click_action": "https://status.im"'
                    + '},'
                    + '"to": "{{ ID }}"' // this get replaced by device id your've registered
                    + '}',
                    ttl: 20
                };
                expect(node2.shh.post(message)).to.equal(null);
            });
        });

        context('misc methods and cleanup', function () {

            it('check client session', function (done) {
                // request status
                var message = {
                    type: "asym",
                    sig: identity1,
                    key: discoveryPubKey,
                    topic: checkClientSessionTopic,
                    ttl: 20
                };
                expect(node1.shh.post(message)).to.equal(null);

                // process server's response
                watchFilter(node1.shh.filter({
                    type: "asym",
                    key: identity1,
                    topics: [confirmClientSessionTopic]
                }), function (err, message) {
                    if (err) return done(err);

                    // process payload
                    var payload = extractPayload(message);
                    expect(payload).to.have.property('server');
                    expect(payload).to.have.property('key');

                    done();
                });
            });

            it('remove client session', function () {
                var message = {
                    type: "asym",
                    sig: identity1,
                    key: discoveryPubKey,
                    topic: dropClientSessionTopic,
                    ttl: 20
                };
                expect(node1.shh.post(message)).to.equal(null);
            });
        });
    });
});