# WARNING: head commit changed in the meantime
Merge remote-tracking branch 'origin/master' into dev-1.3 plus more unit tests plus CircuitBreaker fix
This commit is contained in:
parent
501db30fa8
commit
c21f0ef463
11 changed files with 269 additions and 20 deletions
2
pom.xml
2
pom.xml
|
@ -18,7 +18,7 @@
|
|||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<sebserver-version>1.3-rc2</sebserver-version>
|
||||
<sebserver-version>1.3-rc3</sebserver-version>
|
||||
<build-version>${sebserver-version}</build-version>
|
||||
<revision>${sebserver-version}</revision>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
|
||||
/** A circuit breaker with three states (CLOSED, HALF_OPEN, OPEN)
|
||||
* <p>
|
||||
|
@ -70,6 +71,7 @@ public final class CircuitBreaker<T> {
|
|||
private State state = State.CLOSED;
|
||||
private final AtomicInteger failingCount = new AtomicInteger(0);
|
||||
private long lastSuccessTime;
|
||||
private long lastOpenTime;
|
||||
|
||||
/** Create new CircuitBreakerSupplier.
|
||||
*
|
||||
|
@ -99,6 +101,8 @@ public final class CircuitBreaker<T> {
|
|||
this.maxFailingAttempts = maxFailingAttempts;
|
||||
this.maxBlockingTime = maxBlockingTime;
|
||||
this.timeToRecover = timeToRecover;
|
||||
// Initialize with creation time to get expected cool-down phase time if never was successful since
|
||||
this.lastOpenTime = Utils.getMillisecondsNow();
|
||||
}
|
||||
|
||||
public int getMaxFailingAttempts() {
|
||||
|
@ -122,7 +126,7 @@ public final class CircuitBreaker<T> {
|
|||
}
|
||||
|
||||
public synchronized Result<T> protectedRun(final Supplier<T> supplier) {
|
||||
final long currentTime = System.currentTimeMillis();
|
||||
final long currentTime = Utils.getMillisecondsNow();
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Called on: {} current state is: {} failing count: {}",
|
||||
|
@ -163,7 +167,7 @@ public final class CircuitBreaker<T> {
|
|||
log.debug("Attempt failed. failing count: {}", this.failingCount);
|
||||
}
|
||||
|
||||
final long currentBlockingTime = System.currentTimeMillis() - startTime;
|
||||
final long currentBlockingTime = Utils.getMillisecondsNow() - startTime;
|
||||
final int failing = this.failingCount.incrementAndGet();
|
||||
if (failing > this.maxFailingAttempts || currentBlockingTime > this.maxBlockingTime) {
|
||||
// brake thought to HALF_OPEN state and return error
|
||||
|
@ -174,14 +178,14 @@ public final class CircuitBreaker<T> {
|
|||
this.state = State.HALF_OPEN;
|
||||
this.failingCount.set(0);
|
||||
return Result.ofError(new RuntimeException(
|
||||
"Set CircuitBeaker to half-open state. Cause: " + result.getError().getMessage(),
|
||||
"Set CircuitBeaker to half-open state. Cause: " + result.getError(),
|
||||
result.getError()));
|
||||
} else {
|
||||
// try again
|
||||
return protectedRun(supplier);
|
||||
}
|
||||
} else {
|
||||
this.lastSuccessTime = System.currentTimeMillis();
|
||||
this.lastSuccessTime = Utils.getMillisecondsNow();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -202,9 +206,10 @@ public final class CircuitBreaker<T> {
|
|||
log.debug("Changing state from Half Open to Open and return cached value");
|
||||
}
|
||||
|
||||
this.lastOpenTime = Utils.getMillisecondsNow();
|
||||
this.state = State.OPEN;
|
||||
return Result.ofError(new RuntimeException(
|
||||
"Set CircuitBeaker to open state. Cause: " + result.getError().getMessage(),
|
||||
"Set CircuitBeaker to open state. Cause: " + result.getError(),
|
||||
result.getError()));
|
||||
} else {
|
||||
// on success go to CLOSED state
|
||||
|
@ -228,7 +233,7 @@ public final class CircuitBreaker<T> {
|
|||
log.debug("Handle Open on: {}", startTime);
|
||||
}
|
||||
|
||||
if (startTime - this.lastSuccessTime >= this.timeToRecover) {
|
||||
if (startTime - this.lastOpenTime >= this.timeToRecover) {
|
||||
// if cool-down period is over, go back to HALF_OPEN state and try again
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Time to recover reached. Changing state from Open to Half Open");
|
||||
|
@ -247,6 +252,7 @@ public final class CircuitBreaker<T> {
|
|||
return Result.of(future.get(this.maxBlockingTime, TimeUnit.MILLISECONDS));
|
||||
} catch (final Exception e) {
|
||||
future.cancel(false);
|
||||
log.warn("Max blocking timeout exceeded: {}, {}", this.maxBlockingTime, this.state);
|
||||
return Result.ofError(e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -818,7 +818,8 @@ public class ExamDAOImpl implements ExamDAO {
|
|||
|
||||
log.debug("Using short-name: {} for recovering", shortname);
|
||||
|
||||
final QuizData recoveredQuizData = this.lmsAPIService.getLmsAPITemplate(lmsSetup.id)
|
||||
final QuizData recoveredQuizData = this.lmsAPIService
|
||||
.getLmsAPITemplate(lmsSetup.id)
|
||||
.map(template -> template.getQuizzes(new FilterMap())
|
||||
.getOrThrow()
|
||||
.stream()
|
||||
|
|
|
@ -80,7 +80,7 @@ public abstract class AbstractCourseAccess {
|
|||
environment.getProperty(
|
||||
"sebserver.webservice.circuitbreaker.quizzesRequest.blockingTime",
|
||||
Long.class,
|
||||
Constants.MINUTE_IN_MILLIS),
|
||||
Constants.SECOND_IN_MILLIS * 10),
|
||||
environment.getProperty(
|
||||
"sebserver.webservice.circuitbreaker.quizzesRequest.timeToRecover",
|
||||
Long.class,
|
||||
|
@ -94,7 +94,7 @@ public abstract class AbstractCourseAccess {
|
|||
environment.getProperty(
|
||||
"sebserver.webservice.circuitbreaker.quizzesRequest.blockingTime",
|
||||
Long.class,
|
||||
Constants.MINUTE_IN_MILLIS),
|
||||
Constants.SECOND_IN_MILLIS * 10),
|
||||
environment.getProperty(
|
||||
"sebserver.webservice.circuitbreaker.quizzesRequest.timeToRecover",
|
||||
Long.class,
|
||||
|
@ -112,7 +112,7 @@ public abstract class AbstractCourseAccess {
|
|||
environment.getProperty(
|
||||
"sebserver.webservice.circuitbreaker.chaptersRequest.timeToRecover",
|
||||
Long.class,
|
||||
Constants.MINUTE_IN_MILLIS));
|
||||
Constants.SECOND_IN_MILLIS * 30));
|
||||
|
||||
this.accountDetailRequest = asyncService.createCircuitBreaker(
|
||||
environment.getProperty(
|
||||
|
@ -126,19 +126,28 @@ public abstract class AbstractCourseAccess {
|
|||
environment.getProperty(
|
||||
"sebserver.webservice.circuitbreaker.accountDetailRequest.timeToRecover",
|
||||
Long.class,
|
||||
Constants.SECOND_IN_MILLIS * 10));
|
||||
Constants.SECOND_IN_MILLIS * 30));
|
||||
}
|
||||
|
||||
public Result<List<QuizData>> protectedQuizzesRequest(final FilterMap filterMap) {
|
||||
return this.allQuizzesRequest.protectedRun(allQuizzesSupplier(filterMap));
|
||||
return this.allQuizzesRequest.protectedRun(allQuizzesSupplier(filterMap))
|
||||
.onError(error -> log.error(
|
||||
"Failed to run protectedQuizzesRequest: {}",
|
||||
error.getMessage()));
|
||||
}
|
||||
|
||||
public Result<Collection<QuizData>> protectedQuizzesRequest(final Set<String> ids) {
|
||||
return this.quizzesRequest.protectedRun(quizzesSupplier(ids));
|
||||
return this.quizzesRequest.protectedRun(quizzesSupplier(ids))
|
||||
.onError(error -> log.error(
|
||||
"Failed to run protectedQuizzesRequest: {}",
|
||||
error.getMessage()));
|
||||
}
|
||||
|
||||
public Result<QuizData> protectedQuizRequest(final String id) {
|
||||
return this.quizRequest.protectedRun(quizSupplier(id));
|
||||
return this.quizRequest.protectedRun(quizSupplier(id))
|
||||
.onError(error -> log.error(
|
||||
"Failed to run protectedQuizRequest: {}",
|
||||
error.getMessage()));
|
||||
}
|
||||
|
||||
public Result<ExamineeAccountDetails> getExamineeAccountDetails(final String examineeSessionId) {
|
||||
|
@ -165,7 +174,10 @@ public abstract class AbstractCourseAccess {
|
|||
}
|
||||
|
||||
public Result<Chapters> getCourseChapters(final String courseId) {
|
||||
return this.chaptersRequest.protectedRun(getCourseChaptersSupplier(courseId));
|
||||
return this.chaptersRequest.protectedRun(getCourseChaptersSupplier(courseId))
|
||||
.onError(error -> log.error(
|
||||
"Failed to run getCourseChapters: {}",
|
||||
error.getMessage()));
|
||||
}
|
||||
|
||||
protected abstract Supplier<ExamineeAccountDetails> accountDetailsSupplier(final String examineeSessionId);
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.mockup;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.async.AsyncService;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
|
@ -24,9 +26,17 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplateFactory;
|
|||
@WebServiceProfile
|
||||
public class MockLmsAPITemplateFactory implements LmsAPITemplateFactory {
|
||||
|
||||
private final AsyncService asyncService;
|
||||
private final WebserviceInfo webserviceInfo;
|
||||
private final Environment environment;
|
||||
|
||||
public MockLmsAPITemplateFactory(final WebserviceInfo webserviceInfo) {
|
||||
public MockLmsAPITemplateFactory(
|
||||
final AsyncService asyncService,
|
||||
final Environment environment,
|
||||
final WebserviceInfo webserviceInfo) {
|
||||
|
||||
this.environment = environment;
|
||||
this.asyncService = asyncService;
|
||||
this.webserviceInfo = webserviceInfo;
|
||||
}
|
||||
|
||||
|
@ -38,6 +48,8 @@ public class MockLmsAPITemplateFactory implements LmsAPITemplateFactory {
|
|||
@Override
|
||||
public Result<LmsAPITemplate> create(final APITemplateDataSupplier apiTemplateDataSupplier) {
|
||||
return Result.tryCatch(() -> new MockupLmsAPITemplate(
|
||||
this.asyncService,
|
||||
this.environment,
|
||||
apiTemplateDataSupplier,
|
||||
this.webserviceInfo));
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -19,9 +20,11 @@ import org.joda.time.DateTime;
|
|||
import org.joda.time.DateTimeZone;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.async.AsyncService;
|
||||
import ch.ethz.seb.sebserver.gbl.client.ClientCredentials;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain.LMS_SETUP;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Chapters;
|
||||
|
@ -38,6 +41,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
|||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.APITemplateDataSupplier;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.AbstractCourseAccess;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.NoSEBRestrictionException;
|
||||
|
||||
public class MockupLmsAPITemplate implements LmsAPITemplate {
|
||||
|
@ -48,7 +52,11 @@ public class MockupLmsAPITemplate implements LmsAPITemplate {
|
|||
private final WebserviceInfo webserviceInfo;
|
||||
private final APITemplateDataSupplier apiTemplateDataSupplier;
|
||||
|
||||
private final AbstractCourseAccess abstractCourseAccess;
|
||||
|
||||
MockupLmsAPITemplate(
|
||||
final AsyncService asyncService,
|
||||
final Environment environment,
|
||||
final APITemplateDataSupplier apiTemplateDataSupplier,
|
||||
final WebserviceInfo webserviceInfo) {
|
||||
|
||||
|
@ -56,6 +64,37 @@ public class MockupLmsAPITemplate implements LmsAPITemplate {
|
|||
this.webserviceInfo = webserviceInfo;
|
||||
this.mockups = new ArrayList<>();
|
||||
|
||||
this.abstractCourseAccess = new AbstractCourseAccess(asyncService, environment) {
|
||||
|
||||
@Override
|
||||
protected Supplier<ExamineeAccountDetails> accountDetailsSupplier(final String examineeSessionId) {
|
||||
return () -> MockupLmsAPITemplate.this
|
||||
.getExamineeAccountDetails_protected(examineeSessionId)
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Supplier<List<QuizData>> allQuizzesSupplier(final FilterMap filterMap) {
|
||||
return () -> MockupLmsAPITemplate.this.getQuizzes_protected(filterMap).getOrThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Supplier<Collection<QuizData>> quizzesSupplier(final Set<String> ids) {
|
||||
return () -> MockupLmsAPITemplate.this.getQuizzes_protected(ids).getOrThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Supplier<QuizData> quizSupplier(final String id) {
|
||||
return () -> MockupLmsAPITemplate.this.getQuiz_protected(id).getOrThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Supplier<Chapters> getCourseChaptersSupplier(final String courseId) {
|
||||
return () -> MockupLmsAPITemplate.this.getCourseChapters_protected(courseId).getOrThrow();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
final LmsSetup lmsSetup = this.apiTemplateDataSupplier.getLmsSetup();
|
||||
final Long lmsSetupId = lmsSetup.id;
|
||||
final Long institutionId = lmsSetup.getInstitutionId();
|
||||
|
@ -149,6 +188,10 @@ public class MockupLmsAPITemplate implements LmsAPITemplate {
|
|||
|
||||
@Override
|
||||
public Result<List<QuizData>> getQuizzes(final FilterMap filterMap) {
|
||||
return this.abstractCourseAccess.protectedQuizzesRequest(filterMap);
|
||||
}
|
||||
|
||||
private Result<List<QuizData>> getQuizzes_protected(final FilterMap filterMap) {
|
||||
return Result.tryCatch(() -> {
|
||||
if (!authenticate()) {
|
||||
throw new IllegalArgumentException("Wrong clientId or secret");
|
||||
|
@ -164,6 +207,10 @@ public class MockupLmsAPITemplate implements LmsAPITemplate {
|
|||
|
||||
@Override
|
||||
public Result<QuizData> getQuiz(final String id) {
|
||||
return this.abstractCourseAccess.protectedQuizRequest(id);
|
||||
}
|
||||
|
||||
private Result<QuizData> getQuiz_protected(final String id) {
|
||||
return Result.of(this.mockups
|
||||
.stream()
|
||||
.filter(q -> id.equals(q.id))
|
||||
|
@ -173,6 +220,11 @@ public class MockupLmsAPITemplate implements LmsAPITemplate {
|
|||
|
||||
@Override
|
||||
public Result<Collection<QuizData>> getQuizzes(final Set<String> ids) {
|
||||
return this.abstractCourseAccess.protectedQuizzesRequest(ids);
|
||||
}
|
||||
|
||||
private Result<Collection<QuizData>> getQuizzes_protected(final Set<String> ids) {
|
||||
|
||||
return Result.tryCatch(() -> {
|
||||
if (!authenticate()) {
|
||||
throw new IllegalArgumentException("Wrong clientId or secret");
|
||||
|
@ -193,11 +245,19 @@ public class MockupLmsAPITemplate implements LmsAPITemplate {
|
|||
|
||||
@Override
|
||||
public Result<Chapters> getCourseChapters(final String courseId) {
|
||||
return this.abstractCourseAccess.getCourseChapters(courseId);
|
||||
}
|
||||
|
||||
private Result<Chapters> getCourseChapters_protected(final String courseId) {
|
||||
return Result.ofError(new UnsupportedOperationException());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<ExamineeAccountDetails> getExamineeAccountDetails(final String examineeSessionId) {
|
||||
return this.abstractCourseAccess.getExamineeAccountDetails(examineeSessionId);
|
||||
}
|
||||
|
||||
private Result<ExamineeAccountDetails> getExamineeAccountDetails_protected(final String examineeSessionId) {
|
||||
return Result.ofError(new UnsupportedOperationException());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService;
|
||||
import ch.ethz.seb.sebserver.gbl.client.ClientCredentials;
|
||||
import ch.ethz.seb.sebserver.gbl.client.ProxyData;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
|
||||
public class ClientHttpRequestFactoryServiceTest {
|
||||
|
||||
@Mock
|
||||
Environment environment;
|
||||
@Mock
|
||||
ClientCredentialService clientCredentialService;
|
||||
|
||||
@Before
|
||||
public void initMocks() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetClientHttpRequestFactory() {
|
||||
|
||||
final ClientHttpRequestFactoryService clientHttpRequestFactoryService = new ClientHttpRequestFactoryService(
|
||||
this.environment,
|
||||
this.clientCredentialService,
|
||||
1, 1, 1);
|
||||
|
||||
final ProxyData proxyData = new ProxyData("testPoxy", 8000, new ClientCredentials("test", "test"));
|
||||
|
||||
Mockito.when(this.environment.getActiveProfiles()).thenReturn(new String[] { "dev-gui", "test" });
|
||||
Mockito.when(this.clientCredentialService.getPlainClientSecret(Mockito.any())).thenReturn(Result.of("test"));
|
||||
|
||||
Result<ClientHttpRequestFactory> clientHttpRequestFactory = clientHttpRequestFactoryService
|
||||
.getClientHttpRequestFactory();
|
||||
|
||||
assertNotNull(clientHttpRequestFactory);
|
||||
assertFalse(clientHttpRequestFactory.hasError());
|
||||
ClientHttpRequestFactory instance = clientHttpRequestFactory.get();
|
||||
assertTrue(instance instanceof HttpComponentsClientHttpRequestFactory);
|
||||
|
||||
clientHttpRequestFactory = clientHttpRequestFactoryService
|
||||
.getClientHttpRequestFactory(proxyData);
|
||||
|
||||
assertNotNull(clientHttpRequestFactory);
|
||||
assertFalse(clientHttpRequestFactory.hasError());
|
||||
instance = clientHttpRequestFactory.get();
|
||||
assertTrue(instance instanceof HttpComponentsClientHttpRequestFactory);
|
||||
|
||||
Mockito.when(this.environment.getActiveProfiles()).thenReturn(new String[] { "prod-gui", "prod-ws" });
|
||||
|
||||
clientHttpRequestFactory = clientHttpRequestFactoryService
|
||||
.getClientHttpRequestFactory();
|
||||
|
||||
assertNotNull(clientHttpRequestFactory);
|
||||
assertFalse(clientHttpRequestFactory.hasError());
|
||||
instance = clientHttpRequestFactory.get();
|
||||
assertTrue(instance instanceof HttpComponentsClientHttpRequestFactory);
|
||||
|
||||
clientHttpRequestFactory = clientHttpRequestFactoryService
|
||||
.getClientHttpRequestFactory(proxyData);
|
||||
|
||||
assertNotNull(clientHttpRequestFactory);
|
||||
assertFalse(clientHttpRequestFactory.hasError());
|
||||
instance = clientHttpRequestFactory.get();
|
||||
assertTrue(instance instanceof HttpComponentsClientHttpRequestFactory);
|
||||
}
|
||||
|
||||
}
|
|
@ -76,7 +76,7 @@ public class CircuitBreakerTest {
|
|||
assertEquals(CircuitBreaker.OPEN_STATE_EXCEPTION, result.getError());
|
||||
|
||||
// wait time to recover
|
||||
Thread.sleep(500);
|
||||
Thread.sleep(1000);
|
||||
result = circuitBreaker.protectedRun(tester); // 11. call...
|
||||
assertEquals(State.CLOSED, circuitBreaker.getState());
|
||||
assertEquals("Hello back again", result.get());
|
||||
|
|
|
@ -77,7 +77,7 @@ public class MemoizingCircuitBreakerTest {
|
|||
assertEquals(State.OPEN, circuitBreaker.getState());
|
||||
|
||||
// wait time to recover
|
||||
Thread.sleep(500);
|
||||
Thread.sleep(1000);
|
||||
result = circuitBreaker.get(); // 11. call...
|
||||
assertEquals(State.CLOSED, circuitBreaker.getState());
|
||||
assertEquals("Hello back again", result.get());
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.integration.api.admin;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityName;
|
||||
|
||||
@Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" })
|
||||
public class WebserviceInfoTest extends AdministrationAPIIntegrationTester {
|
||||
|
||||
@Test
|
||||
public void testGetLogo() throws Exception {
|
||||
String result = new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution1Access())
|
||||
.withPath(API.INFO_ENDPOINT + API.LOGO_PATH_SEGMENT)
|
||||
.withPath("/inst1")
|
||||
.withMethod(HttpMethod.GET)
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsString();
|
||||
|
||||
assertEquals("", result);
|
||||
|
||||
result = new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution1Access())
|
||||
.withPath(API.INFO_ENDPOINT + API.LOGO_PATH_SEGMENT)
|
||||
.withPath("/inst2")
|
||||
.withMethod(HttpMethod.GET)
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsString();
|
||||
|
||||
assertEquals("AAA", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getInstitutionInfo() throws Exception {
|
||||
|
||||
final Collection<EntityName> result = new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution1Access())
|
||||
.withPath(API.INFO_ENDPOINT + API.INFO_INST_PATH_SEGMENT)
|
||||
.withMethod(HttpMethod.GET)
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<Collection<EntityName>>() {
|
||||
});
|
||||
|
||||
assertNotNull(result);
|
||||
assertTrue(result.stream().filter(en -> "Institution1".equals(en.name)).findFirst().isPresent());
|
||||
assertTrue(result.stream().filter(en -> "Institution2".equals(en.name)).findFirst().isPresent());
|
||||
assertFalse(result.stream().filter(en -> "Institution3".equals(en.name)).findFirst().isPresent());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
INSERT INTO institution VALUES
|
||||
(1, 'Institution1', 'inst1', null, null, 1),
|
||||
(2, 'Institution2', 'inst2', null, null, 1),
|
||||
(2, 'Institution2', 'inst2', 'AAA', null, 1),
|
||||
(3, 'Institution3', 'inst3', null, null, 0)
|
||||
;
|
||||
|
||||
|
|
Loading…
Reference in a new issue