Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NAE-1970] Verification of Visual ID Generation to Prevent Duplicate IDs #260

Open
wants to merge 1 commit into
base: release/6.4.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@
import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Document
public class Case implements Serializable {

private static final long serialVersionUID = 3687481049847498422L;

private static final AtomicInteger counter = new AtomicInteger(0);

@Id
@Getter
private ObjectId _id;
Expand All @@ -43,6 +46,7 @@ public class Case implements Serializable {
private LocalDateTime lastModified;

@Getter
@Indexed
private String visualId;

@NotNull
Expand Down Expand Up @@ -276,14 +280,18 @@ private void populateDataSetBehaviorAndComponents() {

private String generateVisualId() {
SecureRandom random = new SecureRandom();
int n = _id.getTimestamp() + random.nextInt(99999999);
if (this.title != null) {
n += title.length();
}
long n = _id.getTimestamp();
int count = counter.incrementAndGet();
int k = random.nextInt(99999);
String timestamp = String.format("%011d", n);
String counterString = String.format("%03d", count);
String suffix = String.format("%04d", k);
String finalId = timestamp + counterString + suffix;

if (this.petriNet != null) {
return petriNet.getInitials() + "-" + n;
return petriNet.getInitials() + "-" + finalId;
}
return n + "";
return finalId;
}

public Object getFieldValue(String fieldId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package com.netgrif.application.engine.workflow.service;


import com.netgrif.application.engine.petrinet.domain.PetriNet;
import com.netgrif.application.engine.petrinet.domain.VersionType;
import com.netgrif.application.engine.petrinet.domain.repositories.PetriNetRepository;
import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService;
import com.netgrif.application.engine.startup.SuperCreator;
import com.netgrif.application.engine.startup.SystemUserRunner;
import com.netgrif.application.engine.startup.UriRunner;
import com.netgrif.application.engine.workflow.domain.Case;
import com.netgrif.application.engine.workflow.domain.repositories.TaskRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import java.io.FileInputStream;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

@SpringBootTest
@ActiveProfiles({"test"})
@ExtendWith(SpringExtension.class)
public class VisualIdTest {

@Autowired
private PetriNetRepository petriNetRepository;

@Autowired
private TaskRepository taskRepository;

@Autowired
private MongoTemplate mongoTemplate;

@Autowired
private SystemUserRunner userRunner;

@Autowired
private UriRunner uriRunner;

@Autowired
private IPetriNetService petriNetService;

@Autowired
private SuperCreator superCreator;

PetriNet net;

@BeforeEach
public void setUp() throws Exception {
mongoTemplate.getDb().drop();
taskRepository.deleteAll();
userRunner.run("");
uriRunner.run();

petriNetService.importPetriNet(new FileInputStream("src/test/resources/prikladFM.xml"), VersionType.MAJOR, superCreator.getLoggedSuper());
net = petriNetRepository.findAll().get(0);
assert net != null;
}

@Test
// @RepeatedTest(100)
public void testGenerateVisualIds() throws InterruptedException {
ConcurrentHashMap<String, Integer> ids = new ConcurrentHashMap<>();
ExecutorService executor = Executors.newFixedThreadPool(100);

long startTime = System.nanoTime();

IntStream.range(0, 1000000).forEach(i -> executor.submit(() -> {
Case caseInstance = new Case(net);
String visualId = caseInstance.getVisualId();
ids.put(visualId, ids.getOrDefault(visualId, 0) + 1);
}));

executor.shutdown();
executor.awaitTermination(1, TimeUnit.MINUTES);

long endTime = System.nanoTime();
long duration = TimeUnit.NANOSECONDS.toSeconds(endTime - startTime);

long duplicates = ids.values().stream().filter(count -> count > 1).count();
System.out.println("Total duplicates: " + duplicates);
System.out.println("Time: " + duration + " seconds");
assert duplicates == 0 : "There should be no duplicates";
}

}
Loading