package jnpf.elnService.impl; import jnpf.elnEntity.runtime.ElnRecordEntity; import jnpf.elnEntity.runtime.ElnRecordFieldValueEntity; import jnpf.elnEntity.runtime.ElnRecordFormulaCalculationResult; import jnpf.elnEntity.runtime.ElnRecordRepeatValueEntity; import jnpf.elnEntity.runtime.ElnRecordForms; import jnpf.elnEntity.runtime.ElnRecordRevisionEntity; import jnpf.elnEntity.runtime.ElnRecordVos; import jnpf.elnMapper.ElnRecordFieldValueMapper; import jnpf.elnMapper.ElnRecordMapper; import jnpf.elnMapper.ElnRecordRepeatValueMapper; import jnpf.elnMapper.ElnRecordRevisionMapper; import jnpf.elnService.ElnRecordFormulaCalculationService; import jnpf.lims.api.model.TestWorkItemSnapshotBatch; import jnpf.lims.api.model.TestWorkItemSnapshot; import org.junit.Test; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.assertEquals; public class ElnRecordRecalculationServiceImplTest { @Test public void protectsFullRecalculationWithTaskAccessAndRecordVersion() { ElnRecordEntity record = new ElnRecordEntity(); record.setId("record-1"); record.setJianyanXiangId("item-1"); record.setDangqianXiudingId("revision-1"); record.setFVersion(7); ElnRecordRevisionEntity revision = new ElnRecordRevisionEntity(); revision.setId("revision-1"); revision.setDianziJiluId("record-1"); revision.setBizStatus("DRAFT"); List values = Arrays.asList( calculated("result-a", "SUCCESS"), calculated("result-b", "MISSING_INPUT"), calculated("result-c", "ERROR")); AtomicInteger casCalls = new AtomicInteger(); AtomicInteger updates = new AtomicInteger(); AtomicInteger repeatUpdates = new AtomicInteger(); ElnRecordMapper recordMapper = proxy(ElnRecordMapper.class, (method, args) -> { if ("selectOne".equals(method)) return record; if ("advanceVersion".equals(method)) { assertEquals(7, args[2]); casCalls.incrementAndGet(); return 1; } return null; }); ElnRecordRevisionMapper revisionMapper = proxy( ElnRecordRevisionMapper.class, (method, args) -> "selectOne".equals(method) ? revision : null); ElnRecordFieldValueMapper valueMapper = proxy( ElnRecordFieldValueMapper.class, (method, args) -> { if ("selectList".equals(method)) return new ArrayList<>(values); if ("updateById".equals(method)) { updates.incrementAndGet(); return 1; } return null; }); ElnRecordFormulaCalculationService calculation = new ElnRecordFormulaCalculationService() { @Override public List recalculateAffected( String tenantId, ElnRecordEntity record, ElnRecordRevisionEntity revision, List values, java.util.Set changedBindingIds, String operationCode, String operatorUserId) { return Collections.emptyList(); } @Override public List recalculateAll( String tenantId, ElnRecordEntity actualRecord, ElnRecordRevisionEntity actualRevision, List actualValues, String operationCode, String operatorUserId) { assertEquals("tenant-a", tenantId); assertEquals("operation-1", operationCode); assertEquals("user-1", operatorUserId); return actualValues; } @Override public ElnRecordFormulaCalculationResult recalculateAllWithRepeats( String tenantId, ElnRecordEntity actualRecord, ElnRecordRevisionEntity actualRevision, List actualValues, String operationCode, String operatorUserId) { ElnRecordFormulaCalculationResult result = new ElnRecordFormulaCalculationResult(); result.setFieldValues(actualValues); ElnRecordRepeatValueEntity repeat = new ElnRecordRepeatValueEntity(); repeat.setJisuanZhuangtai("SUCCESS"); result.setRepeatValues(Collections.singletonList(repeat)); return result; } }; ElnRecordRepeatValueMapper repeatValueMapper = proxy( ElnRecordRepeatValueMapper.class, (method, args) -> { if ("updateById".equals(method)) { repeatUpdates.incrementAndGet(); return 1; } return null; }); ElnRecordRecalculationServiceImpl service = new ElnRecordRecalculationServiceImpl( recordMapper, revisionMapper, valueMapper, repeatValueMapper, (itemIds, properties) -> successfulTask(), calculation, () -> new ElnRecordRecalculationServiceImpl.UserContext( "tenant-a", "user-1")); ElnRecordForms.Recalculate command = new ElnRecordForms.Recalculate(); command.setExpectedRecordVersion(7); command.setOperationCode("operation-1"); ElnRecordVos.Recalculated result = service.recalculateAll("record-1", command); assertEquals(Integer.valueOf(8), result.getRecordVersion()); assertEquals(2, result.getSuccessCount()); assertEquals(1, result.getMissingInputCount()); assertEquals(1, result.getErrorCount()); assertEquals(1, casCalls.get()); assertEquals(3, updates.get()); assertEquals(1, repeatUpdates.get()); } private static ElnRecordFieldValueEntity calculated(String bindingId, String status) { ElnRecordFieldValueEntity value = new ElnRecordFieldValueEntity(); value.setMubanBangdingId(bindingId); value.setJisuanZhuangtai(status); return value; } private static TestWorkItemSnapshotBatch successfulTask() { TestWorkItemSnapshot item = new TestWorkItemSnapshot(); item.setTestWorkItemId("item-1"); item.setOutcomeCode("SUCCESS"); TestWorkItemSnapshotBatch batch = new TestWorkItemSnapshotBatch(); batch.setItems(Collections.singletonList(item)); return batch; } @SuppressWarnings("unchecked") private static T proxy(Class type, Invocation invocation) { return (T) Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, (target, method, args) -> { if (method.getDeclaringClass() == Object.class) { if ("toString".equals(method.getName())) return type.getSimpleName(); if ("hashCode".equals(method.getName())) return System.identityHashCode(target); if ("equals".equals(method.getName())) return target == args[0]; } Object result = invocation.invoke(method.getName(), args); if (result != null || !method.getReturnType().isPrimitive()) return result; if (method.getReturnType() == boolean.class) return false; return 0; }); } @FunctionalInterface private interface Invocation { Object invoke(String method, Object[] args); } }