From 9f31988371f42af4ec47680088b26a12d4ea7909 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Fri, 29 Aug 2025 14:29:15 +0000
Subject: [PATCH] [#545] add IT test

---
 opendj-server-legacy/src/test/java/org/opends/server/extensions/StaticGroupIT.java |   38 +++++++++++++++++++
 opendj-server-legacy/src/main/java/org/opends/server/extensions/StaticGroup.java   |    5 ++
 opendj-server-legacy/src/test/java/org/opends/server/extensions/TestUtils.java     |   30 +++++++++++++++
 3 files changed, 73 insertions(+), 0 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/StaticGroup.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/StaticGroup.java
index 58a6f6e..593033a 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/StaticGroup.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/StaticGroup.java
@@ -86,6 +86,11 @@
  */
 public class StaticGroup extends Group<StaticGroupImplementationCfg>
 {
+  // Геттеры для тестов
+  HashSet<CompactDn> getMemberDNs() { return memberDNs; }
+  LinkedList<DN> getNestedGroups() { return nestedGroups; }
+  DN getGroupEntryDN() { return groupEntryDN; }
+  AttributeType getMemberAttributeType() { return memberAttributeType; }
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
   /** The attribute type used to hold the membership list for this group. */
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/extensions/StaticGroupIT.java b/opendj-server-legacy/src/test/java/org/opends/server/extensions/StaticGroupIT.java
new file mode 100644
index 0000000..48112f1
--- /dev/null
+++ b/opendj-server-legacy/src/test/java/org/opends/server/extensions/StaticGroupIT.java
@@ -0,0 +1,38 @@
+package org.opends.server.extensions;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.AfterClass;
+import org.opends.server.types.Modification;
+import java.util.concurrent.*;
+import java.util.*;
+import static org.testng.Assert.*;
+
+public class StaticGroupIT {
+    private static final int THREAD_COUNT = 10;
+    private static final int TOTAL_REQUESTS = 100;
+
+    @Test
+    public void testConcurrentUpdateMembersNoDeadlock() throws Exception {
+        StaticGroup group = TestUtils.createNestedTestGroup();
+        List<Modification> modifications = TestUtils.createAddUserModifications();
+        ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
+        List<Future<?>> futures = new ArrayList<>();
+        for (int i = 0; i < TOTAL_REQUESTS; i++) {
+            futures.add(executor.submit(() -> {
+                try {
+                    group.updateMembers(modifications);
+                } catch (org.opends.server.types.DirectoryException e) {
+                    throw new RuntimeException(e);
+                }
+            }));
+        }
+        for (Future<?> f : futures) {
+            f.get(10, TimeUnit.SECONDS);
+        }
+        executor.shutdown();
+    assertTrue(executor.awaitTermination(30, TimeUnit.SECONDS));
+    // Проверяем, что группа содержит пользователя
+    assertTrue(group.isMember(TestUtils.TEST_USER_DN, null));
+    }
+}
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/extensions/TestUtils.java b/opendj-server-legacy/src/test/java/org/opends/server/extensions/TestUtils.java
new file mode 100644
index 0000000..f0403cb
--- /dev/null
+++ b/opendj-server-legacy/src/test/java/org/opends/server/extensions/TestUtils.java
@@ -0,0 +1,30 @@
+package org.opends.server.extensions;
+
+import java.util.*;
+import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.ModificationType;
+import org.opends.server.types.Modification;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.Attributes;
+
+public class TestUtils {
+    public static final DN TEST_USER_DN = DN.valueOf("cn=Test User,ou=Users,dc=com,dc=example");
+    public static final DN LEVEL1_DN = DN.valueOf("cn=Level1,ou=Groups,dc=com,dc=example");
+    public static final DN LEVEL2_DN = DN.valueOf("cn=Level2,ou=Groups,dc=com,dc=example");
+
+    public static StaticGroup createNestedTestGroup() {
+        // Минимальная реализация для теста
+        StaticGroup group = new StaticGroup();
+    group.getMemberDNs().clear();
+    group.getNestedGroups().clear();
+    // Устанавливаем значения через рефлексию, если нужно, либо через конструктор/методы
+    // Для теста достаточно очистить коллекции и использовать LEVEL2_DN
+        return group;
+    }
+
+    public static List<Modification> createAddUserModifications() {
+        Attribute attr = Attributes.create("member", TEST_USER_DN.toString());
+        Modification mod = new Modification(ModificationType.ADD, attr);
+        return Collections.singletonList(mod);
+    }
+}

--
Gitblit v1.10.0