Spring boot 提供了 Schedule Job 的功能,簡單的設定就可以依排程啟動程式,但應用系統可能分散式執行於多台主機,需要一個控制檔確認執行狀控。若需要完整的任務排程,可以加入一款功能強大的Quartz開源任務排程套件,因為多使用一個開源套件,多一分風險(弱點修復、版權問題),所以建議盡量以Spring Boot 提供的相依套件為主,這樣相依套件的版本,也會由spring-boot-starter-parent會幫忙管理,不必特別指定,當然若Spring Boot 提供的相依套件有弱點則可以於POM單獨排除,並指定特定版本使用 (相容性要測試)。
準備提供基本的Schedule Job 功能,以方便後續增加任何排程,只需要比照案例,簡單增加一個Worker,其他都由設計好的架構控制與啟動。
** 遇到發文存檔失敗,所以分兩部分發文,這裡準備兩個檔案,分別控制檔案SysScheduleCtlEntity 以及排程執行紀錄檔案SysScheduleLogEntity。其他排程設定與執行相關,請參考(5-2) - Spring Boot 排程作業(Schedule) URL: https://ithelp.ithome.com.tw/articles/10398750
主要是為了Schedule Job執行控制使用,依 dataType key值,
這裡只提供Entity資料以及測試程式,其他請參考以下 Spring Boot資料庫設計與存取文件
** Entity 程式
package tw.lewishome.webapp.database.primary.entity;
import java.io.Serializable;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.Index;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import tw.lewishome.webapp.database.audit.EntityAudit;
/**
* SysScheduleCtlEntity Table Entity
*
* @author lewis
*/
@Entity
// 資料庫的 Table 名稱 因為有需要以scheduleTaskName查詢與處理,所以這裡指定一個可重複的Index
@Table(name = "sysschedulectl", indexes = @Index(name = "idx_taskname", columnList = "scheduleTaskName", unique = false))
@Data
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
public class SysScheduleCtlEntity extends EntityAudit<String> {
/**
* Fix for javadoc warning :
* use of default constructor, which does not provide a comment
* Constructs a new SysScheduleCtlEntity instance.
* This is the default constructor, implicitly provided by the compiler
* if no other constructors are defined.
*/
public SysScheduleCtlEntity() {
// Constructor body (can be empty)
}
private static final long serialVersionUID = 1L;
/** Primary Key */
@EmbeddedId
public DataKey dataKey;
/** Server Name */
@Column(name = "serverName", length = 128)
public String serverName;
/** Schedule Running Flag */
@Column(name = "runFlag")
public Boolean runFlag = true;
/**
* Entity Key
*
*/
@Embeddable
@Data
public static class DataKey implements Serializable {
/**
* Fix for javadoc warning :
* use of default constructor, which does not provide a comment
* Constructs a new DataKey instance.
* This is the default constructor, implicitly provided by the compiler
* if no other constructors are defined.
*/
public DataKey() {
// Constructor body (can be empty)
}
private static final long serialVersionUID = 1L;
/** Schedule Task Name */
@Column(name = "scheduleTaskName", length = 128)
public String scheduleTaskName;
/**
* data Type for schedule controller
* controller check runFlag for run or not
* taskLock lock for task is running , if no tasklock record means task is not
* running
* masterServer schedule main server name , only main server can do schedule
* need
* initialize
*/
@Column(name = "dataType", length = 64)
public String dataType = ""; // controller or taskLock or masterServer
}
/** MyBatis TypeHandler for DataKey */
public static class DataKeyHandler extends BaseTypeHandler<DataKey> {
/**
* Fix for javadoc warning :
* use of default constructor, which does not provide a comment
* Constructs a new AsyncServiceWorkerSample instance.
* This is the default constructor, implicitly provided by the compiler
* if no other constructors are defined.
*/
public DataKeyHandler() {
// Constructor body (can be empty)
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, DataKey parameter, JdbcType jdbcType)
throws SQLException {
try {
ps.setString(1, parameter.getScheduleTaskName());
ps.setString(2, parameter.getDataType());
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public DataKey getNullableResult(ResultSet rs, String columnName) throws SQLException {
DataKey dataKey = new DataKey();
if (rs.wasNull() == false) {
dataKey.setScheduleTaskName(rs.getString("schedule_task_name"));
dataKey.setDataType(rs.getString("data_type"));
}
return dataKey;
}
@Override
public DataKey getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
DataKey dataKey = new DataKey();
if (rs.wasNull() == false) {
dataKey.setScheduleTaskName(rs.getString(1));
dataKey.setDataType(rs.getString(2));
}
return dataKey;
}
@Override
public DataKey getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
DataKey dataKey = new DataKey();
if (cs.wasNull() == false) {
dataKey.setScheduleTaskName(cs.getString(1));
dataKey.setDataType(cs.getString(2));
}
return dataKey;
}
}
}
** Repository 程式
基本Repository外,增加 deleteByDataType 的 Method.
package tw.lewishome.webapp.database.primary.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import tw.lewishome.webapp.database.primary.entity.SysScheduleCtlEntity;
/**
* SysScheduleCtl JPA Repository
*
* @author lewis
* @version $Id: $Id
*/
@Transactional
@Repository
public interface SysScheduleCtlRepository extends JpaRepository<SysScheduleCtlEntity, SysScheduleCtlEntity.DataKey>,
JpaSpecificationExecutor<SysScheduleCtlEntity> {
@Modifying
@Transactional
@Query("DELETE FROM SysScheduleCtlEntity u WHERE u.dataKey.dataType = :parmDataType")
void deleteByDataType(@Param("parmDataType") String dataType);
}
** Mapper 測試程式
3. SysScheduleCtlMapperTest.java
package tw.lewishome.webapp.database.primary.mybatis;
import static org.junit.jupiter.api.Assertions.*;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import tw.lewishome.webapp.database.primary.entity.SysScheduleCtlEntity;
/**
* SysScheduleCtlMapper Integration Tests
*
* Tests for SysScheduleCtlMapper using MyBatis mapper with real database.
* @BeforeEach to add test data and @AfterEach to clean up.
*
* @author lewis
*/
@SpringBootTest
@TestPropertySource(locations = "classpath:application.properties")
public class SysScheduleCtlMapperTest {
@Autowired
private SysScheduleCtlMapper sysScheduleCtlMapper;
private SysScheduleCtlEntity testEntity;
private SysScheduleCtlEntity testEntity2;
/**
* Setup test data before each test
* Creates test schedule control entities and inserts them to database
* Also cleans up any existing test data to ensure clean state
*/
@BeforeEach
void setUp() {
// Clean up any existing test data
cleanupTestSchedule("TEST_SCHEDULE_001", "TYPE_001");
cleanupTestSchedule("TEST_SCHEDULE_002", "TYPE_002");
// Create first test entity
testEntity = new SysScheduleCtlEntity();
SysScheduleCtlEntity.DataKey dataKey1 = new SysScheduleCtlEntity.DataKey();
dataKey1.setScheduleTaskName("TEST_SCHEDULE_001");
dataKey1.setDataType("TYPE_001");
testEntity.setDataKey(dataKey1);
testEntity.setServerName("SERVER_001");
testEntity.setRunFlag(true);
// Create second test entity
testEntity2 = new SysScheduleCtlEntity();
SysScheduleCtlEntity.DataKey dataKey2 = new SysScheduleCtlEntity.DataKey();
dataKey2.setScheduleTaskName("TEST_SCHEDULE_002");
dataKey2.setDataType("TYPE_002");
testEntity2.setDataKey(dataKey2);
testEntity2.setServerName("SERVER_002");
testEntity2.setRunFlag(false);
// Insert both test entities to database
sysScheduleCtlMapper.insert(testEntity);
sysScheduleCtlMapper.insert(testEntity2);
}
/**
* Cleanup test data after each test
* Removes all test entities from database
*/
@AfterEach
void tearDown() {
cleanupTestSchedule("TEST_SCHEDULE_001", "TYPE_001");
cleanupTestSchedule("TEST_SCHEDULE_002", "TYPE_002");
}
/**
* Helper method to cleanup a test schedule by taskName and dataType
*
* @param scheduleTaskName the schedule task name to cleanup
* @param dataType the data type to cleanup
*/
private void cleanupTestSchedule(String scheduleTaskName, String dataType) {
sysScheduleCtlMapper.deleteByDataKey(scheduleTaskName, dataType);
}
/**
* Test: Find all schedule control records
* Verifies that findByAll returns all entities
*/
@Test
void testFindByAll() {
// Query all records
List<SysScheduleCtlEntity> found = sysScheduleCtlMapper.findByAll();
// Verify entities were found
assertNotNull(found);
assertTrue(found.size() >= 2, "Should find at least 2 test schedules");
// Verify test entities are in results
boolean found1 = found.stream()
.anyMatch(e -> "TEST_SCHEDULE_001".equals(e.getDataKey().getScheduleTaskName()));
assertTrue(found1, "Should find TEST_SCHEDULE_001");
boolean found2 = found.stream()
.anyMatch(e -> "TEST_SCHEDULE_002".equals(e.getDataKey().getScheduleTaskName()));
assertTrue(found2, "Should find TEST_SCHEDULE_002");
}
/**
* Test: Find schedule control by data key
* Verifies that findByDataKey returns correct entity
*/
@Test
void testFindByDataKey() {
// Query by data key
SysScheduleCtlEntity found = sysScheduleCtlMapper.findByDataKey("TEST_SCHEDULE_001", "TYPE_001");
// Verify entity was found
assertNotNull(found);
assertEquals("TEST_SCHEDULE_001", found.getDataKey().getScheduleTaskName());
assertEquals("TYPE_001", found.getDataKey().getDataType());
assertEquals("SERVER_001", found.getServerName());
assertTrue(found.getRunFlag());
}
/**
* Test: Find schedule control by schedule task name
* Verifies that findBySysScheduleTaskName returns matching entities
*/
@Test
void testFindBySysScheduleTaskName() {
// Query by schedule task name
List<SysScheduleCtlEntity> found = sysScheduleCtlMapper.findByScheduleTaskName("TEST_SCHEDULE_001");
// Verify entity was found
assertNotNull(found);
assertTrue(found.size() >= 1, "Should find at least 1 schedule");
// Verify first result matches
assertEquals("TEST_SCHEDULE_001", found.get(0).getDataKey().getScheduleTaskName());
assertEquals("SERVER_001", found.get(0).getServerName());
}
/**
* Test: Insert schedule control record
* Verifies that entity is inserted correctly
*/
@Test
void testInsertScheduleCtl() {
// Create new entity
SysScheduleCtlEntity newEntity = new SysScheduleCtlEntity();
SysScheduleCtlEntity.DataKey dataKey = new SysScheduleCtlEntity.DataKey();
dataKey.setScheduleTaskName("TEST_INSERT_SCHEDULE");
dataKey.setDataType("TYPE_INSERT");
newEntity.setDataKey(dataKey);
newEntity.setServerName("SERVER_INSERT");
newEntity.setRunFlag(true);
// Insert entity
int result = sysScheduleCtlMapper.insert(newEntity);
// Verify insertion
assertEquals(1, result, "Should insert 1 row");
// Query to verify
SysScheduleCtlEntity found = sysScheduleCtlMapper.findByDataKey("TEST_INSERT_SCHEDULE", "TYPE_INSERT");
assertNotNull(found);
assertEquals("SERVER_INSERT", found.getServerName());
// Cleanup
cleanupTestSchedule("TEST_INSERT_SCHEDULE", "TYPE_INSERT");
}
/**
* Test: Delete schedule control record
* Verifies that entity can be deleted
*/
@Test
void testDeleteByDataKey() {
// Verify entity exists
SysScheduleCtlEntity found = sysScheduleCtlMapper.findByDataKey("TEST_SCHEDULE_001", "TYPE_001");
assertNotNull(found);
// Delete entity
int result = sysScheduleCtlMapper.deleteByDataKey("TEST_SCHEDULE_001", "TYPE_001");
// Verify deletion
assertEquals(1, result, "Should delete 1 row");
// Query to verify deletion
SysScheduleCtlEntity notFound = sysScheduleCtlMapper.findByDataKey("TEST_SCHEDULE_001", "TYPE_001");
assertNull(notFound, "Entity should be deleted");
}
/**
* Test: Verify all fields of saved entity
* Ensures all entity fields are correctly stored and retrieved
*/
@Test
void testEntityFieldsArePersisted() {
// Query entity
SysScheduleCtlEntity found = sysScheduleCtlMapper.findByDataKey("TEST_SCHEDULE_002", "TYPE_002");
// Verify all fields
assertNotNull(found);
assertEquals("TEST_SCHEDULE_002", found.getDataKey().getScheduleTaskName());
assertEquals("TYPE_002", found.getDataKey().getDataType());
assertEquals("SERVER_002", found.getServerName());
assertFalse(found.getRunFlag());
}
/**
* Test: Find schedule by different task names
* Verifies that findBySysScheduleTaskName works for multiple records
*/
@Test
void testFindBySysScheduleTaskNameMultiple() {
// Query for each task name
List<SysScheduleCtlEntity> found1 = sysScheduleCtlMapper.findByScheduleTaskName("TEST_SCHEDULE_001");
List<SysScheduleCtlEntity> found2 = sysScheduleCtlMapper.findByScheduleTaskName("TEST_SCHEDULE_002");
// Verify results
assertNotNull(found1);
assertNotNull(found2);
assertTrue(found1.size() >= 1);
assertTrue(found2.size() >= 1);
assertEquals("TEST_SCHEDULE_001", found1.get(0).getDataKey().getScheduleTaskName());
assertEquals("TEST_SCHEDULE_002", found2.get(0).getDataKey().getScheduleTaskName());
}
/**
* Test: Find non-existent schedule
* Verifies that findByDataKey returns null for non-existent record
*/
@Test
void testFindNonExistentSchedule() {
// Query for non-existent entity
SysScheduleCtlEntity found = sysScheduleCtlMapper.findByDataKey("NON_EXISTENT", "TYPE_NONE");
// Verify result is null
assertNull(found, "Should not find non-existent entity");
}
}
** Repository 測試程式
4. SysScheduleCtlRepositoryTest.java
package tw.lewishome.webapp.database.primary.repository;
import static org.junit.jupiter.api.Assertions.*;
import java.util.List;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import tw.lewishome.webapp.database.primary.entity.SysScheduleCtlEntity;
/**
* SysScheduleCtlRepository Integration Tests
*
* Tests for SysScheduleCtlRepository using real repository with
*
* @BeforeEach to add test data and @AfterEach to clean up.
*
* @author lewis
*/
/**
* SysScheduleCtlRepository Integration Tests
*
* Tests for SysScheduleCtlRepository using real repository with
*
* @BeforeEach to add test data and @AfterEach to clean up.
*
* @author lewis
*/
@SpringBootTest
@TestPropertySource(locations = "classpath:application.properties")
public class SysScheduleCtlRepositoryTest {
@Autowired
private SysScheduleCtlRepository sysScheduleCtlRepository;
private SysScheduleCtlEntity testEntity;
private SysScheduleCtlEntity testEntity2;
/**
* Setup test data before each test
* Creates test schedule control entities and saves them to database
* Also cleans up any existing test data to ensure clean state
*/
@BeforeEach
void setUp() {
// Clean up any existing test data
cleanupTestSchedule("TEST_SCHEDULE_001", "controller");
cleanupTestSchedule("TEST_SCHEDULE_002", "taskLock");
// Create first test entity
testEntity = new SysScheduleCtlEntity();
SysScheduleCtlEntity.DataKey dataKey1 = new SysScheduleCtlEntity.DataKey();
dataKey1.setScheduleTaskName("TEST_SCHEDULE_001");
dataKey1.setDataType("controller");
testEntity.setDataKey(dataKey1);
testEntity.setServerName("SERVER_001");
testEntity.setRunFlag(true);
// Create second test entity
testEntity2 = new SysScheduleCtlEntity();
SysScheduleCtlEntity.DataKey dataKey2 = new SysScheduleCtlEntity.DataKey();
dataKey2.setScheduleTaskName("TEST_SCHEDULE_002");
dataKey2.setDataType("taskLock");
testEntity2.setDataKey(dataKey2);
testEntity2.setServerName("SERVER_002");
testEntity2.setRunFlag(false);
// Save both test entities to database
testEntity = sysScheduleCtlRepository.saveAndFlush(testEntity);
testEntity2 = sysScheduleCtlRepository.saveAndFlush(testEntity2);
}
/**
* Cleanup test data after each test
* Removes all test entities from database
*/
@AfterEach
void tearDown() {
cleanupTestSchedule("TEST_SCHEDULE_001", "controller");
cleanupTestSchedule("TEST_SCHEDULE_002", "taskLock");
}
/**
* Helper method to cleanup a test schedule by task name and data type
*
* @param taskName the schedule task name to cleanup
* @param dataType the data type to cleanup
*/
private void cleanupTestSchedule(String taskName, String dataType) {
SysScheduleCtlEntity.DataKey key = new SysScheduleCtlEntity.DataKey();
key.setScheduleTaskName(taskName);
key.setDataType(dataType);
Optional<SysScheduleCtlEntity> entity = sysScheduleCtlRepository.findById(key);
if (entity.isPresent()) {
sysScheduleCtlRepository.delete(entity.get());
sysScheduleCtlRepository.flush();
}
}
/**
* Test: Create new schedule control entity
* Verifies that entity can be saved and returned with ID
*/
@Test
void testCreateScheduleEntity() {
SysScheduleCtlEntity newEntity = new SysScheduleCtlEntity();
SysScheduleCtlEntity.DataKey dataKey = new SysScheduleCtlEntity.DataKey();
dataKey.setScheduleTaskName("NEW_SCHEDULE");
dataKey.setDataType("controller");
newEntity.setDataKey(dataKey);
newEntity.setServerName("NEW_SERVER");
newEntity.setRunFlag(true);
SysScheduleCtlEntity savedEntity = sysScheduleCtlRepository.saveAndFlush(newEntity);
assertNotNull(savedEntity);
assertEquals("NEW_SCHEDULE", savedEntity.getDataKey().getScheduleTaskName());
assertEquals("controller", savedEntity.getDataKey().getDataType());
assertEquals("NEW_SERVER", savedEntity.getServerName());
assertEquals(true, savedEntity.getRunFlag());
// Cleanup
cleanupTestSchedule("NEW_SCHEDULE", "controller");
}
/**
* Test: Read schedule entity by ID
* Verifies that findById returns correct entity
*/
@Test
void testReadScheduleEntityById() {
Optional<SysScheduleCtlEntity> found = sysScheduleCtlRepository.findById(testEntity.getDataKey());
assertTrue(found.isPresent());
assertEquals("TEST_SCHEDULE_001", found.get().getDataKey().getScheduleTaskName());
assertEquals("controller", found.get().getDataKey().getDataType());
assertEquals("SERVER_001", found.get().getServerName());
assertEquals(true, found.get().getRunFlag());
}
/**
* Test: Update schedule control entity
* Verifies that entity updates are persisted correctly
*/
@Test
void testUpdateScheduleEntity() {
Optional<SysScheduleCtlEntity> found = sysScheduleCtlRepository.findById(testEntity.getDataKey());
assertTrue(found.isPresent());
SysScheduleCtlEntity entity = found.get();
entity.setServerName("UPDATED_SERVER");
entity.setRunFlag(false);
sysScheduleCtlRepository.saveAndFlush(entity);
Optional<SysScheduleCtlEntity> updated = sysScheduleCtlRepository.findById(testEntity.getDataKey());
assertTrue(updated.isPresent());
assertEquals("UPDATED_SERVER", updated.get().getServerName());
assertEquals(false, updated.get().getRunFlag());
}
/**
* Test: Delete schedule control entity
* Verifies that entity can be deleted and no longer found
*/
@Test
void testDeleteScheduleEntity() {
Optional<SysScheduleCtlEntity> found = sysScheduleCtlRepository.findById(testEntity.getDataKey());
assertTrue(found.isPresent());
sysScheduleCtlRepository.delete(testEntity);
sysScheduleCtlRepository.flush();
Optional<SysScheduleCtlEntity> notFound = sysScheduleCtlRepository.findById(testEntity.getDataKey());
assertFalse(notFound.isPresent());
testEntity = null;
}
/**
* Test: Find all schedule entities
* Verifies that findAll returns all entities
*/
@Test
void testFindAllScheduleEntities() {
List<SysScheduleCtlEntity> all = sysScheduleCtlRepository.findAll();
assertNotNull(all);
assertTrue(all.size() >= 2, "Should have at least 2 test schedules");
long count = all.stream()
.filter(e -> ("TEST_SCHEDULE_001".equals(e.getDataKey().getScheduleTaskName()) ||
"TEST_SCHEDULE_002".equals(e.getDataKey().getScheduleTaskName())))
.count();
assertEquals(2, count, "Should find exactly 2 test schedules");
}
/**
* Test: Find by ID that does not exist
* Verifies that findById returns empty Optional for non-existent entity
*/
@Test
void testFindScheduleEntityByIdNotFound() {
SysScheduleCtlEntity.DataKey nonExistentKey = new SysScheduleCtlEntity.DataKey();
nonExistentKey.setScheduleTaskName("NON_EXISTENT");
nonExistentKey.setDataType("controller");
Optional<SysScheduleCtlEntity> found = sysScheduleCtlRepository.findById(nonExistentKey);
assertFalse(found.isPresent());
}
/**
* Test: Verify all fields are persisted correctly
* Ensures all entity fields are correctly stored and retrieved
*/
@Test
void testEntityFieldsArePersisted() {
Optional<SysScheduleCtlEntity> found = sysScheduleCtlRepository.findById(testEntity2.getDataKey());
assertTrue(found.isPresent());
SysScheduleCtlEntity entity = found.get();
assertEquals("TEST_SCHEDULE_002", entity.getDataKey().getScheduleTaskName());
assertEquals("taskLock", entity.getDataKey().getDataType());
assertEquals("SERVER_002", entity.getServerName());
assertEquals(false, entity.getRunFlag());
}
/**
* Test: Toggle run flag
* Verifies that run flag can be toggled and persisted
*/
@Test
void testToggleRunFlag() {
Optional<SysScheduleCtlEntity> found = sysScheduleCtlRepository.findById(testEntity.getDataKey());
assertTrue(found.isPresent());
SysScheduleCtlEntity entity = found.get();
boolean originalFlag = entity.getRunFlag();
entity.setRunFlag(!originalFlag);
sysScheduleCtlRepository.saveAndFlush(entity);
Optional<SysScheduleCtlEntity> updated = sysScheduleCtlRepository.findById(testEntity.getDataKey());
assertTrue(updated.isPresent());
assertEquals(!originalFlag, updated.get().getRunFlag());
}
/**
* Test: Count all schedules
* Verifies that repository count method works correctly
*/
@Test
void testCountSchedules() {
long count = sysScheduleCtlRepository.count();
assertTrue(count >= 2, "Should have at least 2 schedules");
}
/**
* Test: Save multiple entities
* Verifies that multiple entities can be saved and retrieved
*/
@Test
void testSaveMultipleEntities() {
SysScheduleCtlEntity entity3 = new SysScheduleCtlEntity();
SysScheduleCtlEntity.DataKey dataKey3 = new SysScheduleCtlEntity.DataKey();
dataKey3.setScheduleTaskName("TEST_SCHEDULE_003");
dataKey3.setDataType("masterServer");
entity3.setDataKey(dataKey3);
entity3.setServerName("SERVER_003");
entity3.setRunFlag(true);
SysScheduleCtlEntity entity4 = new SysScheduleCtlEntity();
SysScheduleCtlEntity.DataKey dataKey4 = new SysScheduleCtlEntity.DataKey();
dataKey4.setScheduleTaskName("TEST_SCHEDULE_004");
dataKey4.setDataType("controller");
entity4.setDataKey(dataKey4);
entity4.setServerName("SERVER_004");
entity4.setRunFlag(false);
sysScheduleCtlRepository.saveAndFlush(entity3);
sysScheduleCtlRepository.saveAndFlush(entity4);
List<SysScheduleCtlEntity> all = sysScheduleCtlRepository.findAll();
assertTrue(all.size() >= 4, "Should have at least 4 schedules after saving");
// Cleanup
cleanupTestSchedule("TEST_SCHEDULE_003", "masterServer");
cleanupTestSchedule("TEST_SCHEDULE_004", "controller");
}
/**
* Test: Update server name
* Verifies that server name field can be updated independently
*/
@Test
void testUpdateServerName() {
Optional<SysScheduleCtlEntity> found = sysScheduleCtlRepository.findById(testEntity.getDataKey());
assertTrue(found.isPresent());
SysScheduleCtlEntity entity = found.get();
entity.setServerName("CHANGED_SERVER");
sysScheduleCtlRepository.saveAndFlush(entity);
Optional<SysScheduleCtlEntity> updated = sysScheduleCtlRepository.findById(testEntity.getDataKey());
assertTrue(updated.isPresent());
assertEquals("CHANGED_SERVER", updated.get().getServerName());
assertEquals(true, updated.get().getRunFlag()); // Verify runFlag unchanged
}
/**
* Test: deleteByDataType repository method
* Verifies that all records with the given dataType are removed
*/
@Test
void testDeleteByDataType() {
// Prepare entities with a unique dataType to avoid interfering with other tests
String targetDataType = "deleteme";
cleanupTestSchedule("DELETE_ME_001", targetDataType);
cleanupTestSchedule("DELETE_ME_002", targetDataType);
cleanupTestSchedule("KEEP_ME_001", "keepme");
SysScheduleCtlEntity del1 = new SysScheduleCtlEntity();
SysScheduleCtlEntity.DataKey dk1 = new SysScheduleCtlEntity.DataKey();
dk1.setScheduleTaskName("DELETE_ME_001");
dk1.setDataType(targetDataType);
del1.setDataKey(dk1);
del1.setServerName("S1");
del1.setRunFlag(true);
SysScheduleCtlEntity del2 = new SysScheduleCtlEntity();
SysScheduleCtlEntity.DataKey dk2 = new SysScheduleCtlEntity.DataKey();
dk2.setScheduleTaskName("DELETE_ME_002");
dk2.setDataType(targetDataType);
del2.setDataKey(dk2);
del2.setServerName("S2");
del2.setRunFlag(false);
SysScheduleCtlEntity keep = new SysScheduleCtlEntity();
SysScheduleCtlEntity.DataKey dk3 = new SysScheduleCtlEntity.DataKey();
dk3.setScheduleTaskName("KEEP_ME_001");
dk3.setDataType("keepme");
keep.setDataKey(dk3);
keep.setServerName("S3");
keep.setRunFlag(true);
sysScheduleCtlRepository.saveAndFlush(del1);
sysScheduleCtlRepository.saveAndFlush(del2);
sysScheduleCtlRepository.saveAndFlush(keep);
// Sanity check: ensure records persisted
List<SysScheduleCtlEntity> before = sysScheduleCtlRepository.findAll();
long foundTargetBefore = before.stream()
.filter(e -> targetDataType.equals(e.getDataKey().getDataType()))
.count();
assertTrue(foundTargetBefore >= 2, "Should have at least 2 records to delete for target dataType");
// Perform deleteByDataType and flush
sysScheduleCtlRepository.deleteByDataType(targetDataType);
sysScheduleCtlRepository.flush();
// Verify deletion
List<SysScheduleCtlEntity> after = sysScheduleCtlRepository.findAll();
long foundTargetAfter = after.stream()
.filter(e -> targetDataType.equals(e.getDataKey().getDataType()))
.count();
assertEquals(0, foundTargetAfter, "All records with target dataType should be removed");
// Verify other data types unaffected
long keepCount = after.stream()
.filter(e -> "keepme".equals(e.getDataKey().getDataType()))
.count();
assertTrue(keepCount >= 1, "Records with other dataTypes should remain");
// Cleanup
cleanupTestSchedule("DELETE_ME_001", targetDataType);
cleanupTestSchedule("DELETE_ME_002", targetDataType);
cleanupTestSchedule("KEEP_ME_001", "keepme");
}
}
主要是為了紀錄Schedule Job 由哪一台何時開始執行以及結束執行(Audit的CreateDate與LastModifyDate)
package tw.lewishome.webapp.database.primary.entity;
import java.io.Serializable;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.UUID;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import tw.lewishome.webapp.database.audit.EntityAudit;
/**
* SysScheduleLog Table Entity
*
* @author lewis
* @version $Id: $Id
*/
@Entity
@Table(name = "sysschedulelog") // 資料庫的 Table 名稱
@Data
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
public class SysScheduleLogEntity extends EntityAudit<String> {
/**
* Fix for javadoc warning :
* use of default constructor, which does not provide a comment
* Constructs a new SysScheduleLogEntity instance.
* This is the default constructor, implicitly provided by the compiler
* if no other constructors are defined.
*/
public SysScheduleLogEntity() {
// Constructor body (can be empty)
}
private static final long serialVersionUID = 1L;
/** Primary Key */
@EmbeddedId
public DataKey dataKey;
/** Schedule Task Name */
@Column(name = "scheduleTaskName", length = 128)
public String scheduleTaskName;
/** Server Name */
@Column(name = "serverName", length = 128)
public String serverName;
/**
* Entity Key
*
*/
@Embeddable
@Data
public static class DataKey implements Serializable {
/**
* Fix for javadoc warning :
* use of default constructor, which does not provide a comment
* Constructs a new DataKey instance.
* This is the default constructor, implicitly provided by the compiler
* if no other constructors are defined.
*/
public DataKey() {
// Constructor body (can be empty)
}
private static final long serialVersionUID = 1L;
/** UUID */
@Column(name = "uuid", length = 64)
public String uuid = UUID.randomUUID().toString();
}
/**
* MyBatis TypeHandler for DataKey
*/
/**
* MyBatis BaseTypeHandler} for converting between the application's
* DataKey object and its JDBC representation.
*
*/
public static class DataKeyHandler extends BaseTypeHandler<DataKey> {
/**
* Fix for javadoc warning :
* use of default constructor, which does not provide a comment
* Constructs a new AsyncServiceWorkerSample instance.
* This is the default constructor, implicitly provided by the compiler
* if no other constructors are defined.
*/
public DataKeyHandler() {
// Constructor body (can be empty)
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, DataKey parameter, JdbcType jdbcType)
throws SQLException {
try {
ps.setString(1, parameter.getUuid());
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public DataKey getNullableResult(ResultSet rs, String columnName) throws SQLException {
DataKey dataKey = new DataKey();
if (rs.wasNull() == false) {
dataKey.setUuid(rs.getString("uuid"));
}
return dataKey;
}
@Override
public DataKey getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
DataKey dataKey = new DataKey();
if (rs.wasNull() == false) {
dataKey.setUuid(rs.getString(1));
}
return dataKey;
}
@Override
public DataKey getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
DataKey dataKey = new DataKey();
if (cs.wasNull() == false) {
dataKey.setUuid(cs.getString(1));
}
return dataKey;
}
}
}
** Mapper 測試程式
2. SysSchedulelogMapperTest.java
package tw.lewishome.webapp.database.primary.mybatis;
import static org.junit.jupiter.api.Assertions.*;
import java.util.List;
import java.util.UUID;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import tw.lewishome.webapp.database.primary.entity.SysScheduleLogEntity;
/**
* SysScheduleLogMapper Unit Tests
*
* Tests for SysScheduleLogMapper using real mapper with database.
*
* @author lewis
*/
@SpringBootTest
public class SysScheduleLogMapperTest {
@Autowired
private SysScheduleLogMapper sysScheduleLogMapper;
private SysScheduleLogEntity testEntity1;
private SysScheduleLogEntity testEntity2;
private String testUuid1;
private String testUuid2;
@BeforeEach
void setUp() {
// Generate test UUIDs
testUuid1 = UUID.randomUUID().toString();
testUuid2 = UUID.randomUUID().toString();
// Create first test entity
testEntity1 = new SysScheduleLogEntity();
SysScheduleLogEntity.DataKey dataKey1 = new SysScheduleLogEntity.DataKey();
dataKey1.setUuid(testUuid1);
testEntity1.setDataKey(dataKey1);
testEntity1.setScheduleTaskName("TEST_TASK_001");
testEntity1.setServerName("TEST_SERVER_001");
// Create second test entity
testEntity2 = new SysScheduleLogEntity();
SysScheduleLogEntity.DataKey dataKey2 = new SysScheduleLogEntity.DataKey();
dataKey2.setUuid(testUuid2);
testEntity2.setDataKey(dataKey2);
testEntity2.setScheduleTaskName("TEST_TASK_002");
testEntity2.setServerName("TEST_SERVER_002");
// Save both test entities to database
sysScheduleLogMapper.deleteById(testUuid1);
sysScheduleLogMapper.insert(testEntity1);
sysScheduleLogMapper.deleteById(testUuid2);
sysScheduleLogMapper.insert(testEntity2);
}
/**
* Cleanup test data after each test
* Removes all test entities from database
*/
@AfterEach
void tearDown() {
sysScheduleLogMapper.deleteById(testUuid1);
sysScheduleLogMapper.deleteById(testUuid2);
}
/**
* Test: Mapper is not null
* Verifies that mapper is properly autowired
*/
@Test
void testMapperIsNotNull() {
assertNotNull(sysScheduleLogMapper, "SysScheduleLogMapper should be autowired");
}
/**
* Test: Find all returns list of entities
* Verifies that findByAll returns all test entities
*/
@Test
void testFindByAllReturnsListOfEntities() {
List<SysScheduleLogEntity> list = sysScheduleLogMapper.findByAll();
assertNotNull(list);
assertTrue(list.size() >= 2, "Should contain at least 2 test entities");
}
/**
* Test: Find by UUID returns correct data
* Verifies that findScheduleTaskName returns matching entity
*/
@Test
void testFindScheduleTaskNameReturnsCorrectData() {
List<SysScheduleLogEntity> result = sysScheduleLogMapper.findScheduleTaskName("TEST_TASK_001");
assertNotNull(result);
assertTrue(result.size() >= 1, "Should find at least 1 result");
boolean found = result.stream()
.anyMatch(e -> testUuid1.equals(e.getDataKey().getUuid()) &&
"TEST_TASK_001".equals(e.getScheduleTaskName()));
assertTrue(found, "Should find entity with UUID1 and task name TEST_TASK_001");
}
/**
* Test: Find schedule task with no matches
* Verifies that empty list is returned for non-matching query
*/
@Test
void testFindScheduleTaskNameReturnsEmptyList() {
List<SysScheduleLogEntity> result = sysScheduleLogMapper.findScheduleTaskName("NON_EXISTENT_TASK");
assertNotNull(result);
boolean notFound = result.stream()
.anyMatch(e -> testUuid1.equals(e.getDataKey().getUuid()) ||
testUuid2.equals(e.getDataKey().getUuid()));
assertFalse(notFound, "Should not find test entities");
}
/**
* Test: Find multiple invocations
* Verifies that mapper can be called multiple times
*/
@Test
void testFindMultipleInvocations() {
List<SysScheduleLogEntity> result1 = sysScheduleLogMapper.findScheduleTaskName("TEST_TASK_001");
assertNotNull(result1);
assertTrue(result1.size() >= 1);
List<SysScheduleLogEntity> result2 = sysScheduleLogMapper.findScheduleTaskName("TEST_TASK_002");
assertNotNull(result2);
assertTrue(result2.size() >= 1);
}
/**
* Test: Find by UUID returns all fields
* Verifies that all fields are correctly retrieved from database
*/
@Test
void testFindScheduleTaskNameReturnsAllFields() {
List<SysScheduleLogEntity> result = sysScheduleLogMapper.findScheduleTaskName("TEST_TASK_001");
assertNotNull(result);
assertTrue(result.size() >= 1);
SysScheduleLogEntity found = result.stream()
.filter(e -> testUuid1.equals(e.getDataKey().getUuid()))
.findFirst()
.orElse(null);
assertNotNull(found);
assertEquals(testUuid1, found.getDataKey().getUuid());
assertEquals("TEST_TASK_001", found.getScheduleTaskName());
assertEquals("TEST_SERVER_001", found.getServerName());
}
/**
* Test: Insert and find entity
* Verifies that inserted entity can be retrieved
*/
@Test
void testInsertAndFindEntity() {
String newUuid = UUID.randomUUID().toString();
SysScheduleLogEntity newEntity = new SysScheduleLogEntity();
SysScheduleLogEntity.DataKey dataKey = new SysScheduleLogEntity.DataKey();
dataKey.setUuid(newUuid);
newEntity.setDataKey(dataKey);
newEntity.setScheduleTaskName("INSERT_TEST_TASK");
newEntity.setServerName("INSERT_TEST_SERVER");
// Insert
int insertResult = sysScheduleLogMapper.insert(newEntity);
assertEquals(1, insertResult, "Insert should return 1");
// Find and verify
List<SysScheduleLogEntity> found = sysScheduleLogMapper.findScheduleTaskName("INSERT_TEST_TASK");
assertNotNull(found);
assertTrue(found.size() >= 1);
boolean hasInserted = found.stream()
.anyMatch(e -> newUuid.equals(e.getDataKey().getUuid()) &&
"INSERT_TEST_TASK".equals(e.getScheduleTaskName()));
assertTrue(hasInserted, "Should find inserted entity");
// Cleanup
sysScheduleLogMapper.deleteById(newUuid);
}
/**
* Test: Update schedule log entity
* Verifies that entity fields can be updated
*/
@Test
void testUpdateScheduleLogEntity() {
// Verify entity exists before update
List<SysScheduleLogEntity> beforeUpdate = sysScheduleLogMapper.findScheduleTaskName("TEST_TASK_001");
assertNotNull(beforeUpdate);
assertTrue(beforeUpdate.size() >= 1);
// Update
SysScheduleLogEntity entity = beforeUpdate.stream()
.filter(e -> testUuid1.equals(e.getDataKey().getUuid()))
.findFirst()
.orElse(null);
assertNotNull(entity);
entity.setScheduleTaskName("UPDATED_TASK_001");
entity.setServerName("UPDATED_SERVER_001");
int updateResult = sysScheduleLogMapper.update(entity);
assertEquals(1, updateResult, "Update should return 1");
// Verify update
List<SysScheduleLogEntity> afterUpdate = sysScheduleLogMapper.findScheduleTaskName("UPDATED_TASK_001");
assertNotNull(afterUpdate);
boolean hasUpdated = afterUpdate.stream()
.anyMatch(e -> testUuid1.equals(e.getDataKey().getUuid()) &&
"UPDATED_TASK_001".equals(e.getScheduleTaskName()) &&
"UPDATED_SERVER_001".equals(e.getServerName()));
assertTrue(hasUpdated, "Should find updated entity with new values");
// Reset for cleanup
entity.setScheduleTaskName("TEST_TASK_001");
entity.setServerName("TEST_SERVER_001");
sysScheduleLogMapper.update(entity);
}
/**
* Test: Delete by UUID
* Verifies that entity can be deleted and no longer found
*/
@Test
void testDeleteByUuid() {
// Verify entity exists before delete
List<SysScheduleLogEntity> beforeDelete = sysScheduleLogMapper.findScheduleTaskName("TEST_TASK_001");
assertNotNull(beforeDelete);
boolean foundBefore = beforeDelete.stream()
.anyMatch(e -> testUuid1.equals(e.getDataKey().getUuid()));
assertTrue(foundBefore, "Entity should exist before delete");
// Delete
int deleteResult = sysScheduleLogMapper.deleteById(testUuid1);
assertEquals(1, deleteResult, "Delete should return 1");
// Verify entity is deleted
List<SysScheduleLogEntity> afterDelete = sysScheduleLogMapper.findByAll();
assertNotNull(afterDelete);
boolean foundAfter = afterDelete.stream()
.anyMatch(e -> testUuid1.equals(e.getDataKey().getUuid()));
assertFalse(foundAfter, "Entity should not be found after deletion");
// Re-insert for tearDown cleanup
testEntity1.setScheduleTaskName("TEST_TASK_001");
testEntity1.setServerName("TEST_SERVER_001");
sysScheduleLogMapper.insert(testEntity1);
}
/**
* Test: Delete non-existent entity
* Verifies that deleting non-existent entity returns 0
*/
@Test
void testDeleteNonExistentEntity() {
String nonExistentUuid = UUID.randomUUID().toString();
int deleteResult = sysScheduleLogMapper.deleteById(nonExistentUuid);
assertEquals(0, deleteResult, "Delete non-existent entity should return 0");
}
/**
* Test: Find second entity with correct data
* Verifies second test entity data
*/
@Test
void testFindScheduleTaskNameReturnsCorrectDataForSecondEntity() {
List<SysScheduleLogEntity> result = sysScheduleLogMapper.findScheduleTaskName("TEST_TASK_002");
assertNotNull(result);
assertTrue(result.size() >= 1);
boolean found = result.stream()
.anyMatch(e -> testUuid2.equals(e.getDataKey().getUuid()) &&
"TEST_TASK_002".equals(e.getScheduleTaskName()) &&
"TEST_SERVER_002".equals(e.getServerName()));
assertTrue(found, "Should find second entity with correct data");
}
/**
* Test: Update schedule task name only
* Verifies that schedule task name can be updated independently
*/
@Test
void testUpdateScheduleTaskNameOnly() {
// Get entity
List<SysScheduleLogEntity> found = sysScheduleLogMapper.findScheduleTaskName("TEST_TASK_001");
assertNotNull(found);
assertTrue(found.size() >= 1);
SysScheduleLogEntity entity = found.stream()
.filter(e -> testUuid1.equals(e.getDataKey().getUuid()))
.findFirst()
.orElse(null);
assertNotNull(entity);
// Update only task name
entity.setScheduleTaskName("PARTIAL_UPDATE_TASK");
int updateResult = sysScheduleLogMapper.update(entity);
assertEquals(1, updateResult, "Update should return 1");
// Verify only task name changed
List<SysScheduleLogEntity> updated = sysScheduleLogMapper.findScheduleTaskName("PARTIAL_UPDATE_TASK");
assertNotNull(updated);
boolean hasUpdated = updated.stream()
.anyMatch(e -> testUuid1.equals(e.getDataKey().getUuid()) &&
"PARTIAL_UPDATE_TASK".equals(e.getScheduleTaskName()) &&
"TEST_SERVER_001".equals(e.getServerName())); // Original server name
assertTrue(hasUpdated, "Only task name should change, server name should remain");
// Reset for cleanup
entity.setScheduleTaskName("TEST_TASK_001");
sysScheduleLogMapper.update(entity);
}
/**
* Test: Find by all with multiple invocations
* Verifies that findByAll consistently returns all entities
*/
@Test
void testFindByAllMultipleInvocations() {
List<SysScheduleLogEntity> all1 = sysScheduleLogMapper.findByAll();
assertNotNull(all1);
int initialSize = all1.size();
List<SysScheduleLogEntity> all2 = sysScheduleLogMapper.findByAll();
assertNotNull(all2);
assertEquals(initialSize, all2.size(), "findByAll should return consistent results");
boolean hasEntity1 = all2.stream()
.anyMatch(e -> testUuid1.equals(e.getDataKey().getUuid()));
boolean hasEntity2 = all2.stream()
.anyMatch(e -> testUuid2.equals(e.getDataKey().getUuid()));
assertTrue(hasEntity1 && hasEntity2, "Should contain both test entities");
}
/**
* Test: Update server name only
* Verifies that server name can be updated independently
*/
@Test
void testUpdateServerNameOnly() {
// Get entity
List<SysScheduleLogEntity> found = sysScheduleLogMapper.findScheduleTaskName("TEST_TASK_002");
assertNotNull(found);
assertTrue(found.size() >= 1);
SysScheduleLogEntity entity = found.stream()
.filter(e -> testUuid2.equals(e.getDataKey().getUuid()))
.findFirst()
.orElse(null);
assertNotNull(entity);
// Update only server name
entity.setServerName("UPDATED_SERVER_002");
int updateResult = sysScheduleLogMapper.update(entity);
assertEquals(1, updateResult, "Update should return 1");
// Verify only server name changed
List<SysScheduleLogEntity> updated = sysScheduleLogMapper.findScheduleTaskName("TEST_TASK_002");
assertNotNull(updated);
boolean hasUpdated = updated.stream()
.anyMatch(e -> testUuid2.equals(e.getDataKey().getUuid()) &&
"TEST_TASK_002".equals(e.getScheduleTaskName()) && // Original task name
"UPDATED_SERVER_002".equals(e.getServerName()));
assertTrue(hasUpdated, "Only server name should change, task name should remain");
// Reset for cleanup
entity.setServerName("TEST_SERVER_002");
sysScheduleLogMapper.update(entity);
}
}
** Repository 測試程式
3. SysSchedulelogRepositoryTest.java
/**
* Test: Find by ID that does not exist
* Verifies that findById returns empty Optional for non-existent log
*/
@Test
void testFindByIdNotFound() {
SysScheduleLogEntity.DataKey nonExistentKey = new SysScheduleLogEntity.DataKey();
nonExistentKey.setUuid(UUID.randomUUID().toString());
Optional<SysScheduleLogEntity> found = sysScheduleLogRepository.findById(nonExistentKey);
assertFalse(found.isPresent());
}
/**
* Test: Find schedule logs by schedule task name with no matches
* Verifies that empty list is returned when no entities match
*/
@Test
void testFindAllScheduleLogByScheduleTaskName_NoMatch() {
List<SysScheduleLogEntity> found = sysScheduleLogRepository
.findAllScheduleLogByScheduleTaskName("NON_EXISTENT_TASK");
assertNotNull(found);
boolean hasTestLog = found.stream()
.anyMatch(e -> testUuid1.equals(e.getDataKey().getUuid()) ||
testUuid2.equals(e.getDataKey().getUuid()));
assertFalse(hasTestLog, "Should not find test schedule logs with non-matching task name");
}
/**
* Test: Find schedule logs by task name with no matches (Native SQL)
* Verifies that native SQL returns empty list when no entities match
*/
@Test
void testFindAllScheduleLogByScheduleTaskName2_NoMatch() {
List<SysScheduleLogEntity> found = sysScheduleLogRepository
.findAllScheduleLogByScheduleTaskName2("NON_EXISTENT_NATIVE_TASK");
assertNotNull(found);
boolean hasTestLog = found.stream()
.anyMatch(e -> testUuid1.equals(e.getDataKey().getUuid()) ||
testUuid2.equals(e.getDataKey().getUuid()));
assertFalse(hasTestLog, "Should not find test schedule logs with non-matching task name");
}
/**
* Test: Save and retrieve schedule log with all fields
* Verifies persistence and retrieval of complete entity
*/
@Test
void testSaveAndRetrieveCompleteScheduleLog() {
String newUuid = UUID.randomUUID().toString();
SysScheduleLogEntity newLog = new SysScheduleLogEntity();
SysScheduleLogEntity.DataKey newDataKey = new SysScheduleLogEntity.DataKey();
newDataKey.setUuid(newUuid);
newLog.setDataKey(newDataKey);
newLog.setScheduleTaskName("COMPLETE_TEST_TASK");
newLog.setServerName("COMPLETE_TEST_SERVER");
SysScheduleLogEntity saved = sysScheduleLogRepository.saveAndFlush(newLog);
assertNotNull(saved);
Optional<SysScheduleLogEntity> retrieved = sysScheduleLogRepository.findById(saved.getDataKey());
assertTrue(retrieved.isPresent());
SysScheduleLogEntity entity = retrieved.get();
assertEquals(newUuid, entity.getDataKey().getUuid());
assertEquals("COMPLETE_TEST_TASK", entity.getScheduleTaskName());
assertEquals("COMPLETE_TEST_SERVER", entity.getServerName());
// Cleanup
cleanupTestScheduleLog(newUuid);
}
/**
* Test: Count total schedule logs
* Verifies that repository count method works correctly
*/
@Test
void testCountScheduleLogs() {
long count = sysScheduleLogRepository.count();
assertTrue(count >= 2, "Should have at least 2 schedule logs");
}
/**
* Test: Update schedule task name
* Verifies that schedule task name field can be updated independently
*/
@Test
void testUpdateScheduleTaskName() {
Optional<SysScheduleLogEntity> found = sysScheduleLogRepository.findById(testEntity.getDataKey());
assertTrue(found.isPresent());
SysScheduleLogEntity entity = found.get();
entity.setScheduleTaskName("CHANGED_TASK_NAME");
sysScheduleLogRepository.saveAndFlush(entity);
Optional<SysScheduleLogEntity> updated = sysScheduleLogRepository.findById(testEntity.getDataKey());
assertTrue(updated.isPresent());
assertEquals("CHANGED_TASK_NAME", updated.get().getScheduleTaskName());
assertEquals("SERVER_001", updated.get().getServerName()); // Verify serverName unchanged
}
/**
* Test: Update server name
* Verifies that server name field can be updated independently
*/
@Test
void testUpdateServerName() {
Optional<SysScheduleLogEntity> found = sysScheduleLogRepository.findById(testEntity2.getDataKey());
assertTrue(found.isPresent());
SysScheduleLogEntity entity = found.get();
entity.setServerName("CHANGED_SERVER");
sysScheduleLogRepository.saveAndFlush(entity);
Optional<SysScheduleLogEntity> updated = sysScheduleLogRepository.findById(testEntity2.getDataKey());
assertTrue(updated.isPresent());
assertEquals("CHANGED_SERVER", updated.get().getServerName());
assertEquals("TEST_SCHEDULE_TASK_002", updated.get().getScheduleTaskName()); // Verify task name unchanged
}
/**
* Test: Save multiple entities
* Verifies that multiple entities can be saved and retrieved
*/
@Test
void testSaveMultipleEntities() {
String uuid3 = UUID.randomUUID().toString();
String uuid4 = UUID.randomUUID().toString();
SysScheduleLogEntity entity3 = new SysScheduleLogEntity();
SysScheduleLogEntity.DataKey key3 = new SysScheduleLogEntity.DataKey();
key3.setUuid(uuid3);
entity3.setDataKey(key3);
entity3.setScheduleTaskName("BATCH_TASK_001");
entity3.setServerName("BATCH_SERVER_001");
SysScheduleLogEntity entity4 = new SysScheduleLogEntity();
SysScheduleLogEntity.DataKey key4 = new SysScheduleLogEntity.DataKey();
key4.setUuid(uuid4);
entity4.setDataKey(key4);
entity4.setScheduleTaskName("BATCH_TASK_002");
entity4.setServerName("BATCH_SERVER_002");
sysScheduleLogRepository.saveAndFlush(entity3);
sysScheduleLogRepository.saveAndFlush(entity4);
List<SysScheduleLogEntity> all = sysScheduleLogRepository.findAll();
assertTrue(all.size() >= 4, "Should have at least 4 schedule logs after saving");
// Cleanup
cleanupTestScheduleLog(uuid3);
cleanupTestScheduleLog(uuid4);
}
}