Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@
<artifactId>spring-webmvc</artifactId>
<version>5.3.23</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.15.2</version>
</dependency>
</dependencies>

<build>
Expand Down
34 changes: 16 additions & 18 deletions src/main/java/city/makeour/moc/MocClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestClient.ResponseSpec;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.core.type.TypeReference;

import city.makeour.moc.ngsiv2.Ngsiv2Client;
import city.makeour.ngsi.v2.api.EntitiesApi;
import city.makeour.ngsi.v2.invoker.ApiClient;
Expand Down Expand Up @@ -149,30 +154,28 @@ public ResponseSpec getEntity(String entityId, String type) {
return this.entities().retrieveEntityWithResponseSpec(entityId, type, null, null, "keyValues");
}

// Map版(メインロジック)
public ResponseSpec updateEntity(String id, String type, Map<String, Object> attributesToUpdate) {
if (id == null || id.isBlank()) throw new IllegalArgumentException("id is required");
if (type == null || type.isBlank()) throw new IllegalArgumentException("type is required");
if (attributesToUpdate == null) attributesToUpdate = java.util.Collections.emptyMap();

try {
// Existence check
this.entities()
.retrieveEntityWithResponseSpec(id, type, null, null, "keyValues")
.toEntity(Object.class);

// Exists -> POST (keyValues 形式でそのまま送る)
return this.client.updateEntityAttributes(
id,
"application/json",
attributesToUpdate, // Object(Map) をそのまま PATCH
attributesToUpdate,
type,
"keyValues"
);

} catch (org.springframework.web.client.RestClientResponseException e) {
if (e.getStatusCode().value() != 404) throw e;

// Not found -> create (従来通り)
java.util.Map<String, Object> body = new java.util.HashMap<>();
body.put("id", id);
body.put("type", type);
Expand All @@ -181,22 +184,17 @@ public ResponseSpec updateEntity(String id, String type, Map<String, Object> att
}
}

// 指定された ID と Type を持つEntityを削除
public ResponseSpec deleteEntity(String entityId, String type) {
if (entityId == null || entityId.isBlank()) {
throw new IllegalArgumentException("id is required");
}
// EntitiesApi に定義されている removeEntityWithResponseSpec を呼び出す
return this.entities().removeEntityWithResponseSpec(entityId, type);
}

// 指定された ID を持つEntityを削除
public ResponseSpec deleteEntity(String entityId) {
return this.deleteEntity(entityId, null);
// Object版(Mapに変換してMap版に委譲)
public ResponseSpec updateEntity(String id, String type, Object o) {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

Map<String, Object> m = mapper.convertValue(o, new TypeReference<Map<String, Object>>() {});
return updateEntity(id, type, m);
}
Comment on lines -193 to 196
Copy link
Contributor

Choose a reason for hiding this comment

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

deleteEntityは削除しない方がいいかも






}
92 changes: 22 additions & 70 deletions src/test/java/city/makeour/moc/MocClientTest.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package city.makeour.moc;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;

Expand Down Expand Up @@ -126,10 +125,10 @@ void testAuth() throws GeneralSecurityException, NoSuchAlgorithmException {
@Test
@DisplayName("エンティティを作成・取得できるかのテスト(最小版)")
@EnabledIfEnvironmentVariables({
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_USER_POOL_ID", matches = ".*"),
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_CLIENT_ID", matches = ".*"),
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_USERNAME", matches = ".*"),
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_PASSWORD", matches = ".*")
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_USER_POOL_ID", matches = ".*"),
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_CLIENT_ID", matches = ".*"),
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_USERNAME", matches = ".*"),
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_PASSWORD", matches = ".*")
})
void testCreateAndGetEntity_Minimal() throws GeneralSecurityException, NoSuchAlgorithmException {
MocClient client = new MocClient();
Expand All @@ -152,108 +151,61 @@ void testCreateAndGetEntity_Minimal() throws GeneralSecurityException, NoSuchAlg

assertNotNull(retrievedEntity);
assertEquals(entityId, retrievedEntity.getId());
}
}

@Test
@DisplayName("updateEntityのUpsert(作成・更新)ロジックをテストする")
@EnabledIfEnvironmentVariables({
@DisplayName("updateEntityのUpsert(作成・更新)ロジックをテストする")
@EnabledIfEnvironmentVariables({
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_USER_POOL_ID", matches = ".*"),
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_CLIENT_ID", matches = ".*"),
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_USERNAME", matches = ".*"),
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_PASSWORD", matches = ".*")
})
})
void testUpdateEntity_UpsertLogic() throws GeneralSecurityException, NoSuchAlgorithmException {
MocClient client = new MocClient();
client.setMocAuthInfo(System.getenv("TEST_COGNITO_USER_POOL_ID"), System.getenv("TEST_COGNITO_CLIENT_ID"));
client.login(System.getenv("TEST_COGNITO_USERNAME"), System.getenv("TEST_COGNITO_PASSWORD"));

String entityId = "urn:ngsi-ld:TestUpsert:" + UUID.randomUUID().toString();
String entityType = "TestUpsertType";

// 1. "作成" (Insert) pathのテスト
// エンティティが存在しない --> catchブロックの this.createEntity
Map<String, Object> initialAttrs = new HashMap<>();
initialAttrs.put("temperature", 25);
initialAttrs.put("humidity", 50); // "temperature" 以外の属性も指定

client.updateEntity(entityId, entityType, initialAttrs);

// 検証 (作成)
ParameterizedTypeReference<Map<String, Object>> mapType = new ParameterizedTypeReference<>() {};
ParameterizedTypeReference<Map<String, Object>> mapType = new ParameterizedTypeReference<>() {
};
Map<String, Object> createdEntity = client.getEntity(entityId, entityType).body(mapType);

assertNotNull(createdEntity);
assertEquals(entityId, createdEntity.get("id"));
assertEquals(25, createdEntity.get("temperature"));
assertEquals(50, createdEntity.get("humidity"));

// 2. "更新" (Update/PATCH) pathのテスト
// エンティティが既に存在する --> tryブロックの updateExistingEntityAttributesWithResponseSpec
Map<String, Object> updateAttrs = new HashMap<>();
updateAttrs.put("temperature", 30); // 更新
updateAttrs.put("seatNumber", 10); // 追加
updateAttrs.put("temperature", 30); // 更新
updateAttrs.put("seatNumber", 10); // 追加
updateAttrs.put("status", "active");

client.updateEntity(entityId, entityType, updateAttrs);

// 検証 (更新)
Map<String, Object> updatedEntity = client.getEntity(entityId, entityType).body(mapType);

assertNotNull(updatedEntity);
// 更新・追加されている
assertEquals(30, updatedEntity.get("temperature"));
assertEquals(10, updatedEntity.get("seatNumber"));
// 最初の作成時から変更されず残っている
assertEquals(50, updatedEntity.get("humidity"));

assertEquals("active", updatedEntity.get("status"));
}

@Test
@DisplayName("deleteEntityのテスト(ID+Type指定、IDのみ指定の2パターン)")
@EnabledIfEnvironmentVariables({
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_USER_POOL_ID", matches = ".*"),
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_CLIENT_ID", matches = ".*"),
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_USERNAME", matches = ".*"),
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_PASSWORD", matches = ".*")
})
void testDeleteEntity() throws GeneralSecurityException, NoSuchAlgorithmException {
// 1. セットアップ
MocClient client = new MocClient();
client.setMocAuthInfo(System.getenv("TEST_COGNITO_USER_POOL_ID"), System.getenv("TEST_COGNITO_CLIENT_ID"));
client.login(System.getenv("TEST_COGNITO_USERNAME"), System.getenv("TEST_COGNITO_PASSWORD"));

String type = "TestDeleteType";

// ケース 1: deleteEntity(id, type)
String id1 = "urn:ngsi-ld:TestDelete:1:" + UUID.randomUUID().toString();

// データ作成(既存のupdateEntityを利用して作成)
client.updateEntity(id1, type, Map.of("value", 100));

// 削除実行(テスト対象)
client.deleteEntity(id1, type).toBodilessEntity();

// 検証: 取得しようとして 404 Not Found になることを確認
RestClientResponseException ex1 = assertThrows(RestClientResponseException.class, () -> {
client.getEntity(id1, type).toBodilessEntity();
});
assertEquals(HttpStatus.NOT_FOUND.value(), ex1.getStatusCode().value());

// ケース 2: deleteEntity(id) - IDのみでの削除
String id2 = "urn:ngsi-ld:TestDelete:2:" + UUID.randomUUID().toString();

// データ作成
client.updateEntity(id2, type, Map.of("value", 200));

// 削除実行(テスト対象)
client.deleteEntity(id2).toBodilessEntity();

// 検証: 取得しようとして 404 Not Found になることを確認
RestClientResponseException ex2 = assertThrows(RestClientResponseException.class, () -> {
client.getEntity(id2, type).toBodilessEntity();
});
assertEquals(HttpStatus.NOT_FOUND.value(), ex2.getStatusCode().value());
assertEquals("active", updatedEntity.get("status"));
}

}