package cc.blynk.integration.tcp;
import cc.blynk.integration.IntegrationBase;
import cc.blynk.integration.model.tcp.ClientPair;
import cc.blynk.integration.model.tcp.TestAppClient;
import cc.blynk.server.application.AppServer;
import cc.blynk.server.core.BaseServer;
import cc.blynk.server.core.model.DashBoard;
import cc.blynk.server.core.model.Pin;
import cc.blynk.server.core.model.Profile;
import cc.blynk.server.core.model.widgets.OnePinWidget;
import cc.blynk.server.core.model.widgets.Widget;
import cc.blynk.server.core.model.widgets.notifications.Notification;
import cc.blynk.server.core.model.widgets.notifications.Twitter;
import cc.blynk.server.core.protocol.model.messages.ResponseMessage;
import cc.blynk.server.core.protocol.model.messages.appllication.LoadProfileGzippedBinaryMessage;
import cc.blynk.server.hardware.HardwareServer;
import cc.blynk.utils.JsonParser;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.zip.DeflaterOutputStream;
import static cc.blynk.server.core.protocol.enums.Command.*;
import static cc.blynk.server.core.protocol.enums.Response.*;
import static cc.blynk.server.core.protocol.model.messages.MessageFactory.produce;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
/**
* The Blynk Project.
* Created by Dmitriy Dumanskiy.
* Created on 2/2/2015.
*
*/
@RunWith(MockitoJUnitRunner.class)
public class ShareProfileWorkflowTest extends IntegrationBase {
private BaseServer appServer;
private BaseServer hardwareServer;
private ClientPair clientPair;
private static OnePinWidget getWidgetByPin(Profile profile, int pin) {
for (Widget widget : profile.dashBoards[0].widgets) {
if (widget instanceof OnePinWidget) {
OnePinWidget onePinWidget = (OnePinWidget) widget;
if (onePinWidget.pin != Pin.NO_PIN && onePinWidget.pin == pin) {
return onePinWidget;
}
}
}
return null;
}
@Before
public void init() throws Exception {
this.hardwareServer = new HardwareServer(holder).start();
this.appServer = new AppServer(holder).start();
this.clientPair = initAppAndHardPair();
}
@After
public void shutdown() {
this.appServer.close();
this.hardwareServer.close();
this.clientPair.stop();
}
@Test
public void testGetShareTokenNoDashId() throws Exception {
clientPair.appClient.send("getShareToken");
verify(clientPair.appClient.responseMock, timeout(1000)).channelRead(any(), eq(new ResponseMessage(1, NOT_ALLOWED)));
}
@Test
public void testGetShareToken() throws Exception {
clientPair.appClient.send("getShareToken 1");
String token = clientPair.appClient.getBody();
assertNotNull(token);
assertEquals(32, token.length());
ClientPair clientPair2 = initAppAndHardPair("localhost", tcpAppPort, tcpHardPort, "dima2@mail.ua 1", "user_profile_json_2.txt", properties, 10000);
clientPair2.appClient.send("getSharedDash " + token);
String dashboard = clientPair2.appClient.getBody();
DashBoard serverDash = JsonParser.parseDashboard(dashboard);
//todo fix
serverDash.devices = null;
Profile profile = parseProfile(readTestUserProfile());
Twitter twitter = profile.dashBoards[0].getWidgetByType(Twitter.class);
clearPrivateData(twitter);
Notification notification = profile.dashBoards[0].getWidgetByType(Notification.class);
clearPrivateData(notification);
//one field update, cause it is hard to compare.
profile.dashBoards[0].updatedAt = serverDash.updatedAt;
assertNotNull(serverDash.sharedToken);
serverDash.sharedToken = null;
assertEquals(profile.dashBoards[0].toString(), serverDash.toString());
clientPair.appClient.send("loadProfileGzipped");
profile = parseProfile(clientPair.appClient.getBody(2));
profile.dashBoards[0].updatedAt = 0;
Notification originalNotification = profile.dashBoards[0].getWidgetByType(Notification.class);
assertNotNull(originalNotification);
assertEquals(1, originalNotification.androidTokens.size());
assertEquals("token", originalNotification.androidTokens.get("uid"));
Twitter originalTwitter = profile.dashBoards[0].getWidgetByType(Twitter.class);
assertNotNull(originalTwitter);
assertEquals("token", originalTwitter.token);
assertEquals("secret", originalTwitter.secret);
}
@Test
public void getShareTokenAndLoginViaIt() throws Exception {
clientPair.appClient.send("getShareToken 1");
String token = clientPair.appClient.getBody();
assertNotNull(token);
assertEquals(32, token.length());
TestAppClient appClient2 = new TestAppClient("localhost", tcpAppPort, properties);
appClient2.start();
appClient2.send("shareLogin " + "dima@mail.ua " + token + " Android 24");
verify(appClient2.responseMock, timeout(500)).channelRead(any(), eq(new ResponseMessage(1, OK)));
clientPair.appClient.send("hardware 1 vw 1 1");
verify(appClient2.responseMock, timeout(1000)).channelRead(any(), eq(produce(2, APP_SYNC, b("1 vw 1 1"))));
appClient2.send("hardware 1 vw 2 2");
verify(clientPair.appClient.responseMock, timeout(1000)).channelRead(any(), eq(produce(2, APP_SYNC, b("1 vw 2 2"))));
clientPair.appClient.reset();
clientPair.hardwareClient.reset();
appClient2.reset();
appClient2.send("hardware 1 ar 30");
verify(clientPair.appClient.responseMock, after(500).never()).channelRead(any(), any());
verify(clientPair.hardwareClient.responseMock, after(500).never()).channelRead(any(), eq(produce(1, HARDWARE, b("ar 30"))));
clientPair.appClient.send("hardware 1 ar 30");
verify(appClient2.responseMock, after(500).never()).channelRead(any(), any());
verify(clientPair.hardwareClient.responseMock, after(500).never()).channelRead(any(), eq(produce(2, HARDWARE, b("ar 30"))));
clientPair.hardwareClient.reset();
clientPair.hardwareClient.send("ping");
appClient2.send("hardware 1 pm 2 2");
verify(clientPair.appClient.responseMock, after(500).never()).channelRead(any(), any());
verify(clientPair.hardwareClient.responseMock, after(500).atMost(1)).channelRead(any(), any());
clientPair.appClient.send("hardware 1 ar 30");
verify(appClient2.responseMock, after(500).never()).channelRead(any(), any());
verify(clientPair.hardwareClient.responseMock, after(500).never()).channelRead(any(), eq(produce(2, HARDWARE, b("ar 30"))));
clientPair.appClient.send("hardware 1 pm 2 2");
verify(appClient2.responseMock, after(250).never()).channelRead(any(), any());
verify(clientPair.hardwareClient.responseMock, after(250).never()).channelRead(any(), eq(produce(3, HARDWARE, b("pm 2 2"))));
}
@Test
public void testSharingChargingCorrect() throws Exception {
clientPair.appClient.send("getEnergy");
verify(clientPair.appClient.responseMock, timeout(500)).channelRead(any(), eq(produce(1, GET_ENERGY, "7500")));
clientPair.appClient.reset();
clientPair.appClient.send("getShareToken 1");
String token = clientPair.appClient.getBody();
assertNotNull(token);
assertEquals(32, token.length());
clientPair.appClient.send("getEnergy");
verify(clientPair.appClient.responseMock, timeout(500)).channelRead(any(), eq(produce(2, GET_ENERGY, "6500")));
clientPair.appClient.reset();
clientPair.appClient.send("getShareToken 1");
token = clientPair.appClient.getBody();
assertNotNull(token);
assertEquals(32, token.length());
clientPair.appClient.send("getEnergy");
verify(clientPair.appClient.responseMock, timeout(500)).channelRead(any(), eq(produce(2, GET_ENERGY, "6500")));
clientPair.appClient.reset();
clientPair.appClient.send("getShareToken 1");
token = clientPair.appClient.getBody();
assertNotNull(token);
assertEquals(32, token.length());
clientPair.appClient.send("getShareToken 1");
clientPair.appClient.send("getShareToken 1");
clientPair.appClient.send("getShareToken 1");
clientPair.appClient.send("getEnergy");
verify(clientPair.appClient.responseMock, timeout(500)).channelRead(any(), eq(produce(5, GET_ENERGY, "6500")));
}
@Test
public void checkStateWasChanged() throws Exception {
clientPair.appClient.send("getShareToken 1");
String token = clientPair.appClient.getBody();
assertNotNull(token);
assertEquals(32, token.length());
TestAppClient appClient2 = new TestAppClient("localhost", tcpAppPort, properties);
appClient2.start();
appClient2.send("shareLogin " + "dima@mail.ua " + token + " Android 24");
verify(appClient2.responseMock, timeout(500)).channelRead(any(), eq(new ResponseMessage(1, OK)));
clientPair.appClient.send("hardware 1 vw 1 1");
verify(appClient2.responseMock, timeout(1000)).channelRead(any(), eq(produce(2, APP_SYNC, b("1 vw 1 1"))));
appClient2.send("hardware 1 vw 2 2");
verify(clientPair.appClient.responseMock, timeout(1000)).channelRead(any(), eq(produce(2, APP_SYNC, b("1 vw 2 2"))));
clientPair.appClient.reset();
appClient2.reset();
//check from master side
clientPair.appClient.send("hardware 1 aw 3 1");
verify(clientPair.hardwareClient.responseMock, timeout(1000)).channelRead(any(), eq(produce(1, HARDWARE, b("aw 3 1"))));
clientPair.appClient.send("loadProfileGzipped");
String profileString = clientPair.appClient.getBody();
assertNotNull(profileString);
Profile profile = parseProfile(profileString);
OnePinWidget tmp = getWidgetByPin(profile, 3);
assertNotNull(tmp);
assertEquals("1", tmp.value);
//check from slave side
appClient2.send("hardware 1 aw 3 150");
verify(clientPair.hardwareClient.responseMock, timeout(1000)).channelRead(any(), eq(produce(1, HARDWARE, b("aw 3 150"))));
clientPair.appClient.reset();
clientPair.appClient.send("loadProfileGzipped");
profileString = clientPair.appClient.getBody();
assertNotNull(profileString);
profile = parseProfile(profileString);
tmp = getWidgetByPin(profile, 3);
assertNotNull(tmp);
assertEquals("150", tmp.value);
//check from hard side
clientPair.hardwareClient.send("hardware aw 3 151");
verify(clientPair.appClient.responseMock, timeout(1000)).channelRead(any(), eq(produce(1, HARDWARE, b("1 aw 3 151"))));
clientPair.appClient.reset();
clientPair.appClient.send("loadProfileGzipped");
profileString = clientPair.appClient.getBody();
assertNotNull(profileString);
profile = parseProfile(profileString);
tmp = getWidgetByPin(profile, 3);
assertNotNull(tmp);
assertEquals("151", tmp.value);
}
@Test
public void checkSharingMessageWasReceived() throws Exception {
clientPair.appClient.send("getShareToken 1");
String token = clientPair.appClient.getBody();
assertNotNull(token);
assertEquals(32, token.length());
TestAppClient appClient2 = new TestAppClient("localhost", tcpAppPort, properties);
appClient2.start();
appClient2.send("shareLogin " + "dima@mail.ua " + token + " Android 24");
verify(appClient2.responseMock, timeout(500)).channelRead(any(), eq(new ResponseMessage(1, OK)));
clientPair.appClient.send("sharing 1 off");
verify(clientPair.appClient.responseMock, timeout(500)).channelRead(any(), eq(new ResponseMessage(2, OK)));
verify(appClient2.responseMock, timeout(500)).channelRead(any(), eq(produce(2, SHARING, b("1 off"))));
}
@Test
public void checkBothClientsReceiveMessage() throws Exception {
clientPair.appClient.send("getShareToken 1");
String token = clientPair.appClient.getBody();
assertNotNull(token);
assertEquals(32, token.length());
TestAppClient appClient2 = new TestAppClient("localhost", tcpAppPort, properties);
appClient2.start();
appClient2.send("shareLogin " + "dima@mail.ua " + token + " Android 24");
verify(appClient2.responseMock, timeout(500)).channelRead(any(), eq(new ResponseMessage(1, OK)));
//check from hard side
clientPair.hardwareClient.send("hardware aw 3 151");
verify(clientPair.appClient.responseMock, timeout(1000)).channelRead(any(), eq(produce(1, HARDWARE, b("1 aw 3 151"))));
verify(appClient2.responseMock, timeout(1000)).channelRead(any(), eq(produce(1, HARDWARE, b("1 aw 3 151"))));
clientPair.hardwareClient.send("hardware aw 3 152");
verify(clientPair.appClient.responseMock, timeout(1000)).channelRead(any(), eq(produce(2, HARDWARE, b("1 aw 3 152"))));
verify(appClient2.responseMock, timeout(1000)).channelRead(any(), eq(produce(2, HARDWARE, b("1 aw 3 152"))));
clientPair.appClient.reset();
clientPair.appClient.send("loadProfileGzipped");
String profileString = clientPair.appClient.getBody();
assertNotNull(profileString);
Profile profile = parseProfile(profileString);
OnePinWidget tmp = getWidgetByPin(profile, 3);
assertNotNull(tmp);
assertEquals("152", tmp.value);
}
@Test
public void wrongSharedToken() throws Exception {
clientPair.appClient.send("getShareToken 1");
String token = clientPair.appClient.getBody();
assertNotNull(token);
assertEquals(32, token.length());
TestAppClient appClient2 = new TestAppClient("localhost", tcpAppPort, properties);
appClient2.start();
appClient2.send("shareLogin " + "dima@mail.ua " + token+"a" + " Android 24");
verify(appClient2.responseMock, timeout(1000)).channelRead(any(), eq(new ResponseMessage(1, NOT_ALLOWED)));
}
@Test
public void revokeSharedToken() throws Exception {
clientPair.appClient.send("getShareToken 1");
String token = clientPair.appClient.getBody();
assertNotNull(token);
assertEquals(32, token.length());
TestAppClient appClient2 = new TestAppClient("localhost", tcpAppPort, properties);
appClient2.start();
appClient2.send("shareLogin " + "dima@mail.ua " + token + " Android 24");
verify(appClient2.responseMock, timeout(1000)).channelRead(any(), eq(new ResponseMessage(1, OK)));
clientPair.appClient.reset();
appClient2.reset();
assertFalse(clientPair.appClient.isClosed());
assertFalse(appClient2.isClosed());
clientPair.appClient.send("refreshShareToken 1");
token = clientPair.appClient.getBody();
assertNotNull(token);
assertEquals(32, token.length());
verify(appClient2.responseMock, timeout(1000)).channelRead(any(), eq(new ResponseMessage(1, NOT_ALLOWED)));
assertFalse(clientPair.appClient.isClosed());
assertTrue(appClient2.isClosed());
TestAppClient appClient3 = new TestAppClient("localhost", tcpAppPort, properties);
appClient3.start();
appClient3.send("shareLogin " + "dima@mail.ua " + token + " Android 24");
verify(appClient3.responseMock, timeout(1000)).channelRead(any(), eq(new ResponseMessage(1, OK)));
}
@Test
public void testDeactivateAndActivateForSubscriptions() throws Exception {
clientPair.appClient.send("getShareToken 1");
String token = clientPair.appClient.getBody();
assertNotNull(token);
assertEquals(32, token.length());
TestAppClient appClient2 = new TestAppClient("localhost", tcpAppPort, properties);
appClient2.start();
appClient2.send("shareLogin " + "dima@mail.ua " + token + " Android 24");
TestAppClient appClient3 = new TestAppClient("localhost", tcpAppPort, properties);
appClient3.start();
appClient3.send("shareLogin " + "dima@mail.ua " + token + " Android 24");
verify(appClient2.responseMock, timeout(500)).channelRead(any(), eq(new ResponseMessage(1, OK)));
verify(appClient3.responseMock, timeout(500)).channelRead(any(), eq(new ResponseMessage(1, OK)));
clientPair.appClient.send("deactivate 1");
verify(clientPair.appClient.responseMock, timeout(500)).channelRead(any(), eq(new ResponseMessage(2, OK)));
verify(appClient2.responseMock, timeout(500)).channelRead(any(), eq(produce(2, DEACTIVATE_DASHBOARD, "1")));
verify(appClient3.responseMock, timeout(500)).channelRead(any(), eq(produce(2, DEACTIVATE_DASHBOARD, "1")));
clientPair.appClient.send("activate 1");
verify(clientPair.appClient.responseMock, timeout(500)).channelRead(any(), eq(new ResponseMessage(3, OK)));
verify(appClient2.responseMock, timeout(500)).channelRead(any(), eq(produce(3, ACTIVATE_DASHBOARD, "1")));
verify(appClient3.responseMock, timeout(500)).channelRead(any(), eq(produce(3, ACTIVATE_DASHBOARD, "1")));
}
@Test
public void loadGzippedProfileForSharedBoard() throws Exception{
clientPair.appClient.send("getShareToken 1");
String token = clientPair.appClient.getBody();
assertNotNull(token);
assertEquals(32, token.length());
TestAppClient appClient2 = new TestAppClient("localhost", tcpAppPort, properties);
appClient2.start();
appClient2.send("shareLogin " + "dima@mail.ua " + token + " Android 24");
verify(appClient2.responseMock, timeout(500)).channelRead(any(), eq(new ResponseMessage(1, OK)));
clientPair.appClient.reset();
clientPair.appClient.send("loadProfileGzipped");
String body = clientPair.appClient.getBody();
appClient2.send("loadProfileGzipped");
verify(appClient2.responseMock, timeout(500)).channelRead(any(), eq(new LoadProfileGzippedBinaryMessage(2, compress(body))));
}
public static byte[] compress(String value) throws IOException {
byte[] stringData = value.getBytes(StandardCharsets.UTF_8);
ByteArrayOutputStream baos = new ByteArrayOutputStream(stringData.length);
try (OutputStream out = new DeflaterOutputStream(baos)) {
out.write(stringData);
}
return baos.toByteArray();
}
@Test
public void testGetShareTokenAndRefresh() throws Exception {
clientPair.appClient.send("getShareToken 1");
String token = clientPair.appClient.getBody();
assertNotNull(token);
assertEquals(32, token.length());
ClientPair clientPair2 = initAppAndHardPair("localhost", tcpAppPort, tcpHardPort, "dima2@mail.ua 1", "user_profile_json_2.txt", properties, 10000);
clientPair2.appClient.send("getSharedDash " + token);
String dashboard = clientPair2.appClient.getBody();
assertNotNull(dashboard);
clientPair.appClient.reset();
clientPair.appClient.send("refreshShareToken 1");
String refreshedToken = clientPair.appClient.getBody();
assertNotNull(refreshedToken);
assertNotEquals(refreshedToken, token);
clientPair.appClient.reset();
clientPair.appClient.send("getSharedDash " + token);
verify(clientPair.appClient.responseMock, timeout(500)).channelRead(any(), eq(new ResponseMessage(1, INVALID_TOKEN)));
clientPair.appClient.reset();
clientPair.appClient.send("getSharedDash " + refreshedToken);
dashboard = clientPair.appClient.getBody();
DashBoard serverDash = JsonParser.parseDashboard(dashboard);
//todo fix
serverDash.devices = null;
assertNotNull(dashboard);
Profile profile = parseProfile(readTestUserProfile());
Twitter twitter = profile.dashBoards[0].getWidgetByType(Twitter.class);
clearPrivateData(twitter);
Notification notification = profile.dashBoards[0].getWidgetByType(Notification.class);
clearPrivateData(notification);
//one field update, cause it is hard to compare.
DashBoard temp = JsonParser.parseDashboard(dashboard);
profile.dashBoards[0].updatedAt = temp.updatedAt;
assertNotNull(serverDash.sharedToken);
serverDash.sharedToken = null;
assertEquals(profile.dashBoards[0].toString(), serverDash.toString());
//System.out.println(dashboard);
}
@Test
public void testMasterMasterSyncWorksWithoutToken() throws Exception {
TestAppClient appClient2 = new TestAppClient("localhost", tcpAppPort, properties);
appClient2.start();
appClient2.send("login " + "dima@mail.ua 1 Android 24");
verify(appClient2.responseMock, timeout(500)).channelRead(any(), eq(new ResponseMessage(1, OK)));
clientPair.appClient.send("hardware 1 vw 1 1");
verify(appClient2.responseMock, timeout(1000)).channelRead(any(), eq(produce(1, APP_SYNC, b("1 vw 1 1"))));
appClient2.send("hardware 1 vw 2 2");
verify(clientPair.appClient.responseMock, timeout(1000)).channelRead(any(), eq(produce(2, APP_SYNC, b("1 vw 2 2"))));
}
private static void clearPrivateData(Notification n) {
n.iOSTokens.clear();
n.androidTokens.clear();
}
private static void clearPrivateData(Twitter t) {
t.username = null;
t.token = null;
t.secret = null;
}
}