Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add unit tests for runtime #1157

Merged
merged 3 commits into from
Apr 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ private ThreadPoolExecutor createAsyncExecutor() {
ASYNC_INIT_METHOD_EXECUTOR_BEAN_NAME, Supplier.class).get();
}

private void ensureAsyncTasksFinish() {
void ensureAsyncTasksFinish() {
for (Future<?> future : futures) {
try {
future.get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ public Object invoke(final MethodInvocation invocation) throws Throwable {
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
initCountDownLatch.countDown();
isAsyncCalling = false;
asyncMethodFinish();
}
});
return null;
Expand All @@ -101,4 +100,9 @@ public Object invoke(final MethodInvocation invocation) throws Throwable {
}
return invocation.getMethod().invoke(targetObject, invocation.getArguments());
}

void asyncMethodFinish() {
this.initCountDownLatch.countDown();
this.isAsyncCalling = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,7 @@ public void afterRefresh(SofaGenericApplicationContext context, Throwable throwa
ComponentInfo componentInfo = new SpringContextComponent(componentName, implementation,
sofaRuntimeContext);
componentManager.register(componentInfo);
}

if (throwable != null) {
} else {
Collection<ComponentInfo> componentInfos = componentManager
.getComponentInfosByApplicationContext(context);
for (ComponentInfo componentInfo : componentInfos) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alipay.sofa.runtime.async;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.support.GenericApplicationContext;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier;

import static com.alipay.sofa.runtime.async.AsyncInitMethodManager.ASYNC_INIT_METHOD_EXECUTOR_BEAN_NAME;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

/**
* Tests for {@link AsyncInitMethodManager}.
*
* @author huzijie
* @version AsyncInitMethodManagerTests.java, v 0.1 2023年04月10日 10:39 AM huzijie Exp $
*/
public class AsyncInitMethodManagerTests {

@Test
void submitTaskSuccess() {
AsyncInitMethodManager manager = new AsyncInitMethodManager();
ExecutorService executorService = Executors.newFixedThreadPool(3);
GenericApplicationContext applicationContext = new GenericApplicationContext();
applicationContext.getBeanFactory().registerSingleton(ASYNC_INIT_METHOD_EXECUTOR_BEAN_NAME, (Supplier<Object>) () -> executorService);
applicationContext.refresh();
manager.setApplicationContext(applicationContext);
// Submit 3 tasks
for (int i = 0; i < 3; i++) {
manager.submitTask(() -> {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}

manager.ensureAsyncTasksFinish();

// Verify that all tasks finished successfully
assertThat(manager.isStartUpFinish()).isTrue();

// Shut down the executor service
executorService.shutdown();
}

@Test
void submitTaskException() {
AsyncInitMethodManager manager = new AsyncInitMethodManager();
ExecutorService executorService = Executors.newFixedThreadPool(3);
GenericApplicationContext applicationContext = new GenericApplicationContext();
applicationContext.getBeanFactory().registerSingleton(ASYNC_INIT_METHOD_EXECUTOR_BEAN_NAME, (Supplier<Object>) () -> executorService);
applicationContext.refresh();
manager.setApplicationContext(applicationContext);
// Submit 3 tasks
for (int i = 0; i < 3; i++) {
manager.submitTask(() -> {
throw new RuntimeException("task fail");
});
}

assertThatThrownBy(manager::ensureAsyncTasksFinish)
.isInstanceOf(RuntimeException.class)
.hasMessageContaining("Async init task finish fail")
.hasRootCauseMessage("task fail");

// Verify that all tasks finished successfully
assertThat(manager.isStartUpFinish()).isFalse();

// Shut down the executor service
executorService.shutdown();
}

@Test
void registerAsyncInitBean() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AsyncInitMethodManager manager = new AsyncInitMethodManager();
String beanName = "myBean";
String asyncInitMethodName = "initAsync";
manager.registerAsyncInitBean(beanFactory, beanName, asyncInitMethodName);
assertThat(manager.findAsyncInitMethod(beanFactory, beanName)).isEqualTo(
asyncInitMethodName);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alipay.sofa.runtime.async;

import com.alipay.sofa.runtime.sample.SampleService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.aop.framework.ProxyFactory;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;

/**
* Tests for {@link AsyncInitializeBeanMethodInvoker}.
*
* @author huzijie
* @version AsyncInitializeBeanMethodInvokerTests.java, v 0.1 2023年04月10日 10:41 AM huzijie Exp $
*/
@ExtendWith(MockitoExtension.class)
public class AsyncInitializeBeanMethodInvokerTests {

@Mock
private AsyncInitMethodManager asyncInitMethodManager;

private final String currentThreadName = Thread.currentThread().getName();

private final String beanName = "test";

private SampleService asyncSampleService;

private AsyncInitializeBeanMethodInvoker asyncInitializeBeanMethodInvoker;

@BeforeEach
void setUp() {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setInterfaces(SampleService.class);
asyncInitializeBeanMethodInvoker = new AsyncInitializeBeanMethodInvoker(
asyncInitMethodManager, new AsyncSampleServiceImpl(), beanName, "service");
proxyFactory.addAdvice(asyncInitializeBeanMethodInvoker);
asyncSampleService = (SampleService) proxyFactory.getProxy();
}

@Test
void invokeNormal() {
when(asyncInitMethodManager.isStartUpFinish()).thenReturn(true);
assertThat(asyncSampleService.service()).isEqualTo(currentThreadName);
}

@Test
void invokeCallOtherMethod() throws ExecutionException, InterruptedException {
when(asyncInitMethodManager.isStartUpFinish()).thenReturn(false);
assertThat(asyncSampleService.service()).isEqualTo(null);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> asyncSampleService.test());
assertThat(future.isDone()).isFalse();
asyncInitializeBeanMethodInvoker.asyncMethodFinish();
assertThat(future.get()).isNotEqualTo(currentThreadName);
}

@Test
void invokeTwice() throws ExecutionException, InterruptedException {
when(asyncInitMethodManager.isStartUpFinish()).thenReturn(false);
assertThat(asyncSampleService.service()).isEqualTo(null);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> asyncSampleService.service());
assertThat(future.isDone()).isFalse();
asyncInitializeBeanMethodInvoker.asyncMethodFinish();
assertThat(future.get()).isNotEqualTo(currentThreadName);
assertThat(asyncSampleService.service()).isEqualTo(currentThreadName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alipay.sofa.runtime.async;

import com.alipay.sofa.runtime.sample.SampleService;

/**
* @author huzijie
* @version AsyncSampleServiceImpl.java, v 0.1 2023年04月10日 10:54 AM huzijie Exp $
*/
public class AsyncSampleServiceImpl implements SampleService {

@Override
public String service() {
Thread thread = Thread.currentThread();
return thread.getName();
}

@Override
public String test() {
Thread thread = Thread.currentThread();
return thread.getName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alipay.sofa.runtime.context;

import com.alipay.sofa.boot.context.SofaGenericApplicationContext;
import com.alipay.sofa.runtime.api.component.ComponentName;
import com.alipay.sofa.runtime.model.ComponentType;
import com.alipay.sofa.runtime.spi.component.ComponentInfo;
import com.alipay.sofa.runtime.spi.component.ComponentManager;
import com.alipay.sofa.runtime.spi.component.SofaRuntimeContext;
import com.alipay.sofa.runtime.spi.component.SofaRuntimeManager;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.util.Collections;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;

/**
* Tests for {@link ComponentContextRefreshInterceptor}.
*
* @author huzijie
* @version ComponentContextRefreshInterceptorTests.java, v 0.1 2023年04月10日 11:22 AM huzijie Exp $
*/
public class ComponentContextRefreshInterceptorTests {

@Test
void afterRefreshWithNullThrowableShouldRegisterComponent() {
// Arrange
SofaRuntimeManager sofaRuntimeManager = Mockito.mock(SofaRuntimeManager.class);
ComponentManager componentManager = Mockito.mock(ComponentManager.class);
Mockito.when(sofaRuntimeManager.getComponentManager()).thenReturn(componentManager);
SofaRuntimeContext sofaRuntimeContext = Mockito.mock(SofaRuntimeContext.class);
Mockito.when(sofaRuntimeManager.getSofaRuntimeContext()).thenReturn(sofaRuntimeContext);
SofaGenericApplicationContext context = new SofaGenericApplicationContext();
ComponentContextRefreshInterceptor interceptor = new ComponentContextRefreshInterceptor(
sofaRuntimeManager);

// Act
interceptor.afterRefresh(context, null);

// Assert
Mockito.verify(componentManager, times(1)).register(any());
}

@Test
void afterRefreshWithThrowableShouldUnregisterComponents() {
// Arrange
SofaRuntimeManager sofaRuntimeManager = Mockito.mock(SofaRuntimeManager.class);
ComponentManager componentManager = Mockito.mock(ComponentManager.class);
Mockito.when(sofaRuntimeManager.getComponentManager()).thenReturn(componentManager);
SofaGenericApplicationContext context = new SofaGenericApplicationContext();
ComponentInfo componentInfo = Mockito.mock(ComponentInfo.class);
Mockito.when(componentInfo.getName()).thenReturn(
new ComponentName(new ComponentType("test"), "TestComponent"));
Mockito.when(componentManager.getComponentInfosByApplicationContext(context)).thenReturn(
Collections.singletonList(componentInfo));
ComponentContextRefreshInterceptor interceptor = new ComponentContextRefreshInterceptor(
sofaRuntimeManager);

// Act
interceptor.afterRefresh(context, new Throwable());

// Assert
Mockito.verify(componentManager, times(1)).unregister(any());
}

}
Loading