@@ -2221,4 +2221,118 @@ private MemberEntity mockMemberEntity() {
22212221 private InputStream read (String resource ) throws IOException {
22222222 return this .getClass ().getResourceAsStream (resource );
22232223 }
2224+
2225+ @ Test
2226+ public void shouldSearchUsers_hasResults_ordersUniqueAndPopulateFlags () {
2227+ UserServiceImpl spyUserService = spy (userService );
2228+
2229+ // Search engine returns duplicated ids and one unknown id
2230+ List <String > docs = Arrays .asList ("u1" , "u2" , "u1" , "u3" , "u4" , "u3" );
2231+ io .gravitee .rest .api .service .impl .search .SearchResult searchResult = new io .gravitee .rest .api .service .impl .search .SearchResult (
2232+ docs ,
2233+ 42
2234+ );
2235+ when (searchEngineService .search (eq (EXECUTION_CONTEXT ), any ())).thenReturn (searchResult );
2236+
2237+ // Prepare fetched users (u4 is missing on purpose)
2238+ UserEntity ue1 = new UserEntity ();
2239+ ue1 .setId ("u1" );
2240+ UserEntity ue2 = new UserEntity ();
2241+ ue2 .setId ("u2" );
2242+ UserEntity ue3 = new UserEntity ();
2243+ ue3 .setId ("u3" );
2244+ doReturn (new HashSet <>(Arrays .asList (ue1 , ue2 , ue3 ))).when (spyUserService ).findByIds (eq (EXECUTION_CONTEXT ), anyCollection ());
2245+
2246+ // Mock roles for Primary Owner checks
2247+ RoleEntity apiPORole = mockRoleEntity (RoleScope .API , "PRIMARY_OWNER" );
2248+ RoleEntity appPORole = mockRoleEntity (RoleScope .APPLICATION , "PRIMARY_OWNER" );
2249+ when (roleService .findPrimaryOwnerRoleByOrganization (ORGANIZATION , RoleScope .API )).thenReturn (apiPORole );
2250+ when (roleService .findPrimaryOwnerRoleByOrganization (ORGANIZATION , RoleScope .APPLICATION )).thenReturn (appPORole );
2251+
2252+ // Only u2 is primary owner (API). Others not.
2253+ when (
2254+ membershipService .getMembershipsByMemberAndReferenceAndRole (
2255+ eq (MembershipMemberType .USER ),
2256+ eq ("u2" ),
2257+ eq (MembershipReferenceType .API ),
2258+ eq (apiPORole .getId ())
2259+ )
2260+ )
2261+ .thenReturn (
2262+ java .util .Collections .<io .gravitee .rest .api .model .MembershipEntity >singleton (
2263+ new io .gravitee .rest .api .model .MembershipEntity ()
2264+ )
2265+ );
2266+ when (
2267+ membershipService .getMembershipsByMemberAndReferenceAndRole (
2268+ eq (MembershipMemberType .USER ),
2269+ eq ("u1" ),
2270+ eq (MembershipReferenceType .API ),
2271+ eq (apiPORole .getId ())
2272+ )
2273+ )
2274+ .thenReturn (java .util .Collections .<io .gravitee .rest .api .model .MembershipEntity >emptySet ());
2275+ when (
2276+ membershipService .getMembershipsByMemberAndReferenceAndRole (
2277+ eq (MembershipMemberType .USER ),
2278+ eq ("u3" ),
2279+ eq (MembershipReferenceType .API ),
2280+ eq (apiPORole .getId ())
2281+ )
2282+ )
2283+ .thenReturn (java .util .Collections .<io .gravitee .rest .api .model .MembershipEntity >emptySet ());
2284+
2285+ // No application PO for anyone
2286+ when (
2287+ membershipService .getMembershipsByMemberAndReferenceAndRole (
2288+ eq (MembershipMemberType .USER ),
2289+ anyString (),
2290+ eq (MembershipReferenceType .APPLICATION ),
2291+ eq (appPORole .getId ())
2292+ )
2293+ )
2294+ .thenReturn (java .util .Collections .<io .gravitee .rest .api .model .MembershipEntity >emptySet ());
2295+
2296+ // Tokens per user: u1=1, u2=3, u3=0
2297+ when (tokenService .findByUser ("u1" )).thenReturn (Collections .singletonList (new io .gravitee .rest .api .model .TokenEntity ()));
2298+ when (tokenService .findByUser ("u2" ))
2299+ .thenReturn (
2300+ Arrays .asList (
2301+ new io .gravitee .rest .api .model .TokenEntity (),
2302+ new io .gravitee .rest .api .model .TokenEntity (),
2303+ new io .gravitee .rest .api .model .TokenEntity ()
2304+ )
2305+ );
2306+ when (tokenService .findByUser ("u3" )).thenReturn (Collections .emptyList ());
2307+
2308+ io .gravitee .rest .api .model .common .Pageable pageable = new io .gravitee .rest .api .model .common .PageableImpl (2 , 5 );
2309+
2310+ io .gravitee .common .data .domain .Page <UserEntity > page = spyUserService .search (EXECUTION_CONTEXT , "john" , pageable );
2311+
2312+ // Then: order preserved, duplicates removed, missing id filtered out
2313+ List <UserEntity > content = page .getContent ();
2314+ assertEquals (3 , content .size ());
2315+ assertEquals ("u1" , content .get (0 ).getId ());
2316+ assertEquals ("u2" , content .get (1 ).getId ());
2317+ assertEquals ("u3" , content .get (2 ).getId ());
2318+
2319+ // Page metadata
2320+ assertEquals (2 , page .getPageNumber ());
2321+ assertEquals (5 , page .getPageElements ());
2322+ assertEquals (42 , page .getTotalElements ());
2323+
2324+ // Flags populated
2325+ assertFalse (content .get (0 ).isPrimaryOwner ());
2326+ assertTrue (content .get (1 ).isPrimaryOwner ());
2327+ assertFalse (content .get (2 ).isPrimaryOwner ());
2328+
2329+ assertEquals (1 , content .get (0 ).getNbActiveTokens ());
2330+ assertEquals (3 , content .get (1 ).getNbActiveTokens ());
2331+ assertEquals (0 , content .get (2 ).getNbActiveTokens ());
2332+
2333+ // Verify that search was called and populateUserFlags implied calls
2334+ verify (searchEngineService ).search (eq (EXECUTION_CONTEXT ), any ());
2335+ verify (roleService ).findPrimaryOwnerRoleByOrganization (ORGANIZATION , RoleScope .API );
2336+ verify (roleService ).findPrimaryOwnerRoleByOrganization (ORGANIZATION , RoleScope .APPLICATION );
2337+ }
22242338}
0 commit comments