Skip to content
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
17 changes: 15 additions & 2 deletions framework/db/src/main/java/com/cloud/utils/db/Filter.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,21 @@ public Filter(Class<?> clazz, String field, boolean ascending) {
}

public Filter(long limit) {
_orderBy = " ORDER BY RAND()";
_limit = limit;
this(limit, true);
}

/**
* Constructor for creating a filter with random ordering
* @param limit the maximum number of results to return
* @param randomize if true, orders results randomly
*/
public Filter(long limit, boolean randomize) {
if (randomize) {
_orderBy = " ORDER BY RAND()" ;
_limit = limit;
} else {
_limit = limit;
}
Comment on lines +69 to +74
Copy link
Member

@winterhazel winterhazel Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (randomize) {
_orderBy = " ORDER BY RAND()" ;
_limit = limit;
} else {
_limit = limit;
}
_limit = limit;
if (randomize) {
_orderBy = " ORDER BY RAND()" ;
}

}

public Filter(Long offset, Long limit) {
Expand Down
58 changes: 58 additions & 0 deletions framework/db/src/test/java/com/cloud/utils/db/FilterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,62 @@ public void testAddOrderBy() {
Assert.assertTrue(filter.getOrderBy().split(",").length == 3);
Assert.assertTrue(filter.getOrderBy().split(",")[2].trim().toLowerCase().equals("test.fld_int asc"));
}


@Test
public void testFilterWithLimitOnly() {
Filter filter = new Filter(5);

Assert.assertEquals(Long.valueOf(5), filter.getLimit());
Assert.assertNull(filter.getOrderBy());
Assert.assertNull(filter.getOffset());
}

@Test
public void testFilterWithLimitAndRandomizeFalse() {
Filter filter = new Filter(10, false);

Assert.assertEquals(Long.valueOf(10), filter.getLimit());
Assert.assertNull(filter.getOrderBy());
Assert.assertNull(filter.getOffset());
}

@Test
public void testFilterWithLimitAndRandomizeTrue() {
Filter filter = new Filter(3, true);

Assert.assertNull(filter.getLimit());
Assert.assertNotNull(filter.getOrderBy());
Assert.assertTrue(filter.getOrderBy().contains("ORDER BY RAND()"));
Assert.assertTrue(filter.getOrderBy().contains("LIMIT 3"));
Assert.assertEquals(" ORDER BY RAND() LIMIT 3", filter.getOrderBy());
}

@Test
public void testFilterRandomizeWithDifferentLimits() {
Filter filter1 = new Filter(1, true);
Filter filter10 = new Filter(10, true);
Filter filter100 = new Filter(100, true);

Assert.assertEquals(" ORDER BY RAND() LIMIT 1", filter1.getOrderBy());
Assert.assertEquals(" ORDER BY RAND() LIMIT 10", filter10.getOrderBy());
Assert.assertEquals(" ORDER BY RAND() LIMIT 100", filter100.getOrderBy());
}

@Test
public void testFilterConstructorBackwardsCompatibility() {
// Test that Filter(long) behaves differently now (no ORDER BY RAND())
// compared to Filter(long, true) which preserves old behavior
Filter simpleLimitFilter = new Filter(1);
Filter randomFilter = new Filter(1, true);

// Simple limit filter should just set limit
Assert.assertEquals(Long.valueOf(1), simpleLimitFilter.getLimit());
Assert.assertNull(simpleLimitFilter.getOrderBy());

// Random filter should set orderBy with RAND()
Assert.assertNull(randomFilter.getLimit());
Assert.assertNotNull(randomFilter.getOrderBy());
Assert.assertTrue(randomFilter.getOrderBy().contains("RAND()"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.junit.Assert;
import org.junit.Before;
Expand Down Expand Up @@ -263,4 +264,71 @@ public void multiJoinSameTableTest() {
" INNER JOIN tableA tableA2Alias ON tableC.column3=tableA2Alias.column2 " +
" INNER JOIN tableA tableA3Alias ON tableD.column4=tableA3Alias.column3 AND tableD.column5=? ", joinString.toString());
}


@Test
public void testLockOneRandomRowUsesRandomFilter() {
// Create a mock DAO to test lockOneRandomRow behavior
GenericDaoBase<DbTestVO, Long> testDao = Mockito.mock(GenericDaoBase.class);

// Capture the filter passed to the search method
final Filter[] capturedFilter = new Filter[1];

Mockito.when(testDao.lockOneRandomRow(Mockito.any(SearchCriteria.class), Mockito.anyBoolean()))
.thenCallRealMethod();

Mockito.when(testDao.search(Mockito.any(SearchCriteria.class), Mockito.any(Filter.class),
Mockito.anyBoolean(), Mockito.anyBoolean()))
.thenAnswer(invocation -> {
capturedFilter[0] = invocation.getArgument(1);
return new ArrayList<DbTestVO>();
});

SearchCriteria<DbTestVO> sc = Mockito.mock(SearchCriteria.class);
testDao.lockOneRandomRow(sc, true);

// Verify that the filter uses random ordering
Assert.assertNotNull(capturedFilter[0]);
Assert.assertNotNull(capturedFilter[0].getOrderBy());
Assert.assertTrue(capturedFilter[0].getOrderBy().contains("ORDER BY RAND()"));
Assert.assertTrue(capturedFilter[0].getOrderBy().contains("LIMIT 1"));
}

@Test
public void testLockOneRandomRowReturnsNullOnEmptyResult() {
GenericDaoBase<DbTestVO, Long> testDao = Mockito.mock(GenericDaoBase.class);

Mockito.when(testDao.lockOneRandomRow(Mockito.any(SearchCriteria.class), Mockito.anyBoolean()))
.thenCallRealMethod();

Mockito.when(testDao.search(Mockito.any(SearchCriteria.class), Mockito.any(Filter.class),
Mockito.anyBoolean(), Mockito.anyBoolean()))
.thenReturn(new ArrayList<DbTestVO>());

SearchCriteria<DbTestVO> sc = Mockito.mock(SearchCriteria.class);
DbTestVO result = testDao.lockOneRandomRow(sc, true);

Assert.assertNull(result);
}

@Test
public void testLockOneRandomRowReturnsFirstElement() {
GenericDaoBase<DbTestVO, Long> testDao = Mockito.mock(GenericDaoBase.class);
DbTestVO expectedResult = new DbTestVO();
List<DbTestVO> resultList = new ArrayList<>();
resultList.add(expectedResult);

Mockito.when(testDao.lockOneRandomRow(Mockito.any(SearchCriteria.class), Mockito.anyBoolean()))
.thenCallRealMethod();

Mockito.when(testDao.search(Mockito.any(SearchCriteria.class), Mockito.any(Filter.class),
Mockito.anyBoolean(), Mockito.anyBoolean()))
.thenReturn(resultList);

SearchCriteria<DbTestVO> sc = Mockito.mock(SearchCriteria.class);
DbTestVO result = testDao.lockOneRandomRow(sc, true);

Assert.assertNotNull(result);
Assert.assertEquals(expectedResult, result);
}
}
Loading