Skip to content

Commit 15fac26

Browse files
authored
Label REST API with v1 version (#132)
1 parent 8d0b905 commit 15fac26

File tree

5 files changed

+247
-26
lines changed

5 files changed

+247
-26
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
44

55
## [[NEXT]](https://github.com/iExecBlockchainComputing/iexec-blockchain-adapter-api/releases/tag/vNEXT) 2024
66

7+
### New Features
8+
9+
- Label REST API with `v1` version. (#132)
10+
711
### Quality
812

913
- Remove `/tasks/{chainTaskId}` endpoint, the adapter must only call `initialize` and `finalize` **PoCo** methods. (#130)

iexec-blockchain-adapter-api-library/src/main/java/com/iexec/blockchain/api/BlockchainAdapterApiClient.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,17 @@ public interface BlockchainAdapterApiClient {
3535
@RequestLine("GET /metrics")
3636
String getMetrics();
3737

38-
@RequestLine("POST /tasks/initialize?chainDealId={chainDealId}&taskIndex={taskIndex}")
38+
@RequestLine("POST /v1/tasks/initialize?chainDealId={chainDealId}&taskIndex={taskIndex}")
3939
String requestInitializeTask(@Param("chainDealId") String chainDealId,
4040
@Param("taskIndex") int taskIndex);
4141

42-
@RequestLine("GET /tasks/initialize/{chainTaskId}/status")
42+
@RequestLine("GET /v1/tasks/initialize/{chainTaskId}/status")
4343
CommandStatus getStatusForInitializeTaskRequest(@Param("chainTaskId") String chainTaskId);
4444

45-
@RequestLine("POST /tasks/finalize/{chainTaskId}")
45+
@RequestLine("POST /v1/tasks/finalize/{chainTaskId}")
4646
String requestFinalizeTask(@Param("chainTaskId") String chainTaskId, TaskFinalizeArgs taskFinalizeArgs);
4747

48-
@RequestLine("GET /tasks/finalize/{chainTaskId}/status")
48+
@RequestLine("GET /v1/tasks/finalize/{chainTaskId}/status")
4949
CommandStatus getStatusForFinalizeTaskRequest(@Param("chainTaskId") String chainTaskId);
5050

5151
// endregion

src/main/java/com/iexec/blockchain/command/task/TaskController.java

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,16 @@
2727

2828
import static com.iexec.blockchain.swagger.OpenApiConfig.SWAGGER_BASIC_AUTH;
2929

30+
/**
31+
* @deprecated Call /v1/tasks endpoints in {@code TaskControllerV1}
32+
*/
33+
@Deprecated(forRemoval = true)
3034
@RestController
3135
@RequestMapping("/tasks")
32-
public class TaskController {
33-
34-
private final TaskInitializeService taskInitializeService;
35-
private final TaskFinalizeService taskFinalizeService;
36+
public class TaskController extends TaskControllerV1 {
3637

3738
public TaskController(TaskInitializeService taskInitializeService, TaskFinalizeService taskFinalizeService) {
38-
this.taskInitializeService = taskInitializeService;
39-
this.taskFinalizeService = taskFinalizeService;
39+
super(taskInitializeService, taskFinalizeService);
4040
}
4141

4242
/**
@@ -46,17 +46,13 @@ public TaskController(TaskInitializeService taskInitializeService, TaskFinalizeS
4646
* @param taskIndex index of the task int the bag
4747
* @return blockchain task ID if successful
4848
*/
49+
@Override
4950
@Operation(security = @SecurityRequirement(name = SWAGGER_BASIC_AUTH))
5051
@PostMapping("/initialize")
5152
public ResponseEntity<String> requestInitializeTask(
5253
@RequestParam String chainDealId,
5354
@RequestParam int taskIndex) {
54-
String chainTaskId =
55-
taskInitializeService.start(chainDealId, taskIndex);
56-
if (!chainTaskId.isEmpty()) {
57-
return ResponseEntity.ok(chainTaskId);
58-
}
59-
return ResponseEntity.badRequest().build();
55+
return super.requestInitializeTask(chainDealId, taskIndex);
6056
}
6157

6258
/**
@@ -65,13 +61,12 @@ public ResponseEntity<String> requestInitializeTask(
6561
* @param chainTaskId blockchain ID of the task
6662
* @return status
6763
*/
64+
@Override
6865
@Operation(security = @SecurityRequirement(name = SWAGGER_BASIC_AUTH))
6966
@GetMapping("/initialize/{chainTaskId}/status")
7067
public ResponseEntity<CommandStatus> getStatusForInitializeTaskRequest(
7168
@PathVariable String chainTaskId) {
72-
return taskInitializeService.getStatusForCommand(chainTaskId)
73-
.map(ResponseEntity::ok)
74-
.orElse(ResponseEntity.notFound().build());
69+
return super.getStatusForInitializeTaskRequest(chainTaskId);
7570
}
7671

7772
/**
@@ -81,15 +76,13 @@ public ResponseEntity<CommandStatus> getStatusForInitializeTaskRequest(
8176
* @param args input arguments for `finalize task`
8277
* @return blockchain task ID if successful
8378
*/
79+
@Override
8480
@Operation(security = @SecurityRequirement(name = SWAGGER_BASIC_AUTH))
8581
@PostMapping("/finalize/{chainTaskId}")
8682
public ResponseEntity<String> requestFinalizeTask(
8783
@PathVariable String chainTaskId,
8884
@RequestBody TaskFinalizeArgs args) {
89-
if (!taskFinalizeService.start(chainTaskId, args).isEmpty()) {
90-
return ResponseEntity.ok(chainTaskId);
91-
}
92-
return ResponseEntity.badRequest().build();
85+
return super.requestFinalizeTask(chainTaskId, args);
9386
}
9487

9588
/**
@@ -98,13 +91,12 @@ public ResponseEntity<String> requestFinalizeTask(
9891
* @param chainTaskId blockchain ID of the task
9992
* @return status
10093
*/
94+
@Override
10195
@Operation(security = @SecurityRequirement(name = SWAGGER_BASIC_AUTH))
10296
@GetMapping("/finalize/{chainTaskId}/status")
10397
public ResponseEntity<CommandStatus> getStatusForFinalizeTaskRequest(
10498
@PathVariable String chainTaskId) {
105-
return taskFinalizeService.getStatusForCommand(chainTaskId)
106-
.map(ResponseEntity::ok)
107-
.orElse(ResponseEntity.notFound().build());
99+
return super.getStatusForFinalizeTaskRequest(chainTaskId);
108100
}
109101

110102
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright 2024-2024 IEXEC BLOCKCHAIN TECH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.iexec.blockchain.command.task;
18+
19+
import com.iexec.blockchain.api.CommandStatus;
20+
import com.iexec.blockchain.command.task.finalize.TaskFinalizeService;
21+
import com.iexec.blockchain.command.task.initialize.TaskInitializeService;
22+
import com.iexec.common.chain.adapter.args.TaskFinalizeArgs;
23+
import io.swagger.v3.oas.annotations.Operation;
24+
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
25+
import org.springframework.http.ResponseEntity;
26+
import org.springframework.web.bind.annotation.*;
27+
28+
import static com.iexec.blockchain.swagger.OpenApiConfig.SWAGGER_BASIC_AUTH;
29+
30+
@RestController
31+
@RequestMapping("/v1/tasks")
32+
public class TaskControllerV1 {
33+
34+
private final TaskInitializeService taskInitializeService;
35+
private final TaskFinalizeService taskFinalizeService;
36+
37+
public TaskControllerV1(TaskInitializeService taskInitializeService, TaskFinalizeService taskFinalizeService) {
38+
this.taskInitializeService = taskInitializeService;
39+
this.taskFinalizeService = taskFinalizeService;
40+
}
41+
42+
/**
43+
* Start the asynchronous `initialize task` blockchain remote call.
44+
*
45+
* @param chainDealId blockchain deal ID
46+
* @param taskIndex index of the task int the bag
47+
* @return blockchain task ID if successful
48+
*/
49+
@Operation(security = @SecurityRequirement(name = SWAGGER_BASIC_AUTH))
50+
@PostMapping("/initialize")
51+
public ResponseEntity<String> requestInitializeTask(@RequestParam String chainDealId,
52+
@RequestParam int taskIndex) {
53+
String chainTaskId = taskInitializeService.start(chainDealId, taskIndex);
54+
if (!chainTaskId.isEmpty()) {
55+
return ResponseEntity.ok(chainTaskId);
56+
}
57+
return ResponseEntity.badRequest().build();
58+
}
59+
60+
/**
61+
* Read status for the asynchronous `initialize task` blockchain remote call.
62+
*
63+
* @param chainTaskId blockchain ID of the task
64+
* @return status
65+
*/
66+
@Operation(security = @SecurityRequirement(name = SWAGGER_BASIC_AUTH))
67+
@GetMapping("/initialize/{chainTaskId}/status")
68+
public ResponseEntity<CommandStatus> getStatusForInitializeTaskRequest(@PathVariable String chainTaskId) {
69+
return taskInitializeService.getStatusForCommand(chainTaskId)
70+
.map(ResponseEntity::ok)
71+
.orElse(ResponseEntity.notFound().build());
72+
}
73+
74+
/**
75+
* Start the asynchronous `finalize task` blockchain remote call.
76+
*
77+
* @param chainTaskId blockchain task ID
78+
* @param args input arguments for `finalize task`
79+
* @return blockchain task ID if successful
80+
*/
81+
@Operation(security = @SecurityRequirement(name = SWAGGER_BASIC_AUTH))
82+
@PostMapping("/finalize/{chainTaskId}")
83+
public ResponseEntity<String> requestFinalizeTask(@PathVariable String chainTaskId,
84+
@RequestBody TaskFinalizeArgs args) {
85+
if (!taskFinalizeService.start(chainTaskId, args).isEmpty()) {
86+
return ResponseEntity.ok(chainTaskId);
87+
}
88+
return ResponseEntity.badRequest().build();
89+
}
90+
91+
/**
92+
* Read status for the asynchronous `finalize task` blockchain remote call.
93+
*
94+
* @param chainTaskId blockchain ID of the task
95+
* @return status
96+
*/
97+
@Operation(security = @SecurityRequirement(name = SWAGGER_BASIC_AUTH))
98+
@GetMapping("/finalize/{chainTaskId}/status")
99+
public ResponseEntity<CommandStatus> getStatusForFinalizeTaskRequest(@PathVariable String chainTaskId) {
100+
return taskFinalizeService.getStatusForCommand(chainTaskId)
101+
.map(ResponseEntity::ok)
102+
.orElse(ResponseEntity.notFound().build());
103+
}
104+
105+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright 2024-2024 IEXEC BLOCKCHAIN TECH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.iexec.blockchain.command.task;
18+
19+
import com.iexec.blockchain.api.CommandStatus;
20+
import com.iexec.blockchain.command.task.finalize.TaskFinalizeService;
21+
import com.iexec.blockchain.command.task.initialize.TaskInitializeService;
22+
import com.iexec.common.chain.adapter.args.TaskFinalizeArgs;
23+
import org.junit.jupiter.api.BeforeEach;
24+
import org.junit.jupiter.api.Test;
25+
import org.junit.jupiter.params.ParameterizedTest;
26+
import org.junit.jupiter.params.provider.EnumSource;
27+
import org.mockito.InjectMocks;
28+
import org.mockito.Mock;
29+
import org.mockito.MockitoAnnotations;
30+
import org.springframework.http.ResponseEntity;
31+
32+
import java.util.Optional;
33+
34+
import static org.assertj.core.api.Assertions.assertThat;
35+
import static org.mockito.Mockito.when;
36+
37+
class TaskControllerV1Tests {
38+
39+
private static final String CHAIN_DEAL_ID = "0x1";
40+
private static final int TASK_INDEX = 0;
41+
private static final String CHAIN_TASK_ID = "0x2";
42+
43+
@Mock
44+
private TaskInitializeService taskInitializeService;
45+
@Mock
46+
private TaskFinalizeService taskFinalizeService;
47+
@InjectMocks
48+
private TaskControllerV1 taskController;
49+
50+
@BeforeEach
51+
void init() {
52+
MockitoAnnotations.openMocks(this);
53+
}
54+
55+
// region requestInitializeTask
56+
@Test
57+
void shouldNotifyInitializeCommandSubmissionFailure() {
58+
when(taskInitializeService.start(CHAIN_DEAL_ID, TASK_INDEX)).thenReturn("");
59+
assertThat(taskController.requestInitializeTask(CHAIN_DEAL_ID, TASK_INDEX))
60+
.isEqualTo(ResponseEntity.badRequest().build());
61+
}
62+
63+
@Test
64+
void shouldNotifyInitializeCommandSubmissionSuccess() {
65+
when(taskInitializeService.start(CHAIN_DEAL_ID, TASK_INDEX)).thenReturn(CHAIN_TASK_ID);
66+
assertThat(taskController.requestInitializeTask(CHAIN_DEAL_ID, TASK_INDEX))
67+
.isEqualTo(ResponseEntity.ok(CHAIN_TASK_ID));
68+
}
69+
// endregion
70+
71+
// region getStatusForInitializeTaskRequest
72+
@ParameterizedTest
73+
@EnumSource(value = CommandStatus.class)
74+
void shouldReturnInitializeCommandStatusWhenAvailable(CommandStatus status) {
75+
when(taskInitializeService.getStatusForCommand(CHAIN_TASK_ID)).thenReturn(Optional.of(status));
76+
assertThat(taskController.getStatusForInitializeTaskRequest(CHAIN_TASK_ID))
77+
.isEqualTo(ResponseEntity.ok(status));
78+
}
79+
80+
@Test
81+
void shouldNotReturnInitializeCommandStatusWhenEmpty() {
82+
when(taskInitializeService.getStatusForCommand(CHAIN_TASK_ID)).thenReturn(Optional.empty());
83+
assertThat(taskController.getStatusForInitializeTaskRequest(CHAIN_TASK_ID))
84+
.isEqualTo(ResponseEntity.notFound().build());
85+
}
86+
// endregion
87+
88+
// region requestFinalizeTask
89+
@Test
90+
void shouldNotifyFinalizeCommandSubmissionFailure() {
91+
when(taskFinalizeService.start(CHAIN_TASK_ID, TaskFinalizeArgs.builder().build())).thenReturn("");
92+
assertThat(taskController.requestFinalizeTask(CHAIN_TASK_ID, TaskFinalizeArgs.builder().build()))
93+
.isEqualTo(ResponseEntity.badRequest().build());
94+
}
95+
96+
@Test
97+
void shouldNotifyFinalizeCommandSubmissionSuccess() {
98+
when(taskFinalizeService.start(CHAIN_TASK_ID, TaskFinalizeArgs.builder().build())).thenReturn(CHAIN_TASK_ID);
99+
assertThat(taskController.requestFinalizeTask(CHAIN_TASK_ID, TaskFinalizeArgs.builder().build()))
100+
.isEqualTo(ResponseEntity.ok(CHAIN_TASK_ID));
101+
}
102+
// endregion
103+
104+
// region getStatusForFinalizeTaskRequest
105+
@ParameterizedTest
106+
@EnumSource(value = CommandStatus.class)
107+
void shouldReturnFinalizeCommandStatusWhenAvailable(CommandStatus status) {
108+
when(taskFinalizeService.getStatusForCommand(CHAIN_TASK_ID)).thenReturn(Optional.of(status));
109+
assertThat(taskController.getStatusForFinalizeTaskRequest(CHAIN_TASK_ID))
110+
.isEqualTo(ResponseEntity.ok(status));
111+
}
112+
113+
@Test
114+
void shouldNotReturnFinalizeCommandStatusWhenEmpty() {
115+
when(taskFinalizeService.getStatusForCommand(CHAIN_TASK_ID)).thenReturn(Optional.empty());
116+
assertThat(taskController.getStatusForFinalizeTaskRequest(CHAIN_TASK_ID))
117+
.isEqualTo(ResponseEntity.notFound().build());
118+
}
119+
// endregion
120+
}

0 commit comments

Comments
 (0)