QNJR-GROUP / EasyTransaction

A distribute transaction solution(分布式事务) unified the usage of TCC , SAGA ,FMT (seata/fescar AutoCompensation), reliable message, compensate and so on;
Apache License 2.0
2.36k stars 808 forks source link

测试代码中,扣除钱的代码将钱/2 调用两次的目的是为了证明什么 #21

Closed Moouna closed 6 years ago

Moouna commented 6 years ago

在测试代码中,怎么也不理解要把钱/2并且调用两次的目的,而且我/10调用10次测试就跑不了了~,求帮忙。

skyesx commented 6 years ago

除以2 只是为了说明,同一个远程方法可以在同一个事务代码里独立多次调用(之前的版本一个事务里只支持调用一次相同的方法), 除以10 跑不了的表现/异常 是啥?

Moouna commented 6 years ago

感谢回答,junit跑出来的测试通过不了,只改了如下代码:OrderService里面的173行。

WalletPayTccMethodRequest deductRequest = new WalletPayTccMethodRequest();
        deductRequest.setUserId(userId);
        deductRequest.setPayAmount(money/10);
        //return future for the benefits of performance enhance(batch write execute log and batch execute RPC)
        //返回future是为了能方便的优化性能(批量写日志及批量调用RPC)
        Future<WalletPayTccMethodResult> deductFuture = null;
        if(checkExecuteForTestCase(deductRequest.getClass())){
            /**
             * 执行两遍,每次都扣一半的钱,以测试相同方法在业务上调用两次的场景
             */
            deductFuture = transaction.execute(deductRequest);
            deductFuture = transaction.execute(deductRequest);
            deductFuture = transaction.execute(deductRequest);
            deductFuture = transaction.execute(deductRequest);
            deductFuture = transaction.execute(deductRequest);
            deductFuture = transaction.execute(deductRequest);
            deductFuture = transaction.execute(deductRequest);
            deductFuture = transaction.execute(deductRequest);
            deductFuture = transaction.execute(deductRequest);
            deductFuture = transaction.execute(deductRequest);
        }```
应该是事务失败了失败原因不太懂,请帮我看下,以下为几个表的数据信息
Order表信息:
![_20180227094551](https://user-images.githubusercontent.com/24785172/36706065-20738408-1ba3-11e8-96fa-2ffcad58c684.png)
wallet表信息:
`1  5000    0`
最后结果是测试失败。

java.lang.AssertionError at org.junit.Assert.fail(Assert.java:86) at org.junit.Assert.assertTrue(Assert.java:41) at org.junit.Assert.assertTrue(Assert.java:52) at com.yiqiniu.easytrans.test.FullTest.test(FullTest.java:186) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

skyesx commented 6 years ago

看下idempotent表的信息,可以的话,把整个运行日志,搞个附件放上来

Moouna commented 6 years ago

附件为日志和表的xls文件 日志及idempotent表信息.zip

skyesx commented 6 years ago

如果是

Assert.assertTrue(pointService.getUserPoint(1) == 7000);

这一行的校验错了的话,有可能是 1、MQ里上一次单元测试存在没有被消费的消息,而这一次测试时,被消费了,测试代码里只清理了数据库数据,但是没有清理消息队列数据,所以可以尝试调整下MQ消费位置,或者手工清空MQ数据后重试 2、MQ的数据还没被消费,可以在执行这一句前打个断点,等一会再执行Assert看看是否正常

Moouna commented 6 years ago

没到那里,在 Assert.assertTrue(accountingService.getTotalCost(1) == 5000);错的 而且清空了kafka和zookeeper的全数据测试结果还是不通过。 之前测试通过的时候记得是order表中有8个1000和3个-1000 现在里面全是1000了 没有-1000总共11个1000

skyesx commented 6 years ago

我这边也测试了下,执行了10遍扣款,是会偶尔UT不过,UT不过的主要原因是因为存在一些异步的操作还没执行完就执行了 ASSERT。

我稍微调整了下UT,你更新下看看, #22

Moouna commented 6 years ago

测试过了,还有点疑问:等10秒不好吧。这业务系统还能用么,正常来说核心系统每秒几百单还是很轻松的。 在毫秒级的响应上有什么建议么?

skyesx commented 6 years ago

这个等待的时间是为 “刻意营造的多次失败重试案例” 而设定的,正常情况下,达到最终一致的时间是非常快的,基本上主事务执行完成,后续跟进的从事务就马上会执行,除非遇到了异常。

Moouna commented 6 years ago

恩恩,我再看下,了解的还是不够充分,感谢协助。