Java tutorial
/** * Copyright Microsoft Open Technologies, Inc. * * All Rights Reserved * * 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 * * THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION * ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A * PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT. * * See the Apache License, Version 2.0 for the specific language * governing permissions and limitations under the License. */ package com.msopentech.odatajclient.engine.it; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import com.msopentech.odatajclient.engine.client.http.HttpMethod; import com.msopentech.odatajclient.engine.communication.ODataClientErrorException; import com.msopentech.odatajclient.engine.communication.request.UpdateType; import com.msopentech.odatajclient.engine.communication.request.cud.ODataDeleteRequest; import com.msopentech.odatajclient.engine.communication.request.cud.ODataEntityCreateRequest; import com.msopentech.odatajclient.engine.communication.request.cud.ODataEntityUpdateRequest; import com.msopentech.odatajclient.engine.communication.request.retrieve.ODataEntityRequest; import com.msopentech.odatajclient.engine.communication.response.ODataDeleteResponse; import com.msopentech.odatajclient.engine.communication.response.ODataEntityCreateResponse; import com.msopentech.odatajclient.engine.communication.response.ODataEntityUpdateResponse; import com.msopentech.odatajclient.engine.communication.response.ODataRetrieveResponse; import com.msopentech.odatajclient.engine.data.ODataCollectionValue; import com.msopentech.odatajclient.engine.data.ODataComplexValue; import com.msopentech.odatajclient.engine.data.ODataPrimitiveValue; import com.msopentech.odatajclient.engine.data.ODataProperty; import com.msopentech.odatajclient.engine.data.ODataValue; import com.msopentech.odatajclient.engine.data.metadata.edm.EdmSimpleType; import com.msopentech.odatajclient.engine.data.ODataObjectFactory; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import com.msopentech.odatajclient.engine.data.EntryResource; import com.msopentech.odatajclient.engine.data.FeedResource; import com.msopentech.odatajclient.engine.data.ODataEntity; import com.msopentech.odatajclient.engine.data.ODataInlineEntity; import com.msopentech.odatajclient.engine.data.ODataLink; import com.msopentech.odatajclient.engine.data.atom.AtomEntry; import com.msopentech.odatajclient.engine.data.json.JSONV3Entry; import com.msopentech.odatajclient.engine.data.ODataEntitySet; import com.msopentech.odatajclient.engine.data.ODataInlineEntitySet; import com.msopentech.odatajclient.engine.uri.URIBuilder; import com.msopentech.odatajclient.engine.format.ODataPubFormat; import com.msopentech.odatajclient.engine.client.ODataClientFactory; import com.msopentech.odatajclient.engine.client.ODataV3Client; import com.msopentech.odatajclient.engine.utils.URIUtils; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; import java.net.URI; import java.util.HashSet; import java.util.Locale; import java.util.Properties; import java.util.Set; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.junit.BeforeClass; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class AbstractTest { /** * Logger. */ protected static final Logger LOG = LoggerFactory.getLogger(AbstractTest.class); protected static final String TEST_PRODUCT_TYPE = "Microsoft.Test.OData.Services.AstoriaDefaultService.Product"; protected static final String servicesODataServiceRootURL = "http://services.odata.org/V3/(S(csquyjnoaywmz5xcdbfhlc1p))/OData/OData.svc/"; protected static ODataV3Client client; protected static String testDefaultServiceRootURL; protected static String testActionOverloadingServiceRootURL; protected static String testKeyAsSegmentServiceRootURL; protected static String testODataWriterDefaultServiceRootURL; protected static String testOpenTypeServiceRootURL; protected static String testPrimitiveKeysServiceRootURL; protected static String testLargeModelServiceRootURL; protected static String testAuthServiceRootURL; @BeforeClass public static void setUpODataServiceRoot() throws IOException { String testBaseURL = null; InputStream propStream = null; try { propStream = AbstractTest.class.getResourceAsStream("/test.properties"); final Properties props = new Properties(); props.load(propStream); testBaseURL = props.getProperty("test.base.url"); } catch (Exception e) { LOG.error("Could not load test.properties", e); } finally { if (propStream != null) { propStream.close(); } } assertNotNull("Check value for the 'test.base.url' property", testBaseURL); testDefaultServiceRootURL = testBaseURL + "/DefaultService.svc"; testActionOverloadingServiceRootURL = testBaseURL + "/ActionOverloadingService.svc"; testKeyAsSegmentServiceRootURL = testBaseURL + "/KeyAsSegmentService.svc"; testODataWriterDefaultServiceRootURL = testBaseURL + "/ODataWriterDefaultService.svc"; testOpenTypeServiceRootURL = testBaseURL + "/OpenTypeService.svc"; testPrimitiveKeysServiceRootURL = testBaseURL + "/PrimitiveKeys.svc"; testLargeModelServiceRootURL = testBaseURL + "/LargeModelService.svc"; testAuthServiceRootURL = "http://localhost:9080/DefaultService.svc"; } /** * This is needed for correct number handling (Double, for example). */ @BeforeClass public static void setEnglishLocale() { Locale.setDefault(Locale.ENGLISH); } @BeforeClass public static void setClientInstance() { client = ODataClientFactory.getV3(); } protected void checkLinks(final Collection<ODataLink> original, final Collection<ODataLink> actual) { assertTrue(original.size() <= actual.size()); for (ODataLink originalLink : original) { ODataLink foundOriginal = null; ODataLink foundActual = null; for (ODataLink actualLink : actual) { if (actualLink.getType() == originalLink.getType() && (originalLink.getLink() == null || actualLink.getLink().toASCIIString() .endsWith(originalLink.getLink().toASCIIString())) && actualLink.getName().equals(originalLink.getName())) { foundOriginal = originalLink; foundActual = actualLink; } } assertNotNull(foundOriginal); assertNotNull(foundActual); if (foundOriginal instanceof ODataInlineEntity && foundActual instanceof ODataInlineEntity) { final ODataEntity originalInline = ((ODataInlineEntity) foundOriginal).getEntity(); assertNotNull(originalInline); final ODataEntity actualInline = ((ODataInlineEntity) foundActual).getEntity(); assertNotNull(actualInline); checkProperties(originalInline.getProperties(), actualInline.getProperties()); } } } protected void checkProperties(final Collection<ODataProperty> original, final Collection<ODataProperty> actual) { assertTrue(original.size() <= actual.size()); // re-organize actual properties into a Map<String, ODataProperty> final Map<String, ODataProperty> actualProps = new HashMap<String, ODataProperty>(actual.size()); for (ODataProperty prop : actual) { assertFalse(actualProps.containsKey(prop.getName())); actualProps.put(prop.getName(), prop); } assertTrue(actual.size() <= actualProps.size()); for (ODataProperty prop : original) { assertNotNull(prop); if (actualProps.containsKey(prop.getName())) { final ODataProperty actualProp = actualProps.get(prop.getName()); assertNotNull(actualProp); if (prop.getValue() != null && actualProp.getValue() != null) { checkPropertyValue(prop.getName(), prop.getValue(), actualProp.getValue()); } } else { // nothing ... maybe :FC_KeepInContent="false" // ..... no assert can be done .... } } } protected void checkPropertyValue(final String propertyName, final ODataValue original, final ODataValue actual) { assertNotNull("Null original value for " + propertyName, original); assertNotNull("Null actual value for " + propertyName, actual); assertEquals("Type mismatch for '" + propertyName + "'", original.getClass().getSimpleName(), actual.getClass().getSimpleName()); if (original.isComplex()) { final List<ODataProperty> originalFileds = new ArrayList<ODataProperty>(); for (ODataProperty prop : original.asComplex()) { originalFileds.add(prop); } final List<ODataProperty> actualFileds = new ArrayList<ODataProperty>(); for (ODataProperty prop : (ODataComplexValue) actual) { actualFileds.add(prop); } checkProperties(originalFileds, actualFileds); } else if (original.isCollection()) { assertTrue(original.asCollection().size() <= actual.asCollection().size()); boolean found = original.asCollection().isEmpty(); for (ODataValue originalValue : original.asCollection()) { for (ODataValue actualValue : actual.asCollection()) { try { checkPropertyValue(propertyName, originalValue, actualValue); found = true; } catch (AssertionError ignore) { // ignore } } } assertTrue("Found " + actual + " but expected " + original, found); } else { assertTrue("Primitive value for '" + propertyName + "' type mismatch", original.asPrimitive().getTypeName().equals(actual.asPrimitive().getTypeName())); assertEquals("Primitive value for '" + propertyName + "' mismatch", original.asPrimitive().toString(), actual.asPrimitive().toString()); } } protected ODataEntity getSampleCustomerInfo(final int id, final String sampleinfo) { final ODataEntity entity = ODataObjectFactory .newEntity("Microsoft.Test.OData.Services.AstoriaDefaultService.CustomerInfo"); entity.setMediaEntity(true); entity.addProperty(ODataObjectFactory.newPrimitiveProperty("Information", client.getPrimitiveValueBuilder().setText(sampleinfo).setType(EdmSimpleType.String).build())); return entity; } protected ODataEntity getSampleCustomerProfile(final int id, final String sampleName, final boolean withInlineInfo) { final ODataEntity entity = ODataObjectFactory .newEntity("Microsoft.Test.OData.Services.AstoriaDefaultService.Customer"); // add name attribute entity.addProperty(ODataObjectFactory.newPrimitiveProperty("Name", client.getPrimitiveValueBuilder().setText(sampleName).setType(EdmSimpleType.String).build())); // add key attribute entity.addProperty(ODataObjectFactory.newPrimitiveProperty("CustomerId", client.getPrimitiveValueBuilder() .setText(String.valueOf(id)).setType(EdmSimpleType.Int32).build())); // add BackupContactInfo attribute (collection) final ODataCollectionValue backupContactInfoValue = new ODataCollectionValue( "Collection(Microsoft.Test.OData.Services.AstoriaDefaultService.ContactDetails)"); entity.addProperty(ODataObjectFactory.newCollectionProperty("BackupContactInfo", backupContactInfoValue)); // add BackupContactInfo.ContactDetails attribute (complex) final ODataComplexValue contactDetails = new ODataComplexValue( "Microsoft.Test.OData.Services.AstoriaDefaultService.ContactDetails"); backupContactInfoValue.add(contactDetails); // add BackupContactInfo.ContactDetails.AlternativeNames attribute (collection) final ODataCollectionValue altNamesValue = new ODataCollectionValue("Collection(Edm.String)"); altNamesValue .add(client.getPrimitiveValueBuilder().setText("myname").setType(EdmSimpleType.String).build()); contactDetails.add(ODataObjectFactory.newCollectionProperty("AlternativeNames", altNamesValue)); // add BackupContactInfo.ContactDetails.EmailBag attribute (collection) final ODataCollectionValue emailBagValue = new ODataCollectionValue("Collection(Edm.String)"); emailBagValue.add(client.getPrimitiveValueBuilder().setText("myname@mydomain.com") .setType(EdmSimpleType.String).build()); contactDetails.add(ODataObjectFactory.newCollectionProperty("EmailBag", emailBagValue)); // add BackupContactInfo.ContactDetails.ContactAlias attribute (complex) final ODataComplexValue contactAliasValue = new ODataComplexValue( "Microsoft.Test.OData.Services.AstoriaDefaultService.Aliases"); contactDetails.add(ODataObjectFactory.newComplexProperty("ContactAlias", contactAliasValue)); // add BackupContactInfo.ContactDetails.ContactAlias.AlternativeNames attribute (collection) final ODataCollectionValue aliasAltNamesValue = new ODataCollectionValue("Collection(Edm.String)"); aliasAltNamesValue.add(client.getPrimitiveValueBuilder().setText("myAlternativeName") .setType(EdmSimpleType.String).build()); contactAliasValue.add(ODataObjectFactory.newCollectionProperty("AlternativeNames", aliasAltNamesValue)); if (withInlineInfo) { final ODataInlineEntity inlineInfo = ODataObjectFactory.newInlineEntity("Info", URI.create("Customer(" + id + ")/Info"), getSampleCustomerInfo(id, sampleName + "_Info")); inlineInfo.getEntity().setMediaEntity(true); entity.addLink(inlineInfo); } return entity; } protected void debugEntry(final EntryResource entry, final String message) { if (LOG.isDebugEnabled()) { final StringWriter writer = new StringWriter(); client.getSerializer().entry(entry, writer); writer.flush(); LOG.debug(message + "\n{}", writer.toString()); } } protected void debugFeed(final FeedResource feed, final String message) { if (LOG.isDebugEnabled()) { final StringWriter writer = new StringWriter(); client.getSerializer().feed(feed, writer); writer.flush(); LOG.debug(message + "\n{}", writer.toString()); } } protected void debugODataProperty(final ODataProperty property, final String message) { LOG.debug(message + "\n{}", property.toString()); } protected void debugODataValue(final ODataValue value, final String message) { LOG.debug(message + "\n{}", value.toString()); } protected void debugODataEntity(final ODataEntity entity, final String message) { if (LOG.isDebugEnabled()) { StringWriter writer = new StringWriter(); client.getSerializer().entry(client.getBinder().getEntry(entity, AtomEntry.class), writer); writer.flush(); LOG.debug(message + " (Atom)\n{}", writer.toString()); writer = new StringWriter(); client.getSerializer().entry(client.getBinder().getEntry(entity, JSONV3Entry.class), writer); writer.flush(); LOG.debug(message + " (JSON)\n{}", writer.toString()); } } protected void debugInputStream(final InputStream input, final String message) { if (LOG.isDebugEnabled()) { try { LOG.debug(message + "\n{}", IOUtils.toString(input)); } catch (IOException e) { LOG.error("Error writing stream", e); } finally { IOUtils.closeQuietly(input); } } } protected String getETag(final URI uri) { final ODataRetrieveResponse<ODataEntity> res = client.getRetrieveRequestFactory().getEntityRequest(uri) .execute(); try { return res.getEtag(); } finally { res.close(); } } protected ODataEntity read(final ODataPubFormat format, final URI editLink) { final ODataEntityRequest req = client.getRetrieveRequestFactory().getEntityRequest(editLink); req.setFormat(format); final ODataRetrieveResponse<ODataEntity> res = req.execute(); final ODataEntity entity = res.getBody(); assertNotNull(entity); if (ODataPubFormat.JSON_FULL_METADATA == format || ODataPubFormat.ATOM == format) { assertEquals(req.getURI(), entity.getEditLink()); } return entity; } protected ODataEntity createEntity(final String serviceRootURL, final ODataPubFormat format, final ODataEntity original, final String entitySetName) { final URIBuilder uriBuilder = client.getURIBuilder(serviceRootURL); uriBuilder.appendEntitySetSegment(entitySetName); debugODataEntity(original, "About to create"); final ODataEntityCreateRequest createReq = client.getCUDRequestFactory() .getEntityCreateRequest(uriBuilder.build(), original); createReq.setFormat(format); final ODataEntityCreateResponse createRes = createReq.execute(); assertEquals(201, createRes.getStatusCode()); assertEquals("Created", createRes.getStatusMessage()); final ODataEntity created = createRes.getBody(); assertNotNull(created); debugODataEntity(created, "Just created"); return created; } protected ODataEntity compareEntities(final String serviceRootURL, final ODataPubFormat format, final ODataEntity original, final int actualObjectId, final Collection<String> expands) { final URIBuilder uriBuilder = client.getURIBuilder(serviceRootURL).appendEntityTypeSegment("Customer") .appendKeySegment(actualObjectId); // search expanded if (expands != null) { for (String expand : expands) { uriBuilder.expand(expand); } } final ODataEntityRequest req = client.getRetrieveRequestFactory().getEntityRequest(uriBuilder.build()); req.setFormat(format); final ODataRetrieveResponse<ODataEntity> res = req.execute(); assertEquals(200, res.getStatusCode()); final ODataEntity actual = res.getBody(); assertNotNull(actual); // check defined links checkLinks(original.getAssociationLinks(), actual.getAssociationLinks()); checkLinks(original.getEditMediaLinks(), actual.getEditMediaLinks()); checkLinks(original.getNavigationLinks(), actual.getNavigationLinks()); // check defined properties equality checkProperties(original.getProperties(), actual.getProperties()); return actual; } protected void cleanAfterCreate(final ODataPubFormat format, final ODataEntity created, final boolean includeInline, final String baseUri) { final Set<URI> toBeDeleted = new HashSet<URI>(); toBeDeleted.add(created.getEditLink()); if (includeInline) { for (ODataLink link : created.getNavigationLinks()) { if (link instanceof ODataInlineEntity) { final ODataEntity inline = ((ODataInlineEntity) link).getEntity(); if (inline.getEditLink() != null) { toBeDeleted.add(URIUtils.getURI(baseUri, inline.getEditLink().toASCIIString())); } } if (link instanceof ODataInlineEntitySet) { final ODataEntitySet inline = ((ODataInlineEntitySet) link).getEntitySet(); for (ODataEntity entity : inline.getEntities()) { if (entity.getEditLink() != null) { toBeDeleted.add(URIUtils.getURI(baseUri, entity.getEditLink().toASCIIString())); } } } } } assertFalse(toBeDeleted.isEmpty()); for (URI link : toBeDeleted) { final ODataDeleteRequest deleteReq = client.getCUDRequestFactory().getDeleteRequest(link); final ODataDeleteResponse deleteRes = deleteReq.execute(); assertEquals(204, deleteRes.getStatusCode()); assertEquals("No Content", deleteRes.getStatusMessage()); deleteRes.close(); final ODataEntityRequest retrieveReq = client.getRetrieveRequestFactory().getEntityRequest(link); // bug that needs to be fixed on the SampleService - cannot get entity not found with header // Accept: application/json;odata=minimalmetadata retrieveReq.setFormat(format == ODataPubFormat.JSON_FULL_METADATA ? ODataPubFormat.JSON : format); Exception exception = null; try { retrieveReq.execute(); fail(); } catch (ODataClientErrorException e) { exception = e; assertEquals(404, e.getStatusLine().getStatusCode()); } assertNotNull(exception); } } protected void updateEntityDescription(final ODataPubFormat format, final ODataEntity changes, final UpdateType type) { updateEntityDescription(format, changes, type, null); } protected void updateEntityDescription(final ODataPubFormat format, final ODataEntity changes, final UpdateType type, final String etag) { updateEntityStringProperty("Description", format, changes, type, etag); } protected void updateEntityStringProperty(final String propertyName, final ODataPubFormat format, final ODataEntity changes, final UpdateType type, final String etag) { final URI editLink = changes.getEditLink(); final String newm = "New " + propertyName + "(" + System.currentTimeMillis() + ")"; ODataProperty propertyValue = changes.getProperty(propertyName); final String oldm; if (propertyValue == null) { oldm = null; } else { oldm = propertyValue.getValue().toString(); changes.removeProperty(propertyValue); } assertNotEquals(newm, oldm); changes.addProperty(ODataObjectFactory.newPrimitiveProperty(propertyName, client.getPrimitiveValueBuilder().setText(newm).build())); update(type, changes, format, etag); final ODataEntity actual = read(format, editLink); propertyValue = null; for (ODataProperty prop : actual.getProperties()) { if (prop.getName().equals(propertyName)) { propertyValue = prop; } } assertNotNull(propertyValue); assertEquals(newm, propertyValue.getValue().toString()); } protected void update(final UpdateType type, final ODataEntity changes, final ODataPubFormat format, final String etag) { final ODataEntityUpdateRequest req = client.getCUDRequestFactory().getEntityUpdateRequest(type, changes); if (client.getConfiguration().isUseXHTTPMethod()) { assertEquals(HttpMethod.POST, req.getMethod()); } else { assertEquals(type.getMethod(), req.getMethod()); } req.setFormat(format); if (StringUtils.isNotBlank(etag)) { req.setIfMatch(etag); // Product include ETag header into the response ..... } final ODataEntityUpdateResponse res = req.execute(); assertEquals(204, res.getStatusCode()); } }