,
42 | nextElement: ClassicElement,
43 | container: Element,
44 | callback?: (component: ClassicComponent
) => any): ClassicComponent
;
45 | function unstable_renderSubtreeIntoContainer
(
46 | parentComponent: Component,
47 | nextElement: ReactElement,
48 | container: Element,
49 | callback?: (component: Component
) => any): Component
;
50 | }
51 |
52 | namespace __DOMServer {
53 | function renderToString(element: ReactElement): string;
54 | function renderToStaticMarkup(element: ReactElement): string;
55 | var version: string;
56 | }
57 | }
58 |
59 | declare module "react-dom" {
60 | import DOM = __React.__DOM;
61 | export = DOM;
62 | }
63 |
64 | declare module "react-dom/server" {
65 | import DOMServer = __React.__DOMServer;
66 | export = DOMServer;
67 | }
--------------------------------------------------------------------------------
/service/src/main/java/ru/qatools/selenograph/gridrouter/SessionsCountsPerUser.java:
--------------------------------------------------------------------------------
1 | package ru.qatools.selenograph.gridrouter;
2 |
3 | import ru.qatools.gridrouter.sessions.GridRouterUserStats;
4 |
5 | import java.io.Serializable;
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | import static java.lang.Math.round;
10 | import static java.lang.String.format;
11 |
12 | /**
13 | * @author Ilya Sadykov
14 | */
15 | public class SessionsCountsPerUser extends HashMap implements Serializable, GridRouterUserStats {
16 |
17 | public SessionsCountsPerUser(Map counts) {
18 | resetStats(counts);
19 | }
20 |
21 | public SessionsCountsPerUser() {
22 | // need to have no-args constructor
23 | }
24 |
25 | public static BrowserContext fromBrowserString(String browser) {
26 | final String[] parts = browser.replaceAll("\\[DOT\\]", ".").split(":");
27 | return new UserBrowser().withUser(parts[0]).withBrowser(parts[1]).withVersion(parts[2]);
28 | }
29 |
30 | public static String toBrowserString(BrowserContext browser) {
31 | return toBrowserString(browser.getUser(), browser.getBrowser(), browser.getVersion());
32 | }
33 |
34 | public static String toBrowserString(String user, String browser, String version) {
35 | return format("%s:%s:%s", user, browser, version).replaceAll("\\.", "[DOT]");
36 | }
37 |
38 | public SessionsState getFor(String user, String browser, String version) {
39 | return get(toBrowserString(user, browser, version));
40 | }
41 |
42 | public void updateStats(SessionsCountsPerUser counts) {
43 | counts.entrySet().forEach(count -> {
44 | putIfAbsent(count.getKey(), new SessionsState());
45 | final SessionsState state = get(count.getKey());
46 | state.setRaw(count.getValue().getRaw());
47 | state.setMax(state.getRaw() > state.getMax() ? state.getRaw() : state.getMax());
48 | state.setAvg(round(((float) state.getAvg() + (float) state.getRaw()) / 2.0f));
49 | state.setBrowser(count.getValue().getBrowser());
50 | state.setVersion(count.getValue().getVersion());
51 | state.setUser(count.getValue().getUser());
52 | });
53 | }
54 |
55 | public void resetStats(Map counts) {
56 | counts.entrySet().forEach(e -> {
57 | final BrowserContext browser = e.getKey();
58 | final Integer count = e.getValue();
59 | putIfAbsent(toBrowserString(browser), new SessionsState());
60 | final SessionsState state = get(toBrowserString(browser));
61 | state.setRaw(count);
62 | state.setAvg(count);
63 | state.setMax(count);
64 | state.setBrowser(browser.getBrowser());
65 | state.setVersion(browser.getVersion());
66 | state.setUser(browser.getUser());
67 | state.setTimestamp(browser.getTimestamp());
68 | });
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/service/src/main/java/ru/qatools/selenograph/ext/jackson/SelenographDeserializers.java:
--------------------------------------------------------------------------------
1 | package ru.qatools.selenograph.ext.jackson;
2 |
3 | import com.fasterxml.jackson.core.JsonParser;
4 | import com.fasterxml.jackson.core.JsonToken;
5 | import com.fasterxml.jackson.databind.*;
6 | import com.fasterxml.jackson.databind.deser.Deserializers;
7 | import com.fasterxml.jackson.databind.deser.std.DateDeserializers;
8 | import com.fasterxml.jackson.databind.deser.std.NumberDeserializers;
9 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
10 |
11 | import java.io.IOException;
12 | import java.util.Date;
13 |
14 | import static ru.yandex.qatools.camelot.util.TypesUtil.isLong;
15 |
16 | /**
17 | * @author Ilya Sadykov
18 | */
19 | public class SelenographDeserializers extends Deserializers.Base {
20 |
21 | @Override
22 | public JsonDeserializer> findBeanDeserializer(JavaType type, DeserializationConfig config, BeanDescription beanDesc) throws JsonMappingException {
23 | if (isLong(type.getRawClass())) {
24 | return new LongDeserializer();
25 | }
26 | if (type.getRawClass().equals(Date.class)) {
27 | return new DateDeserializer();
28 | }
29 | return super.findBeanDeserializer(type, config, beanDesc);
30 | }
31 |
32 | private static class LongDeserializer extends StdDeserializer {
33 | NumberDeserializers.LongDeserializer longDeserializer = //NOSONAR
34 | new NumberDeserializers.LongDeserializer(Long.class, 0L);
35 |
36 | LongDeserializer() {
37 | super(Long.class);
38 | }
39 |
40 | @Override
41 | public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
42 | final boolean array = p.hasToken(JsonToken.START_ARRAY);
43 | if (p.hasToken(JsonToken.START_OBJECT) || array) {
44 | p.nextToken();
45 | long value;
46 | if(array){
47 | p.nextToken();
48 | value = Long.parseLong(p.getText());
49 | } else {
50 | value = Long.parseLong(p.nextTextValue());
51 | }
52 | p.nextToken();
53 | return value;
54 | }
55 | return longDeserializer.deserialize(p, ctxt);
56 | }
57 | }
58 |
59 | private static class DateDeserializer extends StdDeserializer {
60 | DateDeserializers.DateDeserializer dateDeserializer = new DateDeserializers.DateDeserializer(); //NOSONAR
61 |
62 | protected DateDeserializer() {
63 | super(Date.class);
64 | }
65 |
66 | @Override
67 | public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
68 | if (p.hasToken(JsonToken.START_OBJECT)) {
69 | p.nextToken();
70 | p.nextToken();
71 | long value = Long.parseLong(p.getText());
72 | p.nextToken();
73 | return new Date(value);
74 | }
75 | return dateDeserializer.deserialize(p, ctxt);
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/service/src/test/java/ru/qatools/selenograph/gridrouter/QueueWaitAvailableBrowsersCheckerTest.java:
--------------------------------------------------------------------------------
1 | package ru.qatools.selenograph.gridrouter;
2 |
3 | import org.junit.Before;
4 | import org.junit.Test;
5 | import org.junit.runner.RunWith;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import ru.qatools.gridrouter.config.Version;
8 | import ru.qatools.selenograph.ext.SelenographDB;
9 | import ru.yandex.qatools.camelot.test.*;
10 |
11 | import static com.jayway.awaitility.Awaitility.await;
12 | import static java.lang.Thread.sleep;
13 | import static java.util.UUID.randomUUID;
14 | import static java.util.concurrent.TimeUnit.SECONDS;
15 | import static java.util.stream.IntStream.rangeClosed;
16 | import static org.hamcrest.MatcherAssert.assertThat;
17 | import static org.hamcrest.Matchers.equalTo;
18 | import static org.hamcrest.Matchers.notNullValue;
19 | import static org.mockito.Matchers.any;
20 | import static org.mockito.Mockito.timeout;
21 | import static org.mockito.Mockito.verify;
22 |
23 | /**
24 | * @author Ilya Sadykov
25 | */
26 | @DisableTimers
27 | @RunWith(CamelotTestRunner.class)
28 | public class QueueWaitAvailableBrowsersCheckerTest {
29 |
30 | @Helper
31 | TestHelper helper;
32 |
33 | @Autowired
34 | QueueWaitAvailableBrowsersChecker queue;
35 |
36 | @PluginMock
37 | QueueWaitAvailableBrowsersChecker mock;
38 |
39 | @AggregatorState(QueueWaitAvailableBrowsersChecker.class)
40 | AggregatorStateStorage repo;
41 |
42 | @Autowired
43 | SelenographDB database;
44 |
45 | @Before
46 | public void setUp() throws Exception {
47 | database.clear();
48 | }
49 |
50 | @Test
51 | public void testCountEnqueuedRequests() throws Exception {
52 | final String reqId = randomUUID().toString();
53 | rangeClosed(0, 2).forEach(i -> queue.onWait("user", "firefox", version("33"), reqId, i));
54 | verify(mock, timeout(4000L).times(1)).onBeforeRequest(any(), any());
55 | verify(mock, timeout(4000L).times(1)).onEnqueued(any(), any());
56 | await().atMost(4, SECONDS).until(() -> state("user-firefox-33"), notNullValue());
57 |
58 | assertThat(state("user-firefox-33").size(), equalTo(1));
59 |
60 | queue.onWaitFinished("user", "firefox", version("33"), reqId, 3);
61 | verify(mock, timeout(2000L).times(1)).onDequeued(any(), any());
62 |
63 | await().atMost(2, SECONDS).until(() -> state("user-firefox-33").size(), equalTo(0));
64 | }
65 |
66 | @Test
67 | public void testExpiredRequestsRemoval() throws Exception {
68 | queue.onWait("user", "firefox", version("33"), "reqId", 0);
69 | await().atMost(4, SECONDS).until(() -> state("user-firefox-33"), notNullValue());
70 | assertThat(state("user-firefox-33").size(), equalTo(1));
71 | sleep(1000);
72 | helper.invokeTimersFor(QueueWaitAvailableBrowsersChecker.class);
73 | await().atMost(2, SECONDS).until(() -> state("user-firefox-33").size(), equalTo(0));
74 | }
75 |
76 | private WaitAvailableBrowserState state(String key) {
77 | return repo.getActual(key);
78 | }
79 |
80 | private Version version(String number) {
81 | final Version version = new Version();
82 | version.setNumber(number);
83 | return version;
84 | }
85 | }
--------------------------------------------------------------------------------
/service/src/main/java/ru/qatools/selenograph/gridrouter/ApiResource.java:
--------------------------------------------------------------------------------
1 | package ru.qatools.selenograph.gridrouter;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import ru.qatools.gridrouter.config.HostSelectionStrategy;
5 | import ru.qatools.selenograph.ext.SelenographDB;
6 | import ru.yandex.qatools.camelot.api.AggregatorRepository;
7 | import ru.yandex.qatools.camelot.api.annotations.Repository;
8 |
9 | import javax.ws.rs.GET;
10 | import javax.ws.rs.Path;
11 | import javax.ws.rs.PathParam;
12 | import javax.ws.rs.Produces;
13 | import java.io.IOException;
14 | import java.text.SimpleDateFormat;
15 | import java.util.Date;
16 | import java.util.List;
17 | import java.util.Map;
18 |
19 | import static java.util.Collections.emptyMap;
20 | import static java.util.stream.Collectors.toList;
21 | import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
22 | import static ru.yandex.qatools.camelot.util.MapUtil.map;
23 |
24 | /**
25 | * @author Innokenty Shuvalov innokenty@yandex-team.ru
26 | */
27 | @Path("/selenograph")
28 | public class ApiResource {
29 |
30 | private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MMM,dd HH:mm:ss.SSS");
31 |
32 | @Repository(QueueWaitAvailableBrowsersChecker.class)
33 | AggregatorRepository queueRepo;
34 |
35 | @Autowired
36 | SelenographDB database;
37 |
38 | @Autowired
39 | @SuppressWarnings("SpringJavaAutowiredMembersInspection")
40 | private HostSelectionStrategy strategy;
41 |
42 | @GET
43 | @Path("/strategy")
44 | @Produces({APPLICATION_JSON})
45 | public StrategyData getStrategy() throws IOException {
46 | return new StrategyData(strategy);
47 | }
48 |
49 | @GET
50 | @Path("/queues")
51 | @Produces({APPLICATION_JSON})
52 | public List