Commit 7893a300 authored by ethiraj krishnamanaidu's avatar ethiraj krishnamanaidu
Browse files

Merge branch 'listAllTenants-api' into 'master'

New Partition API - list all partition id

See merge request !15
parents ee979956 e695e71c
Pipeline #13716 passed with stages
in 14 minutes and 8 seconds
......@@ -96,6 +96,33 @@ paths:
security:
- JWT:
- global
'/partitions':
get:
tags:
- partition-api
summary: list
operationId: listUsingGET
consumes:
- application/json
produces:
- application/json
parameters:
responses:
'200':
description: OK
schema:
type: array
items:
type: string
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Not Found
security:
- JWT:
- global
post:
tags:
- partition-api
......
......@@ -8,6 +8,8 @@
* [Get partition details](#get-partition)
* [Create a new partition](#create-partition)
* [Delete an existing partition](#delete-partition)
* [List of partitions](#list-partition)
## Introduction <a name="introduction"></a>
Partition service is responsible for creating and retrieving the partition specific properties (secret and non-secret) on behalf of other services.
......@@ -139,4 +141,34 @@ curl --request DELETE \
--header 'Authorization: Bearer <JWT>' \
--header 'Content-Type: application/json'
```
</details>
\ No newline at end of file
</details>
### List partitions <a name="list-partition"></a>
Consuming services can use this API to list all partitions Id.
```
GET api/partition/v1/partitions
```
<details><summary>curl</summary>
```
curl --request GET \
--url 'https://<base_url>/api/partition/v1/partitions' \
--header 'Authorization: Bearer <JWT>' \
--header 'Content-Type: application/json'
```
</details>
A sample output is shown below.
<details><summary>Sample response</summary>
```
[
"default-dev",
"opendes"
]
```
</details>
[Back to Table of Contents](#TOC)
\ No newline at end of file
......@@ -27,6 +27,7 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import javax.validation.Valid;
import java.net.URI;
import java.util.List;
import java.util.Map;
@RestController
......@@ -59,4 +60,11 @@ public class PartitionApi {
this.partitionService.deletePartition(partitionId);
return ResponseEntity.noContent().build();
}
@GetMapping
@PreAuthorize("@authorizationFilter.hasPermissions()")
public List<String> list() {
List<String> partitions = this.partitionService.getAllPartitions();
return partitions;
}
}
......@@ -16,6 +16,8 @@ package org.opengroup.osdu.partition.provider.interfaces;
import org.opengroup.osdu.partition.model.PartitionInfo;
import java.util.List;
public interface IPartitionService {
PartitionInfo createPartition(String partitionId, PartitionInfo partitionInfo);
......@@ -23,4 +25,6 @@ public interface IPartitionService {
PartitionInfo getPartition(String partitionId);
boolean deletePartition(String partitionId);
List<String> getAllPartitions();
}
\ No newline at end of file
......@@ -17,5 +17,5 @@ package org.opengroup.osdu.partition.provider.interfaces;
import org.opengroup.osdu.core.common.cache.ICache;
import org.opengroup.osdu.partition.model.PartitionInfo;
public interface IPartitionServiceCache extends ICache<String, PartitionInfo> {
public interface IPartitionServiceCache<String, V> extends ICache<String, V> {
}
......@@ -21,10 +21,13 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import javax.inject.Inject;
import java.util.List;
@Service
public class CachedPartitionServiceImpl implements IPartitionService {
private static final String PARTITION_LIST_KEY = "getAllPartitions";
@Inject
@Qualifier("partitionServiceImpl")
private IPartitionService partitionService;
......@@ -32,6 +35,9 @@ public class CachedPartitionServiceImpl implements IPartitionService {
@Inject
private IPartitionServiceCache partitionServiceCache;
@Inject
private IPartitionServiceCache partitionListCache;
@Override
public PartitionInfo createPartition(String partitionId, PartitionInfo partitionInfo) {
PartitionInfo pi = partitionService.createPartition(partitionId, partitionInfo);
......@@ -45,7 +51,7 @@ public class CachedPartitionServiceImpl implements IPartitionService {
@Override
public PartitionInfo getPartition(String partitionId) {
PartitionInfo pi = partitionServiceCache.get(partitionId);
PartitionInfo pi = (PartitionInfo) partitionServiceCache.get(partitionId);
if (pi == null) {
pi = partitionService.getPartition(partitionId);
......@@ -70,4 +76,18 @@ public class CachedPartitionServiceImpl implements IPartitionService {
return false;
}
@Override
public List<String> getAllPartitions() {
List<String> partitions = (List<String>)partitionListCache.get(PARTITION_LIST_KEY);
if (partitions == null) {
partitions = partitionService.getAllPartitions();
if (partitions != null) {
partitionListCache.put(PARTITION_LIST_KEY, partitions);
}
}
return partitions;
}
}
......@@ -33,7 +33,9 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.*;
......@@ -112,4 +114,17 @@ public class PartitionApiTest {
throw ae;
}
}
@Test
public void should_return200AndListAllPartition() {
List<String> partitions = new ArrayList<>();
partitions.add("tenant1");
partitions.add("tenant2");
when(partitionService.getAllPartitions()).thenReturn(partitions);
List<String> result = this.sut.list();
assertNotNull(result);
assertEquals(partitions.size(), result.size());
}
}
\ No newline at end of file
......@@ -23,6 +23,9 @@ import org.opengroup.osdu.partition.model.PartitionInfo;
import org.opengroup.osdu.partition.provider.interfaces.IPartitionService;
import org.opengroup.osdu.partition.provider.interfaces.IPartitionServiceCache;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
......@@ -35,6 +38,9 @@ public class CachedPartitionServiceImplTest {
@Mock
private IPartitionServiceCache partitionServiceCache;
@Mock
private IPartitionServiceCache partitionListCache;
@InjectMocks
private CachedPartitionServiceImpl cachedPartitionServiceImpl;
......@@ -97,4 +103,16 @@ public class CachedPartitionServiceImplTest {
verify(partitionServiceCache, times(1)).get(partId);
}
@Test
public void getAllPartitions() {
List<String> partitions = new ArrayList<>();
when(partitionServiceImpl.getAllPartitions()).thenReturn(partitions);
cachedPartitionServiceImpl.getAllPartitions();
String partKey = "getAllPartitions";
verify(partitionListCache, times(1)).get(partKey);
verify(partitionServiceImpl, times(1)).getAllPartitions();
verify(partitionListCache, times(1)).put(partKey, partitions);
}
}
\ No newline at end of file
......@@ -22,7 +22,7 @@ import org.springframework.stereotype.Service;
* We don't want to use cache. Implement a dummy service to always return a cache miss.
*/
@Service
public class PartitionServiceDummyCacheImpl implements IPartitionServiceCache {
public class PartitionServiceDummyCacheImpl implements IPartitionServiceCache<String, Object> {
public PartitionServiceDummyCacheImpl() {
}
......@@ -43,7 +43,7 @@ public class PartitionServiceDummyCacheImpl implements IPartitionServiceCache {
}
@Override
public void put(String arg0, PartitionInfo arg1) {
public void put(String arg0, Object arg1) {
return;
}
}
......@@ -129,5 +129,11 @@ public class PartitionServiceImpl implements IPartitionService {
return ssmHelper.deletePartitionSecrets(partitionId);
}
@Override
public List<String> getAllPartitions() {
//TODO: Pending to be implemented
return null;
}
}
package org.opengroup.osdu.partition.provider.azure.cache;
import org.opengroup.osdu.core.common.cache.VmCache;
import org.opengroup.osdu.partition.model.PartitionInfo;
import org.opengroup.osdu.partition.provider.interfaces.IPartitionServiceCache;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@Qualifier("partitionListCache")
public class PartitionListCacheImpl extends VmCache<String, List<String>> implements IPartitionServiceCache<String, List<String>> {
public PartitionListCacheImpl() {
super(5 * 60, 1000);
}
}
......@@ -3,10 +3,14 @@ package org.opengroup.osdu.partition.provider.azure.cache;
import org.opengroup.osdu.core.common.cache.VmCache;
import org.opengroup.osdu.partition.model.PartitionInfo;
import org.opengroup.osdu.partition.provider.interfaces.IPartitionServiceCache;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
@Service
public class PartitionServiceCacheImpl extends VmCache<String, PartitionInfo> implements IPartitionServiceCache {
@Primary
@Qualifier("partitionServiceCache")
public class PartitionServiceCacheImpl extends VmCache<String, PartitionInfo> implements IPartitionServiceCache<String, PartitionInfo> {
public PartitionServiceCacheImpl() {
super(5 * 60, 1000);
......
......@@ -21,10 +21,7 @@ import org.opengroup.osdu.partition.model.Property;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
@Component
public class PartitionTableStore {
......@@ -131,4 +128,15 @@ public class PartitionTableStore {
private String getTenantSafeSecreteId(String partitionId, String secreteName) {
return String.format("%s-%s", partitionId, secreteName);
}
public List<String> getAllPartitions() {
List<String> partitions = new ArrayList<>();
Iterable<PartitionEntity> results = (Iterable<PartitionEntity>)
this.cloudTableStore.queryByKey(PartitionEntity.class,
ROW_KEY, ID);
for (PartitionEntity tableEntity : results) {
partitions.add(tableEntity.getPartitionKey());
}
return partitions;
}
}
......@@ -23,7 +23,9 @@ import org.opengroup.osdu.partition.provider.interfaces.IPartitionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
......@@ -65,4 +67,9 @@ public class PartitionServiceImpl implements IPartitionService {
return true;
}
@Override
public List<String> getAllPartitions() {
return this.tableStore.getAllPartitions();
}
}
\ No newline at end of file
// Copyright 2017-2020, Schlumberger
//
// 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
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, eitsher express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.opengroup.osdu.partition.provider.azure.persistence;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.table.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.opengroup.osdu.core.common.model.http.AppException;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.junit.Assert.*;
import static org.mockito.Mockito.when;
@RunWith(PowerMockRunner.class)
public class CloudTableStoreTest {
@Mock
private CloudTable cloudTableClient;
@InjectMocks
private CloudTableStore sut;
@Test
public void should_empty_whenRecordNotExists() {
Iterable<PartitionEntity> results = (Iterable<PartitionEntity>) sut.queryByKey(PartitionEntity.class,
"partitionKey", "partitionId");
assertNotNull(results);
}
@Test
public void should_empty_whenRecordExists() throws StorageException {
try {
TableBatchOperation tbOp = new TableBatchOperation();
when(cloudTableClient.execute(new TableBatchOperation())).thenThrow(new StorageException("Error", "Error", null));
sut.insertBatchEntities(tbOp);
fail("should not be here");
} catch (AppException e) {
assertEquals(500, e.getError().getCode());
assertEquals("error creating partition", e.getError().getReason());
}
}
@Test
public void when_call_queryByCompoundKey() {
Iterable<? extends TableEntity> result = sut.queryByCompoundKey(PartitionEntity.class, "RowKey", "id", "value", "partitionId");
assertNotNull(result);
}
@Test
public void when_wrongInput_ThrowException() {
try {
sut.queryByCompoundKey(PartitionEntity.class, null, null, null, null);
fail("Should not be here");
} catch (Exception e) {
assertNotNull(e);
}
}
@Test
public void when_call_queryByKey() {
Iterable<? extends TableEntity> result = sut.queryByKey(PartitionEntity.class, "PartitionKey", "partitionId");
assertNotNull(result);
}
@Test
public void when_call_queryByKey_wrongInput_ThrowException() {
try {
sut.queryByKey(PartitionEntity.class, null, null);
fail("Should not be here");
} catch (Exception e) {
assertNotNull(e);
}
}
}
// Copyright 2017-2020, Schlumberger
//
// 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
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.opengroup.osdu.partition.provider.azure.persistence;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.opengroup.osdu.core.common.model.http.AppException;
import org.opengroup.osdu.partition.model.PartitionInfo;
import org.opengroup.osdu.partition.model.Property;
import org.powermock.modules.junit4.PowerMockRunner;
import java.util.*;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.when;
@RunWith(PowerMockRunner.class)
public class PartitionTableStoreTest {
@InjectMocks
private PartitionTableStore sut;
@Mock
private CloudTableStore cloudTableStore;
private static final String PARTITION_ID = "partitionId";
private static final String PARTITION_KEY = "PartitionKey";
@Test
public void should_returnFalse_whenPartitionNotExists() {
boolean exist = sut.partitionExists(PARTITION_ID);
assertFalse(exist);
}
@Test
public void should_get_partitionInfo() {
Collection<PartitionEntity> list = new ArrayList<>();
PartitionEntity partitionEntity = new PartitionEntity(PARTITION_ID, "name");
list.add(partitionEntity);
when(cloudTableStore.queryByKey(PartitionEntity.class, PARTITION_KEY, PARTITION_ID)).thenReturn((Iterable) list);
Map<String, Property> partition = sut.getPartition(PARTITION_ID);
assertNotNull(partition);
assertEquals(1, partition.size());
}
@Test
public void should_returnEmpty_when_partitionNotFound() {
Map<String, Property> partition = sut.getPartition(PARTITION_ID);
assertNotNull(partition);
assertEquals(0, partition.size());
}
@Test
public void should_addPartiton_whenPartionProvided() {
sut.addPartition(PARTITION_ID, new PartitionInfo());
}
@Test
public void should_returnException_whenNoPartitionInfo() {
doThrow(new AppException(500, "Error", "error creating partition")).when(cloudTableStore).insertBatchEntities(any());
try {
sut.addPartition(PARTITION_ID, new PartitionInfo());
fail("Should not be here");
} catch (AppException e) {
assertEquals(500, e.getError().getCode());
assertEquals("error creating partition", e.getError().getMessage());
}
}
@Test
public void should_getAll_partitions() {
Collection<PartitionEntity> list = new ArrayList<>();
PartitionEntity partitionEntity = new PartitionEntity(PARTITION_ID, "name");
list.add(partitionEntity);
when(cloudTableStore.queryByKey(PartitionEntity.class, "RowKey", "id")).thenReturn((Iterable) list);
List<String> partitions = sut.getAllPartitions();
assertNotNull(partitions);
assertEquals(1, partitions.size());
}
@Test
public void delete_partition() {
Collection<PartitionEntity> list = new ArrayList<>();
PartitionEntity partitionEntity = new PartitionEntity(PARTITION_ID, "name");
list.add(partitionEntity);
when(cloudTableStore.queryByKey(PartitionEntity.class, PARTITION_KEY, PARTITION_ID)).thenReturn((Iterable) list);
sut.deletePartition(PARTITION_ID);
}