Skip to content

Commit

Permalink
fix: failing segmentor tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Abhi591 authored and rohitesh-wingify committed Jul 18, 2024
1 parent 3466108 commit 8f5614d
Show file tree
Hide file tree
Showing 27 changed files with 3,936 additions and 38 deletions.
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

[1.1.0] - 2024-06-07
[1.2.0] - 2024-06-17

### Fixed
Send event properties as third param in trackEvent() call
- Fixed segmentation evaluator issues where `contains` and `Greater than equal to` operator were not working as expected.
- Added unit test cases for the segmentation evaluator and decision maker

`[1.1.0] - 2024-06-07

### Fixed
Send event properties as third param in trackEvent() call`

[1.0.0] - 2024-05-31

Expand Down
11 changes: 3 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ limitations under the License. -->

<groupId>com.vwo.sdk</groupId>
<artifactId>vwo-fme-java-sdk</artifactId>
<version>1.1.0</version>
<version>1.2.1</version>
<packaging>jar</packaging>

<name>VWO FME Java SDK</name>
Expand Down Expand Up @@ -305,12 +305,12 @@ limitations under the License. -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.13.2</version>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.2.2</version>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
Expand All @@ -335,11 +335,6 @@ limitations under the License. -->
<artifactId>gson</artifactId>
<version>2.8.9</version> <!-- Make sure to use the latest version -->
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
<dependency>
<groupId>com.github.eprst</groupId>
<artifactId>murmur3</artifactId>
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/vwo/VWOClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ public Map<String, Boolean> trackEvent(String eventName, VWOContext context) {
* @param attributeValue - The value of the attribute to set.
* @param context User context
*/
public void setAttribute(String attributeKey, String attributeValue, VWOContext context) {
public void setAttribute(String attributeKey, Object attributeValue, VWOContext context) {
String apiName = "setAttribute";
try {
LoggerService.log(LogLevelEnum.DEBUG, "API_CALLED", new HashMap<String, String>() {{
Expand All @@ -218,14 +218,14 @@ public void setAttribute(String attributeKey, String attributeValue, VWOContext
throw new IllegalArgumentException("TypeError: attributeKey should be a string");
}

if (!DataTypeUtil.isString(attributeValue)) {
if (!DataTypeUtil.isString(attributeValue) && !DataTypeUtil.isNumber(attributeValue) && !DataTypeUtil.isBoolean(attributeValue)) {
LoggerService.log(LogLevelEnum.ERROR, "API_INVALID_PARAM", new HashMap<String, String>() {{
put("apiName", apiName);
put("key", "eventName");
put("type", DataTypeUtil.getType(attributeValue));
put("correctType", "String");
put("correctType", "String, Number, Boolean");
}});
throw new IllegalArgumentException("TypeError: attributeValue should be a string");
throw new IllegalArgumentException("TypeError: attributeValue should be a string, number or boolean");
}

if (context == null || context.getId() == null || context.getId().isEmpty()) {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/vwo/api/SetAttributeAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class SetAttributeAPI {
* @param attributeValue The value of the attribute to set.
* @param context The user context model containing user-specific data.
*/
public static void setAttribute(Settings settings, String attributeKey, String attributeValue, VWOContext context) {
public static void setAttribute(Settings settings, String attributeKey, Object attributeValue, VWOContext context) {
createAndSendImpressionForSetAttribute(settings, attributeKey, attributeValue, context);
}

Expand All @@ -49,7 +49,7 @@ public static void setAttribute(Settings settings, String attributeKey, String a
private static void createAndSendImpressionForSetAttribute(
Settings settings,
String attributeKey,
String attributeValue,
Object attributeValue,
VWOContext context
) {
// Get base properties for the event
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ public ResponseModel GET(RequestModel requestModel){
String contentType = connection.getHeaderField("Content-Type");

if (statusCode != 200 || !contentType.contains("application/json")) {
String error = "Invalid response. Status Code: " + statusCode + ", Response : " + connection.getResponseMessage();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
String error = "Invalid response " + in.readLine()+ ", Status Code: " + statusCode + ", Response : " + connection.getResponseMessage();
responseModel.setError(new Exception(error));
return responseModel;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ public void setContextualData(Settings settings, Feature feature, VWOContext con
this.evaluator.settings = settings;
this.evaluator.feature = feature;

// if user agent and ipAddress both are null or empty, return
if ((context.getUserAgent() == null || context.getUserAgent().isEmpty()) && (context.getIpAddress() == null || context.getIpAddress().isEmpty())) {
return;
}

// If gateway service is required and the base URL is not the default one, fetch the data from the gateway service
if (feature.getIsGatewayServiceRequired() && !UrlService.getBaseUrl().contains(Constants.HOST_NAME) && (context.getVwo() == null)) {
Map<String, String> queryParams = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ public enum SegmentOperandRegexEnum {
REGEX_MATCH("^regex\\((.*)\\)"),
STARTING_STAR("^\\*"),
ENDING_STAR("\\*$"),
GREATER_THAN_MATCH("^gt((\\d+\\.?\\d*)|(\\.\\d+))"),
GREATER_THAN_EQUAL_TO_MATCH("^gte((\\d+\\.?\\d*)|(\\.\\d+))"),
LESS_THAN_MATCH("^lt((\\d+\\.?\\d*)|(\\.\\d+))"),
LESS_THAN_EQUAL_TO_MATCH("^lte((\\d+\\.?\\d*)|(\\.\\d+))");
GREATER_THAN_MATCH("^gt\\((\\d+\\.?\\d*|\\.\\d+)\\)"),
GREATER_THAN_EQUAL_TO_MATCH("^gte\\((\\d+\\.?\\d*|\\.\\d+)\\)"),
LESS_THAN_MATCH("^lt\\((\\d+\\.?\\d*|\\.\\d+)\\)"),
LESS_THAN_EQUAL_TO_MATCH("^lte\\((\\d+\\.?\\d*|\\.\\d+)\\)");

private final String regex;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public boolean some(JsonNode dslNodes, Map<String, Object> customVariables) {
String featureIdKey = featureIdKeys.next();
String featureIdValue = featureIdObject.get(featureIdKey).asText();

if (featureIdValue.equals("on")) {
if (featureIdValue.equals("on") || featureIdValue.equals("off")) {
List<Feature> features = settings.getFeatures();
Feature feature = features.stream()
.filter(f -> f.getId() == Integer.parseInt(featureIdKey))
Expand All @@ -128,6 +128,9 @@ public boolean some(JsonNode dslNodes, Map<String, Object> customVariables) {
if (feature != null) {
String featureKey = feature.getKey();
boolean result = checkInUserStorage(settings, featureKey, context);
if (featureIdValue.equals("off")) {
return !result;
}
return result;
} else {
LoggerService.log(LogLevelEnum.DEBUG, "Feature not found with featureIdKey: " + featureIdKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.vwo.packages.segmentation_evaluator.evaluators;

import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -71,11 +72,23 @@ public Boolean evaluateCustomVariableDSL(JsonNode dslOperandValue, Map<String, O
} else {
// Process other types of operands
Object tagValue = properties.get(operandKey);
if (tagValue == null) {
tagValue = "";
}
tagValue = preProcessTagValue(tagValue.toString());
Map<String, Object> preProcessOperandValue = preProcessOperandValue(operandValue);
Map<String, Object> processedValues = processValues(preProcessOperandValue.get("operandValue"), tagValue);
tagValue = processedValues.get("tagValue");

// Convert numeric values to strings if processing wildcard pattern
SegmentOperandValueEnum operandType = (SegmentOperandValueEnum) preProcessOperandValue.get("operandType");
if (operandType == SegmentOperandValueEnum.STARTING_ENDING_STAR_VALUE ||
operandType == SegmentOperandValueEnum.STARTING_STAR_VALUE ||
operandType == SegmentOperandValueEnum.ENDING_STAR_VALUE ||
operandType == SegmentOperandValueEnum.REGEX_VALUE) {
processedValues.put("tagValue", processedValues.get("tagValue").toString());
}

tagValue = processedValues.get("tagValue");
return extractResult(operandType, processedValues.get("operandValue").toString().trim().replace("\"", ""), tagValue.toString());
}
}
Expand Down Expand Up @@ -162,23 +175,38 @@ public String preProcessTagValue(String tagValue) {
}

private Map<String, Object> processValues(Object operandValue, Object tagValue) {
// Convert operand and tag values to floats
Double processedOperandValue;
Double processedTagValue;
Map<String, Object> result = new HashMap<>();

// Process operandValue
result.put("operandValue", convertValue(operandValue));

// Process tagValue
result.put("tagValue", convertValue(tagValue));

return result;
}

private String convertValue(Object value) {
// Check if the value is a boolean
if (value instanceof Boolean) {
return value.toString(); // Convert boolean to "true" or "false"
}

try {
processedOperandValue = Double.parseDouble(operandValue.toString());
processedTagValue = Double.parseDouble(tagValue.toString());
// Attempt to convert to a numeric value
double numericValue = Double.parseDouble(value.toString());
// Check if the numeric value is actually an integer
if (numericValue == (int) numericValue) {
return String.valueOf((int) numericValue); // Remove '.0' by converting to int
} else {
// Format float to avoid scientific notation for large numbers
DecimalFormat df = new DecimalFormat("#.##############"); // Adjust the pattern as needed
return df.format(numericValue);
}
} catch (NumberFormatException e) {
// Return original values if conversion fails
result.put("operandValue", operandValue);
result.put("tagValue", tagValue);
return result;
// Return the value as-is if it's not a number
return value.toString();
}
// Convert numeric values back to strings
result.put("operandValue", processedOperandValue.toString());
result.put("tagValue", processedTagValue.toString());
return result;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ public static boolean checkValuePresent(Map<String, List<String>> expectedMap, M
for (String key : actualMap.keySet()) {
if (expectedMap.containsKey(key)) {
List<String> expectedValues = expectedMap.get(key);
// convert expectedValues to lowercase
expectedValues.replaceAll(String::toLowerCase);
String actualValue = actualMap.get(key);

// Handle wildcard patterns for all keys
for (String val : expectedValues) {
if (val.startsWith("wildcard(") && val.endsWith(")")) {
String wildcardPattern = val.substring(9, val.length() - 1); // Extract pattern from wildcard string
Pattern regex = Pattern.compile(wildcardPattern.replace("*", ".*")); // Convert wildcard pattern to regex
Pattern regex = Pattern.compile(wildcardPattern.replace("*", ".*"), Pattern.CASE_INSENSITIVE); // Convert wildcard pattern to regex
Matcher matcher = regex.matcher(actualValue);
if (matcher.matches()) {
return true; // Match found, return true
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/vwo/utils/NetworkUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ private static void addCustomEventProperties(EventArchPayload properties, Map<St
* @param attributeValue The value of the attribute.
* @return
*/
public static Map<String, Object> getAttributePayloadData(Settings settings, String userId, String eventName, String attributeKey, String attributeValue) {
public static Map<String, Object> getAttributePayloadData(Settings settings, String userId, String eventName, String attributeKey, Object attributeValue) {
EventArchPayload properties = getEventBasePayload(settings, userId, eventName, null, null);
properties.getD().getEvent().getProps().setIsCustomEvent(true);
properties.getD().getVisitor().getProps().put(attributeKey, attributeValue);
Expand Down
Empty file.
83 changes: 83 additions & 0 deletions src/test/java/unit/packages/decision_maker/DecisionMakerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* Copyright 2024 Wingify Software Pvt. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package unit.packages.decision_maker;

import com.vwo.packages.decision_maker.DecisionMaker;
import org.junit.jupiter.api.*;

import static org.junit.jupiter.api.Assertions.assertEquals;

import static org.mockito.Mockito.*;
public class DecisionMakerTest {

private DecisionMaker decisionMaker;

@BeforeEach
public void setUp() {
decisionMaker = new DecisionMaker();
}

@Test
public void testGenerateBucketValue() {
long hashValue = 2147483647; // Example hash value
int maxValue = 100;
int multiplier = 1;
int expectedBucketValue = (int) Math.floor((maxValue * ((double) hashValue / Math.pow(2, 32)) + 1) * multiplier);
int bucketValue = decisionMaker.generateBucketValue(hashValue, maxValue, multiplier);
assertEquals(expectedBucketValue, bucketValue);
}

@Test
public void testGetBucketValueForUser() {
String userId = "user123";
int maxValue = 100;
long mockHashValue = 123456789; // Mocked hash value

DecisionMaker spyDecisionMaker = spy(decisionMaker);
when(spyDecisionMaker.generateHashValue(userId)).thenReturn(mockHashValue);

int expectedBucketValue = spyDecisionMaker.generateBucketValue(mockHashValue, maxValue);
int bucketValue = spyDecisionMaker.getBucketValueForUser(userId, maxValue);

assertEquals(expectedBucketValue, bucketValue);
}

@Test
public void testCalculateBucketValue() {
String str = "testString";
int multiplier = 1;
int maxValue = 10000;
long mockHashValue = 987654321; // Mocked hash value

DecisionMaker spyDecisionMaker = spy(decisionMaker);
when(spyDecisionMaker.generateHashValue(str)).thenReturn(mockHashValue);

int expectedBucketValue = spyDecisionMaker.generateBucketValue(mockHashValue, maxValue, multiplier);
int bucketValue = spyDecisionMaker.calculateBucketValue(str, multiplier, maxValue);

assertEquals(expectedBucketValue, bucketValue);
}

@Test
public void testGenerateHashValue() {
String hashKey = "key123";
long expectedHashValue = 2360047679L; // Expected hash value (this should be determined by actual hash function behavior)

// Assuming you have a way to determine the expected hash value
long hashValue = decisionMaker.generateHashValue(hashKey);
assertEquals(expectedHashValue, hashValue);
}
}
Loading

0 comments on commit 8f5614d

Please sign in to comment.