Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add tests for submodel methods #360

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
00146aa
feat: add tests for getSubmodelByIdValueOnly + getSubmodelByIdMetadat…
ShehriyarShariq-Fraunhofer Jul 26, 2024
7d85df3
Merge branch 'main' into add-test-cases-for-submodel-methods
ShehriyarShariq-Fraunhofer Jul 31, 2024
f647536
fix: update patch tests
ShehriyarShariq-Fraunhofer Aug 18, 2024
eec4505
Merge branch 'main' into add-test-cases-for-submodel-methods
ShehriyarShariq-Fraunhofer Aug 26, 2024
9d72aa0
fix: remove patchSubmodelElements test for non existing element
ShehriyarShariq-Fraunhofer Aug 26, 2024
a3145d3
Empty commit to trigger the CI
mateusmolina-iese Aug 27, 2024
ea76b10
Merge branch 'main' into add-test-cases-for-submodel-methods
ShehriyarShariq-Fraunhofer Sep 2, 2024
b55df5f
fix: error handling for ApiException
ShehriyarShariq-Fraunhofer Sep 2, 2024
ecb50f2
Merge branch 'add-test-cases-for-submodel-methods' of https://github.…
ShehriyarShariq-Fraunhofer Sep 2, 2024
cef93d3
Triggering the CI
mateusmolina-iese Sep 3, 2024
97c9a0b
fix: getSubmodelByIdMetadata exception handler update
ShehriyarShariq-Fraunhofer Sep 11, 2024
2864040
refactor: remove space + add additional assert
ShehriyarShariq-Fraunhofer Sep 11, 2024
6f8be7a
Merge branch 'add-test-cases-for-submodel-methods' of https://github.…
ShehriyarShariq-Fraunhofer Sep 11, 2024
d4ab075
refactor: revert line removal
ShehriyarShariq-Fraunhofer Sep 11, 2024
22bc4b1
refactor: revert line removal
ShehriyarShariq-Fraunhofer Sep 11, 2024
af6a98c
fix: add test for getSubmodelByIdValueOnly in HTTP Controller
ShehriyarShariq-Fraunhofer Sep 17, 2024
f20b967
Triggering the CI
mateusmolina-iese Sep 17, 2024
e8477f8
fix: add metadata api
ShehriyarShariq-Fraunhofer Oct 1, 2024
8dbabf5
stash
ShehriyarShariq-Fraunhofer Oct 1, 2024
b6dedc0
Merge branch 'main' into add-test-cases-for-submodel-methods
ShehriyarShariq-Fraunhofer Oct 15, 2024
888b53d
stash
ShehriyarShariq-Fraunhofer Oct 15, 2024
1afe2e3
Merge branch 'main' into add-test-cases-for-submodel-methods
ShehriyarShariq-Fraunhofer Oct 21, 2024
8dada1d
stash
ShehriyarShariq-Fraunhofer Oct 22, 2024
df593c2
stash
ShehriyarShariq-Fraunhofer Oct 27, 2024
6b0241d
stash
ShehriyarShariq-Fraunhofer Oct 29, 2024
195c4c2
fix: reset AuthorizedSubmodelRepository
ShehriyarShariq-Fraunhofer Oct 31, 2024
191eb3e
fix: reset AuthorizedSubmodelRepository
ShehriyarShariq-Fraunhofer Oct 31, 2024
b9f069c
Merge branch 'main' into pr/ShehriyarShariq-Fraunhofer/360
mateusmolina-iese Nov 4, 2024
41e1079
test: refactor expectation of SubmodelRepositorySuite metadata test
mateusmolina-iese Nov 4, 2024
5b4f3b4
fix: submodel metadata deser. mismatch
mateusmolina-iese Nov 4, 2024
e1610da
fix: submodel metadata deser. mismatch 2
mateusmolina-iese Nov 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,16 @@ public OperationVariable[] invokeOperation(String submodelId, String idShortPath

@Override
public SubmodelValueOnly getSubmodelByIdValueOnly(String submodelId) throws ElementDoesNotExistException {
return new SubmodelValueOnly(getSubmodelByIdMetadata(submodelId).getSubmodelElements());
return new SubmodelValueOnly(getSubmodel(submodelId).getSubmodelElements());
}

@Override
public Submodel getSubmodelByIdMetadata(String submodelId) throws ElementDoesNotExistException {
return repoApi.getSubmodelById(submodelId, null, null);
try {
return repoApi.getSubmodelByIdMetadata(submodelId, null);
} catch (ApiException e) {
throw mapExceptionSubmodelAccess(submodelId, e);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.StringJoiner;
import java.util.function.Consumer;
Expand Down Expand Up @@ -238,6 +239,123 @@ private HttpRequest.Builder getSubmodelByIdRequestBuilder(String submodelIdentif
return localVarRequestBuilder;
}

/**
* Returns the metadata attributes of a specific Submodel
*
* @param submodelIdentifier
* The Submodel’s unique id (UTF8-BASE64-URL-encoded) (required)
* @param level
* Determines the structural depth of the respective resource content
* (optional, default to deep)
* @return SubmodelMetadata
* @throws ApiException
* if fails to make API call
*/
public Submodel getSubmodelByIdMetadata(String submodelIdentifier, String level) throws ApiException {

ApiResponse<Submodel> localVarResponse = getSubmodelByIdMetadataWithHttpInfo(submodelIdentifier, level);
return localVarResponse.getData();
}

/**
* Returns the metadata attributes of a specific Submodel
*
* @param submodelIdentifier
* The Submodel’s unique id (UTF8-BASE64-URL-encoded) (required)
* @param level
* Determines the structural depth of the respective resource content
* (optional, default to deep)
* @return ApiResponse&lt;SubmodelMetadata&gt;
* @throws ApiException
* if fails to make API call
*/
public ApiResponse<Submodel> getSubmodelByIdMetadataWithHttpInfo(String submodelIdentifier, String level) throws ApiException {
String submodelIdentifierAsBytes = ApiClient.base64UrlEncode(submodelIdentifier);
return getSubmodelByIdMetadataWithHttpInfoNoUrlEncoding(submodelIdentifierAsBytes, level);

}

/**
* Returns the metadata attributes of a specific Submodel
*
* @param submodelIdentifier
* The Submodel’s unique id (UTF8-BASE64-URL-encoded) (required)
* @param level
* Determines the structural depth of the respective resource content
* (optional, default to deep)
* @return ApiResponse&lt;SubmodelMetadata&gt;
* @throws ApiException
* if fails to make API call
*/
public ApiResponse<Submodel> getSubmodelByIdMetadataWithHttpInfoNoUrlEncoding(String submodelIdentifier, String level) throws ApiException {
HttpRequest.Builder localVarRequestBuilder = getSubmodelByIdMetadataRequestBuilder(submodelIdentifier, level);
try {
HttpResponse<InputStream> localVarResponse = memberVarHttpClient.send(localVarRequestBuilder.build(), HttpResponse.BodyHandlers.ofInputStream());
if (memberVarResponseInterceptor != null) {
memberVarResponseInterceptor.accept(localVarResponse);
}
try {
if (localVarResponse.statusCode() / 100 != 2) {
throw getApiException("getSubmodelByIdMetadata", localVarResponse);
}
Submodel deserializedSubmodel = localVarResponse.body() == null ? null : memberVarObjectMapper.readValue(localVarResponse.body(), new TypeReference<Submodel>() {
});

if (deserializedSubmodel != null && deserializedSubmodel.getSubmodelElements() != null && deserializedSubmodel.getSubmodelElements().isEmpty())
deserializedSubmodel.setSubmodelElements(null);

return new ApiResponse<>(localVarResponse.statusCode(), localVarResponse.headers().map(), deserializedSubmodel);
} finally {
}
} catch (IOException e) {
throw new ApiException(e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new ApiException(e);
}
}

private HttpRequest.Builder getSubmodelByIdMetadataRequestBuilder(String submodelIdentifier, String level) throws ApiException {
// verify the required parameter 'submodelIdentifier' is set
if (submodelIdentifier == null) {
throw new ApiException(400, "Missing the required parameter 'submodelIdentifier' when calling getSubmodelByIdMetadata");
}

HttpRequest.Builder localVarRequestBuilder = HttpRequest.newBuilder();

String localVarPath = "/submodels/{submodelIdentifier}/$metadata".replace("{submodelIdentifier}", ApiClient.urlEncode(submodelIdentifier.toString()));

List<Pair> localVarQueryParams = new ArrayList<>();
StringJoiner localVarQueryStringJoiner = new StringJoiner("&");
String localVarQueryParameterBaseName;
localVarQueryParameterBaseName = "level";
localVarQueryParams.addAll(ApiClient.parameterToPairs("level", level));

if (!localVarQueryParams.isEmpty() || localVarQueryStringJoiner.length() != 0) {
StringJoiner queryJoiner = new StringJoiner("&");
localVarQueryParams.forEach(p -> queryJoiner.add(p.getName() + '=' + p.getValue()));
if (localVarQueryStringJoiner.length() != 0) {
queryJoiner.add(localVarQueryStringJoiner.toString());
}
localVarRequestBuilder.uri(URI.create(memberVarBaseUri + localVarPath + '?' + queryJoiner.toString()));
} else {
localVarRequestBuilder.uri(URI.create(memberVarBaseUri + localVarPath));
}

localVarRequestBuilder.header("Accept", "application/json");

addAuthorizationHeaderIfAuthIsEnabled(localVarRequestBuilder);

localVarRequestBuilder.method("GET", HttpRequest.BodyPublishers.noBody());
if (memberVarReadTimeout != null) {
localVarRequestBuilder.timeout(memberVarReadTimeout);
}
if (memberVarInterceptor != null) {
memberVarInterceptor.accept(localVarRequestBuilder);
}
return localVarRequestBuilder;
}

/**
* Creates a new Submodel
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.eclipse.digitaltwin.basyx.core.exceptions.NotInvokableException;
import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult;
import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo;
import org.eclipse.digitaltwin.basyx.serialization.SubmodelMetadataUtil;
import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository;
import org.eclipse.digitaltwin.basyx.submodelservice.DummySubmodelFactory;
import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelService;
Expand Down Expand Up @@ -280,7 +281,7 @@ public void getSubmodelByIdMetadata() throws JsonProcessingException {
Submodel expectedSubmodel = buildDummySubmodelWithNoSmElement(ID);
expectedSubmodel.setSubmodelElements(null);
repo.createSubmodel(expectedSubmodel);

Submodel retrievedSubmodelMetadata = repo.getSubmodelByIdMetadata(ID);
retrievedSubmodelMetadata.setSubmodelElements(null);

Expand Down Expand Up @@ -347,6 +348,44 @@ public void invokeNonOperation() {

submodelRepo.invokeOperation(DummySubmodelFactory.SUBMODEL_TECHNICAL_DATA_ID, SubmodelServiceHelper.SUBMODEL_TECHNICAL_DATA_ANNOTATED_RELATIONSHIP_ELEMENT_ID_SHORT, new OperationVariable[0]);
}

@Test
public void getSubmodelByIdValueOnlyExistingSubmodel() {
SubmodelRepository repo = getSubmodelRepositoryWithDummySubmodels();

String submodelId = DummySubmodelFactory.SUBMODEL_OPERATIONAL_DATA_ID;
Submodel expectedSubmodel = DummySubmodelFactory.createOperationalDataSubmodel();
SubmodelValueOnly expectedValueOnly = new SubmodelValueOnly(expectedSubmodel.getSubmodelElements());

SubmodelValueOnly valueOnly = repo.getSubmodelByIdValueOnly(submodelId);

assertEquals(expectedValueOnly.getIdShort(), valueOnly.getIdShort());
assertEquals(expectedValueOnly.getValuesOnlyMap(), valueOnly.getValuesOnlyMap());
}

@Test(expected = ElementDoesNotExistException.class)
public void getSubmodelByIdValueOnlyNonExistingSubmodel() {
SubmodelRepository repo = getSubmodelRepositoryWithDummySubmodels();
repo.getSubmodelByIdValueOnly("nonExistingSubmodelId");
}

@Test
public void getSubmodelByIdMetadataExistingSubmodel() {
SubmodelRepository repo = getSubmodelRepositoryWithDummySubmodels();

Submodel expectedMetadata = SubmodelMetadataUtil.extractMetadata(DummySubmodelFactory.createOperationalDataSubmodel());
String submodelId = expectedMetadata.getId();

Submodel metadata = repo.getSubmodelByIdMetadata(submodelId);

assertEquals(expectedMetadata, metadata);
}

@Test(expected = ElementDoesNotExistException.class)
public void getSubmodelByIdMetadataNonExistingSubmodel() {
SubmodelRepository repo = getSubmodelRepositoryWithDummySubmodels();
repo.getSubmodelByIdMetadata("nonExistingSubmodelId");
}

private Submodel buildDummySubmodel(String id) {
return new DefaultSubmodel.Builder().id(id).submodelElements(new DefaultProperty.Builder().idShort("prop").value("testValue").valueType(DataTypeDefXsd.STRING).build()).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,21 @@ public void getFileFromNotExistElement() throws FileNotFoundException, Unsupport
assertEquals(HttpStatus.NOT_FOUND.value(), response.getCode());
}

@Test
public void getSubmodelByIdValueOnly() throws IOException, ParseException {
String submodelIdentifier = Base64UrlEncodedIdentifier.encodeIdentifier(DummySubmodelFactory.createTechnicalDataSubmodel().getId());
String url = getURL() + "/" + submodelIdentifier + "/$value";

String expectedSubmodelJSON = getJSONValueAsString("SingleSubmodelValueOnly.json");

CloseableHttpResponse response = BaSyxHttpTestUtils.executeGetOnURL(url);
assertEquals(HttpStatus.OK.value(), response.getCode());

String actualSubmodelJSON = BaSyxHttpTestUtils.getResponseAsString(response);

BaSyxHttpTestUtils.assertSameJSONContent(expectedSubmodelJSON, actualSubmodelJSON);
}

private String extractFileNameFromContentDisposition(String contentDisposition) {
for (String part : contentDisposition.split(";")) {
part = part.trim();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
{
"SubmodelElementList": [
{
"min": 200,
"max": 300
},
"5000"
],
"EntityData": {
"statements": [
{
"MaxRotationSpeed": "5000"
},
{
"RotationSpeedRange": {
"min": 200,
"max": 300
}
}
],
"entityType": "CoManagedEntity",
"globalAssetId": "globalAssetID",
"specificAssetIds": [
{
"specificAssetIdName": "specificValue"
}
]
},
"RelationshipElement": {
"first": {
"type": "ModelReference",
"keys": [
{
"type": "DataElement",
"value": "DataElement"
}
]
},
"second": {
"type": "ExternalReference",
"keys": [
{
"type": "BasicEventElement",
"value": "BasicEventElement"
}
]
}
},
"ReferenceElement": {
"type": "ModelReference",
"keys": [
{
"type": "DataElement",
"value": "DataElement"
}
]
},
"BlobData": {
"contentType": "application/xml",
"value": "Test content of XML file"
},
"SubmodelElementCollection": {
"MaxRotationSpeed": "5000",
"FileData": {
"contentType": "application/json",
"value": "testFile.json"
}
},
"MultiLanguage": [
{
"en": "Hello"
},
{
"de": "Hallo"
}
],
"AnnotatedRelationshipElement": {
"first": {
"type": "ModelReference",
"keys": [
{
"type": "DataElement",
"value": "DataElement"
}
]
},
"second": {
"type": "ExternalReference",
"keys": [
{
"type": "BasicEventElement",
"value": "BasicEventElement"
}
]
},
"annotation": [
{
"MaxRotationSpeed": "5000"
},
{
"RotationSpeedRange": {
"min": 200,
"max": 300
}
}
]
},
"MaxRotationSpeed": "5000",
"RotationSpeedRange": {
"min": 200,
"max": 300
},
"FileData": {
"contentType": "application/json",
"value": "testFile.json"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,12 @@ public PropertyValue(String value) {
public String getValue() {
return value;
}

@Override
public boolean equals(Object obj) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to override equals here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In getSubmodelByIdValueOnlyExistingSubmodel, I need to compare the objects of type SubmodelValueOnly which have a Map of items where the value is of type SubmodelElementValue.

PropertyValue implements the interface SubmodelElementValue, hence, when i compare the SubmodelValueOnly objects, I'm actually comparing their map of items to check if they are equal.

Given that PropertyValue isn't a primitive data type, I had to add the equals method so that the comparison can be made between the items. The test fails otherwise.

if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
PropertyValue that = (PropertyValue) obj;
return value.equals(that.value);
}
}