package org.activityinfo.server.endpoint.odk;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.collect.Sets;
import com.google.common.io.Files;
import com.google.common.io.Resources;
import com.google.inject.Provider;
import com.google.inject.util.Providers;
import org.activityinfo.fixtures.InjectionSupport;
import org.activityinfo.io.xform.form.XForm;
import org.activityinfo.legacy.shared.command.GetFormClass;
import org.activityinfo.legacy.shared.command.UpdateFormClass;
import org.activityinfo.model.auth.AuthenticatedUser;
import org.activityinfo.model.form.FormClass;
import org.activityinfo.model.form.FormField;
import org.activityinfo.model.legacy.CuidAdapter;
import org.activityinfo.model.resource.ResourceId;
import org.activityinfo.model.type.number.QuantityType;
import org.activityinfo.server.command.CommandTestCase2;
import org.activityinfo.server.command.ResourceLocatorSyncImpl;
import org.activityinfo.server.database.OnDataSet;
import org.activityinfo.service.DeploymentConfiguration;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import javax.persistence.EntityManager;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Paths;
import java.util.Properties;
import java.util.Set;
import static com.google.common.io.Resources.asByteSource;
import static com.google.common.io.Resources.getResource;
import static javax.ws.rs.core.Response.Status.CREATED;
import static javax.ws.rs.core.Response.Status.fromStatusCode;
import static org.activityinfo.model.legacy.CuidAdapter.activityFormClass;
import static org.activityinfo.model.legacy.CuidAdapter.field;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
@SuppressWarnings("AppEngineForbiddenCode")
@RunWith(InjectionSupport.class)
public class FormResourceTest extends CommandTestCase2 {
public static final int ACTIVITY_ID = 11218;
public static final int USER_ID = 9944;
private FormResource formResource;
private FormSubmissionResource formSubmissionResource;
private ResourceLocatorSyncImpl resourceLocator;
@Before
public void setUp() throws IOException {
resourceLocator = new ResourceLocatorSyncImpl(getDispatcherSync());
Provider<AuthenticatedUser> authProvider = Providers.of(new AuthenticatedUser("", USER_ID, "jorden@bdd.com"));
OdkFormFieldBuilderFactory fieldFactory = new OdkFormFieldBuilderFactory(resourceLocator);
AuthTokenProvider tokenService = new AuthTokenProvider();
TestBlobstoreService blobstore = new TestBlobstoreService();
TestInstanceIdService idService = new TestInstanceIdService();
SubmissionArchiver backupService = new SubmissionArchiver(
new DeploymentConfiguration(new Properties()));
formResource = new FormResource(resourceLocator, authProvider, fieldFactory, tokenService);
formSubmissionResource = new FormSubmissionResource(
getDispatcherSync(), resourceLocator, tokenService, null, null, blobstore, idService, backupService);
}
@Test
@OnDataSet("/dbunit/chad-form.db.xml")
public void getBlankForm() throws Exception {
setUser(USER_ID);
Response form = this.formResource.form(ACTIVITY_ID);
validate(form);
}
private void validate(Response form) throws JAXBException, URISyntaxException, IOException, InterruptedException, ParserConfigurationException, SAXException {
File file = new File(targetDir(), "form.xml");
JAXBContext context = JAXBContext.newInstance(XForm.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(form.getEntity(), file);
validate(file);
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document document = documentBuilder.parse(file);
Element userID = (Element) document.getElementsByTagName("userID").item(0);
assertThat(userID.getTextContent(), equalTo("XYZ"));
}
@Test
@OnDataSet("/dbunit/invalid-relevance.db.xml")
public void invalidExpr() throws Exception {
setUser(USER_ID);
FormClass formClass = execute(new GetFormClass(CuidAdapter.activityFormClass(ACTIVITY_ID))).getFormClass();
FormField field = new FormField(ResourceId.generateFieldId(QuantityType.TYPE_CLASS));
field.setLabel("Question");
field.setType(new QuantityType());
field.setRelevanceConditionExpression("DELETED_FIELD=1");
formClass.addElement(field);
execute(new UpdateFormClass(formClass));
Response form = this.formResource.form(ACTIVITY_ID);
validate(form);
}
@Test
@OnDataSet("/dbunit/sites-simple1.db.xml")
public void itemSet() throws IOException {
ItemSetBuilder builder = new ItemSetBuilder(resourceLocator, injector.getProvider(EntityManager.class));
StreamingOutput output = builder.build(CuidAdapter.activityFormClass(1));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
output.write(baos);
System.out.println(new String(baos.toByteArray()));
}
@Test @OnDataSet("/dbunit/sites-simple1.db.xml")
public void current() throws IOException {
}
@Test @OnDataSet("/dbunit/chad-form.db.xml")
public void parse() throws IOException {
byte bytes[] = asByteSource(getResource(FormResourceTest.class, "form.mime")).read();
Response response = formSubmissionResource.submit(bytes);
assertEquals(CREATED, fromStatusCode(response.getStatus()));
//Map<String, Object> map = store.getLastUpdated().getProperties();
// assertEquals(7, map.size());
// assertEquals(CLASS_ID.asString(), map.get("classId"));
// assertEquals(new ReferenceValue(partnerInstanceId(507, 562)).asRecord(), map.get(fieldName(PARTNER_FIELD)));
// assertEquals(new LocalDate(2005, 8, 31).asRecord(), map.get(fieldName(END_DATE_FIELD)));
// assertEquals("09/06/06", map.get(CODE_FIELD));
// assertEquals(new ReferenceValue(entity(141796)).asRecord(), map.get("a1081f11"));
// assertNull(map.get("i5346"));
// assertEquals(new NarrativeValue("Awesome.").asRecord(), map.get("a1081f14"));
// assertNotNull(map.get("backupBlobId"));
}
@Test @OnDataSet("/dbunit/chad-form.db.xml")
public void parseWithBlankComments() throws IOException {
byte bytes[] = asByteSource(getResource(FormResourceTest.class, "form-no-comments.mime")).read();
Response response = formSubmissionResource.submit(bytes);
assertEquals(CREATED, fromStatusCode(response.getStatus()));
//Map<String, Object> map = store.getLastUpdated().getProperties();
// assertEquals(7, map.size());
// assertEquals(CLASS_ID.asString(), map.get("classId"));
// assertEquals(new ReferenceValue(partnerInstanceId(507, 562)).asRecord(), map.get(fieldName(PARTNER_FIELD)));
// assertEquals(new LocalDate(2005, 8, 31).asRecord(), map.get(fieldName(END_DATE_FIELD)));
// assertEquals("09/06/06", map.get(CODE_FIELD));
// assertEquals(new ReferenceValue(entity(141796)).asRecord(), map.get("a1081f11"));
// assertNull(map.get("i5346"));
// assertEquals(new NarrativeValue("Awesome.").asRecord(), map.get("a1081f14"));
// assertNotNull(map.get("backupBlobId"));
}
private String fieldName(int fieldIndex) {
return field(activityFormClass(ACTIVITY_ID), fieldIndex).asString();
}
private File targetDir() {
String relPath = getClass().getProtectionDomain().getCodeSource().getLocation().getFile();
File targetDir = new File(relPath + "../../target");
if (!targetDir.exists()) {
targetDir.mkdir();
}
return targetDir;
}
public void validate(File file) throws URISyntaxException, IOException, InterruptedException {
URL validatorJar = Resources.getResource(FormResourceTest.class, "odk-validate-1.4.3.jar");
String[] command = {"java", "-jar", Paths.get(validatorJar.toURI()).toString(), file.getAbsolutePath()};
System.out.println(Joiner.on(' ').join(command));
ProcessBuilder validator = new ProcessBuilder(command);
validator.inheritIO();
int exitCode = validator.start().waitFor();
if(exitCode != 0) {
System.out.println("Offending XML: " + Files.toString(file, Charsets.UTF_8));
}
assertThat(exitCode, equalTo(0));
}
private class AuthTokenProvider implements AuthenticationTokenService {
@Override
public String createAuthenticationToken(int userId, ResourceId formClassId) {
return "XYZ";
}
@Override
public AuthenticatedUser authenticate(String authenticationToken) {
Set<String> tokens = Sets.newHashSet("LDbRuQsl", "token:3e2a26585ac83ff5", "token:c55536ea93b0c7da");
if(tokens.contains(authenticationToken)) {
AuthenticatedUser user = new AuthenticatedUser("", USER_ID, "@");
setUser(user.getId());
return user;
}
throw new AssertionError("Not authenticated");
}
}
private static class TestInstanceIdService implements InstanceIdService {
final private Set<String> set = Sets.newHashSet();
@Override
public boolean exists(String instanceId) {
return set.contains(instanceId);
}
@Override
public void submit(String instanceId) {
set.add(instanceId);
}
}
}