Skip to content

Commit

Permalink
Merge pull request #120 from near-daos/develop
Browse files Browse the repository at this point in the history
Merge develop to release branch
  • Loading branch information
vhorin-mp authored Jan 19, 2022
2 parents 9c674fd + 8663870 commit 5295fdd
Show file tree
Hide file tree
Showing 20 changed files with 376 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ NEAR_CREDENTIALS_DIR=.near-credentials
NEAR_CONTRACT_NAME=sputnikv2.testnet
NEAR_TOKEN_FACTORY_CONTRACT_NAME=tokenfactory.testnet
NEAR_BRIDGE_TOKEN_FACTORY_CONTRACT_NAME=f.ropsten.testnet
NEAR_TOKEN_API_URL=https://www.sodaki.com/api
NEAR_TOKEN_API_URL=https://sodaki.com/api

AGGREGATOR_POLLING_INTERVAL=2000
AGGREGATOR_TOKEN_POLLING_INTERVAL=7000
Expand Down
2 changes: 1 addition & 1 deletion .github/env.develop
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ K8S_INGRESS_HOST=api.dev.app.astrodao.com
WALLET_CALLBACK_URL=https://dev.app.astrodao.com/callback/transaction
NEAR_BRIDGE_TOKEN_FACTORY_CONTRACT_NAME=f.ropsten.testnet
TEST_ENV_NAME=dev
NEAR_TOKEN_API_URL=https://www.sodaki.com/api
NEAR_TOKEN_API_URL=https://sodaki.com/api
AGGREGATOR_TOKEN_PRICES_POLLING_INTERVAL=100000
# 12 hours
AGGREGATOR_DAO_STATUS_POLLING_INTERVAL=43200000
Expand Down
2 changes: 1 addition & 1 deletion .github/env.production
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ K8S_INGRESS_HOST=api.app.astrodao.com
WALLET_CALLBACK_URL=https://app.astrodao.com/callback/transaction
NEAR_BRIDGE_TOKEN_FACTORY_CONTRACT_NAME=factory.bridge.near
NEAR_NFT_WHITELIST_CONTRACTS=starpause.mintbase1.near
NEAR_TOKEN_API_URL=https://www.sodaki.com/api
NEAR_TOKEN_API_URL=https://sodaki.com/api
AGGREGATOR_TOKEN_PRICES_POLLING_INTERVAL=100000
# 12 hours
AGGREGATOR_DAO_STATUS_POLLING_INTERVAL=43200000
Expand Down
2 changes: 1 addition & 1 deletion .github/env.staging
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ K8S_INGRESS_HOST=api.staging.app.astrodao.com
WALLET_CALLBACK_URL=https://staging.app.astrodao.com/callback/transaction
NEAR_BRIDGE_TOKEN_FACTORY_CONTRACT_NAME=factory.bridge.near
NEAR_NFT_WHITELIST_CONTRACTS=starpause.mintbase1.near
NEAR_TOKEN_API_URL=https://www.sodaki.com/api
NEAR_TOKEN_API_URL=https://sodaki.com/api
AGGREGATOR_TOKEN_PRICES_POLLING_INTERVAL=100000
# 12 hours
AGGREGATOR_DAO_STATUS_POLLING_INTERVAL=43200000
Expand Down
2 changes: 1 addition & 1 deletion .github/env.test
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ K8S_INGRESS_HOST=api.testnet.app.astrodao.com
WALLET_CALLBACK_URL=https://testnet.app.astrodao.com/callback/transaction
NEAR_BRIDGE_TOKEN_FACTORY_CONTRACT_NAME=f.ropsten.testnet
TEST_ENV_NAME=testnet
NEAR_TOKEN_API_URL=https://www.sodaki.com/api
NEAR_TOKEN_API_URL=https://sodaki.com/api
AGGREGATOR_TOKEN_PRICES_POLLING_INTERVAL=100000
# 12 hours
AGGREGATOR_DAO_STATUS_POLLING_INTERVAL=43200000
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Astro API Gateway

[![Release version](https://img.shields.io/github/v/release/near-daos/astro-api-gateway)](https://github.com/near-daos/astro-api-gateway/releases/)
[![Build](https://github.com/near-daos/astro-api-gateway/actions/workflows/build-deploy.yaml/badge.svg)](https://github.com/near-daos/astro-api-gateway/actions/workflows/build-deploy.yaml)
[![Launch API Autotests On Schedule](https://github.com/near-daos/astro-api-gateway/actions/workflows/launch-autotests-on-schedule.yaml/badge.svg)](https://github.com/near-daos/astro-api-gateway/actions/workflows/launch-autotests-on-schedule.yaml)
[![Telegram group](https://img.shields.io/badge/-Telegram%20group-blue)](https://t.me/astro_near)

Astro API Gateway contains list of services used by DAO applications based on [Sputnik DAO Contracts](https://github.com/near-daos/sputnik-dao-contract) version 2 on [NEAR Protocol](https://near.org/).

Main features:
Expand Down
2 changes: 1 addition & 1 deletion apps/aggregator/deployment/app-chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,4 @@ environment:
# Every day at 23:55
aggregator_dao_stats_cron_time: "55 23 * * *"
wallet_callback_url: ""
near_token_api_url: "https://www.sodaki.com/api"
near_token_api_url: "https://sodaki.com/api"
2 changes: 1 addition & 1 deletion test-framework/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This framework is intended to be used for testing of Sputnik v2 API
[![Launch API Autotests On Schedule](https://github.com/near-daos/astro-api-gateway/actions/workflows/launch-autotests-on-schedule.yaml/badge.svg)](https://github.com/near-daos/astro-api-gateway/actions/workflows/launch-autotests-on-schedule.yaml)
[![Manual API Autotests run](https://github.com/near-daos/astro-api-gateway/actions/workflows/run-autotests.yaml/badge.svg)](https://github.com/near-daos/astro-api-gateway/actions/workflows/run-autotests.yaml)

##Test execution reports
## Test execution reports
- [API test coverage and Allure reports - **develop** environment](https://automation-report.app.astrodao.com/develop/)
- [API test coverage and Allure reports - **testnet** environment](https://automation-report.app.astrodao.com/test/)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package api.app.astrodao.com.core.controllers;

import api.app.astrodao.com.core.clients.HttpClient;
import api.app.astrodao.com.core.utils.JsonUtils;
import api.app.astrodao.com.openapi.models.SubscriptionDeleteDto;
import api.app.astrodao.com.openapi.models.SubscriptionDto;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.Collections;

@Component
@RequiredArgsConstructor
public class SubscriptionsApi {
protected final HttpClient httpClient;

@Value("${framework.api.url}")
private String apiUrl;

public ResponseEntity<String> subscribeDao(String accountId, String publicKey, String signature, String daoId) {
HttpHeaders httpHeaders = httpClient.getBasicHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
httpHeaders.setAccept(Collections.singletonList(MediaType.ALL));

UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(apiUrl);
builder.pathSegment("subscriptions");

SubscriptionDto subscriptionDto = new SubscriptionDto();
subscriptionDto.setAccountId(accountId);
subscriptionDto.setPublicKey(publicKey);
subscriptionDto.setSignature(signature);
subscriptionDto.setDaoId(daoId);

HttpEntity<?> httpEntity = new HttpEntity<>(JsonUtils.writeValueAsString(subscriptionDto), httpHeaders);
return httpClient.post(builder.toUriString(), httpEntity, String.class);
}

public ResponseEntity<String> accountSubscriptions(String accountId) {
HttpHeaders httpHeaders = httpClient.getBasicHeaders();
httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(apiUrl);
builder.pathSegment("subscriptions", "account-subscriptions", "{accountId}");

return httpClient.get(builder.build().toString(), new HttpEntity<>(httpHeaders), String.class, accountId);
}

public ResponseEntity<String> deleteSubscription(String accountId, String publicKey, String signature, String daoId) {
HttpHeaders httpHeaders = httpClient.getBasicHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
httpHeaders.setAccept(Collections.singletonList(MediaType.ALL));

UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(apiUrl);
builder.pathSegment("subscriptions", daoId);

SubscriptionDeleteDto subscriptionDto = new SubscriptionDeleteDto();
subscriptionDto.setAccountId(accountId);
subscriptionDto.setPublicKey(publicKey);
subscriptionDto.setSignature(signature);

HttpEntity<?> httpEntity = new HttpEntity<>(JsonUtils.writeValueAsString(subscriptionDto), httpHeaders);
return httpClient.delete(builder.toUriString(), httpEntity, String.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ public class TransactionsApi {
@Value("${framework.api.url}")
private String apiUrl;

@Value("${framework.app.url}")
private String appUrl;

public ResponseEntity<String> triggerCallback(String accountId, String transactionHashes) {
HttpHeaders httpHeaders = httpClient.getBasicHeaders();
httpHeaders.setAccept(Collections.singletonList(MediaType.ALL));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package api.app.astrodao.com.core.dto.api.subscription;

import api.app.astrodao.com.openapi.models.Subscription;

import java.util.ArrayList;

public class Subscriptions extends ArrayList<Subscription> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package api.app.astrodao.com.core.exceptions;

public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package api.app.astrodao.com.core.exceptions;

public class NotEnoughBalanceExecution extends RuntimeException {
public NotEnoughBalanceExecution(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.parameters.HeaderParameter;
import io.swagger.v3.oas.models.parameters.QueryParameter;
import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import io.swagger.v3.oas.models.servers.Server;
Expand Down Expand Up @@ -72,14 +73,24 @@ public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttp
.collect(Collectors.toMap(s -> s[0], s -> s[1]))
.forEach((n, v) -> mediaType.getSchema().addProperties(n, new Schema().example(v)));
}
operation.requestBody(new RequestBody().content(
new Content().addMediaType(request.getHeaders().getContentType().toString(), mediaType))
);
}

ClientHttpResponse response = execution.execute(request, body);

operation.responses(new ApiResponses().addApiResponse(valueOf(response.getRawStatusCode()),
new ApiResponse().content(
new Content().addMediaType(response.getHeaders().getContentType().toString(), new MediaType())))
);
if (response.getHeaders().getContentType() != null) {
operation.responses(new ApiResponses().addApiResponse(valueOf(response.getRawStatusCode()),
new ApiResponse().content(
new Content().addMediaType(response.getHeaders().getContentType().toString(), new MediaType())))
);
} else {
operation.responses(new ApiResponses().addApiResponse(valueOf(response.getRawStatusCode()),
new ApiResponse().content(
new Content().addMediaType(ApiResponses.DEFAULT, new MediaType())))
);
}

PathItem pathItem = new PathItem();
pathItem.operation(PathItem.HttpMethod.valueOf(request.getMethod().name()), operation);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import api.app.astrodao.com.core.exceptions.CLIExecutionNotSuccessful;
import api.app.astrodao.com.core.exceptions.FailedToExecuteCLICommand;
import api.app.astrodao.com.core.exceptions.NotEnoughBalanceExecution;
import io.qameta.allure.Allure;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -39,11 +40,19 @@ public synchronized static List<String> execute(String command) {
output.stream().collect(Collectors.joining(System.lineSeparator())));

int exitValue = process.exitValue();
String outputText = output.stream().collect(Collectors.joining(System.lineSeparator()));
if (exitValue != 0) {
throw new CLIExecutionNotSuccessful(
String.format("Something went wrong, got '%s' exit value for the process, console output:\n%s",
exitValue, output.stream().collect(Collectors.joining(System.lineSeparator())))
);
if (outputText.contains("not enough balance")) {
throw new NotEnoughBalanceExecution(
String.format("Looks like you don't have enough balance for the account, console output:\n%s",
outputText)
);
} else {
throw new CLIExecutionNotSuccessful(
String.format("Something went wrong, got '%s' exit value for the process, console output:\n%s",
exitValue, outputText)
);
}
}

return output;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

@UtilityClass
public class JsonUtils {
private static final ObjectMapper MAPPER;
public static final ObjectMapper MAPPER;

static {
MAPPER = new ObjectMapper();
Expand Down
8 changes: 7 additions & 1 deletion test-framework/src/main/resources/configs/framework.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,10 @@ test:
aggregation.timeout: ${TEST_AGG_TIMEOUT:20}

framework:
http.timeout: 20
http.timeout: 20

accounts:
account1:
accountId: testdao2.testnet
publicKey: ed25519:8kqG6dyAheDqzoZh4hk9HbjBngG6fTnCD4zTw6sVud9K
signature: JJoq7fvBh6JXH9kVXtV0SoeT3YDSm9Gr6Ug4cmJNXAtuU2bZFu9/8bN26xw7MwYBRdWTZr2v81JZDO9zYaE8Dg==
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ public <T, D> void assertDtoValueIsNull(T dto, Function<T, D> valueExtractor, St
.isNull();
}

@Step("User sees string contains value")
public void assertStringContainsValue(String value, String expectedValue) {
assertThat(value)
.as("String should contain value.")
.contains(expectedValue);
}

public <T> T getResponseDto(ResponseEntity<String> entity, Class<T> clazz) {
return JsonUtils.readValue(entity.getBody(), clazz);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package api.app.astrodao.com.steps;

import api.app.astrodao.com.core.annotations.Steps;
import api.app.astrodao.com.core.controllers.SubscriptionsApi;
import api.app.astrodao.com.core.dto.api.subscription.Subscriptions;
import api.app.astrodao.com.core.exceptions.EntityNotFoundException;
import api.app.astrodao.com.openapi.models.Subscription;
import io.qameta.allure.Step;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import java.util.Objects;

import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;

@Steps
@RequiredArgsConstructor
public class SubscriptionsApiSteps extends BaseSteps {
private final SubscriptionsApi subscriptionsApi;

public void cleanUpSubscriptions(String accountId, String publicKey, String signature) {
ResponseEntity<String> response = subscriptionsApi.accountSubscriptions(accountId);
assertResponseStatusCode(response, HttpStatus.OK);
Subscriptions subscriptions = getResponseDto(response, Subscriptions.class);
subscriptions.forEach(p -> {
ResponseEntity<String> resp = subscriptionsApi.deleteSubscription(accountId, publicKey, signature, p.getId());
assertResponseStatusCode(resp, HttpStatus.OK);
});
}

@Step("User subscribes to DAO")
public ResponseEntity<String> subscribeDao(String accountId, String publicKey, String signature, String daoId) {
return subscriptionsApi.subscribeDao(accountId, publicKey, signature, daoId);
}

@Step("User get subscriptions")
public ResponseEntity<String> accountSubscriptions(String accountId) {
return subscriptionsApi.accountSubscriptions(accountId);
}

@Step("User deletes subscription")
public ResponseEntity<String> deleteSubscription(String accountId, String publicKey, String signature, String daoId) {
return subscriptionsApi.deleteSubscription(accountId, publicKey, signature, daoId);
}

public Subscription getCreatedSubscription(Subscriptions subscriptions, String subscriptionId) {
return subscriptions.stream()
.filter(p -> Objects.equals(p.getId(), subscriptionId)).findFirst()
.orElseThrow(() -> new EntityNotFoundException("Subscription not found"));
}

@Step("User sees subscription is not present in a list")
public void verifySubscriptionHasBeenDeleted(Subscriptions subscriptions, String subscriptionId) {
assertThat(subscriptions)
.as(String.format("'%s' subscription should not be present in collection.", subscriptionId))
.map(Subscription::getId)
.doesNotContain(subscriptionId);
}
}
Loading

0 comments on commit 5295fdd

Please sign in to comment.