Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
TousAntiCovid sources
Cléa Server
Commits
3ef9dc5c
Commit
3ef9dc5c
authored
Apr 20, 2021
by
Figue Orange
Browse files
add venueType wildcard and no duplicates validators + refactor selection algo (tests not ok)
parent
7770258e
Changes
11
Hide whitespace changes
Inline
Side-by-side
clea-batch/src/main/resources/application.yaml
View file @
3ef9dc5c
...
...
@@ -30,7 +30,7 @@ clea:
-
'
1,1,1,3,1,3.0,2.0'
-
'
*,*,*,3,1,3.0,2.0'
-
'
3,*,*,3,1,3.0,2.0'
-
'
*,*,*
,1,1,3.0,2.0'
-
'
2,1,1
,1,1,3.0,2.0'
batch
:
duration-unit-in-seconds
:
3600
cluster
:
...
...
clea-scoring-conf/src/main/java/fr/gouv/clea/clea/scoring/configuration/ScoringConfiguration.java
View file @
3ef9dc5c
...
...
@@ -8,54 +8,81 @@ import java.util.stream.Collectors;
@Slf4j
public
abstract
class
ScoringConfiguration
{
abstract
public
List
<?
extends
ScoringConfigurationItem
>
getScorings
();
public
abstract
List
<?
extends
ScoringConfigurationItem
>
getScorings
();
public
ScoringConfigurationItem
getConfigurationFor
(
int
venueType
,
int
venueCategory1
,
int
venueCategory2
)
{
log
.
debug
(
"Fetching rules candidates for venueType : {}, venueCategory1 : {}, venuCategory2: {}"
,
venueType
,
venueCategory1
,
venueCategory2
);
log
.
info
(
"Fetching rules candidates for venueType : {}, venueCategory1 : {}, venuCategory2: {}"
,
venueType
,
venueCategory1
,
venueCategory2
);
List
<
ScoringConfigurationItem
>
compatibleRules
=
this
.
getScorings
().
stream
()
.
filter
(
scoring
->
scoring
.
isCompatibleWith
(
venueType
,
venueCategory1
,
venueCategory2
))
.
collect
(
Collectors
.
toList
());
log
.
debug
(
"Found {} compatibles rules"
,
compatibleRules
.
size
());
ScoringConfigurationItem
selectedRule
=
null
;
log
.
info
(
"Found {} compatibles rules"
,
compatibleRules
.
size
());
//Only one match found
if
(
compatibleRules
.
size
()
==
1
)
{
log
.
info
(
"Found suitable rule {}"
,
compatibleRules
.
get
(
0
));
return
compatibleRules
.
get
(
0
);
}
//All are wildcarded, then rule to apply is the default one
if
(
allAreWilcarded
(
venueType
,
venueCategory1
,
venueCategory2
))
{
getConfigurationFor
(
ScoringConfigurationItem
.
wildcardValue
,
ScoringConfigurationItem
.
wildcardValue
,
ScoringConfigurationItem
.
wildcardValue
);
}
ScoringConfigurationItem
bestRuleCandidate
=
compatibleRules
.
get
(
0
);
for
(
ScoringConfigurationItem
rule
:
compatibleRules
)
{
if
(
rule
.
isFullMatch
())
{
log
.
info
(
"Found matching rule {}"
,
rule
);
selectedRule
=
rule
;
break
;
}
else
if
(
rule
.
getVenueType
()
!=
ScoringConfigurationItem
.
wildcardValue
&&
(
rule
.
getVenueCategory1
()
==
ScoringConfigurationItem
.
wildcardValue
||
rule
.
getVenueCategory2
()
==
ScoringConfigurationItem
.
wildcardValue
)
)
{
if
(
rule
.
getVenueCategory1
()
!=
ScoringConfigurationItem
.
wildcardValue
)
{
log
.
info
(
"Found suitable rule {}"
,
rule
);
selectedRule
=
rule
;
break
;
}
}
else
if
(
rule
.
getVenueType
()
==
ScoringConfigurationItem
.
wildcardValue
&&
(
rule
.
getVenueCategory1
()
==
ScoringConfigurationItem
.
wildcardValue
||
rule
.
getVenueCategory2
()
==
ScoringConfigurationItem
.
wildcardValue
)
)
{
if
(
rule
.
getVenueCategory1
()
!=
ScoringConfigurationItem
.
wildcardValue
)
{
log
.
info
(
"Found suitable rule {}"
,
rule
);
selectedRule
=
rule
;
break
;
}
return
rule
;
}
else
if
(
bothCategoryAreWildcard
(
bestRuleCandidate
)
&&
firstCategoryIsNotWildcarded
(
rule
))
{
bestRuleCandidate
=
rule
;
}
else
if
(
eitherOneCategoryIsWildcard
(
bestRuleCandidate
)
&&
firstCategoryIsNotWildcarded
(
rule
))
{
bestRuleCandidate
=
rule
;
}
else
if
(
firstCategoryIsNotWildcarded
(
bestRuleCandidate
)
&&
secondCategoryIsNotWildcarded
(
bestRuleCandidate
))
{
return
bestRuleCandidate
;
}
}
log
.
info
(
"Retrieving best rule {}"
,
bestRuleCandidate
);
return
bestRuleCandidate
;
}
private
boolean
allAreWilcarded
(
int
venueType
,
int
venueCategory1
,
int
venueCategory2
)
{
int
count
=
0
;
if
(
venueType
==
ScoringConfigurationItem
.
wildcardValue
)
{
count
++;
}
if
(
venueCategory1
==
ScoringConfigurationItem
.
wildcardValue
)
{
count
++;
}
if
(
venueCategory2
==
ScoringConfigurationItem
.
wildcardValue
)
{
count
++;
}
return
count
==
3
;
}
return
selectedRule
;
private
boolean
eitherOneCategoryIsWildcard
(
ScoringConfigurationItem
rule
)
{
return
isWildcarded
(
rule
.
getVenueCategory1
())
||
isWildcarded
(
rule
.
getVenueCategory2
());
}
private
boolean
bothCategoryAreWildcard
(
ScoringConfigurationItem
rule
)
{
return
isWildcarded
(
rule
.
getVenueCategory1
())
&&
isWildcarded
(
rule
.
getVenueCategory2
());
}
private
boolean
isWildcarded
(
int
venueItem
)
{
return
venueItem
==
ScoringConfigurationItem
.
wildcardValue
;
}
private
boolean
firstCategoryIsNotWildcarded
(
ScoringConfigurationItem
rule
)
{
return
isWildcarded
(
rule
.
getVenueCategory1
());
}
private
boolean
secondCategoryIsNotWildcarded
(
ScoringConfigurationItem
rule
)
{
return
isWildcarded
(
rule
.
getVenueCategory2
());
}
}
clea-scoring-conf/src/main/java/fr/gouv/clea/clea/scoring/configuration/ScoringConfigurationItem.java
View file @
3ef9dc5c
package
fr.gouv.clea.clea.scoring.configuration
;
import
fr.gouv.clea.clea.scoring.configuration.validators.NoDuplicates
;
import
fr.gouv.clea.clea.scoring.configuration.validators.ValidateWildcards
;
import
lombok.AllArgsConstructor
;
import
lombok.Getter
;
import
lombok.ToString
;
import
lombok.experimental.SuperBuilder
;
import
javax.validation.Valid
;
import
javax.validation.constraints.Min
;
import
java.util.Objects
;
// @Valid
@SuperBuilder
@AllArgsConstructor
@ToString
@Getter
@Valid
@ValidateWildcards
@NoDuplicates
public
class
ScoringConfigurationItem
{
public
static
int
wildcardValue
=
-
1
;
@Min
(
value
=
-
1
)
private
int
venueType
;
@Min
(
value
=
-
1
)
private
int
venueCategory1
;
@Min
(
value
=
-
1
)
private
int
venueCategory2
;
/**
* @return the scoring configuration priority. The greater it is, the most priority it has.
* It allows to select a scoring configuration between many that are compatible for a
* tuple(venueType, venueCategory1, venueCategory2).
*/
public
int
getPriority
()
{
int
priority
=
100
;
if
(
venueType
==
wildcardValue
)
{
// venueType is the most important part for configuration selection
priority
-=
51
;
}
if
(
venueCategory1
==
wildcardValue
)
{
// venueCategory1 has priority over venueCategory2
priority
-=
25
;
}
if
(
venueCategory2
==
wildcardValue
)
{
priority
-=
20
;
}
return
priority
;
}
public
boolean
isCompatibleWith
(
int
venueType
,
int
venueCategory1
,
int
venueCategory2
)
{
return
this
.
hasVenueTypeCompatibleWith
(
venueType
)
&&
this
.
hasVenueCategory1CompatibleWith
(
venueCategory1
)
...
...
@@ -78,4 +68,16 @@ public class ScoringConfigurationItem {
return
this
.
getWildCardCount
()
==
0
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
return
true
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
ScoringConfigurationItem
that
=
(
ScoringConfigurationItem
)
o
;
return
getVenueType
()
==
that
.
getVenueType
()
&&
getVenueCategory1
()
==
that
.
getVenueCategory1
()
&&
getVenueCategory2
()
==
that
.
getVenueCategory2
();
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
getVenueType
(),
getVenueCategory1
(),
getVenueCategory2
());
}
}
clea-scoring-conf/src/main/java/fr/gouv/clea/clea/scoring/configuration/validators/NoDuplicates.java
0 → 100644
View file @
3ef9dc5c
package
fr.gouv.clea.clea.scoring.configuration.validators
;
import
javax.validation.Constraint
;
import
javax.validation.Payload
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
import
static
java
.
lang
.
annotation
.
ElementType
.
TYPE
;
@Constraint
(
validatedBy
=
{
NoDuplicatesValidator
.
class
})
@Target
({
TYPE
})
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
NoDuplicates
{
String
message
()
default
"Found at least one duplicate in scoring configuration"
;
Class
<?>[]
groups
()
default
{};
Class
<?
extends
Payload
>[]
payload
()
default
{};
}
clea-scoring-conf/src/main/java/fr/gouv/clea/clea/scoring/configuration/validators/NoDuplicatesValidator.java
0 → 100644
View file @
3ef9dc5c
package
fr.gouv.clea.clea.scoring.configuration.validators
;
import
fr.gouv.clea.clea.scoring.configuration.ScoringConfigurationItem
;
import
javax.validation.ConstraintValidator
;
import
javax.validation.ConstraintValidatorContext
;
import
java.util.ArrayList
;
import
java.util.List
;
public
class
NoDuplicatesValidator
implements
ConstraintValidator
<
NoDuplicates
,
Object
>
{
private
List
<
ScoringConfigurationItem
>
list
;
@Override
public
void
initialize
(
NoDuplicates
noDuplicates
)
{
this
.
list
=
new
ArrayList
<>();
}
@Override
public
boolean
isValid
(
Object
value
,
ConstraintValidatorContext
context
)
{
ScoringConfigurationItem
scoringConfigurationItem
=
(
ScoringConfigurationItem
)
value
;
if
(
list
.
contains
(
scoringConfigurationItem
))
{
return
false
;
}
else
{
list
.
add
(
scoringConfigurationItem
);
return
true
;
}
}
}
clea-scoring-conf/src/main/java/fr/gouv/clea/clea/scoring/configuration/validators/ValidateWildcards.java
0 → 100644
View file @
3ef9dc5c
package
fr.gouv.clea.clea.scoring.configuration.validators
;
import
javax.validation.Constraint
;
import
javax.validation.Payload
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
import
static
java
.
lang
.
annotation
.
ElementType
.
TYPE
;
@Constraint
(
validatedBy
=
{
VenueTypeValidator
.
class
})
@Target
({
TYPE
})
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
ValidateWildcards
{
String
message
()
default
"VenueType can not be wildcarded unless all fields are too"
;
Class
<?>[]
groups
()
default
{};
Class
<?
extends
Payload
>[]
payload
()
default
{};
}
clea-scoring-conf/src/main/java/fr/gouv/clea/clea/scoring/configuration/validators/VenueTypeValidator.java
0 → 100644
View file @
3ef9dc5c
package
fr.gouv.clea.clea.scoring.configuration.validators
;
import
fr.gouv.clea.clea.scoring.configuration.ScoringConfigurationItem
;
import
javax.validation.ConstraintValidator
;
import
javax.validation.ConstraintValidatorContext
;
public
class
VenueTypeValidator
implements
ConstraintValidator
<
ValidateWildcards
,
Object
>
{
@Override
public
boolean
isValid
(
Object
value
,
ConstraintValidatorContext
context
)
{
ScoringConfigurationItem
scoringConfigurationItem
=
(
ScoringConfigurationItem
)
value
;
if
(
allFieldsAreWildcards
(
scoringConfigurationItem
))
{
return
true
;
}
else
{
return
venueTypeIsNotWildcarded
(
scoringConfigurationItem
);
}
}
private
boolean
venueTypeIsNotWildcarded
(
ScoringConfigurationItem
scoringConfigurationItem
)
{
return
scoringConfigurationItem
.
getVenueType
()
!=
ScoringConfigurationItem
.
wildcardValue
||
(
scoringConfigurationItem
.
getVenueCategory1
()
!=
ScoringConfigurationItem
.
wildcardValue
&&
scoringConfigurationItem
.
getVenueCategory2
()
!=
ScoringConfigurationItem
.
wildcardValue
);
}
private
boolean
allFieldsAreWildcards
(
ScoringConfigurationItem
scoringConfigurationItem
)
{
return
scoringConfigurationItem
.
getVenueType
()
==
ScoringConfigurationItem
.
wildcardValue
&&
scoringConfigurationItem
.
getVenueCategory1
()
==
ScoringConfigurationItem
.
wildcardValue
&&
scoringConfigurationItem
.
getVenueCategory2
()
==
ScoringConfigurationItem
.
wildcardValue
;
}
}
clea-scoring-conf/src/test/java/fr/gouv/clea/clea/scoring/configuration/ExposureTimeConfigurationTest.java
View file @
3ef9dc5c
...
...
@@ -26,7 +26,7 @@ class ExposureTimeConfigurationTest {
@Test
void
testExposureTimeConfigurationHasExpectedSize
()
{
assertThat
(
configuration
.
getScorings
()).
hasSize
(
6
);
assertThat
(
configuration
.
getScorings
()).
hasSize
(
4
);
}
@Test
...
...
clea-scoring-conf/src/test/java/fr/gouv/clea/clea/scoring/configuration/RiskConfigurationTest.java
View file @
3ef9dc5c
...
...
@@ -26,12 +26,12 @@ public class RiskConfigurationTest {
@Test
void
testRiskConfigurationHasExpectedSize
()
{
assertThat
(
configuration
.
getScorings
()).
hasSize
(
6
);
assertThat
(
configuration
.
getScorings
()).
hasSize
(
7
);
}
@Test
void
testExposureTimeConfigurationHasExpectedData
()
{
RiskRule
scoring
=
(
RiskRule
)
configuration
.
getScorings
().
get
(
5
);
RiskRule
scoring
=
(
RiskRule
)
configuration
.
getScorings
().
get
(
3
);
assertThat
(
scoring
.
getVenueType
()).
isEqualTo
(
3
);
assertThat
(
scoring
.
getVenueCategory1
()).
isEqualTo
(
ScoringConfigurationItem
.
wildcardValue
);
...
...
clea-scoring-conf/src/test/java/fr/gouv/clea/clea/scoring/configuration/ScoringConfigurationItemTest.java
View file @
3ef9dc5c
...
...
@@ -4,6 +4,7 @@ import fr.gouv.clea.clea.scoring.configuration.exposure.ExposureTimeConfiguratio
import
fr.gouv.clea.clea.scoring.configuration.exposure.ExposureTimeConfigurationConverter
;
import
fr.gouv.clea.clea.scoring.configuration.risk.RiskConfiguration
;
import
fr.gouv.clea.clea.scoring.configuration.risk.RiskConfigurationConverter
;
import
lombok.extern.slf4j.Slf4j
;
import
org.junit.jupiter.api.Test
;
import
org.junit.jupiter.api.extension.ExtendWith
;
import
org.springframework.beans.factory.annotation.Autowired
;
...
...
@@ -20,7 +21,8 @@ import static org.assertj.core.api.Assertions.assertThat;
@EnableConfigurationProperties
(
value
=
{
RiskConfiguration
.
class
,
ExposureTimeConfiguration
.
class
})
@ContextConfiguration
(
classes
=
{
RiskConfigurationConverter
.
class
,
ExposureTimeConfigurationConverter
.
class
})
@ActiveProfiles
(
"test"
)
public
class
ScoringConfigurationItemTest
{
@Slf4j
class
ScoringConfigurationItemTest
{
@Autowired
private
RiskConfiguration
riskConfiguration
;
...
...
@@ -29,18 +31,46 @@ public class ScoringConfigurationItemTest {
private
ExposureTimeConfiguration
exposureTimeConfiguration
;
@Test
void
should_return_the_most_specified_rule
()
{
void
should_return_the_full_wildcard_rule
()
{
assertThat
(
riskConfiguration
.
getConfigurationFor
(
2
,
1
,
1
))
.
isEqualTo
(
riskConfiguration
.
getScorings
().
get
(
0
));
}
@Test
void
should_return_rule_one_one_one
()
{
assertThat
(
riskConfiguration
.
getConfigurationFor
(
1
,
1
,
1
))
.
isEqualTo
(
riskConfiguration
.
getScorings
().
get
(
1
));
}
@Test
void
should_return_the_full_wildcard_rule
()
{
assertThat
(
riskConfiguration
.
getConfigurationFor
(
2
,
1
,
1
))
.
isEqualTo
(
riskConfiguration
.
getScorings
().
get
(
0
));
void
should_return_rule_one_two_three
()
{
assertThat
(
riskConfiguration
.
getConfigurationFor
(
1
,
2
,
3
))
.
isEqualTo
(
riskConfiguration
.
getScorings
().
get
(
2
));
}
@Test
void
should_return_the_rule_three_wildcard_wildcard
()
{
assertThat
(
riskConfiguration
.
getConfigurationFor
(
3
,
2
,
1
))
.
isEqualTo
(
riskConfiguration
.
getScorings
().
get
(
3
));
}
@Test
void
should_return_the_rule_three_one_wildcard
()
{
assertThat
(
riskConfiguration
.
getConfigurationFor
(
3
,
1
,
2
))
.
isEqualTo
(
riskConfiguration
.
getScorings
().
get
(
4
));
}
//TODO: add more tests according to rules set
@Test
void
should_return_the_rule_three_wildcard_two
()
{
assertThat
(
riskConfiguration
.
getConfigurationFor
(
3
,
2
,
2
))
.
isEqualTo
(
riskConfiguration
.
getScorings
().
get
(
5
));
}
@Test
void
should_return_the_rule_three_one_two
()
{
assertThat
(
riskConfiguration
.
getConfigurationFor
(
3
,
1
,
2
))
.
isEqualTo
(
riskConfiguration
.
getScorings
().
get
(
6
));
}
}
clea-scoring-conf/src/test/resources/application-test.yml
View file @
3ef9dc5c
...
...
@@ -4,12 +4,10 @@ clea:
enabled
:
"
true"
rules
:
# venueType, venueCat1, venueCat2, exposureTimeBackward, exposureTimeForward, exposureTimeStaffBackward, exposureTimeStaffForward
-
'
*,*,*,3,11,22,31'
-
'
1,1,1,3,13,23,33'
-
'
*,*,*,2,12,22,32'
-
'
3,*,*,1,11,21,31'
-
'
1,2,3,2,12,22,32'
-
'
*,2,*,2,12,22,32'
-
'
*,*,3,2,12,22,32'
risk
:
enabled
:
"
true"
rules
:
...
...
@@ -17,6 +15,7 @@ clea:
-
'
*,*,*,3,1,3.0,2.0'
-
'
1,1,1,3,1,3.0,2.0'
-
'
1,2,3,3,1,3.0,2.0'
-
'
*,2,*,3,1,3.0,2.0'
-
'
*,*,3,3,1,3.0,2.0'
-
'
3,*,*,3,1,3.0,2.0'
\ No newline at end of file
-
'
3,*,*,3,1,3.0,2.0'
-
'
3,1,*,3,1,3.0,2.0'
-
'
3,*,2,3,1,3.0,2.0'
-
'
3,1,2,3,1,3.0,2.0'
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment