VDM works for one Odata service, doesn't work for another

耗尽温柔 提交于 2021-01-29 06:50:37

问题


I tried to use S4 SDK to connect to S/4 HANA Odata service. S/4 team gave us two services. With same destination, similar code, integration with one service works, with another doesn't.

Best regards

Ying

code used is

final List<User> userList = new DefaultS4cUserMetadataService()
        .getAllUser()
        .select(
            User.USER, 
            User.BUSINESS_UNIT,
            User.COMPANY,
            User.COST_CENTER) 
        .filter(
            User.TIME_STAMP.ge(LocalDateTime.of(1970, Month.JANUARY, 1, 0, 0, 0)))
        .orderBy(User.USER, Order.ASC)
        .execute(configContext);
return userList;

I also called without select and filter, but it get the same error: Internal error with code 500. But for the service to get business role, it worked. The code used to get business role is

final List<IAGBusinessRoleView> businessRoleList =
        new DefaultS4cBusinessRoleMetadataService()
            .getAllIAGBusinessRoleView()
            .select(
                IAGBusinessRoleView.BUS_ROLE_ID,
                IAGBusinessRoleView.USER_NAME,
                IAGBusinessRoleView.UUID,
                IAGBusinessRoleView.DESCRIPTION,
                IAGBusinessRoleView.TIME_STAMP,
                IAGBusinessRoleView.LANGUAGE_KEY)
            .orderBy(IAGBusinessRoleView.BUS_ROLE_ID, Order.ASC)
            .execute(configContext);
return businessRoleList;

It used the same destination.


回答1:


After looking at the problem we found out the S/4HANA service in the background did not behave as expected.

Fur further reference I will describe a way to understand what happens under the hood of the OData VDM.


Making the HTTP calls visible

To see what HTTP requests the OData VDM executes we will build a test which sets up and tears down a local mock server to which the requests will be sent. For that we use Wiremock.

Prerequisites

The only prerequisite for this is that you download the metadata file of the service you want to test against. You can obtain this by using the $metadata endpoint of your target system.

For the PhysicalInventoryDocumentService this might look something like this:

https://myserver.com/sap/opu/odata/sap/API_PHYSICAL_INVENTORY_DOC_SRV/$metadata

The path can be found in the service interface of your service to check. In this example you will find it in the PhysicalInventoryDocumentService:

public interface PhysicalInventoryDocumentService
{
    // ...
    String DEFAULT_SERVICE_PATH = "/sap/opu/odata/sap/API_PHYSICAL_INVENTORY_DOC_SRV";
    // ...
}

Setup the Test

Create a normal test class inside your test directory (SomeTest in this example).

Move the metadata file you downloaded in the previous step into your test-resources directory in a subdirectory named after you test. So in my example I have the following structure: src->test->resources->SomeTest->API_PHYSICAL_INVENTORY_DOC_SRV.edmx.

In your test class add the following lines on the class level:

private static final MockUtil mockUtil = new MockUtil();
@Rule
public final WireMockRule erpServer = mockUtil.mockErpServer();

This will, for every test method, set up a mock server, execute the code, and finally tear the server down again. The MockUtil can be found in the com.sap.cloud.s4hana:testutil library of the S/4HANA Cloud SDK.

Then add the following setUp method:

@Before
public void setUp()
{
    final String metadataAsString =
        TestUtil.readResourceFile(SomeTest.class, "API_PHYSICAL_INVENTORY_DOC_SRV.edmx");
    stubFor(
        get(urlEqualTo("/sap/opu/odata/sap/API_PHYSICAL_INVENTORY_DOC_SRV/$metadata"))
            .willReturn(okXml(metadataAsString)));
}

There you need to replace the class name, the metadata filename, and the url to the one from your service. These lines will tell the mock server to return the metadata if a request is received on the given URL. As this is first step of every OData VDM call this needs to be mocked.

Now create a test method as follows:

@Test
public void testSomething()
    throws ODataException
{
    new DefaultPhysicalInventoryDocumentService().getAllPhysInventoryDocItem().execute();
}

You need to replace the call here with the one you want to actually test/verify.

Run the Test

If you run the test you will receive an error message containing the following table:

[qtp1038820134-18] ERROR WireMock - 
                                               Request was not matched
                                               =======================

-----------------------------------------------------------------------------------------------------------------------
| Closest stub                                             | Request                                                  |
-----------------------------------------------------------------------------------------------------------------------
                                                           |
GET                                                        | GET
/sap/opu/odata/sap/API_PHYSICAL_INVENTORY_DOC_SRV/$metada  | /sap/opu/odata/sap/API_PHYSICAL_INVENTORY_DOC_SRV/A_PhysI<<<<< URL does not match
ta                                                         | nventoryDocItem?$format=json
                                                           |
                                                           |
-----------------------------------------------------------------------------------------------------------------------

This is the usual Wiremock response if the server received a request that was not mocked. On the left you see the closest mocked requst and on the right the actually received request.

You can now use the request on the right via Postman or your browser and verify the behavior directly.



来源:https://stackoverflow.com/questions/55353540/vdm-works-for-one-odata-service-doesnt-work-for-another

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!