diff --git a/force-app/main/algorithms/classes/ClusterCentroidDataAssignmentStep.cls b/force-app/main/algorithms/classes/ClusterCentroidDataAssignmentStep.cls index ef681b7..9cc72d7 100644 --- a/force-app/main/algorithms/classes/ClusterCentroidDataAssignmentStep.cls +++ b/force-app/main/algorithms/classes/ClusterCentroidDataAssignmentStep.cls @@ -84,15 +84,20 @@ public with sharing class ClusterCentroidDataAssignmentStep extends ClusterBatch //Calculating min distance to centroids Integer nearestCentroidIndex = 0; Integer previousCentroidIndex = 0; - Double minDistance = this.runner.calculateDistance(currentDataPoint.values, centroids[nearestCentroidIndex].values); - centroidDistances[0] = minDistance; - for (Integer cindex = 1; cindex < centroidSize; cindex++) { - Double distance = this.runner.calculateDistance(currentDataPoint.values, centroids[cindex].values); + Double minDistance = ClusterDataHelper.DOUBLE_MAX_VALUE; + Double prevMinDistance = ClusterDataHelper.DOUBLE_MAX_VALUE; + for (Integer cindex = 0; cindex < centroidSize; cindex++) { + Double distance = Math.abs(this.runner.calculateDistance(currentDataPoint.values, centroids[cindex].values)); centroidDistances[cindex] = distance; - if (Math.abs(distance) < Math.abs(minDistance)) { + if (distance < minDistance) { + previousCentroidIndex = nearestCentroidIndex; + prevMinDistance = minDistance; minDistance = distance; nearestCentroidIndex = cindex; - previousCentroidIndex = nearestCentroidIndex; + } + else if (distance < prevMinDistance) { + prevMinDistance = distance; + previousCentroidIndex = cindex; } } //We found closest and second closest centroids to the current data point diff --git a/force-app/main/algorithms/classes/ClusterKMeansJobState.cls b/force-app/main/algorithms/classes/ClusterKMeansJobState.cls index 8223721..1f17706 100644 --- a/force-app/main/algorithms/classes/ClusterKMeansJobState.cls +++ b/force-app/main/algorithms/classes/ClusterKMeansJobState.cls @@ -12,12 +12,16 @@ public with sharing class ClusterKMeansJobState extends ClusterJobState { public Boolean hasSwapped; public List<Id> sampleResultsIds; public Integer iterationsCount; + private Boolean hasNearestCentroidsCache; + private Boolean hasNearestCentroidsCalculated; public ClusterKMeansJobState() { this.centroids = new List<ClusterDataPoint>(); this.hasAssignmentChanged = false; this.hasSwapped = false; this.iterationsCount = 0; + this.hasNearestCentroidsCache = false; + this.hasNearestCentroidsCalculated = false; } public override void loadFromMap(Map<String, Object> stateValues) { @@ -73,6 +77,10 @@ public with sharing class ClusterKMeansJobState extends ClusterJobState { } public boolean hasNearestCentroids() { + if (this.hasNearestCentroidsCalculated) { + return this.hasNearestCentroidsCache; + } + this.hasNearestCentroidsCalculated = true; if (this.nearestCentroids != null) { Boolean hasNC = true; for (Integer nnIndex:this.nearestCentroids) { @@ -81,9 +89,11 @@ public with sharing class ClusterKMeansJobState extends ClusterJobState { break; } } + this.hasNearestCentroidsCache = hasNC; return hasNC; } - return false; + this.hasNearestCentroidsCache = false; + return this.hasNearestCentroidsCache; } } \ No newline at end of file diff --git a/force-app/main/algorithms/classes/ClusterKNNPredictor.cls b/force-app/main/algorithms/classes/ClusterKNNPredictor.cls index 8ffe6f6..f396b91 100644 --- a/force-app/main/algorithms/classes/ClusterKNNPredictor.cls +++ b/force-app/main/algorithms/classes/ClusterKNNPredictor.cls @@ -72,7 +72,6 @@ public with sharing class ClusterKNNPredictor { for (ClusterPredictionResult.FieldPrediction prediction:predictionResult.fieldPredictions) { prediction.aggregateValues(nearestNeighbors.size()); } - log.debug(JSON.serialize(clusterPrediction)); predictionResult.clusterIndex = Integer.valueOf(clusterPrediction.fieldValuePredictions[0].value); return predictionResult; } @@ -83,14 +82,14 @@ public with sharing class ClusterKNNPredictor { Id jobId = state.clusterJob.Id; ClusterAccessCheck.checkCRUDPermission(Schema.SObjectType.ClusterJobNeighbor__c); ClusterAccessCheck.checkCRUDPermission(Schema.SObjectType.ClusterJobResult__c); - List<ClusterNeighbor> clusterNeighbors = this.runner.findNearestClusters(recordId, ClusterConstants.NUM_NEAREST_CLUSTERS); + ClusterDataPoint dataPoint = this.runner.getDataPoint(recordId); + List<ClusterNeighbor> clusterNeighbors = this.runner.findNearestClusters(dataPoint, ClusterConstants.NUM_NEAREST_CLUSTERS); List<Integer> nearestClusters = new List<Integer>(); for (ClusterNeighbor cn:clusterNeighbors) { nearestClusters.add(cn.clusterIndex); } log.debug('Retrieved ' + nearestClusters.size() + ' nearest clusters'); //We will retrieve MAX_NEIGHBORS neighbors and then return first numNeighbors - ClusterDataPoint dataPoint = this.runner.getDataPoint(recordId); List<ClusterDataPointNeighbor> neighbors = this.findNearestNeighbors(dataPoint, nearestClusters, ClusterConstants.MAX_NEIGHBORS); List<ClusterJobNeighbor__c> neighborRecords = new List<ClusterJobNeighbor__c>(); for (ClusterDataPointNeighbor neighbor:neighbors) { @@ -167,7 +166,7 @@ public with sharing class ClusterKNNPredictor { if (dataPoint.clusterIndex == nearestClusters[i]) { currentCentroidDistance = distance; } - Integer nextClusterIndex = jobState.getNextClusterIndex(i); + Integer nextClusterIndex = jobState.getNextClusterIndex(nearestClusters[i]); Double nextClusterDistance = this.runner.calculateDPDistance(dataPoint, jobState.centroids[nextClusterIndex]); nearestDataPoints.addAll(this.getRandomDataPoints(ClusterConstants.MIN_KNN_DP_COUNT, nearestClusters[i], distance, nextClusterDistance, jobState)); } @@ -242,29 +241,35 @@ public with sharing class ClusterKNNPredictor { } public ClusterDataPoint[] getRandomDataPoints(Integer count, Integer clusterIndex, Double distanceToCenter, Double distanceToNextCluster, ClusterJobState jobState) { - log.debug('Retrieving nearest random data points in cluster ' + clusterIndex); + log.debug('Retrieving nearest random data points in cluster ' + clusterIndex + ', distanceToCenter: ' + distanceToCenter + ', distanceToNextCluster: ' + distanceToNextCluster); ClusterAccessCheck.checkReadPermission(Schema.SObjectType.ClusterJobResult__c); List<ClusterJobResult__c> jobResults = null; if (distanceToCenter != null) { - Double[] distanceTolerances = new Double[6]; - distanceTolerances[0] = distanceToCenter * 0.0001; //0.001% - distanceTolerances[1] = distanceToCenter * 0.001; //0.01% - distanceTolerances[2] = distanceToCenter * 0.01; //1% - distanceTolerances[3] = distanceToCenter * 0.05; //5% - distanceTolerances[4] = distanceToCenter * 0.1; //10% - distanceTolerances[5] = distanceToCenter * 0.25; //25% + Double[] distanceTolerances = new Double[10]; + distanceTolerances[0] = 0.001; //0.1% + distanceTolerances[1] = 0.002; //0.2% + distanceTolerances[2] = 0.004; //0.2% + distanceTolerances[3] = 0.008; //0.2% + distanceTolerances[4] = 0.01; //1% + distanceTolerances[5] = 0.02; //1% + distanceTolerances[6] = 0.04; //1% + distanceTolerances[7] = 0.05; //5% + distanceTolerances[8] = 0.1; //10% + distanceTolerances[9] = 0.25; //25% for (Integer i=0; i<distanceTolerances.size(); i++) { - Decimal distanceMin = Decimal.valueOf(distanceToCenter - distanceTolerances[i]); - Decimal distanceMax = Decimal.valueOf(distanceToCenter + distanceTolerances[i]); - Decimal nextDistanceMax = Decimal.valueOf(distanceToNextCluster + distanceTolerances[i]); + Decimal distanceMin = Decimal.valueOf(distanceToCenter - distanceToCenter * distanceTolerances[i]); + Decimal distanceMax = Decimal.valueOf(distanceToCenter + distanceToCenter * distanceTolerances[i]); + Decimal nextDistanceMin = Decimal.valueOf(distanceToNextCluster - distanceToCenter * distanceTolerances[i]); + Decimal nextDistanceMax = Decimal.valueOf(distanceToNextCluster + distanceToCenter * distanceTolerances[i]); //We are trying to retrieve results with similar distanceToCenter value to reduce KNN calculations //Here we are looking for an intersection of the current and nearest clusters jobResults = [SELECT Id, Cluster__c, Json__c, Json2__c, Json3__c, Json4__c, Json5__c, RecordId__c, RecordName__c, ClusterNumber__c, ClusterJob__c, DistanceToCluster__c, DistanceToNNCluster__c FROM ClusterJobResult__c WHERE ClusterJob__c = :jobState.clusterJob.Id AND ClusterNumber__c = :clusterIndex - AND (DistanceToCluster__c >= :distanceMin AND DistanceToCluster__c<= :distanceMax AND DistanceToNNCluster__c<=:nextDistanceMax) - ORDER BY Random__c LIMIT :count]; + AND (DistanceToCluster__c >= :distanceMin AND DistanceToCluster__c<= :distanceMax AND DistanceToNNCluster__c<=:nextDistanceMax AND DistanceToNNCluster__c>=:nextDistanceMin) + ORDER BY DistanceToCluster__c DESC LIMIT :count]; if (jobResults.size() > ClusterConstants.MIN_KNN_NEIGHBOR_SIZE) { log.debug('Retrieved ' + jobResults.size() + ' nearest data points with tolerance ' + distanceTolerances[i]); + log.debug('distanceMin: ' + distanceMin + ', distanceMax: ' + distanceMax + ', nextDistanceMax: ' + nextDistanceMax); break; } } diff --git a/force-app/main/algorithms/classes/ClusterPAMDataAssignmentStep.cls b/force-app/main/algorithms/classes/ClusterPAMDataAssignmentStep.cls index b68360c..a875614 100644 --- a/force-app/main/algorithms/classes/ClusterPAMDataAssignmentStep.cls +++ b/force-app/main/algorithms/classes/ClusterPAMDataAssignmentStep.cls @@ -43,22 +43,30 @@ public with sharing class ClusterPAMDataAssignmentStep extends ClusterIterableBa ClusterDataPoint currentRecord = dataPoints[sindex]; //ClusterDataHelper.normalizeObject(currentObject, jobState); //Calculating min distance to centroids - Integer nearestCentroidIndex = 0; + Integer nearestCentroidIndex = -1; + Integer prevNearestCentroidIndex = -1; Boolean isCentroid = false; Integer centroidIndex; - Double minDistance = this.runner.calculateDPDistance(currentRecord, centroids[nearestCentroidIndex]); - for (Integer cindex = 1; cindex < centroidSize; cindex++) { + Double minDistance = ClusterDataHelper.DOUBLE_MAX_VALUE; + Double prevMinDistance = ClusterDataHelper.DOUBLE_MAX_VALUE; + for (Integer cindex = 0; cindex < centroidSize; cindex++) { Boolean isCurrentCentroid = centroids[cindex].recordId == currentRecord.recordId; isCentroid = isCentroid || isCurrentCentroid; if (isCurrentCentroid) { currentRecord.clusterIndex = null; centroidIndex = cindex; } - Double distance = this.runner.calculateDPDistance(currentRecord, centroids[cindex]); - if (Math.abs(distance) < Math.abs(minDistance)) { + Double distance = Math.abs(this.runner.calculateDPDistance(currentRecord, centroids[cindex])); + if (distance < minDistance) { + prevMinDistance = minDistance; + prevNearestCentroidIndex = nearestCentroidIndex; minDistance = distance; nearestCentroidIndex = cindex; } + else if (distance < prevMinDistance) { + prevMinDistance = distance; + prevNearestCentroidIndex = cindex; + } } if (!isCentroid) { //Reassigning to another cluster if needed @@ -72,7 +80,7 @@ public with sharing class ClusterPAMDataAssignmentStep extends ClusterIterableBa } else { //If current dp is a centroid store the nearest centroid - jobState.nearestCentroids[centroidIndex] = nearestCentroidIndex; + jobState.nearestCentroids[centroidIndex] = prevNearestCentroidIndex; } } //Aggregating cost for each centroid/medoid diff --git a/force-app/main/api/classes/ClusterApi.cls b/force-app/main/api/classes/ClusterApi.cls index e3d303e..4c1a7d4 100644 --- a/force-app/main/api/classes/ClusterApi.cls +++ b/force-app/main/api/classes/ClusterApi.cls @@ -98,5 +98,16 @@ global with sharing class ClusterApi { return this.runner.getDataPoint(externalRecordId); } + /** + * Converts an SObject to a data point + * @param record + * SObject record to convert + * @returns ClusterDataPoint object with converted data + */ + global ClusterDataPoint convertToDataPoint(SObject record) { + this.checkRunnerInitialized(); + ClusterSObjectProcessor objectProcessor = this.runner.getSObjectProcessor(); + return objectProcessor.processSObject(record); + } } diff --git a/force-app/main/default/aura/ClusterResultDetailsView/ClusterResultDetailsView.cmp b/force-app/main/default/aura/ClusterResultDetailsView/ClusterResultDetailsView.cmp index 676608e..367f85f 100644 --- a/force-app/main/default/aura/ClusterResultDetailsView/ClusterResultDetailsView.cmp +++ b/force-app/main/default/aura/ClusterResultDetailsView/ClusterResultDetailsView.cmp @@ -1,7 +1,8 @@ <aura:component implements="force:hasRecordId,lightning:actionOverride" controller="ClusterJobDetailsController" extends="c:ClusterUiBaseComponent" access="global"> <aura:attribute name="jobResultDetails" type="Object" access="public" /> - <aura:handler name="init" value="{!this}" action="{!c.onInit}" /> + <ltng:require scripts="{!join(',', + $Resource.clustanUtils + '/clustanUtils.js')}" afterScriptsLoaded="{!c.onInit}" /> <lightning:notificationsLibrary aura:id="notifLib" /> <div class="c-container slds-scope slds-container slds-panel"> diff --git a/force-app/main/default/aura/ClusterResultDetailsView/ClusterResultDetailsViewHelper.js b/force-app/main/default/aura/ClusterResultDetailsView/ClusterResultDetailsViewHelper.js index 2f299b9..f439bde 100644 --- a/force-app/main/default/aura/ClusterResultDetailsView/ClusterResultDetailsViewHelper.js +++ b/force-app/main/default/aura/ClusterResultDetailsView/ClusterResultDetailsViewHelper.js @@ -8,6 +8,8 @@ if (uiModel.jobStateString && uiModel.jobStateString !== '') { uiModel.jobState = JSON.parse(uiModel.jobStateString); } + clustanUtils.decompressJobState(uiModel.jobState); + clustanUtils.decompressDataPointValues(uiModel.jobState, uiModel.dataPoint.values); component.set("v.jobResultDetails", uiModel); let dpDetails = component.find('dataPointDetails'); dpDetails.set('v.dataPoint', uiModel.dataPoint); diff --git a/force-app/main/default/classes/ClusterConstants.cls b/force-app/main/default/classes/ClusterConstants.cls index cefda05..3dddb83 100644 --- a/force-app/main/default/classes/ClusterConstants.cls +++ b/force-app/main/default/classes/ClusterConstants.cls @@ -180,4 +180,10 @@ public with sharing class ClusterConstants { return (String[])JSON.deserialize(getLongTextSettingValue('DefaultClusterColors','[]'), String[].class); } + public static Boolean getStorePredictions() { + Integer storePredictions = getIntegerSettingValue('StorePredictedDataPoints', 0); + return storePredictions == 1; + + } + } \ No newline at end of file diff --git a/force-app/main/default/classes/ClusterPredictController.cls b/force-app/main/default/classes/ClusterPredictController.cls index a086a63..34b6b96 100644 --- a/force-app/main/default/classes/ClusterPredictController.cls +++ b/force-app/main/default/classes/ClusterPredictController.cls @@ -24,7 +24,7 @@ public with sharing class ClusterPredictController { ClusterAccessCheck.checkReadPermission(Schema.SObjectType.ClusterModel__c); ClusterAccessCheck.checkReadPermission(Schema.SObjectType.ClusterJob__c); uiModel.models = new List<ClusterModelWrapper>(); - if (objectDescribe.getSObjectType() == ClusterModel__c.getSObjectType()) { + if (objectDescribe.getKeyPrefix() == ClusterModel__c.getSObjectType().getDescribe().getKeyPrefix()) { ClusterModelWrapper model = ClusterModelBuilderController.loadModel(recordId); uiModel.models.add(model); uiModel.jobId = getLastCompletedJobId(model.modelId); @@ -33,7 +33,7 @@ public with sharing class ClusterPredictController { } uiModel.recordIdNeeded = true; } - else if (objectDescribe.getSObjectType() == ClusterJob__c.getSObjectType()) { + else if (objectDescribe.getKeyPrefix() == ClusterJob__c.getSObjectType().getDescribe().getKeyPrefix()) { List<ClusterJob__c> jobs = [SELECT Id,ClusterModel__c FROM ClusterJob__c WHERE Id = :recordId AND JobStatus__c = :ClusterConstants.JOBSTATUS_COMPLETED WITH SECURITY_ENFORCED ORDER BY CreatedDate DESC LIMIT 1]; if (jobs.size() == 1) { @@ -86,10 +86,10 @@ public with sharing class ClusterPredictController { ClusterAccessCheck.checkReadPermission(Schema.SObjectType.ClusterModel__c); ClusterAccessCheck.checkReadPermission(Schema.SObjectType.ClusterJob__c); ClusterModelWrapper model; - if (objectDescribe.getSObjectType() == ClusterModel__c.getSObjectType()) { + if (objectDescribe.getKeyPrefix() == ClusterModel__c.getSObjectType().getDescribe().getKeyPrefix()) { model = ClusterModelBuilderController.loadModel(jobOrModelId); } - else if (objectDescribe.getSObjectType() == ClusterJob__c.getSObjectType()) { + else if (objectDescribe.getKeyPrefix() == ClusterJob__c.getSObjectType().getDescribe().getKeyPrefix()) { List<ClusterJob__c> jobs = [SELECT Id,ClusterModel__c FROM ClusterJob__c WHERE Id = :jobOrModelId AND JobStatus__c = :ClusterConstants.JOBSTATUS_COMPLETED WITH SECURITY_ENFORCED ORDER BY CreatedDate DESC LIMIT 1]; if (jobs.size() == 1) { @@ -285,7 +285,7 @@ public with sharing class ClusterPredictController { log.debug('Starting k nearest neighbor calculations for record id: ' + recordId); ClusterAccessCheck.checkCRUDPermission(Schema.SObjectType.ClusterJobNeighbor__c); ClusterAlgorithmRunner runner = ClusterAlgorithmFactory.getRunnerFromJobId(jobId); - List<ClusterDataPointNeighbor> neighbors = runner.getPredictor().findNearestNeighbors(recordId, numNeighbors, true); + List<ClusterDataPointNeighbor> neighbors = runner.getPredictor().findNearestNeighbors(recordId, numNeighbors, ClusterConstants.getStorePredictions()); return neighbors; } catch (Exception ex) { diff --git a/force-app/main/default/customMetadata/ClusterSetting.StorePredictedDataPoints.md-meta.xml b/force-app/main/default/customMetadata/ClusterSetting.StorePredictedDataPoints.md-meta.xml new file mode 100644 index 0000000..85d78b9 --- /dev/null +++ b/force-app/main/default/customMetadata/ClusterSetting.StorePredictedDataPoints.md-meta.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <label>Store Predicted Data Points</label> + <protected>false</protected> + <values> + <field>Description__c</field> + <value xsi:type="xsd:string">If 0 new records will not be included into predictions</value> + </values> + <values> + <field>LongTextValue__c</field> + <value xsi:nil="true"/> + </values> + <values> + <field>Value__c</field> + <value xsi:type="xsd:string">0</value> + </values> +</CustomMetadata> diff --git a/force-app/main/test/classes/ClusterApiTest.cls b/force-app/main/test/classes/ClusterApiTest.cls index d685769..8c03f57 100644 --- a/force-app/main/test/classes/ClusterApiTest.cls +++ b/force-app/main/test/classes/ClusterApiTest.cls @@ -11,7 +11,7 @@ public with sharing class ClusterApiTest { User clusterUser = ClusterTestData.createClusterUser(); System.runAs(clusterUser) { Test.startTest(); - List<Lead> leads = [SELECT Id, Name FROM Lead LIMIT 10]; + List<Lead> leads = [SELECT Id, Name, AnnualRevenue, NumberOfEmployees FROM Lead LIMIT 10]; List<ClusterJob__c> jobs = [SELECT Id FROM ClusterJob__c LIMIT 1]; Id jobId = jobs[0].Id; Id recordId = leads[0].Id; @@ -23,6 +23,8 @@ public with sharing class ClusterApiTest { System.assertEquals(true, predictionResult.getClusterIndex() >= 0, 'Incorrect prediction cluster index'); ClusterDataPoint dataPoint = api.getDataPoint(recordId); System.assertEquals(recordId, dataPoint.getExternalId(), 'Incorrect data point id'); + ClusterDataPoint dataPoint2 = api.convertToDataPoint(leads[0]); + System.assertEquals(dataPoint.getRecordName(), dataPoint2.getRecordName(), 'Incorrect data point name'); Double distance = api.calculateDistance(dataPoint.getValues(), dataPoint.getValues()); System.assertEquals(true, ClusterDataHelper.doublesEqual(distance, ClusterDataHelper.DOUBLE_ZERO), 'Incorrect distance'); Test.stopTest(); @@ -35,7 +37,7 @@ public with sharing class ClusterApiTest { User clusterUser = ClusterTestData.createClusterUser(); System.runAs(clusterUser) { Test.startTest(); - List<Lead> leads = [SELECT Id, Name FROM Lead LIMIT 11]; + List<Lead> leads = [SELECT Id, Name, AnnualRevenue, NumberOfEmployees FROM Lead LIMIT 11]; List<ClusterJob__c> jobs = [SELECT Id FROM ClusterJob__c LIMIT 1]; Id jobId = jobs[0].Id; Id recordId = leads[0].Id; diff --git a/force-app/main/test/classes/ClusterKMedoidsPAMRunnerTest.cls b/force-app/main/test/classes/ClusterKMedoidsPAMRunnerTest.cls index 45e0bd0..3739d09 100644 --- a/force-app/main/test/classes/ClusterKMedoidsPAMRunnerTest.cls +++ b/force-app/main/test/classes/ClusterKMedoidsPAMRunnerTest.cls @@ -236,8 +236,14 @@ public with sharing class ClusterKMedoidsPAMRunnerTest { pdaStep.execute(null, dataPoints); pdaStep.finish(null); - //TODO: this asserm might fail if two centroids are top 2 items. Probability is somewhat low - System.assertEquals(true, (state.centroids[0].cost > 0) || (state.centroids[1].cost > 0), 'Centroid cost calculated incorrectly'); + Double centroidCost = 0.0; + for (Integer i = 0; i<state.centroids.size(); i++){ + if (state.centroids[i].cost > 0) { + centroidCost += state.centroids[i].cost; + } + } + + System.assertEquals(true, (centroidCost > 0.0), 'Centroid cost calculated incorrectly'); Boolean isCentroidFirst = false; for (ClusterDataPoint centroid:state.centroids){ if (state.dataPoints[0].recordId == centroid.recordId) { @@ -247,6 +253,7 @@ public with sharing class ClusterKMedoidsPAMRunnerTest { } System.assertEquals(true, state.dataPoints[0].clusterIndex >=0 || isCentroidFirst, 'Assignment to cluster is incorrect'); System.assertEquals(3, state.currentAlgorithmStep, 'Incorrect next step after PAM data assignment'); + System.assertEquals(true, state.hasNearestCentroids(), 'Nearest centroids calculated incorrectly'); Integer currentStep = state.currentAlgorithmStep; ClusterPAMSwapStep swapStep = (ClusterPAMSwapStep)runner.steps[state.currentAlgorithmStep]; @@ -257,8 +264,8 @@ public with sharing class ClusterKMedoidsPAMRunnerTest { swapStep.init(runner); swapStep.execute(null, swapScope); swapStep.finish(null); - System.assertEquals(true, state.hasSwapped, 'There was no centroid swap'); - System.assertEquals(currentStep - 1, state.currentAlgorithmStep, 'Incorrect next step if there is swap'); + //We are not testing if the centroid swap actually hapenned, because long text model has only 10 items + System.assertEquals(state.hasSwapped ? currentStep - 1 : currentStep + 1, state.currentAlgorithmStep, 'Incorrect next step if there is swap'); state.hasSwapped = false; state.currentAlgorithmStep = currentStep; //Setting current step back to swap step diff --git a/sfdx-project.json b/sfdx-project.json index f9cd25b..f73f49e 100644 --- a/sfdx-project.json +++ b/sfdx-project.json @@ -6,10 +6,10 @@ { "path": "force-app", "package": "Cluster Analysis", - "versionName": "v2.0", - "versionNumber": "2.0.0.NEXT", + "versionName": "v2.1", + "versionNumber": "2.1.0.NEXT", "postInstallScript": "ClusterPostInstallHandler", - "ancestorId": "04t3h000003eBAjAAM", + "ancestorId": "04t3h000004m75dAAA", "default": true } ], @@ -25,6 +25,8 @@ "Cluster Analysis@1.5.0-1": "04t3h000003e0yfAAA", "Cluster Analysis@1.5.0-2": "04t3h000003eBAjAAM", "Cluster Analysis@2.0.0-1": "04t3h000004m75YAAQ", - "Cluster Analysis@2.0.0-2": "04t3h000004m75dAAA" + "Cluster Analysis@2.0.0-2": "04t3h000004m75dAAA", + "Cluster Analysis@2.1.0-1": "04t3h000004m7BmAAI", + "Cluster Analysis@2.1.0-2": "04t3h000004m7C1AAI" } } \ No newline at end of file