]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13413 Issues page remains unavailable if indexation is completed with failures
authorPhilippe Perrin <philippe.perrin@sonarsource.com>
Fri, 19 Jun 2020 14:13:22 +0000 (16:13 +0200)
committersonartech <sonartech@sonarsource.com>
Fri, 26 Jun 2020 20:04:58 +0000 (20:04 +0000)
SONAR-13400 Portfolios page remains unavailable if indexation is completed with failures

server/sonar-web/src/main/js/app/components/indexation/IndexationContextProvider.tsx
server/sonar-web/src/main/js/app/components/indexation/IndexationNotificationHelper.ts
server/sonar-web/src/main/js/app/components/indexation/PageUnavailableDueToIndexation.tsx
server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationContextProvider-test.tsx
server/sonar-web/src/main/js/app/components/indexation/__tests__/IndexationNotificationHelper-test.tsx
server/sonar-web/src/main/js/app/components/indexation/__tests__/PageUnavailableDueToIndexation-test.tsx
server/sonar-web/src/main/js/components/hoc/__tests__/withIndexationGuard-test.tsx
server/sonar-web/src/main/js/components/hoc/withIndexationGuard.tsx

index 4483ae34af0205bd5be00f5d372de65477beeaa7..164d1a755721495101a86f36fb1a06b4fc316678 100644 (file)
@@ -52,10 +52,6 @@ export class IndexationContextProvider extends React.PureComponent<
   }
 
   handleNewStatus = (newIndexationStatus: IndexationStatus) => {
-    if (newIndexationStatus.isCompleted) {
-      IndexationNotificationHelper.stopPolling();
-    }
-
     if (this.mounted) {
       this.setState({ status: newIndexationStatus });
     }
index 514e766ce38dc35aee922e25c80d9dea9ae17120..792e7c83e6bfea9758227a1f4510ce097516c951 100644 (file)
@@ -32,8 +32,10 @@ export default class IndexationNotificationHelper {
     this.stopPolling();
 
     // eslint-disable-next-line promise/catch-or-return
-    this.poll(onNewStatus).finally(() => {
-      this.interval = setInterval(() => this.poll(onNewStatus), POLLING_INTERVAL_MS);
+    this.poll(onNewStatus).then(status => {
+      if (!status.isCompleted) {
+        this.interval = setInterval(() => this.poll(onNewStatus), POLLING_INTERVAL_MS);
+      }
     });
   }
 
@@ -47,6 +49,12 @@ export default class IndexationNotificationHelper {
     const status = await getIndexationStatus();
 
     onNewStatus(status);
+
+    if (status.isCompleted) {
+      this.stopPolling();
+    }
+
+    return status;
   }
 
   static markInProgressNotificationAsDisplayed() {
index ef88aa8cef6e171d035361a4f5455581eb34c408..7e50b1aaacd870cc70470d65612b41eb2ad83c4d 100644 (file)
@@ -38,7 +38,10 @@ export enum PageContext {
 
 export class PageUnavailableDueToIndexation extends React.PureComponent<Props> {
   componentDidUpdate() {
-    if (this.props.indexationContext?.status.isCompleted) {
+    if (
+      this.props.indexationContext.status.isCompleted &&
+      !this.props.indexationContext.status.hasFailures
+    ) {
       window.location.reload();
     }
   }
index d381912d60fb4929cdc3ea4d23b735a1410eb500..9b92b363949fabb39366885d2657582d3af419a4 100644 (file)
@@ -49,7 +49,7 @@ it('should not start polling if no issue sync is needed', () => {
   expect(wrapper.state().status).toEqual(expectedStatus);
 });
 
-it('should update the state on new status & stop polling if indexation is complete', () => {
+it('should update the state on new status', () => {
   const wrapper = mountRender();
 
   const triggerNewStatus = (IndexationNotificationHelper.startPolling as jest.Mock).mock
@@ -63,7 +63,6 @@ it('should update the state on new status & stop polling if indexation is comple
   triggerNewStatus(newStatus);
 
   expect(wrapper.state().status).toEqual(newStatus);
-  expect(IndexationNotificationHelper.stopPolling).toHaveBeenCalled();
 });
 
 it('should stop polling when component is destroyed', () => {
index 095d4b3194804c9b7afda9966a17481b4a9c1250..ea3d923dd8536d3a970ee8df8c030f66df794f1f 100644 (file)
@@ -41,7 +41,7 @@ jest.mock('sonar-ui-common/helpers/storage', () => ({
 it('should properly start & stop polling for indexation status', async () => {
   const onNewStatus = jest.fn();
   const newStatus: IndexationStatus = {
-    isCompleted: true,
+    isCompleted: false,
     percentCompleted: 100,
     hasFailures: false
   };
index 9d7f1945d4d12a06494a8f342a764134932dcb14..02892c8f915ec16da6bb1b289a152da8fc589a64 100644 (file)
@@ -28,7 +28,7 @@ it('should render correctly', () => {
   expect(wrapper).toMatchSnapshot();
 });
 
-it('should refresh the page once the indexation is complete', () => {
+it('should not refresh the page once the indexation is complete if there were failures', () => {
   const reload = jest.fn();
   delete window.location;
   (window as any).location = { reload };
@@ -37,14 +37,33 @@ it('should refresh the page once the indexation is complete', () => {
 
   expect(reload).not.toHaveBeenCalled();
 
-  wrapper.setProps({ indexationContext: { status: { isCompleted: true } } });
+  wrapper.setProps({
+    indexationContext: { status: { isCompleted: true, percentCompleted: 100, hasFailures: true } }
+  });
+  wrapper.update();
+
+  expect(reload).not.toHaveBeenCalled();
+});
+
+it('should refresh the page once the indexation is complete if there were NO failures', () => {
+  const reload = jest.fn();
+  delete window.location;
+  (window as any).location = { reload };
+
+  const wrapper = shallowRender();
+
+  expect(reload).not.toHaveBeenCalled();
+
+  wrapper.setProps({
+    indexationContext: { status: { isCompleted: true, percentCompleted: 100, hasFailures: false } }
+  });
   wrapper.update();
 
   expect(reload).toHaveBeenCalled();
 });
 
 function shallowRender(props?: PageUnavailableDueToIndexation['props']) {
-  return shallow(
+  return shallow<PageUnavailableDueToIndexation>(
     <PageUnavailableDueToIndexation
       indexationContext={{
         status: { isCompleted: false, percentCompleted: 23, hasFailures: false }
index c2f4a1bc42ade0f95414d0402d0ff0c8a451b62b..b2716db87ed8534fd1d61288e949021ba4a26695 100644 (file)
@@ -25,11 +25,20 @@ import { PageContext } from '../../../app/components/indexation/PageUnavailableD
 import { IndexationContextInterface } from '../../../types/indexation';
 import withIndexationGuard from '../withIndexationGuard';
 
-it('should render correctly', () => {
-  let wrapper = mountRender();
+it('should not render children because indexation is in progress', () => {
+  const wrapper = mountRender();
   expect(wrapper.find(TestComponent).exists()).toBe(false);
+});
+
+it('should not render children because indexation has failures', () => {
+  const wrapper = mountRender({
+    status: { isCompleted: true, percentCompleted: 100, hasFailures: true }
+  });
+  expect(wrapper.find(TestComponent).exists()).toBe(false);
+});
 
-  wrapper = mountRender({
+it('should render children because indexation is completed without failures', () => {
+  const wrapper = mountRender({
     status: { isCompleted: true, percentCompleted: 100, hasFailures: false }
   });
   expect(wrapper.find(TestComponent).exists()).toBe(true);
index 0036b19fdecda25ab269ee8e9fa02e71b50ae1c3..b1d316f7e475af0660cc10ae8cca88c5d805efff 100644 (file)
@@ -33,7 +33,7 @@ export default function withIndexationGuard<P>(
       return (
         <IndexationContext.Consumer>
           {context =>
-            context?.status.isCompleted ? (
+            context?.status.isCompleted && !context?.status.hasFailures ? (
               <WrappedComponent {...this.props} />
             ) : (
               <PageUnavailableDueToIndexation pageContext={pageContext} />