/*
* Copyright 2015 Evgeny Dolganov (evgenij.dolganov@gmail.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package och;
import static java.util.Collections.*;
import static och.api.model.PropKey.*;
import static och.api.model.RemoteChats.*;
import static och.api.model.chat.account.PrivilegeType.*;
import static och.api.model.tariff.Tariff.*;
import static och.api.model.tariff.TariffMath.*;
import static och.api.model.user.SecurityContext.*;
import static och.comp.ops.BillingOps.*;
import static och.comp.paypal.PaypalClientStub.*;
import static och.comp.web.JsonOps.*;
import static och.front.service.ChatService.*;
import static och.front.service.FrontApp.*;
import static och.util.ConcurrentUtil.*;
import static och.util.DateUtil.*;
import static och.util.NetUtil.*;
import static och.util.StringUtil.*;
import static och.util.Util.*;
import static och.util.servlet.WebUtil.*;
import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import javax.servlet.annotation.WebServlet;
import och.api.model.chat.ChatOperator;
import och.api.model.chat.account.ChatAccount;
import och.api.model.chat.account.PrivilegeType;
import och.api.model.chat.config.Key;
import och.api.model.server.ServerRow;
import och.api.model.user.LoginUserReq;
import och.api.model.user.UpdateUserReq;
import och.api.model.user.User;
import och.api.remote.chats.InitUserTokenReq;
import och.api.remote.chats.UpdateUserSessionsReq;
import och.chat.service.ChatsApp;
import och.chat.web.ChatsAppProvider;
import och.chat.web.servlet.remote.chat.CreateAccount;
import och.chat.web.servlet.remote.chat.GetPausedState;
import och.chat.web.servlet.remote.chat.GetUnblockedAccs;
import och.chat.web.servlet.remote.chat.PutAccConfig;
import och.chat.web.servlet.remote.chat.PutOperator;
import och.chat.web.servlet.remote.chat.RemoveOperator;
import och.chat.web.servlet.remote.chat.SetAccsBlocked;
import och.chat.web.servlet.remote.chat.SetAccsPaused;
import och.chat.web.servlet.remote.chat.UpdateUserContact;
import och.chat.web.servlet.remote.user.InitUserToken;
import och.chat.web.servlet.remote.user.RemoveUserSession;
import och.chat.web.servlet.remote.user.UpdateUserSessions;
import och.comp.billing.standalone.BillingSyncService;
import och.comp.cache.Cache;
import och.comp.cache.impl.CacheImpl;
import och.comp.cache.server.CacheServerContext;
import och.comp.cache.server.CacheSever;
import och.comp.db.base.universal.UniversalQueries;
import och.comp.db.main.MainDb;
import och.comp.db.main.table._f.TariffLastPay;
import och.comp.db.main.table._f.TariffStart;
import och.comp.db.main.table.billing.GetAllBlockedUsers;
import och.comp.db.main.table.billing.UpdateUserBalanceUnsafe;
import och.comp.db.main.table.chat.UpdateAllChatAccounts;
import och.comp.db.main.table.chat.UpdateChatAccountByUid;
import och.comp.mail.stub.MailServiceStub;
import och.comp.mail.stub.SenderStub;
import och.comp.ops.BillingOps;
import och.comp.web.JsonOps;
import och.front.service.BillingService;
import och.front.service.ChatService;
import och.front.service.FrontApp;
import och.front.service.FrontAppTest;
import och.front.service.SecurityService;
import och.front.web.FrontAppProvider;
import och.front.web.servlet.api.GetStatus;
import och.front.web.servlet.remote.ReloadChatsModel;
import och.service.props.impl.MapProps;
import och.util.concurrent.AsyncListener;
import och.util.model.Pair;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import test.BaseTest;
import web.MockHttpServletRequest;
import com.google.gson.JsonObject;
public class FrontAndChats_IntegrationTest extends BaseTest {
private Server chatsServer1;
private int chatsPort1 = 30280;
private String chatsUrl1 = "http://127.0.0.1:"+chatsPort1;
File accountsDir1;
MapProps chatProps1;
private Server chatsServer2;
private int chatsPort2 = 30281;
private String chatsUrl2 = "http://127.0.0.1:"+chatsPort2;
File accountsDir2;
MapProps chatProps2;
private Server frontServer1;
private int frontPort1 = 30282;
private String frontUrl1 = "http://127.0.0.1:"+frontPort1;
private Server frontServer2;
private int frontPort2 = 30283;
private String frontUrl2 = "http://127.0.0.1:"+frontPort2;
String remoteCryptKey = "test123";
MapProps frontProps1;
FrontApp frontApp1;
CopyOnWriteArrayList<Future<?>> frontApp1Asyncs = new CopyOnWriteArrayList<>();
FrontApp frontApp2;
CopyOnWriteArrayList<Future<?>> frontApp2Asyncs = new CopyOnWriteArrayList<>();
ChatsApp chatApp1;
ChatsApp chatApp2;
int cachePort = 12158;
CacheSever cacheSever;
String cacheSecureKey = "dd@#$#%sdfd";
MapProps syncServerProps;
SenderStub syncMailSender;
MailServiceStub syncMailService;
MainDb syncDb;
public FrontAndChats_IntegrationTest() {
this.createDir = true;
}
@Before
public void startServer() throws Exception {
MapProps cacheProps = new MapProps();
FrontAppTest.putDbProps(cacheProps, TEST_DIR);
cacheProps.putVal(db_skipDbCreation, true);
cacheProps.putVal(mail_storeDir, "./test-out/mails-itests");
cacheSever = new CacheSever(cachePort, 2, 10000, cacheSecureKey,cacheProps);
cacheSever.runAsync();
accountsDir1 = new File(TEST_DIR, "accounts1");
accountsDir2 = new File(TEST_DIR, "accounts2");
//chats1
{
chatProps1 = createChatProps();
chatProps1.putVal(chatApp_id, "chats1");
chatProps1.putVal(chats_rootDir, accountsDir1.getPath());
ChatsAppProvider.directProps = chatProps1;
chatsServer1 = new Server(chatsPort1);
chatsServer1.setStopAtShutdown(true);
chatsServer1.setHandler(createChatsServlets());
chatsServer1.start();
}
//front1
{
MapProps props = createFrontProps();
props.putVal(httpServerUrl, frontUrl1);
props.putVal(frontApp_id, "front1");
props.putVal(db_reinit, true);
props.putVal(paypal_clientStub, true);
FrontAppProvider.directProps = props;
frontServer1 = new Server(frontPort1);
frontServer1.setStopAtShutdown(true);
frontServer1.setHandler(createFrontServlets());
frontServer1.start();
frontProps1 = props;
}
//start front1 and init db
sendPost(frontUrl1+"/api/status");
chatApp1 = ChatsAppProvider.lastCreated;
frontApp1 = FrontAppProvider.lastCreated;
frontApp1.addAsyncListener(new AsyncListener() {
@Override
public void onFutureEvent(Future<?> future) {
frontApp1Asyncs.add(future);
}
});
//front2
{
MapProps props = createFrontProps();
props.putVal(httpServerUrl, frontUrl2);
props.putVal(frontApp_id, "front2");
props.putVal(db_reinit, false);
props.putVal(paypal_clientStub, true);
FrontAppProvider.directProps = props;
frontServer2 = new Server(frontPort2);
frontServer2.setStopAtShutdown(true);
frontServer2.setHandler(createFrontServlets());
frontServer2.start();
}
//start front2
sendPost(frontUrl2+"/api/status");
frontApp2 = FrontAppProvider.lastCreated;
frontApp2.addAsyncListener(new AsyncListener() {
@Override
public void onFutureEvent(Future<?> future) {
frontApp2Asyncs.add(future);
}
});
//chats2
{
chatProps2 = createChatProps();
chatProps2.putVal(chatApp_id, "chats2");
chatProps2.putVal(chats_rootDir, accountsDir2.getPath());
ChatsAppProvider.directProps = chatProps2;
chatsServer2 = new Server(chatsPort2);
chatsServer2.setStopAtShutdown(true);
chatsServer2.setHandler(createChatsServlets());
chatsServer2.start();
}
//start chats2
sendPost(chatsUrl2+URL_CHAT_CREATE_ACC);
chatApp2 = ChatsAppProvider.lastCreated;
syncServerProps = new MapProps(frontProps1.toMap());
syncServerProps.putVal(db_skipDbCreation, true);
syncServerProps.putVal(billing_sync_debug_DisableTimer, true);
syncServerProps.putVal(billing_sync_fillBlockedCacheOnStartDelay, 0);
syncServerProps.putVal(billing_sync_lastSyncStore, false);
syncMailSender = new SenderStub();
syncMailService = new MailServiceStub(syncMailSender, syncServerProps);
syncDb = new MainDb(MainDb.createDataSource(syncServerProps), syncServerProps);
}
public MapProps createFrontProps() throws Exception {
MapProps props = FrontAppTest.baseFrontProps(TEST_DIR);
props.putVal(remote_encyptedKey, remoteCryptKey);
props.putVal(chats_server_init_urls, chatsUrl1+" "+toHttps(chatsUrl1));
props.putVal(frontServerUrls, collectionToStr(list(frontUrl1,frontUrl2), ' '));
props.putVal(cache_remote_port, cachePort);
props.putVal(mail_storeDir, "./test-out/mails-itests");
props.putVal(cache_encyptedKey, cacheSecureKey);
return props;
}
public MapProps createChatProps() {
MapProps props = new MapProps();
props.putVal(remote_encyptedKey, remoteCryptKey);
props.putVal(templates_path, "./server-chat/web/WEB-INF/templates");
return props;
}
public static ServletHandler createChatsServlets() {
ServletHandler sh = new ServletHandler();
addServletWithMapping(sh, CreateAccount.class);
addServletWithMapping(sh, PutOperator.class);
addServletWithMapping(sh, RemoveOperator.class);
addServletWithMapping(sh, InitUserToken.class);
addServletWithMapping(sh, RemoveUserSession.class);
addServletWithMapping(sh, UpdateUserSessions.class);
addServletWithMapping(sh, SetAccsBlocked.class);
addServletWithMapping(sh, GetUnblockedAccs.class);
addServletWithMapping(sh, SetAccsPaused.class);
addServletWithMapping(sh, GetPausedState.class);
addServletWithMapping(sh, UpdateUserContact.class);
addServletWithMapping(sh, PutAccConfig.class);
return sh;
}
public static ServletHandler createFrontServlets() {
ServletHandler sh = new ServletHandler();
addServletWithMapping(sh, GetStatus.class);
addServletWithMapping(sh, ReloadChatsModel.class);
return sh;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void addServletWithMapping(ServletHandler sh, Class type){
WebServlet annotation = (WebServlet)type.getAnnotation(WebServlet.class);
String[] paths = annotation.value();
for (String path : paths) {
sh.addServletWithMapping(type, path);
}
}
@After
public void shutdownServer() throws Exception {
FrontAppProvider.directProps = null;
frontServer1.stop();
}
@Test
public void test_all() throws Exception {
pushToSecurityContext_SYSTEM_USER();
try {
//chats
test_chats_Exists_in_chat_server_after_front_init();
test_chats_Get_status_api();
test_chats_Fronts_models_sync_by_cache();
test_chats_InitUserSessions();
test_chats_SendUpdateSessionsReq();
test_chats_CreateAcc_byUser();
test_chats_putAccConfig_byUser();
test_chats_ChangeUserPrivs();
test_chats_ChangeUserNickname();
test_chats_ChangeOperatorEmail();
//tariffs
test_tariffs_changeSync();
//pause sync
test_chats_pauseSync();
//blocks sync
test_chats_blockedSync();
}finally {
popUserFromSecurityContext();
}
}
private void test_chats_ChangeOperatorEmail() throws Exception {
CopyOnWriteArrayList<Future<?>> asyncFutures = new CopyOnWriteArrayList<>();
frontApp1.addAsyncListener((f) -> asyncFutures.add(f));
long userId = 100;
String accUid = "demo";
ChatAccount acc = frontApp1.chats.getAccByUid(accUid, true);
ChatsApp chatApp = acc.server.httpUrl.equals(chatsUrl1) ? chatApp1 : chatApp2;
ChatOperator initOp = chatApp.chats.getOperator(accUid, userId);
String initEmail = initOp.email;
assertNotNull(initEmail);
String psw = "admin";
String newEmail = "someNew@system";
frontApp1.users.updateUser(userId, psw, new UpdateUserReq(newEmail, null, null));
//check chats
{
ChatOperator op = chatApp.chats.getOperator(accUid, userId);
assertEquals(newEmail, op.email);
}
}
private void test_chats_ChangeUserNickname() throws Exception {
ChatService chats1 = frontApp1.chats;
ChatService chats2 = frontApp2.chats;
CopyOnWriteArrayList<Future<?>> asyncFutures = new CopyOnWriteArrayList<>();
frontApp1.addAsyncListener((f) -> asyncFutures.add(f));
long userId = 100;
String nick = "test ChangeUserNickname";
String accUid = "demo";
ChatAccount acc = chats1.getAccByUid(accUid, true);
ChatsApp chatApp = acc.server.httpUrl.equals(chatsUrl1) ? chatApp1 : chatApp2;
ChatOperator initOp = chatApp.chats.getOperator(accUid, userId);
String initEmail = initOp.email;
assertNotNull(initEmail);
chats1.setNickname(accUid, userId, nick);
assertTrue(asyncFutures.size() > 0);
lastFrom(asyncFutures).get();
//check front 2
{
assertEquals(nick, chats2.getAccOperators(accUid).get(userId).nickname);
}
//check chats
{
ChatOperator op = chatApp.chats.getOperator(accUid, userId);
assertEquals(nick, op.name);
assertEquals(initEmail, op.email);
}
}
private void test_chats_blockedSync() throws Exception {
ChatService frontChats1 = frontApp1.chats;
BillingService billing1 = frontApp1.billing;
BillingService billing2 = frontApp2.billing;
UniversalQueries universal = syncDb.universal;
BillingSyncService billingSync = new BillingSyncService();
billingSync.setCacheServerContext(new CacheServerContext(syncServerProps, cacheSever, syncDb, syncMailService));
billingSync.init();
ArrayList<Pair<Long, Boolean>> blockReqs = new ArrayList<>();
BillingOps.SEND_ACCS_BLOCKED_LISTENER = (ownerId, val) -> blockReqs.add(new Pair<Long, Boolean>(ownerId, val));
long userId = 100;
int tariffId = 2;
String accUid = "blockedSync";
List<String> oldAccs = syncDb.chats.getOwnerAccs(userId);
assertTrue(oldAccs.size() > 0);
//Отключаем все другие акки от апдейта
Date longFuture = parseStandartDateTime("02.09.2040 3:00:00");
universal.update(new UpdateAllChatAccounts(new TariffStart(longFuture), new TariffLastPay(longFuture)));
//create acc
frontChats1.createAcc(1, accUid, userId, "test_monthBill", tariffId);
frontChats1.setOperatorForAcc(accUid, userId);
assertEquals(1, frontChats1.getAccOperators(accUid).size());
//ушли в минус - заблокированы все акки
{
correctBalance(syncDb, userId, new BigDecimal(4.99d));
assertEquals("4.99", frontApp1.billing.getUserBalance(userId).toString());
BigDecimal initBalance = billing1.getUserBalance(userId);
String expAmount = "-5.00";
assertFalse(findBalance(universal, userId).accsBlocked);
Date pastPay = parseStandartDateTime("01.08.2014 00:00:00");
Date now = parseStandartDateTime("02.09.2014 3:00:00");
universal.update(new UpdateChatAccountByUid(accUid, new TariffStart(pastPay), new TariffLastPay(pastPay)));
assertEquals(1, billingSync.doSyncWork(false, now));
assertEquals(expAmount, getDeltaVal(userId, initBalance));
//заблокировано в бд
assertEquals("-0.01", billing1.getUserBalance(userId).toString());
assertEquals("-0.01", billing2.getUserBalance(userId).toString());
assertTrue(findBalance(universal, userId).accsBlocked);
List<ChatAccount> ownerAccs = syncDb.chats.getOwnerAccsInfo(userId);
//все акки заблокированы
HashSet<String> serverUrls = new HashSet<>();
for (ChatAccount acc : ownerAccs) {
ChatsApp chatApp = acc.server.httpUrl.equals(chatsUrl1) ? chatApp1 : chatApp2;
assertEquals(true, chatApp.chats.isAccBlocked(acc.uid));
serverUrls.add(acc.server.httpUrl);
}
//тест проводился на разных серверах
assertTrue(serverUrls.size() > 1);
//в кеше есть флаги блока для каждого акка
for(ChatAccount acc : ownerAccs){
assertEquals(true, BillingOps.isAccBlockedFromCache(cacheSever, acc.uid));
}
//явно разблокировываем акки на серверах, чтобы проверить синхронизацию блокировок
for (ChatAccount acc : ownerAccs) {
ChatsApp chatApp = acc.server.httpUrl.equals(chatsUrl1) ? chatApp1 : chatApp2;
chatApp.chats.setAccBlocked(acc.uid, false);
assertEquals(false, chatApp.chats.isAccBlocked(acc.uid));
}
//запускаем синхронизацию
{
Cache newCache = new CacheImpl(0);
BillingSyncService otherBillingSync = new BillingSyncService();
otherBillingSync.setCacheServerContext(new CacheServerContext(syncServerProps, newCache, syncDb, syncMailService));
otherBillingSync.init();
}
//проверяем блокировки после синхронизации
for (ChatAccount acc : ownerAccs) {
ChatsApp chatApp = acc.server.httpUrl.equals(chatsUrl1) ? chatApp1 : chatApp2;
assertEquals(true, chatApp.chats.isAccBlocked(acc.uid));
}
//в кеше тоже все норм
for(ChatAccount acc : ownerAccs){
assertEquals(true, BillingOps.isAccBlockedFromCache(cacheSever, acc.uid));
}
}
//пользователь закинул деньги спустя неделю в ноль и его разблокировали
{
Date now = parseStandartDateTime("12.09.2014 15:45:00");
pushToSecurityContext(new User(userId));
try {
BillingService.PayConfirmCacheData data = new BillingService.PayConfirmCacheData(STUB_TOKEN, defPayAmount, ""+userId);
cacheSever.putVal("pay-confirm-"+userId, toJson(data));
billing2.paypal_finishPayment(now);
} finally {
popUserFromSecurityContext();
}
assertEquals("11.99", billing2.getUserBalance(userId).toString());
assertEquals("11.99", billing1.getUserBalance(userId).toString());
assertFalse(findBalance(universal, userId).accsBlocked);
//все акки разблокированы
for (ChatAccount acc : syncDb.chats.getOwnerAccsInfo(userId)) {
ChatsApp chatApp = acc.server.httpUrl.equals(chatsUrl1) ? chatApp1 : chatApp2;
assertFalse(chatApp.chats.isAccBlocked(acc.uid));
}
//в кеше нет флагов блока для каждого акка
for(String uid : syncDb.chats.getOwnerAccs(userId)){
assertEquals(false, BillingOps.isAccBlockedFromCache(cacheSever, uid));
}
}
//снова заблокировали акк
{
correctBalance(syncDb, userId, new BigDecimal(4.99d));
assertEquals("4.99", frontApp1.billing.getUserBalance(userId).toString());
assertFalse(findBalance(universal, userId).accsBlocked);
Date pastPay = parseStandartDateTime("01.08.2014 00:00:00");
Date now = parseStandartDateTime("02.09.2014 3:00:00");
universal.update(new UpdateChatAccountByUid(accUid, new TariffStart(pastPay), new TariffLastPay(pastPay)));
assertEquals(1, billingSync.doSyncWork(false, now));
//заблокировано в бд
assertTrue(findBalance(universal, userId).accsBlocked);
//все акки заблокированы
for (ChatAccount acc : syncDb.chats.getOwnerAccsInfo(userId)) {
ChatsApp chatApp = acc.server.httpUrl.equals(chatsUrl1) ? chatApp1 : chatApp2;
assertTrue(chatApp.chats.isAccBlocked(acc.uid));
}
}
//проверка заблокированных чатов
{
assertEquals(1, syncDb.universal.select(new GetAllBlockedUsers()).size());
syncMailSender.tasks.clear();
billingSync.checkAccBlocks();
assertEquals(0, syncMailSender.tasks.size());
//разблокировали чат
chatApp1.chats.setAccBlocked(accUid, false);
chatApp2.chats.setAccBlocked(accUid, false);
//проверка отправила письмо админу про рассинхрон
billingSync.checkAccBlocks();
assertEquals(1, syncMailSender.tasks.size());
//заблокировали -- проверка прошла нормально
syncMailSender.tasks.clear();
chatApp1.chats.setAccBlocked(accUid, true);
chatApp2.chats.setAccBlocked(accUid, true);
billingSync.checkAccBlocks();
assertEquals(0, syncMailSender.tasks.size());
}
//Нормируем акки обратно
Date now = new Date();
universal.update(new UpdateAllChatAccounts(new TariffStart(now), new TariffLastPay(now)));
}
private String getDeltaVal(long userId, BigDecimal oldVal) throws Exception{
BigDecimal curBalance = frontApp1.billing.getUserBalance(userId);
return getDeltaVal(curBalance, oldVal);
}
private String getDeltaVal(BigDecimal newVal, BigDecimal oldVal) throws Exception{
return round(newVal.subtract(oldVal)).toString();
}
private void correctBalance(MainDb db, long userId, BigDecimal val) throws Exception {
db.universal.update(new UpdateUserBalanceUnsafe(userId, val));
frontApp1.billing.updateUserBalanceCache(userId, false);
frontApp2.billing.updateUserBalanceCache(userId, false);
}
private void test_chats_pauseSync() throws Exception {
ChatService chats1 = frontApp1.chats;
ChatService chats2 = frontApp2.chats;
CopyOnWriteArrayList<Future<?>> asyncFutures = new CopyOnWriteArrayList<>();
frontApp1.addAsyncListener((f) -> asyncFutures.add(f));
frontApp2.addAsyncListener((f) -> asyncFutures.add(f));
long ownerId = 100;
pushToSecurityContext_SYSTEM_USER();
try {
//init
ChatAccount initAcc = chats1.getAccsForOperator(ownerId).get(0);
String uid = initAcc.uid;
long initTariff = initAcc.tariffId;
assertNotEquals(PAUSE_TARIFF_ID, initAcc.tariffId);
assertEquals(initTariff, chats2.getAccsForOperator(ownerId).get(0).tariffId);
assertEquals(false, chats1.isPausedAcc(uid));
assertEquals(false, chats2.isPausedAcc(uid));
//пауза во фронте 1
pushToSecurityContext(new User(ownerId));
try {
chats1.pauseAccByUser(uid);
} finally {
popUserFromSecurityContext();
}
//sync
lastFrom(asyncFutures).get();
//изменения подхватились во фронте 2
assertEquals(PAUSE_TARIFF_ID, chats2.getAccByUid(uid, false).tariffId);
assertEquals(true, chats1.isPausedAcc(uid));
assertEquals(true, chats2.isPausedAcc(uid));
//и на сервере чатов
ServerRow server = chats1.getAccByUid(uid, true).server;
ChatsApp chatApp = server.httpUrl.equals(chatsUrl1) ? chatApp1 : chatApp2;
assertEquals(true, chatApp.chats.isAccPaused(uid));
//тесты отправки писем админу про рассинхрон
test_billing_checkAccPaused(chatApp, uid, true);
//синхронизация билинга фиксит расхождения бд и серверов
{
//явно отпаузили
chatApp.chats.setAccPaused(uid, false);
assertEquals(false, chatApp.chats.isAccPaused(uid));
//если заново стартанем синк сервер, то будет фикс
{
Cache newCache = new CacheImpl(0);
BillingSyncService otherBillingSync = new BillingSyncService();
otherBillingSync.setCacheServerContext(new CacheServerContext(syncServerProps, newCache, syncDb, syncMailService));
otherBillingSync.init();
assertEquals(true, chatApp.chats.isAccPaused(uid));
}
}
//анпаузили во фронте 2
pushToSecurityContext(new User(ownerId));
try {
chats2.unpauseAccByUser(uid);
} finally {
popUserFromSecurityContext();
}
//sync
lastFrom(asyncFutures).get();
//изменения подхватились повсюду
assertEquals(false, chats1.isPausedAcc(uid));
assertEquals(false, chats2.isPausedAcc(uid));
assertEquals(false, chatApp.chats.isAccPaused(uid));
//тесты отправки писем админу про рассинхрон
test_billing_checkAccPaused(chatApp, uid, false);
//синхронизация билинга фиксит расхождения паузы
{
//явно отпаузили
chatApp.chats.setAccPaused(uid, true);
assertEquals(true, chatApp.chats.isAccPaused(uid));
//если заново стартанем синк сервер, то будет фикс
{
Cache newCache = new CacheImpl(0);
BillingSyncService otherBillingSync = new BillingSyncService();
otherBillingSync.setCacheServerContext(new CacheServerContext(syncServerProps, newCache, syncDb, syncMailService));
otherBillingSync.init();
assertEquals(false, chatApp.chats.isAccPaused(uid));
}
}
}finally {
popUserFromSecurityContext();
}
}
private void test_billing_checkAccPaused(ChatsApp chatApp, String uid, boolean expectedVal) throws Exception{
Cache newCache = new CacheImpl(0);
BillingSyncService billingSync = new BillingSyncService();
billingSync.setCacheServerContext(new CacheServerContext(syncServerProps, newCache, syncDb, syncMailService));
billingSync.init();
//рассинхрона нет
syncMailSender.tasks.clear();
billingSync.checkAccPaused();
assertEquals(0, syncMailSender.tasks.size());
//рассинхрон
assertEquals(expectedVal, chatApp.chats.isAccPaused(uid));
chatApp.chats.setAccPaused(uid, !expectedVal);
assertEquals(!expectedVal, chatApp.chats.isAccPaused(uid));
//отправлено письмо админу
billingSync.checkAccPaused();
assertEquals(1, syncMailSender.tasks.size());
//снова синхрон -- нет писем
chatApp.chats.setAccPaused(uid, expectedVal);
syncMailSender.tasks.clear();
billingSync.checkAccPaused();
assertEquals(0, syncMailSender.tasks.size());
}
private void test_tariffs_changeSync() throws Exception {
ChatService chats1 = frontApp1.chats;
ChatService chats2 = frontApp2.chats;
CopyOnWriteArrayList<Future<?>> asyncFutures = new CopyOnWriteArrayList<>();
frontApp1.addAsyncListener((f) -> asyncFutures.add(f));
long ownerId = 100;
long newTariffId = 2;
pushToSecurityContext_SYSTEM_USER();
try {
//init data
ChatAccount initAcc = chats1.getAccsForOperator(ownerId).get(0);
long initTariff = initAcc.tariffId;
assertNotEquals(initTariff, newTariffId);
assertEquals(null, initAcc.tariffPrevId);
assertEquals(initTariff, chats2.getAccsForOperator(ownerId).get(0).tariffId);
//app1
chats1.updateAccTariff("demo", newTariffId, false);
//sync
lastFrom(asyncFutures).get();
//app2
List<ChatAccount> accs = chats2.getAccsForOperator(ownerId);
ChatAccount acc = accs.get(0);
assertEquals("demo", acc.uid);
assertEquals(newTariffId, acc.tariffId);
assertEquals(Long.valueOf(initTariff), acc.tariffPrevId);
}finally {
popUserFromSecurityContext();
}
}
private void test_chats_ChangeUserPrivs() throws Exception {
ChatService chats1 = frontApp1.chats;
ChatService chats2 = frontApp2.chats;
CopyOnWriteArrayList<Future<?>> asyncFutures = new CopyOnWriteArrayList<>();
frontApp1.addAsyncListener((f) -> asyncFutures.add(f));
long userId1 = 100;
long userId2 = 101;
User user1 = new User(userId1);
String uid = null;
String userEmail2 = "root@system";
//create acc
pushToSecurityContext(user1);
try {
uid = chats1.createAccByUser("changeUserPrivs");
}finally {
popUserFromSecurityContext();
}
lastFrom(asyncFutures).get();
asyncFutures.clear();
String serverUrl = chats1.getServerByAcc(uid).httpUrl;
ChatsApp chatApp = serverUrl.equals(chatsUrl1)? chatApp1 : chatApp2;
assertEquals(set(CHAT_OWNER), chats2.getAccPrivilegesForUser(uid, userId1));
//create op
{
pushToSecurityContext(user1);
try {
chats1.addUserPrivileges(uid, userId2, set(CHAT_OPERATOR));
}finally {
popUserFromSecurityContext();
}
assertTrue(asyncFutures.size() > 0);
lastFrom(asyncFutures).get();
//оператор появился во чатах
pushToSecurityContext_SYSTEM_USER();
try {
assertEquals(set(CHAT_OPERATOR), chats2.getAccPrivilegesForUser(uid, userId2));
ChatOperator op = chatApp.chats.getOperator(uid, userId2);
assertNotNull(op);
assertEquals(userEmail2, op.email);
}finally {
popUserFromSecurityContext();
}
}
//remove op
{
pushToSecurityContext(user1);
try {
chats1.removeUserPrivileges(uid, userId2, set(CHAT_OPERATOR));
}finally {
popUserFromSecurityContext();
}
assertTrue(asyncFutures.size() > 0);
lastFrom(asyncFutures).get();
pushToSecurityContext_SYSTEM_USER();
try {
assertEquals(set(), chats2.getAccPrivilegesForUser(uid, userId2));
assertNull(chatApp.chats.getOperator(uid, userId2));
}finally {
popUserFromSecurityContext();
}
}
}
private void test_chats_putAccConfig_byUser() throws Exception {
ChatService chats1 = frontApp1.chats;
ChatService chats2 = frontApp2.chats;
CopyOnWriteArrayList<Future<?>> asyncFutures = new CopyOnWriteArrayList<>();
frontApp1.addAsyncListener((f) -> asyncFutures.add(f));
User user = new User(100);
String uid = null;
ChatAccount acc;
ChatsApp chatApp;
pushToSecurityContext_SYSTEM_USER();
try {
uid = chats1.getAccsForOperator(user.id).get(0).uid;
acc = chats1.getAccByUid(uid, false);
}finally {
popUserFromSecurityContext();
}
//name
{
String newName = "newName-integrTest";
//front1
pushToSecurityContext(user);
try {
chats1.putAccConfigByUser(uid, Key.name, newName);
}finally {
popUserFromSecurityContext();
}
String serverUrl = chats1.getServerByAcc(uid).httpUrl;
chatApp = serverUrl.equals(chatsUrl1)? chatApp1 : chatApp2;
chatApp.chats.setAsyncListener((f) -> asyncFutures.add(f));
assertTrue(asyncFutures.size() > 0);
getAndClearAllFutures(asyncFutures);
//check in front2
assertEquals(newName, chats2.getAccsForOperator(user.id).get(0).name);
//check in remote acc
assertEquals(newName, chatApp.chats.getAccConfig(uid, Key.name));
}
//feedback_notifyOpsByEmail
{
boolean val = acc.feedback_notifyOpsByEmail;
//front1
pushToSecurityContext(user);
try {
chats1.putAccConfigByUser(uid, Key.feedback_notifyOpsByEmail, !val);
}finally {
popUserFromSecurityContext();
}
getAndClearAllFutures(asyncFutures);
//check in front2
assertEquals( ! val, chats2.getAccsForOperator(user.id).get(0).feedback_notifyOpsByEmail);
//check in remote acc
assertEquals( String.valueOf(!val), chatApp.chats.getAccConfig(uid, Key.feedback_notifyOpsByEmail));
}
}
private void test_chats_CreateAcc_byUser() throws Exception {
ChatService chats1 = frontApp1.chats;
ChatService chats2 = frontApp2.chats;
CopyOnWriteArrayList<Future<?>> asyncFutures = new CopyOnWriteArrayList<>();
frontApp1.addAsyncListener((f) -> asyncFutures.add(f));
User user = new User(100);
String accName = "test_chats_CreateAcc_byUser";
//create in front1
pushToSecurityContext(user);
try {
chats1.createAccByUser(accName);
}finally {
popUserFromSecurityContext();
}
assertTrue(asyncFutures.size() > 0);
lastFrom(asyncFutures).get();
//check in front2
List<ChatAccount> accs2 = chats2.getAccsForOperator(user.id);
assertTrue(accs2.size() > 0);
assertEquals(accName, lastFrom(accs2).name);
}
private void test_chats_SendUpdateSessionsReq() throws Exception {
final CopyOnWriteArrayList<RemoteReqData> reqCounter = new CopyOnWriteArrayList<>();
JsonOps.addPostEncryptedJsonListener((url, req)-> {
if(url.endsWith(URL_CHAT_UPDATE_SESSIONS)) reqCounter.add(new RemoteReqData(url, req));
});
long serverId = 1;
String uid = "demo"+randomSimpleId();
ChatService chats = frontApp1.chats;
long userId = 100;
//create acc
chats.createAcc(serverId, uid, userId, null, 1);
assertEquals(1, reqCounter.size());
{
RemoteReqData data = lastFrom(reqCounter);
assertTrue(data.url.startsWith(chatsUrl1));
UpdateUserSessionsReq req = (UpdateUserSessionsReq) data.req;
assertEquals(userId, req.userId);
assertEquals(set(CHAT_OWNER), req.privilegesByAccount.get(uid));
}
//set operator
chats.setOperatorForAcc(uid, userId);
assertEquals(2, reqCounter.size());
{
RemoteReqData data = lastFrom(reqCounter);
assertTrue(data.url.startsWith(chatsUrl1));
UpdateUserSessionsReq req = (UpdateUserSessionsReq) data.req;
assertEquals(userId, req.userId);
assertEquals(set(CHAT_OWNER, CHAT_OPERATOR), req.privilegesByAccount.get(uid));
}
}
private void test_chats_InitUserSessions() throws Exception {
//init token req counter
final CopyOnWriteArrayList<String> reqCounter = new CopyOnWriteArrayList<>();
JsonOps.addPostEncryptedJsonListener((url, req) -> {
if(url.endsWith(URL_USER_INIT_TOKEN)) reqCounter.add(url);
});
SecurityService security = frontApp1.security;
ChatService chats = frontApp1.chats;
MockHttpServletRequest req = mockReq();
req.setUserAgent("browserAgent-1");
//session in front1
security.createUserSession(req, mockResp(), new LoginUserReq("root", "root", false));
//exception in chat2
chatProps2.putVal(chatApp_debug_failInitToken, true);
String token1 = chats.initUserTokenInAccServers(req);
chatProps2.putVal(chatApp_debug_failInitToken, false);
assertEquals(token1, security.getUserSessionAttr(req, ACC_SESSION_TOKEN));
assertNotNull(chatApp1.security.getUserTokenLivetime(token1));
assertNull(chatApp2.security.getUserTokenLivetime(token1));
//check remote reqs
assertEquals(1, reqCounter.size());
assertTrue(reqCounter.get(0).startsWith(chatsUrl1));
reqCounter.clear();
//token in front1 and chat1, chat2
String token2 = chats.initUserTokenInAccServers(req);
assertEquals(token1, token2);
assertEquals(token2, security.getUserSessionAttr(req, ACC_SESSION_TOKEN));
//token livetime in chats
assertNotNull(chatApp1.security.getUserTokenLivetime(token2));
assertNotNull(chatApp2.security.getUserTokenLivetime(token2));
//user privs in token
{
InitUserTokenReq tokenData1 = chatApp1.security.getUserTokenDataFromCache(token2);
InitUserTokenReq tokenData2 = chatApp2.security.getUserTokenDataFromCache(token2);
assertNotNull(tokenData1);
assertNotNull(tokenData2);
Set<PrivilegeType> privsDemo = tokenData1.privsByAcc.get("demo");
assertEquals(set(CHAT_OPERATOR), privsDemo);
assertEquals(privsDemo, tokenData1.privsByAcc.get("demo2"));
assertEquals(privsDemo, tokenData1.privsByAcc.get("demo3"));
assertEquals(tokenData1.privsByAcc, tokenData2.privsByAcc);
}
//check remote reqs
assertEquals(1, reqCounter.size());
assertTrue(reqCounter.get(0).startsWith(chatsUrl2));
reqCounter.clear();
//no reqs if alredy done
String token3 = chats.initUserTokenInAccServers(req);
assertEquals(token1, token3);
assertEquals(0, reqCounter.size());
//logout in front
security.logout(req, mockResp());
lastFrom(frontApp1Asyncs).get();
assertNull(chatApp1.security.getUserTokenLivetime(token2));
assertNull(chatApp2.security.getUserTokenLivetime(token2));
}
private void test_chats_Fronts_models_sync_by_cache() throws Exception {
ChatService chats1 = frontApp1.chats;
ChatService chats2 = frontApp2.chats;
assertEquals(chats1.getServers(), chats2.getServers());
//front1 -> front2
long serverId = chats1.createServer(chatsUrl2, chatsUrl2);
long accId = chats1.createAcc(serverId, "demo3", 100, null, 1);
assertTrue(frontApp1Asyncs.size() > 0);
lastFrom(frontApp1Asyncs).get();
//check
{
List<ChatAccount> list = chats2.getServerAccs(serverId);
assertTrue(list.size() == 1);
assertEquals("demo3", list.get(0).uid);
}
//front2 -> front1
assertEquals(emptySet(), chats1.getAccPrivilegesForUser(accId, 101));
assertEquals(emptySet(), chats1.getAccPrivilegesForUser(accId, 101));
int userId = 101;
chats2.setOperatorForAcc("demo3", userId);
lastFrom(frontApp2Asyncs).get();
//check
{
assertEquals(set(CHAT_OPERATOR), chats1.getAccPrivilegesForUser(accId, 101));
assertEquals(set(CHAT_OPERATOR), chats2.getAccPrivilegesForUser(accId, 101));
}
//has new account
{
ServerRow server = frontApp1.chats.getServerByAcc("demo3");
assertNotNull(server);
assertEquals(chatsUrl2, server.httpUrl);
}
{
ServerRow server = frontApp2.chats.getServerByAcc("demo3");
assertNotNull(server);
assertEquals(chatsUrl2, server.httpUrl);
}
assertTrue(chatApp2.chats.getRegistredOperators("demo3").size() > 0);
}
private void test_chats_Exists_in_chat_server_after_front_init() throws Exception {
assertEquals(list(DEFAULT_INIT_CHAT_ACC_1, DEFAULT_INIT_CHAT_ACC_2), chatApp1.chats.getAccIds());
assertTrue(chatApp1.chats.getRegistredOperators(DEFAULT_INIT_CHAT_ACC_1).size() > 0);
assertTrue(chatApp1.chats.getRegistredOperators(DEFAULT_INIT_CHAT_ACC_2).size() > 0);
}
private void test_chats_Get_status_api() throws Exception {
//invalid req
{
JsonObject resp = parseJsonResp(sendPost(frontUrl1+"/api/status"));
assertNotNull(resp);
assertFalse(isOkStatus(resp));
}
//invalid req
{
String invalidAccount = DEFAULT_INIT_CHAT_ACC_1+"-no";
JsonObject resp = parseJsonResp(sendPost(frontUrl1+"/api/status", map("data", "{id:'" + invalidAccount + "'}")));
assertNotNull(resp);
assertFalse(isOkStatus(resp));
}
//valid acc1
{
JsonObject resp = parseJsonResp(sendPost(frontUrl1+"/api/status", map("data", "{id:'"+DEFAULT_INIT_CHAT_ACC_1+"'}")));
assertNotNull(resp);
assertTrue(isOkStatus(resp));
}
//valid acc2
{
JsonObject resp = parseJsonResp(sendPost(frontUrl1+"/api/status", map("data", "{id:'"+DEFAULT_INIT_CHAT_ACC_2+"'}")));
assertNotNull(resp);
assertTrue(isOkStatus(resp));
}
}
static class RemoteReqData {
public String url;
public Object req;
public RemoteReqData(String url, Object req) {
super();
this.url = url;
this.req = req;
}
}
}