package jnpf.elnService.impl;
|
|
import jnpf.audit.model.AuditEventDTO;
|
import jnpf.elnEntity.field.ElnFieldVersionEntity;
|
import jnpf.elnEntity.runtime.ElnRecordEntity;
|
import jnpf.elnEntity.runtime.ElnRecordFieldValueEntity;
|
import jnpf.elnEntity.runtime.ElnRecordForms;
|
import jnpf.elnEntity.runtime.ElnRecordRevisionEntity;
|
import jnpf.elnEntity.runtime.ElnRecordVos;
|
import jnpf.elnMapper.ElnFieldVersionMapper;
|
import jnpf.elnMapper.ElnRecordFieldValueMapper;
|
import jnpf.elnMapper.ElnRecordMapper;
|
import jnpf.elnMapper.ElnRecordRevisionMapper;
|
import jnpf.elnService.ElnTestWorkItemSnapshotProvider;
|
import jnpf.elnService.ElnRecordFormulaCalculationService;
|
import jnpf.elnService.ElnRecordSharedFillService;
|
import jnpf.exception.DataException;
|
import jnpf.lims.api.model.TestWorkItemSnapshotBatch;
|
import jnpf.lims.api.model.TestWorkItemSnapshot;
|
import org.junit.Test;
|
|
import java.lang.reflect.InvocationHandler;
|
import java.lang.reflect.Proxy;
|
import java.math.BigDecimal;
|
import java.util.ArrayList;
|
import java.util.Arrays;
|
import java.util.Collections;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Set;
|
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicReference;
|
|
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.fail;
|
|
public class ElnRecordSharedFillServiceImplTest {
|
|
@Test
|
public void rejectsADifferentValueWithoutExplicitOverwriteReason() {
|
ExecuteFixture fixture = new ExecuteFixture("19.00");
|
|
ElnRecordVos.SharedFilled result = fixture.service.execute(fixture.command("20.50"));
|
|
assertEquals("REJECTED", result.getTargets().get(0).getStatus());
|
assertEquals("TARGET_COMMIT_REJECTED", result.getTargets().get(0).getErrorCode());
|
assertEquals("目标字段已有不同值,必须确认覆盖并填写原因",
|
result.getTargets().get(0).getErrorMessage());
|
assertEquals(0, fixture.recordAdvances.get());
|
assertEquals(0, fixture.valueWrites.get());
|
assertEquals(0, fixture.auditEvents.size());
|
}
|
|
@Test
|
public void rejectsAChangedPreviewTokenBeforeStartingAnyTargetTransaction() {
|
ExecuteFixture fixture = new ExecuteFixture(null);
|
ElnRecordForms.SharedFillExecute command = fixture.command("20.50");
|
command.setPreviewToken("stale-preview-token");
|
|
try {
|
fixture.service.execute(command);
|
fail("changed preview token must reject the whole command");
|
} catch (DataException expected) {
|
assertEquals("批量填写预览已变化,请重新预览", expected.getMessage());
|
}
|
assertEquals(0, fixture.transactionCalls.get());
|
assertEquals(0, fixture.recordAdvances.get());
|
assertEquals(0, fixture.valueWrites.get());
|
}
|
|
@Test
|
public void revalidatesPreviewWhenRetryingAnOperationWithoutCommittedTargets() {
|
ExecuteFixture fixture = new ExecuteFixture(null);
|
ElnRecordForms.SharedFillExecute command = fixture.command("20.50");
|
command.setPreviewToken("stale-preview-token");
|
|
for (int attempt = 0; attempt < 2; attempt++) {
|
try {
|
fixture.service.execute(command);
|
fail("a retry without committed targets must revalidate its preview");
|
} catch (DataException expected) {
|
assertEquals("批量填写预览已变化,请重新预览", expected.getMessage());
|
}
|
}
|
assertEquals(0, fixture.transactionCalls.get());
|
assertEquals(0, fixture.recordAdvances.get());
|
}
|
|
@Test
|
public void rejectsAnOperationCodeLongerThanTheAuditContract() {
|
ExecuteFixture fixture = new ExecuteFixture(null);
|
ElnRecordForms.SharedFillExecute command = fixture.command("20.50");
|
command.setOperationCode(String.join("", Collections.nCopies(65, "x")));
|
|
try {
|
fixture.service.execute(command);
|
fail("an oversized operation code must be rejected before execution");
|
} catch (DataException expected) {
|
assertEquals("批量填写操作码长度不能超过64个字符", expected.getMessage());
|
}
|
assertEquals(0, fixture.transactionCalls.get());
|
}
|
|
@Test
|
public void rejectsDuplicateFieldVersionsEvenWhenTheFirstValueIsNull() {
|
ExecuteFixture fixture = new ExecuteFixture(null);
|
ElnRecordForms.SharedFillExecute command = fixture.command("20.50");
|
ElnRecordForms.SharedFillValue first = new ElnRecordForms.SharedFillValue();
|
first.setFieldVersionId("version-shared");
|
ElnRecordForms.SharedFillValue duplicate = new ElnRecordForms.SharedFillValue();
|
duplicate.setFieldVersionId("version-shared");
|
duplicate.setValue("20.50");
|
command.setValues(Arrays.asList(first, duplicate));
|
|
try {
|
fixture.service.execute(command);
|
fail("duplicate field versions must be rejected before execution");
|
} catch (DataException expected) {
|
assertEquals("批量填写字段不能重复", expected.getMessage());
|
}
|
assertEquals(0, fixture.transactionCalls.get());
|
}
|
|
@Test
|
public void continuesWithOtherTargetsAfterOneRecordVersionConflict() {
|
ExecuteFixture fixture = new ExecuteFixture(null);
|
fixture.casFailureRecordId.set("record-1");
|
|
ElnRecordVos.SharedFilled result = fixture.service.execute(
|
fixture.commandForAllTargets("20.50"));
|
|
assertEquals(2, result.getTargets().size());
|
assertEquals("REJECTED", result.getTargets().get(0).getStatus());
|
assertEquals("COMMITTED", result.getTargets().get(1).getStatus());
|
assertEquals(Integer.valueOf(6), result.getTargets().get(1).getRecordVersion());
|
assertEquals(2, fixture.transactionCalls.get());
|
assertEquals(2, fixture.recordAdvances.get());
|
assertEquals(1, fixture.valueWrites.get());
|
assertEquals(1, fixture.formulaCalls.get());
|
assertEquals(1, fixture.auditEvents.size());
|
assertEquals("record-2", fixture.auditEvents.get(0).getTargetId());
|
}
|
|
@Test
|
public void overwritesADifferentValueOnlyWithExplicitReason() {
|
ExecuteFixture fixture = new ExecuteFixture("19.00");
|
ElnRecordForms.SharedFillExecute command = fixture.command("20.50");
|
command.getTargets().get(0).setOverwrite(true);
|
command.getTargets().get(0).setOverwriteReason("环境温度复测修正");
|
|
ElnRecordVos.SharedFilled result = fixture.service.execute(command);
|
|
assertEquals("COMMITTED", result.getTargets().get(0).getStatus());
|
assertEquals(Integer.valueOf(4), result.getTargets().get(0).getRecordVersion());
|
assertEquals(1, fixture.recordAdvances.get());
|
assertEquals(1, fixture.valueWrites.get());
|
assertEquals(1, fixture.formulaCalls.get());
|
assertEquals("环境温度复测修正", fixture.auditEvents.get(0).getReason());
|
}
|
|
@Test
|
public void treatsTheSameDecimalValueAsUnchangedWithoutAdvancingTheRecord() {
|
ExecuteFixture fixture = new ExecuteFixture("20.5");
|
|
ElnRecordVos.SharedFilled result = fixture.service.execute(fixture.command("20.50"));
|
|
assertEquals(1, result.getTargets().size());
|
assertEquals("UNCHANGED", result.getTargets().get(0).getStatus());
|
assertEquals(Integer.valueOf(3), result.getTargets().get(0).getRecordVersion());
|
assertEquals(0, fixture.recordAdvances.get());
|
assertEquals(0, fixture.valueWrites.get());
|
assertEquals(0, fixture.formulaCalls.get());
|
assertEquals(1, fixture.auditEvents.size());
|
assertEquals("BIZ_ACTION", fixture.auditEvents.get(0).getEventType());
|
}
|
|
@Test
|
public void replaysACompletedOperationWithoutRepeatingAnyTargetEffect() {
|
ExecuteFixture fixture = new ExecuteFixture(null);
|
ElnRecordForms.SharedFillExecute command = fixture.command("20.50");
|
|
ElnRecordVos.SharedFilled first = fixture.service.execute(command);
|
ElnRecordVos.SharedFilled retried = fixture.service.execute(command);
|
|
assertEquals("COMMITTED", first.getTargets().get(0).getStatus());
|
assertEquals("COMMITTED", retried.getTargets().get(0).getStatus());
|
assertEquals(Integer.valueOf(4), retried.getTargets().get(0).getRecordVersion());
|
assertEquals(1, fixture.transactionCalls.get());
|
assertEquals(1, fixture.recordAdvances.get());
|
assertEquals(1, fixture.valueWrites.get());
|
assertEquals(1, fixture.formulaCalls.get());
|
assertEquals(1, fixture.auditEvents.size());
|
}
|
|
@Test
|
public void resumesAfterTheTargetCommittedBeforeTheOperationSummary() {
|
InterruptingOperationCoordinator operations =
|
new InterruptingOperationCoordinator();
|
ExecuteFixture fixture = new ExecuteFixture(null, operations);
|
ElnRecordForms.SharedFillExecute command = fixture.command("20.50");
|
|
try {
|
fixture.service.execute(command);
|
fail("the first operation summary must be interrupted");
|
} catch (DataException expected) {
|
assertEquals("模拟操作汇总中断", expected.getMessage());
|
}
|
ElnRecordVos.SharedFilled retried = fixture.service.execute(command);
|
|
assertEquals("COMMITTED", retried.getTargets().get(0).getStatus());
|
assertEquals(Integer.valueOf(4), retried.getTargets().get(0).getRecordVersion());
|
assertEquals(2, fixture.transactionCalls.get());
|
assertEquals(1, fixture.recordAdvances.get());
|
assertEquals(1, fixture.valueWrites.get());
|
assertEquals(1, fixture.formulaCalls.get());
|
assertEquals(1, fixture.auditEvents.size());
|
}
|
|
@Test
|
public void writesOneDecimalTargetAndAdvancesItsRecordOnce() {
|
Map<String, ElnRecordEntity> records = new LinkedHashMap<>();
|
records.put("item-1", record("record-1", "item-1", "revision-1", 3));
|
records.put("item-2", record("record-2", "item-2", "revision-2", 5));
|
Map<String, ElnRecordRevisionEntity> revisions = new LinkedHashMap<>();
|
revisions.put("record-1", revision("revision-1", "record-1"));
|
revisions.put("record-2", revision("revision-2", "record-2"));
|
Map<String, List<ElnRecordFieldValueEntity>> values = new LinkedHashMap<>();
|
ElnRecordFieldValueEntity selectedValue = value(
|
"value-1", "record-1", "revision-1", null);
|
values.put("record-1", Collections.singletonList(selectedValue));
|
values.put("record-2", Collections.singletonList(value(
|
"value-2", "record-2", "revision-2", null)));
|
AtomicReference<String> currentItem = new AtomicReference<>();
|
AtomicInteger recordAdvances = new AtomicInteger();
|
AtomicInteger valueWrites = new AtomicInteger();
|
ElnRecordMapper recordMapper = proxy(ElnRecordMapper.class, (ignored, method, args) -> {
|
if ("selectLiveByTestWorkItem".equals(method.getName())) {
|
currentItem.set((String) args[1]);
|
return records.get(args[1]);
|
}
|
if ("advanceVersion".equals(method.getName())) {
|
recordAdvances.incrementAndGet();
|
return 1;
|
}
|
return null;
|
});
|
ElnRecordRevisionMapper revisionMapper = proxy(
|
ElnRecordRevisionMapper.class, (ignored, method, args) ->
|
"selectOne".equals(method.getName())
|
? revisions.get(records.get(currentItem.get()).getId()) : null);
|
ElnRecordFieldValueMapper valueMapper = proxy(
|
ElnRecordFieldValueMapper.class, (ignored, method, args) -> {
|
if ("selectList".equals(method.getName())) {
|
return values.get(records.get(currentItem.get()).getId());
|
}
|
if ("updateById".equals(method.getName())) {
|
valueWrites.incrementAndGet();
|
return 1;
|
}
|
return null;
|
});
|
ElnFieldVersionMapper versionMapper = proxy(
|
ElnFieldVersionMapper.class, (ignored, method, args) ->
|
"selectOne".equals(method.getName()) ? sharedVersion() : null);
|
AtomicInteger formulaCalls = new AtomicInteger();
|
AtomicReference<Set<String>> changedBindings = new AtomicReference<>();
|
ElnRecordFormulaCalculationService calculation =
|
new ElnRecordFormulaCalculationService() {
|
@Override
|
public List<ElnRecordFieldValueEntity> recalculateAffected(
|
String tenantId, ElnRecordEntity record,
|
ElnRecordRevisionEntity revision,
|
List<ElnRecordFieldValueEntity> currentValues,
|
Set<String> changedBindingIds, String operationCode,
|
String operatorUserId) {
|
formulaCalls.incrementAndGet();
|
changedBindings.set(changedBindingIds);
|
assertEquals("shared-fill-1", operationCode);
|
return Collections.emptyList();
|
}
|
|
@Override
|
public List<ElnRecordFieldValueEntity> recalculateAll(
|
String tenantId, ElnRecordEntity record,
|
ElnRecordRevisionEntity revision,
|
List<ElnRecordFieldValueEntity> currentValues,
|
String operationCode, String operatorUserId) {
|
return Collections.emptyList();
|
}
|
};
|
List<AuditEventDTO> auditEvents = new ArrayList<>();
|
ElnRecordSharedFillService service = new ElnRecordSharedFillServiceImpl(
|
recordMapper, revisionMapper, valueMapper, versionMapper,
|
snapshots(Arrays.asList(snapshot("item-1", "project-1"),
|
snapshot("item-2", "project-1"))),
|
calculation, auditEvents::add,
|
(action, failureAudit) -> action.get(),
|
() -> new ElnRecordSharedFillServiceImpl.UserContext("tenant-a", "user-1"));
|
ElnRecordForms.SharedFillPreview previewCommand = new ElnRecordForms.SharedFillPreview();
|
previewCommand.setTestWorkItemIds(Arrays.asList("item-1", "item-2"));
|
ElnRecordVos.SharedFillPreview preview = service.preview(previewCommand);
|
ElnRecordForms.SharedFillExecute command = new ElnRecordForms.SharedFillExecute();
|
command.setTestWorkItemIds(Arrays.asList("item-1", "item-2"));
|
command.setPreviewToken(preview.getPreviewToken());
|
command.setOperationCode("shared-fill-1");
|
command.setFieldVersionId("version-shared");
|
command.setValue("20.50");
|
ElnRecordForms.SharedFillTarget target = new ElnRecordForms.SharedFillTarget();
|
target.setTestWorkItemId("item-1");
|
target.setRecordId("record-1");
|
target.setExpectedRecordVersion(3);
|
command.setTargets(Collections.singletonList(target));
|
|
ElnRecordVos.SharedFilled result = service.execute(command);
|
|
assertEquals("shared-fill-1", result.getOperationCode());
|
assertEquals(1, result.getTargets().size());
|
assertEquals(result.getTargets().get(0).getErrorMessage(),
|
"COMMITTED", result.getTargets().get(0).getStatus());
|
assertEquals(Integer.valueOf(4), result.getTargets().get(0).getRecordVersion());
|
assertEquals("20.50", selectedValue.getZhiWenben());
|
assertEquals(new BigDecimal("20.50"), selectedValue.getZhiShuzhi());
|
assertEquals("MANUAL", selectedValue.getZhiLaiyuan());
|
assertEquals(1, recordAdvances.get());
|
assertEquals(1, valueWrites.get());
|
assertEquals(1, formulaCalls.get());
|
assertEquals(Collections.singleton("binding-shared"), changedBindings.get());
|
assertEquals(1, auditEvents.size());
|
assertEquals("ELN_RECORD_SHARED_FILL", auditEvents.get(0).getActionCode());
|
assertEquals("shared-fill-1:record-1", auditEvents.get(0).getClientEventId());
|
}
|
|
@Test
|
public void writesMultipleFieldsInOneTargetVersionAndDocumentUpdate() {
|
Map<String, ElnRecordEntity> records = new LinkedHashMap<>();
|
records.put("item-1", record("record-1", "item-1", "revision-1", 3));
|
records.put("item-2", record("record-2", "item-2", "revision-2", 5));
|
Map<String, ElnRecordRevisionEntity> revisions = new LinkedHashMap<>();
|
revisions.put("record-1", revision("revision-1", "record-1"));
|
revisions.put("record-2", revision("revision-2", "record-2"));
|
Map<String, List<ElnRecordFieldValueEntity>> values = new LinkedHashMap<>();
|
ElnRecordFieldValueEntity temperature = value(
|
"value-temperature", "record-1", "revision-1",
|
"binding-temperature", "definition-temperature",
|
"environment_temperature", "version-temperature", null);
|
ElnRecordFieldValueEntity pressure = value(
|
"value-pressure", "record-1", "revision-1",
|
"binding-pressure", "definition-pressure",
|
"environment_pressure", "version-pressure", null);
|
values.put("record-1", Arrays.asList(temperature, pressure));
|
values.put("record-2", Arrays.asList(
|
value("value-temperature-2", "record-2", "revision-2",
|
"binding-temperature-2", "definition-temperature",
|
"environment_temperature", "version-temperature", null),
|
value("value-pressure-2", "record-2", "revision-2",
|
"binding-pressure-2", "definition-pressure",
|
"environment_pressure", "version-pressure", null)));
|
AtomicReference<String> currentItem = new AtomicReference<>();
|
AtomicInteger recordAdvances = new AtomicInteger();
|
AtomicInteger valueWrites = new AtomicInteger();
|
ElnRecordMapper recordMapper = proxy(ElnRecordMapper.class, (ignored, method, args) -> {
|
if ("selectLiveByTestWorkItem".equals(method.getName())) {
|
currentItem.set((String) args[1]);
|
return records.get(args[1]);
|
}
|
if ("advanceVersion".equals(method.getName())) {
|
recordAdvances.incrementAndGet();
|
return 1;
|
}
|
return null;
|
});
|
ElnRecordRevisionMapper revisionMapper = proxy(
|
ElnRecordRevisionMapper.class, (ignored, method, args) ->
|
"selectOne".equals(method.getName())
|
? revisions.get(records.get(currentItem.get()).getId()) : null);
|
ElnRecordFieldValueMapper valueMapper = proxy(
|
ElnRecordFieldValueMapper.class, (ignored, method, args) -> {
|
if ("selectList".equals(method.getName())) {
|
return values.get(records.get(currentItem.get()).getId());
|
}
|
if ("updateById".equals(method.getName())) {
|
valueWrites.incrementAndGet();
|
return 1;
|
}
|
return null;
|
});
|
AtomicInteger versionReads = new AtomicInteger();
|
ElnFieldVersionMapper versionMapper = proxy(
|
ElnFieldVersionMapper.class, (ignored, method, args) -> {
|
if (!"selectOne".equals(method.getName())) return null;
|
return versionReads.getAndIncrement() % 2 == 0
|
? sharedVersion("version-temperature", "definition-temperature", "环境温度")
|
: sharedVersion("version-pressure", "definition-pressure", "环境压力");
|
});
|
AtomicInteger formulaCalls = new AtomicInteger();
|
AtomicReference<Set<String>> changedBindings = new AtomicReference<>();
|
ElnRecordFormulaCalculationService calculation = new ElnRecordFormulaCalculationService() {
|
@Override
|
public List<ElnRecordFieldValueEntity> recalculateAffected(
|
String tenantId, ElnRecordEntity record,
|
ElnRecordRevisionEntity revision,
|
List<ElnRecordFieldValueEntity> currentValues,
|
Set<String> changedBindingIds, String operationCode,
|
String operatorUserId) {
|
formulaCalls.incrementAndGet();
|
changedBindings.set(changedBindingIds);
|
return Collections.emptyList();
|
}
|
|
@Override
|
public List<ElnRecordFieldValueEntity> recalculateAll(
|
String tenantId, ElnRecordEntity record,
|
ElnRecordRevisionEntity revision,
|
List<ElnRecordFieldValueEntity> currentValues,
|
String operationCode, String operatorUserId) {
|
return Collections.emptyList();
|
}
|
};
|
AtomicInteger documentUpdates = new AtomicInteger();
|
AtomicInteger documentValueCount = new AtomicInteger();
|
List<AuditEventDTO> auditEvents = new ArrayList<>();
|
ElnRecordSharedFillService service = new ElnRecordSharedFillServiceImpl(
|
recordMapper, revisionMapper, valueMapper, versionMapper,
|
snapshots(Arrays.asList(snapshot("item-1", "project-1"),
|
snapshot("item-2", "project-1"))),
|
calculation, auditEvents::add,
|
(action, failureAudit) -> action.get(),
|
(tenantId, record, revision, changedValues, operationCode) -> {
|
documentUpdates.incrementAndGet();
|
documentValueCount.set(changedValues.size());
|
},
|
() -> new ElnRecordSharedFillServiceImpl.UserContext("tenant-a", "user-1"));
|
ElnRecordForms.SharedFillPreview previewCommand = new ElnRecordForms.SharedFillPreview();
|
previewCommand.setTestWorkItemIds(Arrays.asList("item-1", "item-2"));
|
ElnRecordVos.SharedFillPreview preview = service.preview(previewCommand);
|
ElnRecordForms.SharedFillExecute command = new ElnRecordForms.SharedFillExecute();
|
command.setTestWorkItemIds(Arrays.asList("item-1", "item-2"));
|
command.setPreviewToken(preview.getPreviewToken());
|
command.setOperationCode("shared-fill-multiple");
|
ElnRecordForms.SharedFillValue temperatureCommand =
|
new ElnRecordForms.SharedFillValue();
|
temperatureCommand.setFieldVersionId("version-temperature");
|
temperatureCommand.setValue("20.50");
|
ElnRecordForms.SharedFillValue pressureCommand =
|
new ElnRecordForms.SharedFillValue();
|
pressureCommand.setFieldVersionId("version-pressure");
|
pressureCommand.setValue("101.325");
|
command.setValues(Arrays.asList(temperatureCommand, pressureCommand));
|
ElnRecordForms.SharedFillTarget target = new ElnRecordForms.SharedFillTarget();
|
target.setTestWorkItemId("item-1");
|
target.setRecordId("record-1");
|
target.setExpectedRecordVersion(3);
|
command.setTargets(Collections.singletonList(target));
|
|
ElnRecordVos.SharedFilled result = service.execute(command);
|
|
assertEquals("COMMITTED", result.getTargets().get(0).getStatus());
|
assertEquals(Integer.valueOf(4), result.getTargets().get(0).getRecordVersion());
|
assertEquals("20.50", temperature.getZhiWenben());
|
assertEquals("101.325", pressure.getZhiWenben());
|
assertEquals(1, recordAdvances.get());
|
assertEquals(2, valueWrites.get());
|
assertEquals(1, formulaCalls.get());
|
assertEquals(new java.util.LinkedHashSet<>(Arrays.asList(
|
"binding-temperature", "binding-pressure")), changedBindings.get());
|
assertEquals(1, documentUpdates.get());
|
assertEquals(2, documentValueCount.get());
|
assertEquals(1, auditEvents.size());
|
assertTrue(auditEvents.get(0).getFieldDiffs().contains("version-temperature"));
|
assertTrue(auditEvents.get(0).getFieldDiffs().contains("version-pressure"));
|
}
|
|
@Test
|
public void previewsTheCommonSharedFieldAndCurrentValuesWithoutWriting() {
|
Map<String, ElnRecordEntity> records = new LinkedHashMap<>();
|
records.put("item-1", record("record-1", "item-1", "revision-1", 3));
|
records.put("item-2", record("record-2", "item-2", "revision-2", 5));
|
List<ElnRecordRevisionEntity> revisions = Arrays.asList(
|
revision("revision-1", "record-1"), revision("revision-2", "record-2"));
|
ElnRecordFieldValueEntity untouched = value(
|
"value-1", "record-1", "revision-1", null);
|
untouched.setZhiLaiyuan(null);
|
List<List<ElnRecordFieldValueEntity>> values = Arrays.asList(
|
Collections.singletonList(untouched),
|
Collections.singletonList(value("value-2", "record-2", "revision-2", "21")));
|
ElnFieldVersionEntity sharedVersion = sharedVersion();
|
AtomicInteger revisionReads = new AtomicInteger();
|
AtomicInteger valueReads = new AtomicInteger();
|
AtomicInteger writes = new AtomicInteger();
|
ElnRecordMapper recordMapper = proxy(ElnRecordMapper.class, (ignored, method, args) -> {
|
if ("selectLiveByTestWorkItem".equals(method.getName())) return records.get(args[1]);
|
countWrite(method.getName(), writes);
|
return null;
|
});
|
ElnRecordRevisionMapper revisionMapper = proxy(ElnRecordRevisionMapper.class, (ignored, method, args) -> {
|
if ("selectOne".equals(method.getName())) return revisions.get(revisionReads.getAndIncrement());
|
countWrite(method.getName(), writes);
|
return null;
|
});
|
ElnRecordFieldValueMapper valueMapper = proxy(ElnRecordFieldValueMapper.class, (ignored, method, args) -> {
|
if ("selectList".equals(method.getName())) return values.get(valueReads.getAndIncrement());
|
countWrite(method.getName(), writes);
|
return null;
|
});
|
ElnFieldVersionMapper versionMapper = proxy(ElnFieldVersionMapper.class, (ignored, method, args) -> {
|
if ("selectOne".equals(method.getName())) return sharedVersion;
|
countWrite(method.getName(), writes);
|
return null;
|
});
|
ElnTestWorkItemSnapshotProvider taskProvider = new ElnTestWorkItemSnapshotProvider() {
|
@Override
|
public TestWorkItemSnapshotBatch resolve(
|
List<String> testWorkItemIds, List<String> properties) {
|
throw new AssertionError("必须使用显式负责人快照接口");
|
}
|
|
@Override
|
public TestWorkItemSnapshotBatch resolveAsActor(
|
String tenantId, String userId,
|
List<String> testWorkItemIds, List<String> properties) {
|
assertEquals("tenant-a", tenantId);
|
assertEquals("user-1", userId);
|
assertEquals(Arrays.asList("item-1", "item-2"), testWorkItemIds);
|
assertEquals(Collections.emptyList(), properties);
|
TestWorkItemSnapshot first =
|
snapshot("item-1", null, "project-1-code");
|
first.setTestDefinitionName("炽灼残渣");
|
TestWorkItemSnapshot second =
|
snapshot("item-2", null, "project-1-code");
|
second.setTestDefinitionName("炽灼残渣");
|
TestWorkItemSnapshotBatch batch = new TestWorkItemSnapshotBatch();
|
batch.setItems(Arrays.asList(first, second));
|
return batch;
|
}
|
};
|
ElnRecordSharedFillService service = new ElnRecordSharedFillServiceImpl(
|
recordMapper, revisionMapper, valueMapper, versionMapper, taskProvider,
|
() -> new ElnRecordSharedFillServiceImpl.UserContext("tenant-a", "user-1"));
|
|
ElnRecordForms.SharedFillPreview command = new ElnRecordForms.SharedFillPreview();
|
command.setTestWorkItemIds(Arrays.asList("item-1", "item-2"));
|
ElnRecordVos.SharedFillPreview result = service.preview(command);
|
|
assertEquals(null, result.getTestDefinitionId());
|
assertEquals("project-1-code", result.getTestDefinitionCode());
|
assertEquals("炽灼残渣", result.getTestDefinitionName());
|
assertEquals(64, result.getPreviewToken().length());
|
assertEquals(1, result.getFields().size());
|
assertEquals("version-shared", result.getFields().get(0).getFieldVersionId());
|
assertEquals("environment_temperature", result.getFields().get(0).getFieldCode());
|
assertEquals("环境温度", result.getFields().get(0).getFieldName());
|
assertTrue(result.getFields().get(0).isConflictingValues());
|
assertEquals(Arrays.asList("item-1", "item-2"),
|
result.getFields().get(0).getTargetTestWorkItemIds());
|
assertEquals(Collections.singletonList("item-2"),
|
result.getFields().get(0).getDefaultExcludedTestWorkItemIds());
|
assertEquals(2, result.getTargets().size());
|
assertEquals("炽灼残渣", result.getTargets().get(0).getTestWorkItemName());
|
assertEquals("炽灼残渣", result.getTargets().get(1).getTestWorkItemName());
|
assertTrue(result.getTargets().get(0).isEligible());
|
assertEquals("record-1", result.getTargets().get(0).getRecordId());
|
assertEquals(Integer.valueOf(3), result.getTargets().get(0).getRecordVersion());
|
assertTrue(result.getTargets().get(0).getCurrentValues().containsKey("version-shared"));
|
assertEquals(null, result.getTargets().get(0).getCurrentValues().get("version-shared"));
|
assertEquals("21", result.getTargets().get(1).getCurrentValues().get("version-shared"));
|
assertEquals(0, writes.get());
|
}
|
|
@Test
|
public void rejectsSharedFillWhenProjectIdsMatchButCodesDiffer() {
|
ElnRecordSharedFillService service = new ElnRecordSharedFillServiceImpl(
|
null, null, null, null,
|
snapshots(Arrays.asList(
|
snapshot("item-1", "project-1", "project-code-1"),
|
snapshot("item-2", "project-1", "project-code-2"))),
|
() -> new ElnRecordSharedFillServiceImpl.UserContext("tenant-a", "user-1"));
|
ElnRecordForms.SharedFillPreview command = new ElnRecordForms.SharedFillPreview();
|
command.setTestWorkItemIds(Arrays.asList("item-1", "item-2"));
|
|
try {
|
service.preview(command);
|
fail("项目编码不一致时必须拒绝批量填写");
|
} catch (DataException expected) {
|
assertEquals("批量填写只允许选择同一检验项目", expected.getMessage());
|
}
|
}
|
|
@Test
|
public void reportsAnIneligibleTargetWithoutDroppingTheBatchOrReadingItsRecord() {
|
AtomicInteger recordReads = new AtomicInteger();
|
ElnRecordMapper recordMapper = proxy(ElnRecordMapper.class, (ignored, method, args) -> {
|
if ("selectLiveByTestWorkItem".equals(method.getName())) {
|
recordReads.incrementAndGet();
|
return record("record-1", "item-1", "revision-1", 3);
|
}
|
return null;
|
});
|
ElnRecordRevisionMapper revisionMapper = proxy(ElnRecordRevisionMapper.class,
|
(ignored, method, args) -> "selectOne".equals(method.getName())
|
? revision("revision-1", "record-1") : null);
|
ElnRecordFieldValueMapper valueMapper = proxy(ElnRecordFieldValueMapper.class,
|
(ignored, method, args) -> "selectList".equals(method.getName())
|
? Collections.singletonList(value(
|
"value-1", "record-1", "revision-1", "20")) : null);
|
ElnFieldVersionMapper versionMapper = proxy(ElnFieldVersionMapper.class,
|
(ignored, method, args) -> "selectOne".equals(method.getName())
|
? sharedVersion() : null);
|
ElnTestWorkItemSnapshotProvider taskProvider = new ElnTestWorkItemSnapshotProvider() {
|
@Override
|
public TestWorkItemSnapshotBatch resolve(
|
List<String> testWorkItemIds, List<String> properties) {
|
throw new AssertionError("must use actor snapshot");
|
}
|
|
@Override
|
public TestWorkItemSnapshotBatch resolveAsActor(
|
String tenantId, String userId,
|
List<String> testWorkItemIds, List<String> properties) {
|
TestWorkItemSnapshot allowed = snapshot("item-1", "project-1");
|
TestWorkItemSnapshot forbidden = snapshot("item-2", null);
|
forbidden.setOutcomeCode("NOT_FOUND");
|
forbidden.setReason("检验项不存在或无权访问");
|
TestWorkItemSnapshotBatch batch = new TestWorkItemSnapshotBatch();
|
batch.setItems(Arrays.asList(allowed, forbidden));
|
return batch;
|
}
|
};
|
ElnRecordSharedFillService service = new ElnRecordSharedFillServiceImpl(
|
recordMapper, revisionMapper, valueMapper, versionMapper, taskProvider,
|
() -> new ElnRecordSharedFillServiceImpl.UserContext("tenant-a", "user-1"));
|
ElnRecordForms.SharedFillPreview command = new ElnRecordForms.SharedFillPreview();
|
command.setTestWorkItemIds(Arrays.asList("item-1", "item-2"));
|
|
ElnRecordVos.SharedFillPreview result = service.preview(command);
|
|
assertEquals(2, result.getTargets().size());
|
assertTrue(result.getTargets().get(0).isEligible());
|
ElnRecordVos.SharedTarget rejected = result.getTargets().get(1);
|
assertFalse(rejected.isEligible());
|
assertEquals("NOT_FOUND", rejected.getErrorCode());
|
assertEquals("检验项不存在或无权访问", rejected.getErrorMessage());
|
assertEquals(1, recordReads.get());
|
}
|
|
@Test
|
public void reportsAMissingRecordAsAnIneligibleTarget() {
|
ElnRecordMapper recordMapper = proxy(ElnRecordMapper.class, (ignored, method, args) -> {
|
if (!"selectLiveByTestWorkItem".equals(method.getName())) return null;
|
return "item-1".equals(args[1])
|
? record("record-1", "item-1", "revision-1", 3) : null;
|
});
|
ElnRecordRevisionMapper revisionMapper = proxy(ElnRecordRevisionMapper.class,
|
(ignored, method, args) -> "selectOne".equals(method.getName())
|
? revision("revision-1", "record-1") : null);
|
ElnRecordFieldValueMapper valueMapper = proxy(ElnRecordFieldValueMapper.class,
|
(ignored, method, args) -> "selectList".equals(method.getName())
|
? Collections.singletonList(value(
|
"value-1", "record-1", "revision-1", "20")) : null);
|
ElnFieldVersionMapper versionMapper = proxy(ElnFieldVersionMapper.class,
|
(ignored, method, args) -> "selectOne".equals(method.getName())
|
? sharedVersion() : null);
|
ElnTestWorkItemSnapshotProvider taskProvider = snapshots(Arrays.asList(
|
snapshot("item-1", "project-1"), snapshot("item-2", "project-1")));
|
ElnRecordSharedFillService service = new ElnRecordSharedFillServiceImpl(
|
recordMapper, revisionMapper, valueMapper, versionMapper, taskProvider,
|
() -> new ElnRecordSharedFillServiceImpl.UserContext("tenant-a", "user-1"));
|
ElnRecordForms.SharedFillPreview command = new ElnRecordForms.SharedFillPreview();
|
command.setTestWorkItemIds(Arrays.asList("item-1", "item-2"));
|
|
ElnRecordVos.SharedFillPreview result = service.preview(command);
|
|
assertTrue(result.getTargets().get(0).isEligible());
|
ElnRecordVos.SharedTarget missing = result.getTargets().get(1);
|
assertFalse(missing.isEligible());
|
assertEquals("RECORD_NOT_FOUND", missing.getErrorCode());
|
assertEquals("检验项电子记录不存在", missing.getErrorMessage());
|
}
|
|
@Test
|
public void reportsANonDraftRevisionWithItsRecordIdentity() {
|
Map<String, ElnRecordEntity> records = new LinkedHashMap<>();
|
records.put("item-1", record("record-1", "item-1", "revision-1", 3));
|
records.put("item-2", record("record-2", "item-2", "revision-2", 5));
|
ElnRecordRevisionEntity historical = revision("revision-2", "record-2");
|
historical.setBizStatus("HISTORICAL");
|
List<ElnRecordRevisionEntity> revisions = Arrays.asList(
|
revision("revision-1", "record-1"), historical);
|
AtomicInteger revisionReads = new AtomicInteger();
|
ElnRecordMapper recordMapper = proxy(ElnRecordMapper.class,
|
(ignored, method, args) -> "selectLiveByTestWorkItem".equals(method.getName())
|
? records.get(args[1]) : null);
|
ElnRecordRevisionMapper revisionMapper = proxy(ElnRecordRevisionMapper.class,
|
(ignored, method, args) -> "selectOne".equals(method.getName())
|
? revisions.get(revisionReads.getAndIncrement()) : null);
|
ElnRecordFieldValueMapper valueMapper = proxy(ElnRecordFieldValueMapper.class,
|
(ignored, method, args) -> "selectList".equals(method.getName())
|
? Collections.singletonList(value(
|
"value-1", "record-1", "revision-1", "20")) : null);
|
ElnFieldVersionMapper versionMapper = proxy(ElnFieldVersionMapper.class,
|
(ignored, method, args) -> "selectOne".equals(method.getName())
|
? sharedVersion() : null);
|
ElnRecordSharedFillService service = new ElnRecordSharedFillServiceImpl(
|
recordMapper, revisionMapper, valueMapper, versionMapper,
|
snapshots(Arrays.asList(snapshot("item-1", "project-1"),
|
snapshot("item-2", "project-1"))),
|
() -> new ElnRecordSharedFillServiceImpl.UserContext("tenant-a", "user-1"));
|
ElnRecordForms.SharedFillPreview command = new ElnRecordForms.SharedFillPreview();
|
command.setTestWorkItemIds(Arrays.asList("item-1", "item-2"));
|
|
ElnRecordVos.SharedFillPreview result = service.preview(command);
|
|
ElnRecordVos.SharedTarget rejected = result.getTargets().get(1);
|
assertFalse(rejected.isEligible());
|
assertEquals("REVISION_NOT_DRAFT", rejected.getErrorCode());
|
assertEquals("电子记录当前修订不可批量填写", rejected.getErrorMessage());
|
assertEquals("record-2", rejected.getRecordId());
|
assertEquals("revision-2", rejected.getRevisionId());
|
assertEquals(Integer.valueOf(5), rejected.getRecordVersion());
|
}
|
|
@Test
|
public void rejectsDuplicateTestWorkItemsBeforeReadingUserOrLimsContext() {
|
ElnRecordSharedFillService service = new ElnRecordSharedFillServiceImpl(
|
null, null, null, null, null,
|
() -> {
|
throw new AssertionError("invalid input must be rejected first");
|
});
|
ElnRecordForms.SharedFillPreview command = new ElnRecordForms.SharedFillPreview();
|
command.setTestWorkItemIds(Arrays.asList("item-1", "item-1", "item-2"));
|
|
try {
|
service.preview(command);
|
fail("duplicate test work items must be rejected");
|
} catch (DataException expected) {
|
assertEquals("批量填写检验项不能重复", expected.getMessage());
|
}
|
}
|
|
@Test
|
public void groupsTargetsByTheirExactSharedFieldVersion() {
|
Map<String, ElnRecordEntity> records = new LinkedHashMap<>();
|
records.put("item-1", record("record-1", "item-1", "revision-1", 3));
|
records.put("item-2", record("record-2", "item-2", "revision-2", 5));
|
List<ElnRecordRevisionEntity> revisions = Arrays.asList(
|
revision("revision-1", "record-1"), revision("revision-2", "record-2"));
|
ElnRecordFieldValueEntity first = value(
|
"value-1", "record-1", "revision-1", "20");
|
ElnRecordFieldValueEntity second = value(
|
"value-2", "record-2", "revision-2", "21");
|
second.setZiduanBanbenId("version-shared-v2");
|
ElnFieldVersionEntity version1 = sharedVersion();
|
ElnFieldVersionEntity version2 = sharedVersion();
|
version2.setId("version-shared-v2");
|
AtomicInteger revisionReads = new AtomicInteger();
|
AtomicInteger valueReads = new AtomicInteger();
|
AtomicInteger versionReads = new AtomicInteger();
|
ElnRecordMapper recordMapper = proxy(ElnRecordMapper.class,
|
(ignored, method, args) -> "selectLiveByTestWorkItem".equals(method.getName())
|
? records.get(args[1]) : null);
|
ElnRecordRevisionMapper revisionMapper = proxy(ElnRecordRevisionMapper.class,
|
(ignored, method, args) -> "selectOne".equals(method.getName())
|
? revisions.get(revisionReads.getAndIncrement()) : null);
|
List<List<ElnRecordFieldValueEntity>> values = Arrays.asList(
|
Collections.singletonList(first), Collections.singletonList(second));
|
ElnRecordFieldValueMapper valueMapper = proxy(ElnRecordFieldValueMapper.class,
|
(ignored, method, args) -> "selectList".equals(method.getName())
|
? values.get(valueReads.getAndIncrement()) : null);
|
List<ElnFieldVersionEntity> versions = Arrays.asList(version1, version2);
|
ElnFieldVersionMapper versionMapper = proxy(ElnFieldVersionMapper.class,
|
(ignored, method, args) -> "selectOne".equals(method.getName())
|
? versions.get(versionReads.getAndIncrement()) : null);
|
ElnRecordSharedFillService service = new ElnRecordSharedFillServiceImpl(
|
recordMapper, revisionMapper, valueMapper, versionMapper,
|
snapshots(Arrays.asList(snapshot("item-1", "project-1"),
|
snapshot("item-2", "project-1"))),
|
() -> new ElnRecordSharedFillServiceImpl.UserContext("tenant-a", "user-1"));
|
ElnRecordForms.SharedFillPreview command = new ElnRecordForms.SharedFillPreview();
|
command.setTestWorkItemIds(Arrays.asList("item-1", "item-2"));
|
|
ElnRecordVos.SharedFillPreview result = service.preview(command);
|
|
assertEquals(2, result.getFields().size());
|
assertEquals("version-shared", result.getFields().get(0).getFieldVersionId());
|
assertEquals(Collections.singletonList("item-1"),
|
result.getFields().get(0).getTargetTestWorkItemIds());
|
assertEquals("version-shared-v2", result.getFields().get(1).getFieldVersionId());
|
assertEquals(Collections.singletonList("item-2"),
|
result.getFields().get(1).getTargetTestWorkItemIds());
|
assertEquals("20", result.getTargets().get(0).getCurrentValues()
|
.get("version-shared"));
|
assertEquals("21", result.getTargets().get(1).getCurrentValues()
|
.get("version-shared-v2"));
|
}
|
|
private static ElnRecordEntity record(
|
String id, String testWorkItemId, String revisionId, int version) {
|
ElnRecordEntity value = new ElnRecordEntity();
|
value.setId(id);
|
value.setJianyanXiangId(testWorkItemId);
|
value.setDangqianXiudingId(revisionId);
|
value.setMubanId("template-1");
|
value.setFTenantId("tenant-a");
|
value.setFVersion(version);
|
value.setFDeleteMark(0);
|
return value;
|
}
|
|
private static final class ExecuteFixture {
|
private final AtomicInteger recordAdvances = new AtomicInteger();
|
private final AtomicInteger valueWrites = new AtomicInteger();
|
private final AtomicInteger formulaCalls = new AtomicInteger();
|
private final AtomicInteger transactionCalls = new AtomicInteger();
|
private final AtomicReference<String> casFailureRecordId = new AtomicReference<>();
|
private final List<AuditEventDTO> auditEvents = new ArrayList<>();
|
private final ElnRecordSharedFillService service;
|
|
private ExecuteFixture(String currentValue) {
|
this(currentValue,
|
new ElnRecordSharedFillServiceImpl.InMemoryOperationCoordinator());
|
}
|
|
private ExecuteFixture(
|
String currentValue,
|
ElnRecordSharedFillServiceImpl.OperationCoordinator operationCoordinator) {
|
Map<String, ElnRecordEntity> records = new LinkedHashMap<>();
|
records.put("item-1", record("record-1", "item-1", "revision-1", 3));
|
records.put("item-2", record("record-2", "item-2", "revision-2", 5));
|
Map<String, ElnRecordRevisionEntity> revisions = new LinkedHashMap<>();
|
revisions.put("record-1", revision("revision-1", "record-1"));
|
revisions.put("record-2", revision("revision-2", "record-2"));
|
Map<String, List<ElnRecordFieldValueEntity>> values = new LinkedHashMap<>();
|
values.put("record-1", Collections.singletonList(value(
|
"value-1", "record-1", "revision-1", currentValue)));
|
values.put("record-2", Collections.singletonList(value(
|
"value-2", "record-2", "revision-2", currentValue)));
|
AtomicReference<String> currentItem = new AtomicReference<>();
|
ElnRecordMapper recordMapper = proxy(ElnRecordMapper.class,
|
(ignored, method, args) -> {
|
if ("selectLiveByTestWorkItem".equals(method.getName())) {
|
currentItem.set((String) args[1]);
|
return records.get(args[1]);
|
}
|
if ("advanceVersion".equals(method.getName())) {
|
recordAdvances.incrementAndGet();
|
return args[1].equals(casFailureRecordId.get()) ? 0 : 1;
|
}
|
return null;
|
});
|
ElnRecordRevisionMapper revisionMapper = proxy(
|
ElnRecordRevisionMapper.class, (ignored, method, args) ->
|
"selectOne".equals(method.getName())
|
? revisions.get(records.get(currentItem.get()).getId()) : null);
|
ElnRecordFieldValueMapper valueMapper = proxy(
|
ElnRecordFieldValueMapper.class, (ignored, method, args) -> {
|
if ("selectList".equals(method.getName())) {
|
return values.get(records.get(currentItem.get()).getId());
|
}
|
if ("updateById".equals(method.getName())) {
|
valueWrites.incrementAndGet();
|
return 1;
|
}
|
return null;
|
});
|
ElnFieldVersionMapper versionMapper = proxy(
|
ElnFieldVersionMapper.class, (ignored, method, args) ->
|
"selectOne".equals(method.getName()) ? sharedVersion() : null);
|
ElnRecordFormulaCalculationService calculation =
|
new ElnRecordFormulaCalculationService() {
|
@Override
|
public List<ElnRecordFieldValueEntity> recalculateAffected(
|
String tenantId, ElnRecordEntity record,
|
ElnRecordRevisionEntity revision,
|
List<ElnRecordFieldValueEntity> currentValues,
|
Set<String> changedBindingIds, String operationCode,
|
String operatorUserId) {
|
formulaCalls.incrementAndGet();
|
return Collections.emptyList();
|
}
|
|
@Override
|
public List<ElnRecordFieldValueEntity> recalculateAll(
|
String tenantId, ElnRecordEntity record,
|
ElnRecordRevisionEntity revision,
|
List<ElnRecordFieldValueEntity> currentValues,
|
String operationCode, String operatorUserId) {
|
return Collections.emptyList();
|
}
|
};
|
service = new ElnRecordSharedFillServiceImpl(
|
recordMapper, revisionMapper, valueMapper, versionMapper,
|
snapshots(Arrays.asList(snapshot("item-1", "project-1"),
|
snapshot("item-2", "project-1"))),
|
calculation, auditEvents::add,
|
(action, failureAudit) -> {
|
transactionCalls.incrementAndGet();
|
return action.get();
|
},
|
(tenantId, record, revision, changedValues, operationCode) -> { },
|
operationCoordinator,
|
() -> new ElnRecordSharedFillServiceImpl.UserContext(
|
"tenant-a", "user-1"));
|
}
|
|
private ElnRecordForms.SharedFillExecute command(String newValue) {
|
ElnRecordForms.SharedFillPreview previewCommand =
|
new ElnRecordForms.SharedFillPreview();
|
previewCommand.setTestWorkItemIds(Arrays.asList("item-1", "item-2"));
|
ElnRecordVos.SharedFillPreview preview = service.preview(previewCommand);
|
ElnRecordForms.SharedFillExecute command =
|
new ElnRecordForms.SharedFillExecute();
|
command.setTestWorkItemIds(Arrays.asList("item-1", "item-2"));
|
command.setPreviewToken(preview.getPreviewToken());
|
command.setOperationCode("shared-fill-1");
|
command.setFieldVersionId("version-shared");
|
command.setValue(newValue);
|
ElnRecordForms.SharedFillTarget target =
|
new ElnRecordForms.SharedFillTarget();
|
target.setTestWorkItemId("item-1");
|
target.setRecordId("record-1");
|
target.setExpectedRecordVersion(3);
|
command.setTargets(Collections.singletonList(target));
|
return command;
|
}
|
|
private ElnRecordForms.SharedFillExecute commandForAllTargets(String newValue) {
|
ElnRecordForms.SharedFillExecute command = command(newValue);
|
ElnRecordForms.SharedFillTarget second =
|
new ElnRecordForms.SharedFillTarget();
|
second.setTestWorkItemId("item-2");
|
second.setRecordId("record-2");
|
second.setExpectedRecordVersion(5);
|
command.setTargets(Arrays.asList(command.getTargets().get(0), second));
|
return command;
|
}
|
}
|
|
private static final class InterruptingOperationCoordinator
|
implements ElnRecordSharedFillServiceImpl.OperationCoordinator {
|
private final Map<String, ElnRecordVos.SharedFillTargetResult> targets =
|
new LinkedHashMap<>();
|
private boolean started;
|
private boolean interrupted;
|
private ElnRecordVos.SharedFilled completed;
|
|
@Override
|
public ElnRecordSharedFillServiceImpl.OperationStart begin(
|
String tenantId, String userId, String operationCode,
|
String requestDigest) {
|
if (completed != null) {
|
return ElnRecordSharedFillServiceImpl.OperationStart.replay(completed);
|
}
|
if (!started) {
|
started = true;
|
return ElnRecordSharedFillServiceImpl.OperationStart.fresh();
|
}
|
return ElnRecordSharedFillServiceImpl.OperationStart.resuming();
|
}
|
|
@Override
|
public ElnRecordVos.SharedFillTargetResult reserveTarget(
|
String tenantId, String userId, String operationCode,
|
ElnRecordForms.SharedFillTarget target) {
|
return targets.get(target.getTestWorkItemId());
|
}
|
|
@Override
|
public void completeTarget(
|
String tenantId, String userId, String operationCode,
|
ElnRecordForms.SharedFillTarget target,
|
ElnRecordVos.SharedFillTargetResult result) {
|
targets.put(target.getTestWorkItemId(), result);
|
}
|
|
@Override
|
public ElnRecordVos.SharedFilled complete(
|
String tenantId, String userId, String operationCode,
|
String requestDigest, ElnRecordVos.SharedFilled result) {
|
if (!interrupted) {
|
interrupted = true;
|
throw new DataException("模拟操作汇总中断");
|
}
|
completed = result;
|
return result;
|
}
|
}
|
|
private static ElnRecordRevisionEntity revision(String id, String recordId) {
|
ElnRecordRevisionEntity value = new ElnRecordRevisionEntity();
|
value.setId(id);
|
value.setDianziJiluId(recordId);
|
value.setBizStatus("DRAFT");
|
value.setFTenantId("tenant-a");
|
value.setFDeleteMark(0);
|
return value;
|
}
|
|
private static ElnRecordFieldValueEntity value(
|
String id, String recordId, String revisionId, String currentValue) {
|
return value(id, recordId, revisionId, "binding-shared",
|
"definition-shared", "environment_temperature",
|
"version-shared", currentValue);
|
}
|
|
private static ElnRecordFieldValueEntity value(
|
String id, String recordId, String revisionId,
|
String bindingId, String definitionId, String fieldCode,
|
String versionId, String currentValue) {
|
ElnRecordFieldValueEntity value = new ElnRecordFieldValueEntity();
|
value.setId(id);
|
value.setDianziJiluId(recordId);
|
value.setXiudingId(revisionId);
|
value.setMubanId("template-1");
|
value.setMubanBangdingId(bindingId);
|
value.setZiduanDingyiId(definitionId);
|
value.setZiduanBianma(fieldCode);
|
value.setZiduanBanbenId(versionId);
|
value.setBangdingJuese("PRIMARY");
|
value.setBangdingZhuangtai("ACTIVE");
|
value.setZhiWenben(currentValue);
|
value.setZhiLaiyuan("MANUAL");
|
value.setFTenantId("tenant-a");
|
value.setFDeleteMark(0);
|
return value;
|
}
|
|
private static ElnFieldVersionEntity sharedVersion() {
|
return sharedVersion("version-shared", "definition-shared", "环境温度");
|
}
|
|
private static ElnFieldVersionEntity sharedVersion(
|
String id, String definitionId, String name) {
|
ElnFieldVersionEntity value = new ElnFieldVersionEntity();
|
value.setId(id);
|
value.setZiduanDingyiId(definitionId);
|
value.setZiduanMingcheng(name);
|
value.setShujuLeixing("DECIMAL");
|
value.setDanwei("℃");
|
value.setPiciMoshi("BATCH_SHARED");
|
value.setBangdingPeizhi("{\"read\":{\"source\":\"NONE\"},\"write\":{\"target\":\"ELN_RECORD\"}}");
|
value.setBizStatus("PUBLISHED");
|
value.setFTenantId("tenant-a");
|
value.setFDeleteMark(0);
|
return value;
|
}
|
|
private static TestWorkItemSnapshot snapshot(String itemId, String projectId) {
|
return snapshot(itemId, projectId,
|
projectId == null ? null : projectId + "-code");
|
}
|
|
private static TestWorkItemSnapshot snapshot(
|
String itemId, String projectId, String projectCode) {
|
TestWorkItemSnapshot item = new TestWorkItemSnapshot();
|
item.setTestWorkItemId(itemId);
|
item.setTestDefinitionId(projectId);
|
item.setTestDefinitionCode(projectCode);
|
item.setOutcomeCode("SUCCESS");
|
item.setTaskStatus("pending_test");
|
return item;
|
}
|
|
private static ElnTestWorkItemSnapshotProvider snapshots(
|
List<TestWorkItemSnapshot> items) {
|
return new ElnTestWorkItemSnapshotProvider() {
|
@Override
|
public TestWorkItemSnapshotBatch resolve(
|
List<String> testWorkItemIds, List<String> properties) {
|
throw new AssertionError("must use actor snapshot");
|
}
|
|
@Override
|
public TestWorkItemSnapshotBatch resolveAsActor(
|
String tenantId, String userId,
|
List<String> testWorkItemIds, List<String> properties) {
|
TestWorkItemSnapshotBatch batch = new TestWorkItemSnapshotBatch();
|
List<TestWorkItemSnapshot> selected = new ArrayList<>();
|
for (String testWorkItemId : testWorkItemIds) {
|
for (TestWorkItemSnapshot item : items) {
|
if (testWorkItemId.equals(item.getTestWorkItemId())) {
|
selected.add(item);
|
break;
|
}
|
}
|
}
|
batch.setItems(selected);
|
return batch;
|
}
|
};
|
}
|
|
private static void countWrite(String methodName, AtomicInteger writes) {
|
if (methodName.startsWith("insert") || methodName.startsWith("update")
|
|| methodName.startsWith("delete")) {
|
writes.incrementAndGet();
|
}
|
}
|
|
@SuppressWarnings("unchecked")
|
private static <T> T proxy(Class<T> type, InvocationHandler handler) {
|
return (T) Proxy.newProxyInstance(type.getClassLoader(), new Class<?>[]{type}, handler);
|
}
|
}
|