Skip to content

Commit 3386c0a

Browse files
authored
⚡️ Fixes #194
With this fix, there is now a "tech-lab-ingester-priorized-technologies" configuration flag, that allow the associated technologies to always be computed first. This is required because we already have some published reports * Renamed finder method and created the component that will allow us to do the effective search * Changed method to use the working one * Adding a not-to-slow test checking that we have, indeed, extracted the priorized technologies first * Things seems to work quite correctly * OH BOY THAT'S SO SATISFYING! * Pretty sure tests should work in CI with that * It's in fact quite hard to test correctly * Let's try this way * Let's try a two-steps init
1 parent 79508a9 commit 3386c0a

File tree

11 files changed

+325
-38
lines changed

11 files changed

+325
-38
lines changed

pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<surefire-plugin.version>3.5.0</surefire-plugin.version>
2525
<!-- Jacoco auto-increasing tests configuration -->
2626
<jacoco.version>0.8.12</jacoco.version>
27-
<jacoco.covered.instructions.target.percentage>0.06</jacoco.covered.instructions.target.percentage>
27+
<jacoco.covered.instructions.target.percentage>0.08</jacoco.covered.instructions.target.percentage>
2828
</properties>
2929
<dependencyManagement>
3030
<dependencies>
@@ -217,6 +217,11 @@
217217
<artifactId>quarkus-junit5</artifactId>
218218
<scope>test</scope>
219219
</dependency>
220+
<dependency>
221+
<groupId>io.quarkus</groupId>
222+
<artifactId>quarkus-junit5-component</artifactId>
223+
<scope>test</scope>
224+
</dependency>
220225
<dependency>
221226
<groupId>io.quarkus</groupId>
222227
<artifactId>quarkus-junit5-mockito</artifactId>

src/main/java/com/zenika/tech/lab/ingester/ProcessIndicatorComputations.java

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public void configure() throws Exception {
5353
.id(FETCH_ALL_INDICATOR_COMPUTATIONS_ROUTE_ID)
5454
.log("🔍 Searching for indicator computations")
5555
// I think it will be necessary to have some kind of batch processing
56-
.process(this::findAllOldestFirst)
56+
.process(this::findAllPriorized)
5757
.log("✅ Found ${body.size} technologies")
5858
.split(body())
5959
.parallelProcessing()
@@ -81,20 +81,20 @@ public void configure() throws Exception {
8181
.endChoice()
8282
.end();
8383
}
84-
public void findAllOldestFirst(Exchange exchange) {
85-
exchange.getMessage().setBody(indicators.findAllOldestFirst());
84+
public void findAllPriorized(Exchange exchange) {
85+
exchange.getMessage().setBody(indicators.findAllPriorized());
8686
}
8787
public boolean canComputeIndicator(Exchange exchange) {
88-
IndicatorComputation indicator = exchange.getMessage().getBody(IndicatorComputation.class);
89-
IndicatorComputer computer = indicatorComputerRoutes.get(indicator.id.indicatorRoute);
90-
if(computer==null) {
91-
Log.errorf("🛑 Indicator computation %s routes to missing indicator computer %s. It won't be computed AT ALL",
92-
indicator,
93-
indicator.id.indicatorRoute);
94-
} else {
95-
return computer.canCompute(indicator.id.technology);
96-
}
97-
return false;
88+
// IndicatorComputation indicator = exchange.getMessage().getBody(IndicatorComputation.class);
89+
// IndicatorComputer computer = indicatorComputerRoutes.get(indicator.id.indicatorRoute);
90+
// if(computer==null) {
91+
// Log.errorf("🛑 Indicator computation %s routes to missing indicator computer %s. It won't be computed AT ALL",
92+
// indicator,
93+
// indicator.id.indicatorRoute);
94+
// } else {
95+
// return computer.canCompute(indicator.id.technology);
96+
// }
97+
return true;
9898
}
9999

100100
public void convertToTechnology(Exchange exchange) {
@@ -106,7 +106,11 @@ public void convertToTechnology(Exchange exchange) {
106106
}
107107
public void convertBackToIndicatorComputation(Exchange exchange, boolean updateDate) {
108108
IndicatorComputation indicatorComputation = exchange.getMessage().getHeader("indicatorComputation", IndicatorComputation.class);
109-
indicators.markIndicator(indicatorComputation, IndicatorComputation.IndicatorComputationStatus.HOLD, updateDate);
110-
exchange.getMessage().setBody(indicatorComputation);
109+
if(indicatorComputation!=null) {
110+
indicators.markIndicator(indicatorComputation, IndicatorComputation.IndicatorComputationStatus.HOLD, updateDate);
111+
exchange.getMessage().setBody(indicatorComputation);
112+
} else {
113+
exchange.setRouteStop(true);
114+
}
111115
}
112116
}

src/main/java/com/zenika/tech/lab/ingester/model/IndicatorComputation.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,22 @@ public String toString() {
8686
return String.format("IndicatorComputation [status=%s, id=%s, date=%s]", status, id, date);
8787
}
8888

89+
@Override
90+
public int hashCode() {
91+
return Objects.hash(id);
92+
}
93+
94+
@Override
95+
public boolean equals(Object obj) {
96+
if (this == obj)
97+
return true;
98+
if (obj == null)
99+
return false;
100+
if (getClass() != obj.getClass())
101+
return false;
102+
IndicatorComputation other = (IndicatorComputation) obj;
103+
return Objects.equals(id, other.id);
104+
}
105+
106+
89107
}

src/main/java/com/zenika/tech/lab/ingester/model/IndicatorComputationRepository.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
11
package com.zenika.tech.lab.ingester.model;
22

3+
import java.util.List;
34
import java.util.Map;
45
import java.util.SortedSet;
6+
import java.util.stream.Collectors;
57

8+
import org.eclipse.microprofile.config.inject.ConfigProperty;
9+
10+
import com.zenika.tech.lab.ingester.Configuration;
611
import com.zenika.tech.lab.ingester.model.export.ComputedIndicators.IndicatorDataPoint;
712

813
import io.quarkus.hibernate.orm.panache.PanacheRepository;
914
import jakarta.enterprise.context.ApplicationScoped;
15+
import jakarta.inject.Inject;
16+
import jakarta.inject.Named;
17+
import jakarta.persistence.EntityManager;
18+
import jakarta.persistence.Query;
1019
import jakarta.transaction.Transactional;
1120

1221
@ApplicationScoped
1322
public class IndicatorComputationRepository implements PanacheRepository<IndicatorComputation>{
23+
@ConfigProperty(name = Configuration.CONFIGURATION_PREFIX + "indicators.computations.findAllPriorized.sql")
24+
public String findAllPriorized;
25+
@Inject EntityManager entityManager;
26+
private List<Long> priorizedIds;
1427
@Transactional
1528
public IndicatorComputation findOrCreateFromTechnology(Technology body, String indicatorRoute) {
1629
IndicatorComputation returned = null;
@@ -26,4 +39,20 @@ public IndicatorComputation findOrCreateFromTechnology(Technology body, String i
2639
persist(returned);
2740
return returned;
2841
}
42+
43+
@Inject public void buildPriorizedIds(List<Technology> priorized) {
44+
priorizedIds = priorized.stream()
45+
.map(t -> t.id)
46+
.collect(Collectors.toList());
47+
}
48+
49+
public Iterable<IndicatorComputation> findAllPriorized() {
50+
Query query = entityManager.createNativeQuery(findAllPriorized, IndicatorComputation.class);
51+
query.setParameter("priorized", getPriorizedIds());
52+
return query.getResultList();
53+
}
54+
55+
List<Long> getPriorizedIds() {
56+
return priorizedIds;
57+
}
2958
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.zenika.tech.lab.ingester.model;
2+
3+
import java.util.List;
4+
import java.util.Optional;
5+
import java.util.stream.Collectors;
6+
7+
import org.eclipse.microprofile.config.inject.ConfigProperty;
8+
9+
import com.zenika.tech.lab.ingester.Configuration;
10+
11+
import io.smallrye.common.annotation.Identifier;
12+
import jakarta.enterprise.context.ApplicationScoped;
13+
import jakarta.enterprise.inject.Produces;
14+
import jakarta.inject.Named;
15+
import jakarta.transaction.Transactional;
16+
import io.quarkus.logging.Log;
17+
import io.quarkus.panache.common.Parameters;
18+
19+
@ApplicationScoped
20+
public class PriorizedTechnologiesProducer {
21+
@Produces
22+
@Transactional
23+
@Named("priorized")
24+
List<Technology> buildPriorizedTechnologiesList(
25+
@ConfigProperty(name=Configuration.CONFIGURATION_PREFIX + "priorized-technologies") List<String> priorized,
26+
TechnologyRepository technologies) {
27+
// In a very, VERY, strange fashion, config is not obtained from injection,
28+
// but from that damn old ServiceProvider thingie
29+
return priorized.stream()
30+
.map(technologyIdentifier -> loadTechnology(technologyIdentifier, technologies))
31+
.flatMap(Optional::stream)
32+
.collect(Collectors.toList());
33+
}
34+
35+
private Optional<Technology> loadTechnology(String value, TechnologyRepository technologies) {
36+
String[] parts = value.split(":");
37+
if(parts.length!=2) {
38+
Log.errorf("configuration property tech-lab-ingester.priorized-technologies contains the invalid value \"\"", value);
39+
return Optional.empty();
40+
} else {
41+
return loadTechnology(parts[0], parts[1], technologies);
42+
}
43+
44+
}
45+
46+
private Optional<Technology> loadTechnology(String platform, String name, TechnologyRepository technologies) {
47+
return technologies.find("platform=:p and name=:n",
48+
Parameters.with("p", platform).and("n", name)
49+
).firstResultOptional();
50+
}
51+
}

src/main/java/com/zenika/tech/lab/ingester/model/Technology.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public class Technology extends PanacheEntityBase {
5252
public String packageManagerUrl;
5353
@AvroDoc("source code repository url")
5454
public String repositoryUrl;
55-
@AvroDoc("Distyribution platform for the technology. It doesn't implies a specific language is used.")
55+
@AvroDoc("Distribution platform for the technology. It doesn't implies a specific language is used.")
5656
public String platform;
5757

5858
public Technology() {}

src/main/java/com/zenika/tech/lab/ingester/processors/IndicatorComputationProcessor.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,39 @@
33
import java.util.Date;
44
import java.util.List;
55

6-
import org.apache.camel.Exchange;
6+
import org.eclipse.microprofile.config.inject.ConfigProperty;
77

8+
import com.zenika.tech.lab.ingester.Configuration;
89
import com.zenika.tech.lab.ingester.model.IndicatorComputation;
10+
import com.zenika.tech.lab.ingester.model.IndicatorComputation.IndicatorComputationStatus;
911
import com.zenika.tech.lab.ingester.model.IndicatorComputationRepository;
1012
import com.zenika.tech.lab.ingester.model.Technology;
11-
import com.zenika.tech.lab.ingester.model.IndicatorComputation.IndicatorComputationStatus;
12-
import com.zenika.tech.lab.ingester.model.export.ComputedIndicators;
1313

1414
import io.quarkus.panache.common.Sort;
1515
import io.quarkus.panache.common.Sort.Direction;
1616
import jakarta.enterprise.context.Dependent;
1717
import jakarta.inject.Inject;
18+
import jakarta.inject.Named;
19+
import jakarta.persistence.Query;
1820
import jakarta.transaction.Transactional;
1921

2022
@Dependent
2123
public class IndicatorComputationProcessor {
2224
@Inject IndicatorComputationRepository indicators;
2325

24-
2526
public void generateIndicatorComputationFor(Technology technology, String r) {
2627
indicators.findOrCreateFromTechnology(technology, r);
2728
}
2829

30+
/**
31+
* Find all indicator computations sorted by priority.
32+
* This priority first takes in account the fact that technology is in
33+
* the priorized technologies list, then sort by indicator computation date
34+
* @return
35+
*/
2936
@Transactional
30-
public Iterable<IndicatorComputation> findAllOldestFirst() {
31-
List<IndicatorComputation> returned = indicators.findAll(
32-
// This ensure we first finish currently computing indicators prior to computing new ones
33-
Sort.by("status", Direction.Descending)
34-
.and("date", Direction.Ascending)
35-
.and("id", Direction.Ascending)).list();
36-
return returned;
37+
public Iterable<IndicatorComputation> findAllPriorized() {
38+
return indicators.findAllPriorized();
3739
}
3840

3941
@Transactional

src/main/resources/application.yaml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@
33
export:
44
INDICATOR:
55
csv:
6+
enabled: true
67
to:
78
gcp:
8-
enabled: false
9+
enabled: true
910
TECHNOLOGY:
1011
csv:
12+
enabled: true
1113
to:
1214
gcp:
13-
enabled: false
15+
enabled: true
1416
projects:
1517
per:
1618
page: 10
@@ -88,6 +90,9 @@ quarkus:
8890
Content-Type: application/json; charset=utf-8
8991
url: https://api.github.com/graphql
9092
tech-lab-ingester:
93+
# Values in this key should be in the form "platform:name"
94+
priorized-technologies:
95+
- NPM:react
9196
export:
9297
INDICATOR_COMPUTATION:
9398
csv:
@@ -104,6 +109,16 @@ tech-lab-ingester:
104109
enabled: false
105110

106111
indicators:
112+
computations:
113+
findAllPriorized:
114+
sql: |
115+
select *
116+
from indicator_computation ic
117+
order by
118+
ic.technology_id in :priorized desc,
119+
ic.status desc,
120+
ic.indicator_date asc,
121+
ic.technology_id asc;
107122
github:
108123
stars:
109124
graphql:

src/test/java/com/zenika/tech/lab/ingester/ProcessIndicatorComputationsTest.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,20 @@
99
import org.apache.camel.quarkus.test.CamelQuarkusTestSupport;
1010
import org.assertj.core.api.Assertions;
1111
import org.assertj.core.api.InstanceOfAssertFactories;
12+
import org.junit.jupiter.api.BeforeAll;
1213
import org.junit.jupiter.api.Test;
14+
import org.mockito.Mockito;
1315

1416
import com.zenika.tech.lab.ingester.model.IndicatorComputation;
1517
import com.zenika.tech.lab.ingester.model.IndicatorComputation.IndicatorComputationStatus;
1618
import com.zenika.tech.lab.ingester.model.IndicatorComputationBuilder;
19+
import com.zenika.tech.lab.ingester.model.IndicatorComputationRepository;
1720
import com.zenika.tech.lab.ingester.model.Technology;
1821
import com.zenika.tech.lab.ingester.model.TechnologyBuilder;
22+
import com.zenika.tech.lab.ingester.model.TechnologyRepository;
1923

24+
import io.quarkus.hibernate.orm.panache.PanacheQuery;
25+
import io.quarkus.test.junit.QuarkusMock;
2026
import io.quarkus.test.junit.QuarkusTest;
2127
import jakarta.inject.Inject;
2228

@@ -25,19 +31,33 @@ class ProcessIndicatorComputationsTest extends CamelQuarkusTestSupport {
2531

2632
@Inject ProducerTemplate producerTemplate;
2733
@Inject ConsumerTemplate consumerTemplate;
34+
@Inject IndicatorComputationRepository indicatorsToMock;
2835

36+
static Technology TESTED_TECHNOLOGY = TechnologyBuilder.technology()
37+
.build();
38+
static String INDICATOR_ROUTE = "log:done with that fake indicator route";
39+
static IndicatorComputation indicatorComputation = IndicatorComputationBuilder
40+
.indicatorComputation()
41+
.technology(TESTED_TECHNOLOGY)
42+
.indicatorRoute(INDICATOR_ROUTE)
43+
.build();
44+
45+
@BeforeAll
46+
public static void setup() {
47+
IndicatorComputationRepository mockingIndicators = Mockito.mock(IndicatorComputationRepository.class);
48+
PanacheQuery mockedQuery = Mockito.mock(PanacheQuery.class);
49+
Mockito.when(mockedQuery.firstResult()).thenReturn(indicatorComputation);
50+
Mockito
51+
.when(mockingIndicators.find(Mockito.anyString(),
52+
Mockito.<Object[]>any() ))
53+
.thenReturn(mockedQuery);
54+
QuarkusMock.installMockForType(mockingIndicators, IndicatorComputationRepository.class);
55+
}
2956

3057
@Test
3158
void testRoutingToCorrectComputer() throws Exception {
3259
// Given
33-
Technology TESTED_TECHNOLOGY = TechnologyBuilder.technology()
34-
.build();
35-
String INDICATOR_ROUTE = "NO INDICATOR ROUTE CONFIFURED";
36-
IndicatorComputation indicatorComputation = IndicatorComputationBuilder
37-
.indicatorComputation()
38-
.technology(TESTED_TECHNOLOGY)
39-
.indicatorRoute(INDICATOR_ROUTE)
40-
.build();
60+
4161
// Replace standard call (which would get data from database)
4262
// by our call (which get only one indicator computation)
4363
AdviceWith.adviceWith(context, ProcessIndicatorComputations.FETCH_ALL_INDICATOR_COMPUTATIONS_ROUTE_ID, a -> {

0 commit comments

Comments
 (0)