private void testUpdateCreate(boolean edit) throws ClassNotFoundException {
    final DateTime dtValue = DateUtil.now();

    mockSampleFields();
    mockDataService();
    mockEntity();
    when(motechDataService.retrieve("id", INSTANCE_ID)).thenReturn(new TestSample());

    List<FieldRecord> fieldRecords =
        asList(
            FieldTestHelper.fieldRecord("strField", String.class.getName(), "", "this is a test"),
            FieldTestHelper.fieldRecord("intField", Integer.class.getName(), "", 16),
            FieldTestHelper.fieldRecord("timeField", Time.class.getName(), "", "10:17"),
            FieldTestHelper.fieldRecord("dtField", DateTime.class.getName(), "", dtValue));

    Long id = (edit) ? INSTANCE_ID : null;
    EntityRecord record = new EntityRecord(id, ENTITY_ID, fieldRecords);

    MDSClassLoader.getInstance().loadClass(TestSample.class.getName());
    instanceService.saveInstance(record);

    ArgumentCaptor<TestSample> captor = ArgumentCaptor.forClass(TestSample.class);
    if (edit) {
      verify(motechDataService).update(captor.capture());
    } else {
      verify(motechDataService).create(captor.capture());
    }

    TestSample sample = captor.getValue();
    assertEquals("this is a test", sample.getStrField());
    assertEquals(Integer.valueOf(16), sample.getIntField());
    assertEquals(new Time(10, 17), sample.getTimeField());
    assertEquals(dtValue, sample.getDtField());
  }
  private void mockLookups() {
    LookupDto lookup =
        new LookupDto(
            TestDataService.LOOKUP_1_NAME,
            true,
            true,
            asList(FieldTestHelper.lookupFieldDto(1L, "strField")),
            true,
            "singleObject",
            asList("strField"));
    when(entityService.getLookupByName(ENTITY_ID, TestDataService.LOOKUP_1_NAME))
        .thenReturn(lookup);
    Map<String, FieldDto> mapping = new HashMap<>();
    mapping.put(
        "strField",
        FieldTestHelper.fieldDto(
            1L, "strField", String.class.getName(), "String field", "Default"));
    when(entityService.getLookupFieldsMapping(ENTITY_ID, TestDataService.LOOKUP_1_NAME))
        .thenReturn(mapping);

    lookup =
        new LookupDto(
            TestDataService.LOOKUP_2_NAME,
            false,
            true,
            asList(FieldTestHelper.lookupFieldDto(1L, "strField")),
            false,
            "multiObject",
            asList("strField"));
    when(entityService.getLookupByName(ENTITY_ID, TestDataService.LOOKUP_2_NAME))
        .thenReturn(lookup);
    when(entityService.getLookupFieldsMapping(ENTITY_ID, TestDataService.LOOKUP_2_NAME))
        .thenReturn(mapping);

    lookup =
        new LookupDto(
            TestDataService.NULL_EXPECTING_LOOKUP_NAME,
            false,
            true,
            asList(FieldTestHelper.lookupFieldDto(3L, "dtField")),
            false,
            "nullParamExpected",
            asList("dtField"));
    when(entityService.getLookupByName(ENTITY_ID, TestDataService.NULL_EXPECTING_LOOKUP_NAME))
        .thenReturn(lookup);
    mapping = new HashMap<>();
    mapping.put(
        "dtField",
        FieldTestHelper.fieldDto(3L, "dtField", DateTime.class.getName(), "DateTime field", null));
    when(entityService.getLookupFieldsMapping(
            ENTITY_ID, TestDataService.NULL_EXPECTING_LOOKUP_NAME))
        .thenReturn(mapping);
  }
  private void mockAnotherEntityFields() {
    FieldDto relatedField =
        FieldTestHelper.fieldDto(
            2L, "testClasses", OneToManyRelationship.class.getName(), "Test Classes", null);
    relatedField.addMetadata(
        new MetadataDto(Constants.MetadataKeys.RELATED_CLASS, TestClass.class.getName()));

    when(entityService.getEntityFieldsForUI(ANOTHER_ENTITY_ID))
        .thenReturn(
            asList(
                FieldTestHelper.fieldDto(1L, "id", Long.class.getName(), "Id", null),
                relatedField));
  }
  @Test
  public void shouldAutoPopulateOwnerAndCreator() {
    when(entityService.getEntityFieldsForUI(ENTITY_ID))
        .thenReturn(
            asList(
                FieldTestHelper.fieldDto(1L, "owner", String.class.getName(), "String field", null),
                FieldTestHelper.fieldDto(
                    1L, "creator", String.class.getName(), "String field", null)));
    mockEntity();
    setUpSecurityContext();

    EntityRecord record = instanceService.newInstance(ENTITY_ID);

    List<FieldRecord> fieldRecords = record.getFields();
    assertEquals(
        asList("motech", "motech"), extract(fieldRecords, on(FieldRecord.class).getValue()));
  }
  @Test
  public void shouldNotAutoPopulateOwnerAndCreatorForNonEditableFields() {
    FieldDto ownerField =
        FieldTestHelper.fieldDto(1L, "owner", String.class.getName(), "String field", null);
    ownerField.setNonEditable(true);
    FieldDto creatorField =
        FieldTestHelper.fieldDto(1L, "creator", String.class.getName(), "String field", null);
    creatorField.setNonEditable(true);

    when(entityService.getEntityFieldsForUI(ENTITY_ID))
        .thenReturn(asList(ownerField, creatorField));
    mockEntity();
    setUpSecurityContext();

    EntityRecord record = instanceService.newInstance(ENTITY_ID);

    List<FieldRecord> fieldRecords = record.getFields();
    assertEquals(asList(null, null), extract(fieldRecords, on(FieldRecord.class).getValue()));
  }
  private void mockSampleFields() {

    when(entityService.getEntityFieldsForUI(ENTITY_ID))
        .thenReturn(
            asList(
                FieldTestHelper.fieldDto(
                    1L, "strField", String.class.getName(), "String field", "Default"),
                FieldTestHelper.fieldDto(
                    2L, "intField", Integer.class.getName(), "Integer field", 7),
                FieldTestHelper.fieldDto(
                    3L, "dtField", DateTime.class.getName(), "DateTime field", null),
                FieldTestHelper.fieldDto(4L, "timeField", Time.class.getName(), "Time field", null),
                // In case of EUDE was created with field name starting from capital letter
                // that capitalized field name will be passed in FieldDto (as LongField in this
                // case).
                // InstanceService should be able to make operations on record regardless of field
                // starts with a capital letter or not.
                FieldTestHelper.fieldDto(
                    5L, "LongField", Long.class.getName(), "Long field", null)));
  }
  @Test
  public void shouldCreateInstanceOfSubclassedEntityWithRelation() {
    mockEntity(SubclassSample.class, ENTITY_ID, entity);
    mockDataService(SubclassSample.class, motechDataService);
    when(motechDataService.retrieve("id", INSTANCE_ID)).thenReturn(new SubclassSample());
    when(entityService.getEntityFieldsForUI(ENTITY_ID))
        .thenReturn(
            asList(
                FieldTestHelper.fieldDto(
                    1L, "superclassInteger", Integer.class.getName(), "Superclass Integer", 7),
                FieldTestHelper.fieldDto(
                    2L, "subclassString", String.class.getName(), "Subclass String", "test"),
                FieldTestHelper.fieldDto(
                    3L,
                    "superclassRelation",
                    TypeDto.ONE_TO_ONE_RELATIONSHIP.getTypeClass(),
                    "Superclass Relationship",
                    null)));

    long relationEntityId = ANOTHER_ENTITY_ID;
    long relationInstanceId = INSTANCE_ID + 1;
    EntityDto relationEntity = mock(EntityDto.class);
    MotechDataService relationDataService = mock(MotechDataService.class);
    mockEntity(TestSample.class, relationEntityId, relationEntity);
    mockDataService(TestSample.class, relationDataService);
    TestSample relatedInstance = new TestSample("test sample", 42);
    when(relationDataService.retrieve("id", relationInstanceId)).thenReturn(relatedInstance);
    when(relationDataService.findById(relationInstanceId)).thenReturn(relatedInstance);

    RelationshipsUpdate relationshipsUpdate = new RelationshipsUpdate();
    relationshipsUpdate.getAddedIds().add(relationInstanceId);

    EntityRecord createRecord =
        new EntityRecord(
            null,
            ENTITY_ID,
            asList(
                FieldTestHelper.fieldRecord("superclassInteger", Integer.class.getName(), "", 77),
                FieldTestHelper.fieldRecord(
                    "subclassString", String.class.getName(), "", "test test"),
                FieldTestHelper.fieldRecord(
                    TypeDto.ONE_TO_ONE_RELATIONSHIP,
                    "superclassRelation",
                    "",
                    relationshipsUpdate)));

    ArgumentCaptor<SubclassSample> createCaptor = ArgumentCaptor.forClass(SubclassSample.class);
    instanceService.saveInstance(createRecord);
    verify(motechDataService).create(createCaptor.capture());

    SubclassSample instance = createCaptor.getValue();
    assertEquals(77, (int) instance.getSuperclassInteger());
    assertEquals("test test", instance.getSubclassString());
    assertNotNull(instance.getSuperclassRelation());
    assertEquals(relatedInstance.getStrField(), instance.getSuperclassRelation().getStrField());
    assertEquals(relatedInstance.getIntField(), instance.getSuperclassRelation().getIntField());
  }
  @Test(expected = ObjectUpdateException.class)
  public void shouldThrowExceptionWhileUpdatingReadonlyField() throws ClassNotFoundException {
    mockDataService();
    mockEntity();
    when(motechDataService.retrieve("id", INSTANCE_ID)).thenReturn(new TestSample());

    List<FieldRecord> fieldRecords =
        asList(
            FieldTestHelper.fieldRecord("strField", String.class.getName(), "", "CannotEditThis"));
    fieldRecords.get(0).setNonEditable(true);

    EntityRecord record = new EntityRecord(INSTANCE_ID, ENTITY_ID, fieldRecords);

    instanceService.saveInstance(record);
  }
 private void mockTestClassFields() {
   when(entityService.getEntityFieldsForUI(TEST_CLASS_ID))
       .thenReturn(
           singletonList(FieldTestHelper.fieldDto(1L, "id", Long.class.getName(), "Id", null)));
 }
  @Test
  public void shouldUpdateRelatedFields() {
    TestSample test1 = new TestSample("someString", 4);
    TestSample test2 = new TestSample("otherString", 5);
    TestSample test3 = new TestSample("sample", 6);

    RelationshipsUpdate oneToOneUpdate = new RelationshipsUpdate();
    oneToOneUpdate.getAddedIds().add(6L);
    RelationshipsUpdate oneToManyUpdate = buildRelationshipUpdate();

    List<FieldRecord> fieldRecords =
        asList(
            FieldTestHelper.fieldRecord("title", String.class.getName(), "String field", "Default"),
            FieldTestHelper.fieldRecord(
                TypeDto.ONE_TO_MANY_RELATIONSHIP, "testSamples", "Related field", oneToManyUpdate),
            FieldTestHelper.fieldRecord(
                TypeDto.ONE_TO_ONE_RELATIONSHIP,
                "testSample",
                "Other Related field",
                oneToOneUpdate));

    EntityRecord entityRecord = new EntityRecord(null, ANOTHER_ENTITY_ID, fieldRecords);

    mockSampleFields();
    mockDataService();
    mockEntity();

    EntityDto entityWithRelatedField = mock(EntityDto.class);
    when(entityService.getEntity(ANOTHER_ENTITY_ID)).thenReturn(entityWithRelatedField);
    when(entityWithRelatedField.getClassName()).thenReturn(AnotherSample.class.getName());
    when(entityWithRelatedField.getId()).thenReturn(ENTITY_ID + 1);

    ServiceReference serviceReferenceForClassWithRelatedField = mock(ServiceReference.class);
    MotechDataService serviceForClassWithRelatedField = mock(MotechDataService.class);
    when(bundleContext.getServiceReference(
            ClassName.getInterfaceName(AnotherSample.class.getName())))
        .thenReturn(serviceReferenceForClassWithRelatedField);
    when(bundleContext.getService(serviceReferenceForClassWithRelatedField))
        .thenReturn(serviceForClassWithRelatedField);
    when(motechDataService.findById(4L)).thenReturn(test1);
    when(motechDataService.findById(5L)).thenReturn(test2);
    when(motechDataService.findById(6L)).thenReturn(test3);
    when(motechDataService.findByIds(oneToManyUpdate.getAddedIds()))
        .thenReturn(Arrays.asList(test1, test2));

    when(entityService.getEntityFieldsForUI(ANOTHER_ENTITY_ID))
        .thenReturn(
            asList(
                FieldTestHelper.fieldDto(
                    5L, "title", String.class.getName(), "String field", "Default"),
                FieldTestHelper.fieldDto(
                    6L,
                    "testSamples",
                    TypeDto.ONE_TO_MANY_RELATIONSHIP.getTypeClass(),
                    "Related field",
                    null)));

    ArgumentCaptor<AnotherSample> captor = ArgumentCaptor.forClass(AnotherSample.class);
    instanceService.saveInstance(entityRecord, null);

    verify(serviceForClassWithRelatedField).create(captor.capture());
    AnotherSample capturedValue = captor.getValue();
    assertEquals(capturedValue.getTestSample(), test3);
    assertEquals(capturedValue.getTestSamples().size(), 3);
    assertEquals(capturedValue.getTitle(), "Default");
    assertTrue(capturedValue.getTestSamples().contains(test1));
    assertFalse(capturedValue.getTestSamples().contains(test3));
    assertTrue(capturedValue.getTestSamples().contains(test2));
  }