Persist failed AI generation records
This commit is contained in:
@@ -19,7 +19,6 @@ import com.ruoyi.generator.domain.front.dto.DatabaseDesignResponse;
|
|||||||
import com.ruoyi.generator.domain.front.dto.DatabaseTableDesign;
|
import com.ruoyi.generator.domain.front.dto.DatabaseTableDesign;
|
||||||
import com.ruoyi.generator.domain.front.dto.GenerateDatabaseRequest;
|
import com.ruoyi.generator.domain.front.dto.GenerateDatabaseRequest;
|
||||||
import com.ruoyi.generator.mapper.front.FrontProjectColumnMapper;
|
import com.ruoyi.generator.mapper.front.FrontProjectColumnMapper;
|
||||||
import com.ruoyi.generator.mapper.front.FrontProjectGenerationMapper;
|
|
||||||
import com.ruoyi.generator.mapper.front.FrontProjectMapper;
|
import com.ruoyi.generator.mapper.front.FrontProjectMapper;
|
||||||
import com.ruoyi.generator.mapper.front.FrontProjectTableMapper;
|
import com.ruoyi.generator.mapper.front.FrontProjectTableMapper;
|
||||||
|
|
||||||
@@ -41,7 +40,7 @@ public class AiGenerateServiceImpl implements IAiGenerateService
|
|||||||
@Autowired
|
@Autowired
|
||||||
private FrontProjectColumnMapper frontProjectColumnMapper;
|
private FrontProjectColumnMapper frontProjectColumnMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
private FrontProjectGenerationMapper frontProjectGenerationMapper;
|
private AiGenerationRecordService generationRecordService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -63,7 +62,7 @@ public class AiGenerateServiceImpl implements IAiGenerateService
|
|||||||
generation.setResponsePayload(aiContent);
|
generation.setResponsePayload(aiContent);
|
||||||
generation.setSuccess("1");
|
generation.setSuccess("1");
|
||||||
generation.setElapsedMs(System.currentTimeMillis() - start);
|
generation.setElapsedMs(System.currentTimeMillis() - start);
|
||||||
frontProjectGenerationMapper.insertFrontProjectGeneration(generation);
|
generationRecordService.insert(generation);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
catch (RuntimeException e)
|
catch (RuntimeException e)
|
||||||
@@ -71,7 +70,7 @@ public class AiGenerateServiceImpl implements IAiGenerateService
|
|||||||
generation.setSuccess("0");
|
generation.setSuccess("0");
|
||||||
generation.setErrorMessage(e.getMessage());
|
generation.setErrorMessage(e.getMessage());
|
||||||
generation.setElapsedMs(System.currentTimeMillis() - start);
|
generation.setElapsedMs(System.currentTimeMillis() - start);
|
||||||
frontProjectGenerationMapper.insertFrontProjectGeneration(generation);
|
generationRecordService.insert(generation);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.ruoyi.generator.service.front;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import com.ruoyi.generator.domain.front.FrontProjectGeneration;
|
||||||
|
import com.ruoyi.generator.mapper.front.FrontProjectGenerationMapper;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class AiGenerationRecordService
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private FrontProjectGenerationMapper frontProjectGenerationMapper;
|
||||||
|
|
||||||
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
|
public void insert(FrontProjectGeneration generation)
|
||||||
|
{
|
||||||
|
frontProjectGenerationMapper.insertFrontProjectGeneration(generation);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,25 @@
|
|||||||
package com.ruoyi.generator.service.front;
|
package com.ruoyi.generator.service.front;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import com.ruoyi.generator.config.DeepSeekProperties;
|
import com.ruoyi.generator.config.DeepSeekProperties;
|
||||||
import com.ruoyi.generator.domain.front.FrontProject;
|
import com.ruoyi.generator.domain.front.FrontProject;
|
||||||
import com.ruoyi.generator.domain.front.FrontProjectColumn;
|
import com.ruoyi.generator.domain.front.FrontProjectColumn;
|
||||||
@@ -38,17 +46,20 @@ public class AiGenerateServiceImplTest
|
|||||||
private FrontProjectColumnMapper frontProjectColumnMapper;
|
private FrontProjectColumnMapper frontProjectColumnMapper;
|
||||||
@Mock
|
@Mock
|
||||||
private FrontProjectGenerationMapper frontProjectGenerationMapper;
|
private FrontProjectGenerationMapper frontProjectGenerationMapper;
|
||||||
|
private AiGenerationRecordService generationRecordService;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception
|
public void setUp() throws Exception
|
||||||
{
|
{
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
service = new AiGenerateServiceImpl();
|
service = new AiGenerateServiceImpl();
|
||||||
|
generationRecordService = new AiGenerationRecordService();
|
||||||
|
setField(generationRecordService, "frontProjectGenerationMapper", frontProjectGenerationMapper);
|
||||||
setField("deepSeekClient", deepSeekClient);
|
setField("deepSeekClient", deepSeekClient);
|
||||||
setField("frontProjectMapper", frontProjectMapper);
|
setField("frontProjectMapper", frontProjectMapper);
|
||||||
setField("frontProjectTableMapper", frontProjectTableMapper);
|
setField("frontProjectTableMapper", frontProjectTableMapper);
|
||||||
setField("frontProjectColumnMapper", frontProjectColumnMapper);
|
setField("frontProjectColumnMapper", frontProjectColumnMapper);
|
||||||
setField("frontProjectGenerationMapper", frontProjectGenerationMapper);
|
setField("generationRecordService", generationRecordService);
|
||||||
setField("validator", new AiDatabaseSchemaValidator());
|
setField("validator", new AiDatabaseSchemaValidator());
|
||||||
setField("ddlBuilder", new MysqlDdlBuilder());
|
setField("ddlBuilder", new MysqlDdlBuilder());
|
||||||
setField("deepSeekProperties", new DeepSeekProperties());
|
setField("deepSeekProperties", new DeepSeekProperties());
|
||||||
@@ -76,11 +87,51 @@ public class AiGenerateServiceImplTest
|
|||||||
assertTrue(response.getSql().contains("CREATE TABLE `car_info`"));
|
assertTrue(response.getSql().contains("CREATE TABLE `car_info`"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void generateDatabasePersistsFailureGenerationRecordBeforePropagatingClientFailure()
|
||||||
|
{
|
||||||
|
RuntimeException failure = new RuntimeException("DeepSeek unavailable");
|
||||||
|
when(frontProjectMapper.selectFrontProjectByUserAndId(7L, 10L)).thenReturn(project());
|
||||||
|
when(deepSeekClient.chat(anyString())).thenThrow(failure);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
service.generateDatabase(7L, 10L, request());
|
||||||
|
fail("Expected client failure");
|
||||||
|
}
|
||||||
|
catch (RuntimeException e)
|
||||||
|
{
|
||||||
|
assertSame(failure, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgumentCaptor<FrontProjectGeneration> generationCaptor = ArgumentCaptor.forClass(FrontProjectGeneration.class);
|
||||||
|
verify(frontProjectGenerationMapper).insertFrontProjectGeneration(generationCaptor.capture());
|
||||||
|
assertEquals("0", generationCaptor.getValue().getSuccess());
|
||||||
|
assertEquals("DeepSeek unavailable", generationCaptor.getValue().getErrorMessage());
|
||||||
|
verify(frontProjectColumnMapper, never()).deleteColumnsByProjectId(10L);
|
||||||
|
verify(frontProjectTableMapper, never()).deleteTablesByProjectId(10L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void generationRecordInsertUsesRequiresNewTransaction() throws Exception
|
||||||
|
{
|
||||||
|
Method method = AiGenerationRecordService.class.getDeclaredMethod("insert", FrontProjectGeneration.class);
|
||||||
|
Transactional transactional = method.getAnnotation(Transactional.class);
|
||||||
|
|
||||||
|
assertNotNull(transactional);
|
||||||
|
assertEquals(Propagation.REQUIRES_NEW, transactional.propagation());
|
||||||
|
}
|
||||||
|
|
||||||
private void setField(String name, Object value) throws Exception
|
private void setField(String name, Object value) throws Exception
|
||||||
{
|
{
|
||||||
Field field = AiGenerateServiceImpl.class.getDeclaredField(name);
|
setField(service, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setField(Object target, String name, Object value) throws Exception
|
||||||
|
{
|
||||||
|
Field field = target.getClass().getDeclaredField(name);
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
field.set(service, value);
|
field.set(target, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private FrontProject project()
|
private FrontProject project()
|
||||||
|
|||||||
Reference in New Issue
Block a user