package org.activityinfo.server.command;
/*
* #%L
* ActivityInfo Server
* %%
* Copyright (C) 2009 - 2013 UNICEF
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import org.activityinfo.legacy.shared.command.*;
import org.activityinfo.legacy.shared.command.result.MonthlyReportResult;
import org.activityinfo.legacy.shared.command.result.SiteResult;
import org.activityinfo.legacy.shared.model.AttributeDTO;
import org.activityinfo.legacy.shared.model.IndicatorRowDTO;
import org.activityinfo.legacy.shared.model.SiteDTO;
import org.activityinfo.legacy.shared.util.Collector;
import org.activityinfo.fixtures.InjectionSupport;
import org.activityinfo.fixtures.MockHibernateModule;
import org.activityinfo.fixtures.Modules;
import org.activityinfo.server.command.handler.sync.TimestampHelper;
import org.activityinfo.server.database.OnDataSet;
import org.activityinfo.server.database.hibernate.entity.AdminEntity;
import org.activityinfo.server.database.hibernate.entity.Location;
import org.activityinfo.server.database.hibernate.entity.LocationType;
import org.activityinfo.server.endpoint.gwtrpc.GwtRpcModule;
import org.activityinfo.server.util.logging.LoggingModule;
import org.activityinfo.model.legacy.KeyGenerator;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import javax.persistence.EntityManager;
import java.sql.SQLException;
import java.util.Date;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.activityinfo.legacy.shared.command.UpdateMonthlyReports.Change;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
@RunWith(InjectionSupport.class)
@Modules({
MockHibernateModule.class,
GwtRpcModule.class,
LoggingModule.class
})
public class SyncIntegrationTest extends LocalHandlerTestCase {
@Inject
private KeyGenerator keyGenerator;
@Before
public void setupLogging() {
Logger.getLogger("org.hibernate").setLevel(Level.ALL);
}
private long nowIsh;
@Test
@OnDataSet("/dbunit/sites-simple1.db.xml")
public void run() throws SQLException, InterruptedException {
synchronizeFirstTime();
Collector<Date> lastUpdate = Collector.newCollector();
syncHistoryTable.get(lastUpdate);
assertThat(lastUpdate.getResult(), is(not(nullValue())));
assertThat(
queryString("select Name from Indicator where IndicatorId=103"),
equalTo("Nb. of distributions"));
assertThat(
queryString("select Name from AdminLevel where AdminLevelId=1"),
equalTo("Province"));
assertThat(
queryString("select Name from AdminEntity where AdminEntityId=21"),
equalTo("Irumu"));
assertThat(queryString("select Name from Location where LocationId=7"),
equalTo("Shabunda"));
assertThat(
queryInt("select value from IndicatorValue where ReportingPeriodId=601 and IndicatorId=6"),
equalTo(35));
assertThat(
queryInt("select PartnerId from partnerInDatabase where databaseid=2"),
equalTo(1));
assertThat(
queryInt("select AttributeGroupId from AttributeGroupInActivity where ActivityId=2"),
equalTo(1));
assertThat(queryInt("select count(*) from LockedPeriod"), equalTo(4));
assertThat(
queryInt("select count(*) from LockedPeriod where ProjectId is not null"),
equalTo(1));
assertThat(
queryInt("select count(*) from LockedPeriod where ActivityId is not null"),
equalTo(1));
assertThat(
queryInt("select count(*) from LockedPeriod where UserDatabaseId is not null"),
equalTo(2));
// / now try updating a site remotely (from another client)
// and veryify that we get the update after we synchronized
Thread.sleep(1000);
SiteDTO s1 = executeLocally(GetSites.byId(1)).getData().get(0);
assertThat((Double) s1.getIndicatorValue(1), equalTo(1500d));
Map<String, Object> changes = Maps.newHashMap();
changes.put(AttributeDTO.getPropertyName(1), true);
changes.put("comments", "newComments");
executeRemotely(new UpdateSite(1, changes));
synchronize();
s1 = executeLocally(GetSites.byId(1)).getData().get(0);
assertThat(s1.getAttributeValue(1), equalTo(true));
assertThat(s1.getAttributeValue(2), equalTo(false));
assertThat(s1.getComments(), equalTo("newComments"));
// old values are preserved...
assertThat(s1.getIndicatorDoubleValue(1), equalTo(1500d));
// Try deleting a site
executeRemotely(new Delete("Site", 1));
synchronize();
SiteResult siteResult = executeLocally(GetSites.byId(1));
assertThat(siteResult.getData().size(), equalTo(0));
// Verify that we haven't toasted the other data
SiteDTO site = executeLocally(GetSites.byId(3)).getData().get(0);
assertThat(site.getIndicatorDoubleValue(1), equalTo(10000d));
}
@Test
@OnDataSet("/dbunit/locations.db.xml")
public void locationsAreChunked() throws SQLException, InterruptedException {
addLocationsToServerDatabase(220);
synchronizeFirstTime();
assertThat(
Integer.valueOf(queryString("select count(*) from Location")),
equalTo(220));
// update a location on the server
serverEm.getTransaction().begin();
Location location = (Location) serverEm.createQuery(
"select l from Location l where l.name = 'Penekusu 26'")
.getSingleResult();
location.setAxe("Motown");
location.setTimeEdited(new Date().getTime());
serverEm.getTransaction().commit();
newRequest();
synchronize();
// todo: store milliseconds in mysql rather than as
// date time which has resolution limited to 1 second
Thread.sleep(1000);
assertThat(
queryInt("select count(*) from Location where Name='Penekusu 26'"),
equalTo(1));
assertThat(
queryString("select axe from Location where Name='Penekusu 26'"),
equalTo("Motown"));
// now create a new location
Location newLocation = new Location();
int locationId = keyGenerator.generateInt();
newLocation.setName("Bukavu");
newLocation.setTimeEdited(new Date().getTime());
newLocation.setId(123456789);
newLocation.setLocationType(serverEm.find(LocationType.class, 1));
newLocation.setId(locationId);
serverEm.getTransaction().begin();
serverEm.persist(newLocation);
serverEm.getTransaction().commit();
newRequest();
synchronize();
assertThat(queryString("select name from Location where LocationId = "
+ locationId),
equalTo("Bukavu"));
}
@Test
@OnDataSet("/dbunit/sites-simple1.db.xml")
public void testGetAdminEntities() throws SQLException, InterruptedException {
synchronizeFirstTime();
executeLocally(new GetAdminEntities(1));
}
@Test
@OnDataSet("/dbunit/monthly-calc-indicators.db.xml")
public void updateMonthlyReports() throws SQLException, InterruptedException {
synchronizeFirstTime();
int siteId = 1;
MonthlyReportResult result = executeLocally(new GetMonthlyReports(siteId, new Month(2009, 1), 5));
IndicatorRowDTO women = result.getData().get(0);
IndicatorRowDTO men = result.getData().get(1);
assertThat(women.getIndicatorName(), equalTo("women"));
assertThat(women.getIndicatorId(), equalTo(7002));
assertThat(men.getIndicatorName(), equalTo("men"));
assertThat(men.getActivityName(), equalTo("NFI"));
assertThat(men.getActivityId(), equalTo(901));
assertThat(men.getIndicatorId(), equalTo(7001));
assertThat(men.getValue(2009, 1), equalTo(200d));
assertThat(women.getValue(2009, 1), equalTo(300d));
assertThat(men.getValue(2009, 2), equalTo(150d));
assertThat(women.getValue(2009, 2), equalTo(330d));
// Update locally
executeLocally(new UpdateMonthlyReports(siteId, Lists.newArrayList(
new Change(men.getIndicatorId(), new Month(2009, 1), 221d),
new Change(men.getIndicatorId(), new Month(2009, 3), 444d),
new Change(women.getIndicatorId(), new Month(2009, 5), 200d),
new Change(men.getIndicatorId(), new Month(2009, 5), 522d))));
result = executeLocally(new GetMonthlyReports(siteId, new Month(2009, 1), 12));
women = result.getData().get(0);
men = result.getData().get(1);
assertThat(men.getValue(2009, 1), equalTo(221d));
assertThat(women.getValue(2009, 1), equalTo(300d));
// same - no change
assertThat(men.getValue(2009, 2), equalTo(150d));
assertThat(women.getValue(2009, 2), equalTo(330d));
// new periods
assertThat(men.getValue(2009, 3), equalTo(444d));
assertThat(women.getValue(2009, 5), equalTo(200d));
assertThat(men.getValue(2009, 5), equalTo(522d));
// Synchronize
synchronize();
newRequest();
MonthlyReportResult remoteResult = executeRemotely(new GetMonthlyReports(siteId, new Month(2009, 1), 12));
women = remoteResult.getData().get(0);
men = remoteResult.getData().get(1);
assertThat(men.getValue(2009, 1), equalTo(221d));
assertThat(women.getValue(2009, 1), equalTo(300d));
// same - no change
assertThat(men.getValue(2009, 2), equalTo(150d));
assertThat(women.getValue(2009, 2), equalTo(330d));
// new periods
assertThat(men.getValue(2009, 3), equalTo(444d));
assertThat(women.getValue(2009, 5), equalTo(200d));
assertThat(men.getValue(2009, 5), equalTo(522d));
newRequest();
// REmote update
executeRemotely(new UpdateMonthlyReports(siteId, Lists.newArrayList(
new Change(men.getIndicatorId(), new Month(2009, 1), 40d),
new Change(women.getIndicatorId(), new Month(2009, 3), 6000d))));
newRequest();
synchronize();
result = executeLocally(new GetMonthlyReports(siteId, new Month(2009, 1), 5));
women = result.getData().get(0);
men = result.getData().get(1);
assertThat(men.getValue(2009, 1), equalTo(40d));
assertThat(women.getValue(2009, 1), equalTo(300d)); // unchanged
assertThat(women.getValue(2009, 3), equalTo(6000d));
}
@Test
@OnDataSet("/dbunit/locations.db.xml")
public void timeStampSurvivesRoundTrip() {
EntityManager entityManager = serverEntityManagerFactory
.createEntityManager();
entityManager.getTransaction().begin();
Location loc = new Location();
loc.setTimeEdited(nowIsh += 1500);
loc.setName("Penekusu");
loc.setLocationType(entityManager.find(LocationType.class, 1));
entityManager.persist(loc);
entityManager.getTransaction().commit();
entityManager.clear();
entityManager.getTransaction().begin();
Location loc2 = entityManager.find(Location.class, loc.getId());
String tsString = TimestampHelper.toString(loc2.getTimeEdited());
long ts = TimestampHelper.fromString(tsString);
assertFalse(loc2 == loc);
assertThat(loc2.getTimeEdited(), equalTo(ts));
entityManager.getTransaction().commit();
entityManager.clear();
entityManager.getTransaction().begin();
Location loc3 = entityManager.find(Location.class, loc.getId());
assertFalse(ts > loc3.getTimeEdited());
assertFalse(ts < loc3.getTimeEdited());
entityManager.close();
}
private void addLocationsToServerDatabase(int count) {
nowIsh = new Date().getTime();
EntityManager entityManager = serverEntityManagerFactory
.createEntityManager();
entityManager.getTransaction().begin();
for (int i = 1; i <= count; ++i) {
Location loc = new Location();
loc.setId(i);
loc.setTimeEdited(nowIsh += 15000);
loc.setName("Penekusu " + i);
loc.getAdminEntities().add(
entityManager.getReference(AdminEntity.class, 2));
loc.getAdminEntities().add(
entityManager.getReference(AdminEntity.class, 12));
loc.setLocationType(entityManager.find(LocationType.class, 1));
entityManager.persist(loc);
entityManager.flush();
assertTrue(loc.getId() != 0);
}
entityManager.getTransaction().commit();
entityManager.close();
}
private String queryString(String sql) throws SQLException {
return localDatabase.selectString(sql);
}
private Integer queryInt(String sql) throws SQLException {
return localDatabase.selectInt(sql);
}
}