Skip to content
Snippets Groups Projects
Commit fd433fec authored by Martin Lowe's avatar Martin Lowe :flag_ca:
Browse files

Merge branch 'zacharysabourin/main/135' into 'main'

feat: Improve code quality

See merge request !150
parents 73034ef4 2309796a
No related branches found
No related tags found
1 merge request!150feat: Improve code quality
Pipeline #30579 passed
Showing
with 276 additions and 69 deletions
......@@ -12,11 +12,13 @@ CREATE TABLE IF NOT EXISTS `CommitValidationMessage` (
CREATE TABLE IF NOT EXISTS `CommitValidationStatus` (
`id` SERIAL,
`commitHash` varchar(100) NOT NULL,
`userMail` varchar(100) NOT NULL,
`project` varchar(100) NOT NULL,
`lastModified` datetime DEFAULT NULL,
`creationDate` datetime DEFAULT NULL,
`provider` varchar(100) NOT NULL,
`repoUrl` varchar(255) DEFAULT NULL,
`entimatedLoc` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);
......
......@@ -124,4 +124,8 @@ public class EclipseQuteTemplateExtensions {
}
return out;
}
private EclipseQuteTemplateExtensions() {
}
}
......@@ -11,6 +11,7 @@
**********************************************************************/
package org.eclipsefoundation.git.eca.dto;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
......@@ -38,7 +39,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
@Table
@Entity
public class CommitValidationMessage extends BareNode {
public class CommitValidationMessage extends BareNode implements Serializable{
public static final DtoTable TABLE = new DtoTable(CommitValidationMessage.class, "cvm");
@Id
......
......@@ -45,10 +45,10 @@ public class JwtHelper {
@ConfigProperty(name = "smallrye.jwt.sign.key.location")
String location;
@ConfigProperty(name = "eclipse.github.default-api-version", defaultValue = "2022-11-28")
String apiVersion;
protected String apiVersion;
@RestClient
GithubAPI ghApi;
protected GithubAPI ghApi;
@Inject
JWTParser parser;
......
......@@ -14,6 +14,8 @@ package org.eclipsefoundation.git.eca.model;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import org.eclipsefoundation.git.eca.namespace.APIStatusCode;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
......@@ -76,6 +78,7 @@ public abstract class CommitStatus {
public abstract static class CommitStatusMessage {
public abstract APIStatusCode getCode();
@Nullable
public abstract String getMessage();
public static Builder builder() {
......@@ -87,7 +90,7 @@ public abstract class CommitStatus {
public abstract static class Builder {
public abstract Builder setCode(APIStatusCode code);
public abstract Builder setMessage(String message);
public abstract Builder setMessage(@Nullable String message);
public abstract CommitStatusMessage build();
}
......
......@@ -40,6 +40,7 @@ public abstract class ValidationRequest {
public abstract List<Commit> getCommits();
@Nullable
public abstract ProviderType getProvider();
@Nullable
......@@ -49,6 +50,8 @@ public abstract class ValidationRequest {
@JsonProperty("strictMode")
public abstract Boolean getStrictMode();
public abstract Builder toBuilder();
public static Builder builder() {
return new AutoValue_ValidationRequest.Builder().setStrictMode(false).setCommits(new ArrayList<>());
}
......@@ -61,7 +64,7 @@ public abstract class ValidationRequest {
public abstract Builder setCommits(List<Commit> commits);
public abstract Builder setProvider(ProviderType provider);
public abstract Builder setProvider(@Nullable ProviderType provider);
public abstract Builder setEstimatedLoc(@Nullable Integer estimatedLoc);
......
......@@ -15,6 +15,7 @@ import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
......@@ -46,6 +47,7 @@ public abstract class ValidationResponse {
public abstract boolean getStrictMode();
@Nullable
public abstract String getFingerprint();
public boolean getPassed() {
......@@ -130,7 +132,7 @@ public abstract class ValidationResponse {
public abstract Builder setStrictMode(boolean strictMode);
public abstract Builder setFingerprint(String fingerprint);
public abstract Builder setFingerprint(@Nullable String fingerprint);
public abstract ValidationResponse build();
}
......
/*********************************************************************
* Copyright (c) 2022 Eclipse Foundation.
* Copyright (c) 2023 Eclipse Foundation.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
......@@ -9,29 +9,19 @@
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipsefoundation.git.eca.resource.mapper;
package org.eclipsefoundation.git.eca.namespace;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
/**
* A Helper class used to centralize the incoming webhook header values
*/
public final class WebhookHeaders {
public static final String GITLAB_EVENT = "X-Gitlab-Event";
import org.eclipsefoundation.core.model.Error;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public static final String GITHUB_EVENT = "X-GitHub-Event";
public static final String GITHUB_DELIVERY = "X-GitHub-Delivery";
/**
* Creates human legible error responses in the case of BadRequestExceptions.
*/
@Provider
public class BadRequestMapper implements ExceptionMapper<BadRequestException> {
private WebhookHeaders() {
private static final Logger LOGGER = LoggerFactory.getLogger(BadRequestMapper.class);
@Override
public Response toResponse(BadRequestException exception) {
LOGGER.error(exception.getMessage());
return new Error(Status.BAD_REQUEST, exception.getMessage()).asResponse();
}
}
......@@ -33,6 +33,7 @@ import org.eclipsefoundation.git.eca.model.RevalidationResponse;
import org.eclipsefoundation.git.eca.model.ValidationRequest;
import org.eclipsefoundation.git.eca.namespace.GitEcaParameterNames;
import org.eclipsefoundation.git.eca.namespace.HCaptchaErrorCodes;
import org.eclipsefoundation.git.eca.namespace.WebhookHeaders;
import org.jboss.resteasy.annotations.jaxrs.HeaderParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -63,8 +64,8 @@ public class GithubWebhooksResource extends GithubAdjacentResource {
* @return an OK status when done processing.
*/
@POST
public Response processGithubWebhook(@HeaderParam("X-GitHub-Delivery") String deliveryId,
@HeaderParam("X-GitHub-Hook-ID") String hookId, @HeaderParam("X-GitHub-Event") String eventType, GithubWebhookRequest request) {
public Response processGithubWebhook(@HeaderParam(WebhookHeaders.GITHUB_DELIVERY) String deliveryId,
@HeaderParam(WebhookHeaders.GITHUB_EVENT) String eventType, GithubWebhookRequest request) {
// If event isn't a pr event, drop as we don't process them
if (!"pull_request".equalsIgnoreCase(eventType)) {
return Response.ok().build();
......
......@@ -83,7 +83,7 @@ public class StatusResource extends GithubAdjacentResource {
public Response getCommitValidationUI(@PathParam("fingerprint") String fingerprint) {
List<CommitValidationStatus> statuses = validation.getHistoricValidationStatus(wrapper, fingerprint);
if (statuses.isEmpty()) {
return Response.status(404).build();
throw new NotFoundException(String.format("Fingerprint '%s' not found", fingerprint));
}
List<Project> ps = projects.retrieveProjectsForRepoURL(statuses.get(0).getRepoUrl(), statuses.get(0).getProvider());
return Response
......
......@@ -25,6 +25,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.lang3.StringUtils;
import org.eclipsefoundation.core.model.RequestWrapper;
import org.eclipsefoundation.core.service.CachingService;
import org.eclipsefoundation.git.eca.api.models.EclipseUser;
......@@ -117,7 +118,7 @@ public class ValidationResource {
messages.add("A commit is required to validate");
}
// check that we have a repo set
if (req.getRepoUrl() == null) {
if (req.getRepoUrl() == null || StringUtils.isBlank(req.getRepoUrl().getPath())) {
messages.add("A base repo URL needs to be set in order to validate");
}
// check that we have a type set
......
......@@ -19,6 +19,7 @@ import javax.ws.rs.core.Response;
import org.eclipsefoundation.core.model.RequestWrapper;
import org.eclipsefoundation.git.eca.api.models.SystemHook;
import org.eclipsefoundation.git.eca.namespace.EventType;
import org.eclipsefoundation.git.eca.namespace.WebhookHeaders;
import org.eclipsefoundation.git.eca.service.SystemHookService;
import org.jboss.resteasy.annotations.jaxrs.HeaderParam;
import org.slf4j.Logger;
......@@ -41,7 +42,7 @@ public class WebhooksResource {
@POST
@Path("system")
public Response processGitlabHook(@HeaderParam("X-Gitlab-Event") String eventHeader, String jsonBody) {
public Response processGitlabHook(@HeaderParam(WebhookHeaders.GITLAB_EVENT) String eventHeader, String jsonBody) {
// Do not process if header is incorrect
if (!"system hook".equalsIgnoreCase(eventHeader)) {
return Response.ok().build();
......
/*********************************************************************
* Copyright (c) 2019 Eclipse Foundation.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipsefoundation.git.eca.resource.mapper;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Catch-all exception mapper to ensure that any error thrown by the service
* will log the error and quit out safely while limiting the response to a
* simple error.
*
* @author Martin Lowe
*
*/
@Provider
public class RuntimeMapper implements ExceptionMapper<RuntimeException> {
private static final Logger LOGGER = LoggerFactory.getLogger(RuntimeMapper.class);
@Override
public Response toResponse(RuntimeException exception) {
LOGGER.error(exception.getMessage(), exception);
// return an empty response with a server error response
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
}
}
......@@ -15,6 +15,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import org.eclipsefoundation.core.exception.ApplicationException;
import org.eclipsefoundation.core.model.RequestWrapper;
import org.eclipsefoundation.efservices.api.models.Project;
import org.eclipsefoundation.git.eca.dto.CommitValidationStatus;
......@@ -98,7 +99,7 @@ public interface ValidationService {
try {
return HexConverter.convertToHexString(MessageDigest.getInstance("MD5").digest(sb.toString().getBytes()));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Error while encoding request fingerprint - couldn't find MD5 algorithm.");
throw new ApplicationException("Error while encoding request fingerprint - couldn't find MD5 algorithm.", e);
}
}
}
......@@ -24,6 +24,7 @@ import javax.ws.rs.core.MultivaluedMap;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.context.ManagedExecutor;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.eclipsefoundation.core.exception.ApplicationException;
import org.eclipsefoundation.core.service.APIMiddleware;
import org.eclipsefoundation.core.service.CachingService;
import org.eclipsefoundation.git.eca.api.GithubAPI;
......@@ -94,7 +95,7 @@ public class DefaultGithubApplicationService implements GithubApplicationService
Thread.currentThread().interrupt();
} catch (Exception e) {
// rewrap exception and throw
throw new RuntimeException(e);
throw new ApplicationException("Thread interrupted while building repository cache, no entries will be available for current call", e);
}
return new MultivaluedMapImpl<>();
}
......
......@@ -74,7 +74,7 @@
</li>
{/if}
</ul>
<a href="{repoUrl}" target="_blank" class="btn btn-primary margin-top-10">Project repository</a>
<a href="{repoUrl}" target="_blank" rel="noopener" class="btn btn-primary margin-top-10">Project repository</a>
</div>
</div>
{#if statuses.getErrorCount > 0}
......@@ -153,7 +153,7 @@
<div>
<form id="git-eca-hook-revalidation" data-request-number="{pullRequestNumber}" data-request-repo="{fullRepoName}" data-request-installation="{installationId}">
<div class="captcha">
<div class="h-captcha" data-sitekey="{config:['eclipse.hcaptcha.sitekey']}"></div>
<div class="h-captcha" data-sitekey="{config:['eclipse.hcaptcha.site-key']}"></div>
</div>
<button class="btn-success margin-top-10 btn form-submit" type="submit">Revalidate</button>
</form>
......@@ -161,7 +161,7 @@
{/if}
</section>
<aside id="main-sidebar-secondy" role="complementary" class="col-md-6 col-sm-8 margin-bottom-60">
<aside id="main-sidebar-secondy" role="complementary" class="col-md-6 col-sm-8 margin-bottom-60" aria-label="eclipse-contributor-agreement">
<div class="region region-sidebar-second solstice-region-element-count-2">
<section id="block-site-login-eclipse-eca-sle-eca-lookup-tool"
class="block block-site-login-eclipse-eca block-region-sidebar-second solstice-block solstice-block-default solstice-block-white-bg block-sle-eca-lookup-tool clearfix">
......@@ -181,7 +181,7 @@
<section id="block-eclipse-api-github-eclipse-api-github-links"
class="block block-eclipse-api-github contextual-links-region block-region-sidebar-second solstice-block block-eclipse-api-github-links clearfix">
<div class="block-content">
<aside class="main-sidebar-default-margin" id="main-sidebar">
<aside class="main-sidebar-default-margin" id="main-sidebar" aria-label="eclipse-contributor-agreement-links">
<ul id="leftnav" class="ul-left-nav fa-ul hidden-print">
<li class="separator"><a class="separator" href="https://www.eclipse.org/legal/ECA.php"> ECA </a></li>
<li><i class="fa fa-caret-right fa-fw" aria-hidden="true"></i> <a href="https://accounts.eclipse.org/user/eca"
......
/*********************************************************************
* Copyright (c) 2023 Eclipse Foundation.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipsefoundation.git.eca.resource;
import java.util.Map;
import java.util.Optional;
import javax.inject.Inject;
import org.eclipsefoundation.core.exception.ApplicationException;
import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest;
import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest.Installation;
import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest.PullRequest;
import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest.PullRequestHead;
import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest.Repository;
import org.eclipsefoundation.git.eca.namespace.WebhookHeaders;
import org.eclipsefoundation.testing.helpers.TestCaseHelper;
import org.eclipsefoundation.testing.models.EndpointTestBuilder;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.test.junit.QuarkusTest;
@QuarkusTest
class GithubWebhooksResourceTest {
private static final String GH_WEBHOOK_BASE_URL = "/webhooks/github";
@Inject
ObjectMapper om;
@Test
void testInvalidEventType() {
EndpointTestBuilder.from(TestCaseHelper.prepareTestCase(GH_WEBHOOK_BASE_URL, new String[] {}, null)
.setHeaderParams(Optional.of(Map.of(WebhookHeaders.GITHUB_EVENT, "nope"))).build()).doPost()
.run();
}
@Test
void testGHWebhook_success() {
EndpointTestBuilder
.from(TestCaseHelper
.prepareTestCase(GH_WEBHOOK_BASE_URL, new String[] {}, null)
.setHeaderParams(Optional.of(Map.of(WebhookHeaders.GITHUB_DELIVERY, "id-1", WebhookHeaders.GITHUB_EVENT, "pull_request")))
.build())
.doPost(createGHWebhook())
.run();
}
private String createGHWebhook() {
try {
return om.writeValueAsString(GithubWebhookRequest.builder()
.setInstallation(Installation.builder().setId("install-id").build())
.setPullRequest(PullRequest
.builder()
.setNumber(42)
.setHead(PullRequestHead.builder().setSha("sha-1234").build())
.setState("open")
.build())
.setRepository(Repository
.builder()
.setFullName("eclipsefdn/sample")
.setHtmlUrl("http://www.github.com/eclipsefdn/sample")
.build())
.build());
} catch (Exception e) {
throw new ApplicationException("Error converting Hook to JSON");
}
}
}
......@@ -97,16 +97,6 @@ class ReportsResourceTest {
RestAssuredTemplates.testGet_validateResponseFormat(GET_REPORT_SUCCESS_CASE);
}
@Test
void getPrivProjReport_failure_invalidResponseFormat() {
RestAssuredTemplates
.testGet(TestCaseHelper
.prepareTestCase(REPORTS_PROJECTS_URL, new String[] { VALID_TEST_ACCESS_KEY }, null)
.setResponseContentType(ContentType.TEXT)
.setStatusCode(500)
.build());
}
@Test
void getPrivProjReport_failure_badAccessKey() {
RestAssuredTemplates.testGet(GET_REPORT_BAD_ACCESS_KEY);
......
/*********************************************************************
* Copyright (c) 2023 Eclipse Foundation.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipsefoundation.git.eca.resource;
import java.util.Collections;
import java.util.Map;
import org.eclipsefoundation.git.eca.test.namespaces.SchemaNamespaceHelper;
import org.eclipsefoundation.testing.helpers.TestCaseHelper;
import org.eclipsefoundation.testing.models.EndpointTestBuilder;
import org.eclipsefoundation.testing.templates.RestAssuredTemplates.EndpointTestCase;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.http.ContentType;
@QuarkusTest
class StatusResourceTest {
public static final String STATUS_BASE_URL = "/eca/status";
public static final String FINGERPRINT_STATUS_BASE_URL = STATUS_BASE_URL + "/{fingerprint}";
public static final String FINGERPRINT_STATUS_UI_BASE_URL = FINGERPRINT_STATUS_BASE_URL + "/ui";
private static final String VALID_FINGERPRINT = "957706b0f31e0ccfc5287c0ebc62dc79";
private static final String INVALID_FINGERPRINT = "nope";
public static final EndpointTestCase GET_STATUS_SUCCESS_CASE = TestCaseHelper
.buildSuccessCase(FINGERPRINT_STATUS_BASE_URL, new String[] { VALID_FINGERPRINT },
SchemaNamespaceHelper.COMMIT_VALIDATION_STATUSES_SCHEMA);
public static final EndpointTestCase GET_STATUS_UI_NOT_FOUND_CASE = TestCaseHelper
.prepareTestCase(FINGERPRINT_STATUS_UI_BASE_URL, new String[] { INVALID_FINGERPRINT }, null)
.setResponseContentType(ContentType.HTML)
.setStatusCode(404).build();
@Test
void testGetValidationStatus_success_validFormatAndSchema() {
EndpointTestBuilder.from(GET_STATUS_SUCCESS_CASE).doGet().andCheckSchema().andCheckFormat().run();
}
@Test
void testGetValidationStatus_success_invalidFingerprint() {
// invalid/not found fingerprint returns 200 with an empty list
EndpointTestBuilder
.from(TestCaseHelper
.prepareTestCase(FINGERPRINT_STATUS_BASE_URL, new String[] { INVALID_FINGERPRINT }, null)
.setBodyValidationParams(Map.of("", Collections.emptyList())).build())
.andCheckBodyParams()
.doGet()
.run();
}
@Test
void testGetValidationStatusUi_success() {
EndpointTestBuilder
.from(TestCaseHelper
.prepareTestCase(FINGERPRINT_STATUS_UI_BASE_URL, new String[] { VALID_FINGERPRINT }, null)
.setResponseContentType(ContentType.HTML).build())
.doGet().run();
}
@Test
void testGetValidationStatusUi_failure_notFound() {
EndpointTestBuilder
.from(TestCaseHelper
.prepareTestCase(FINGERPRINT_STATUS_UI_BASE_URL, new String[] { INVALID_FINGERPRINT }, null)
.setResponseContentType(ContentType.HTML).setStatusCode(404).build())
.doGet().run();
}
}
......@@ -25,6 +25,7 @@ import java.util.UUID;
import javax.inject.Inject;
import org.eclipsefoundation.core.exception.ApplicationException;
import org.eclipsefoundation.core.service.CachingService;
import org.eclipsefoundation.git.eca.model.Commit;
import org.eclipsefoundation.git.eca.model.GitUser;
......@@ -151,7 +152,7 @@ class ValidationResourceTest {
try {
in = json.writeValueAsString(VALIDATE_SUCCESS_BODY);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
throw new ApplicationException("Error converting body to JSON format", e);
}
Assertions.assertTrue(matchesJsonSchemaInClasspath(SchemaNamespaceHelper.VALIDATION_REQUEST_SCHEMA_PATH).matches(in));
......@@ -423,6 +424,59 @@ class ValidationResourceTest {
createGitHubRequest(true, "http://www.github.com/eclipsefdn-tck/tck-ignored", Arrays.asList(c1)));
}
@Test
void testValidate_success_noCommits() {
// We do not block contributions to non-project repos
RestAssuredTemplates
.testPost(VALIDATE_SUCCESS_CASE,
createGitHubRequest(true, "http://www.github.com/eclipsefdn/prototype.git",
Collections.emptyList()));
// Strictmode shouldn't affect the result
RestAssuredTemplates
.testPost(VALIDATE_SUCCESS_CASE,
createGitHubRequest(false, "http://www.github.com/eclipsefdn/prototype.git",
Collections.emptyList()));
}
@Test
void testValidate_failure_noRepoUrl() {
Commit c1 = createStandardUsercommit(USER_WIZARD, USER_NEWBIE);
// We do not block contributions to non-project repos
RestAssuredTemplates
.testPost(VALIDATE_SUCCESS_CASE, createGitHubRequest(true, "", Arrays.asList(c1)));
// Strictmode shouldn't affect the result
RestAssuredTemplates
.testPost(VALIDATE_SUCCESS_CASE,
createGitHubRequest(false, "", Arrays.asList(c1)));
}
@Test
void testValidate_failure_noProvider() {
Commit c1 = createStandardUsercommit(USER_WIZARD, USER_NEWBIE);
// Request with no provider set
ValidationRequest req = ValidationRequest
.builder()
.setStrictMode(true)
.setRepoUrl(URI.create("http://www.github.com/eclipsefdn/prototype.git"))
.setCommits(Arrays.asList(c1))
.build();
// We do not block contributions to non-project repos
RestAssuredTemplates
.testPost(VALIDATE_SUCCESS_CASE, req);
req = req.toBuilder().setStrictMode(false).build();
// Strictmode shouldn't affect the result
RestAssuredTemplates
.testPost(VALIDATE_SUCCESS_CASE, req);
}
/*
* BOT ACCESS TESTS
*/
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment