/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* Licensed 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 org.uberfire.client.mvp;
import java.lang.reflect.Field;
import com.google.gwt.event.logical.shared.AttachEvent;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwtmockito.GwtMock;
import com.google.gwtmockito.GwtMockito;
import com.google.gwtmockito.GwtMockitoTestRunner;
import com.google.gwtmockito.fakes.FakeProvider;
import org.jboss.errai.security.shared.api.identity.User;
import org.jboss.errai.security.shared.api.identity.UserImpl;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.uberfire.backend.vfs.Path;
import org.uberfire.backend.vfs.impl.LockInfo;
import org.uberfire.backend.vfs.impl.LockResult;
import org.uberfire.client.mvp.LockTarget.TitleProvider;
import org.uberfire.client.resources.WorkbenchResources;
import org.uberfire.client.workbench.VFSLockServiceProxy;
import org.uberfire.client.workbench.events.ChangeTitleWidgetEvent;
import org.uberfire.mocks.EventSourceMock;
import org.uberfire.mvp.ParameterizedCommand;
import org.uberfire.mvp.impl.DefaultPlaceRequest;
import org.uberfire.rpc.impl.SessionInfoImpl;
import org.uberfire.workbench.events.NotificationEvent;
import org.uberfire.workbench.events.ResourceUpdatedEvent;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
@RunWith(GwtMockitoTestRunner.class)
@SuppressWarnings("unchecked")
public class LockManagerTest {
@InjectMocks
private LockManagerImpl lockManager;
@Mock
private LockDemandDetector lockDemandDetector;
@Mock
private User user;
@Mock
private VFSLockServiceProxy lockService;
@Mock
private Path path;
@Mock
private EventSourceMock<NotificationEvent> lockNotification;
@Mock
private EventSourceMock<ChangeTitleWidgetEvent> changeTitleEvent;
@Mock
private EventSourceMock<UpdatedLockStatusEvent> updatedLockStatusEvent;
@GwtMock
private TextArea widget;
@GwtMock
private Event event;
private LockTarget target;
private int reloads = 0;
@Before
public void setup() throws Exception {
mockTimer();
GwtMockito.useProviderForType(WorkbenchResources.class,
new FakeProvider<WorkbenchResources>() {
@Override
public WorkbenchResources getFake(Class<?> type) {
return null;
}
});
final Runnable reloadRunnable = new Runnable() {
@Override
public void run() {
reloads++;
}
};
final TitleProvider titleProvider = new TitleProvider() {
@Override
public String getTitle() {
return "";
}
};
target = new LockTarget(path,
widget,
new DefaultPlaceRequest("mockPlace"),
titleProvider,
reloadRunnable);
lockManager.init(target);
when(user.getIdentifier()).thenReturn("mockedUser");
when(lockDemandDetector.isLockRequired(any(Event.class))).thenReturn(true);
}
@Test
public void updateLockInfoOnInit() {
verify(lockService,
times(1)).retrieveLockInfo(any(Path.class),
any(ParameterizedCommand.class));
}
@Test
public void acquireLockOnDemand() {
lockManager.acquireLockOnDemand();
simulateLockDemand();
verify(lockService,
times(1)).acquireLock(any(Path.class),
any(ParameterizedCommand.class));
}
@Test
public void acquireLockDoesNotHitServerIfLocked() {
lockManager.acquireLockOnDemand();
simulateLockFailure();
simulateLockDemand();
verify(lockService,
times(1)).acquireLock(any(Path.class),
any(ParameterizedCommand.class));
simulateLockDemand();
verify(lockService,
times(1)).acquireLock(any(Path.class),
any(ParameterizedCommand.class));
}
@Test
public void notifyLockFailure() throws Exception {
lockManager.acquireLockOnDemand();
simulateLockFailure();
simulateLockDemand();
verify(lockNotification,
times(1)).fire(any(NotificationEvent.class));
}
@Test
public void notifyLockError() throws Exception {
lockManager.acquireLockOnDemand();
simulateLockError();
simulateLockDemand();
verify(lockNotification,
times(1)).fire(any(NotificationEvent.class));
}
@Test
public void reloadOnLockFailure() throws Exception {
lockManager.acquireLockOnDemand();
assertEquals(0,
reloads);
simulateLockFailure();
simulateLockDemand();
assertEquals(1,
reloads);
}
@Test
public void updateTitleOnFocus() {
verify(changeTitleEvent,
never()).fire(any(ChangeTitleWidgetEvent.class));
lockManager.onFocus();
verify(changeTitleEvent,
times(1)).fire(any(ChangeTitleWidgetEvent.class));
}
@Test
public void handleWindowReparenting() {
lockManager.acquireLockOnDemand();
verify(lockDemandDetector,
times(1)).getLockDemandEventTypes();
final ArgumentCaptor<AttachEvent.Handler> handlerCaptor = ArgumentCaptor.forClass(AttachEvent.Handler.class);
verify(widget,
times(1)).addAttachHandler(handlerCaptor.capture());
handlerCaptor.getValue().onAttachOrDetach(new AttachEvent(true) {
});
verify(lockDemandDetector,
times(2)).getLockDemandEventTypes();
}
@Test
public void releaseLockOnSave() {
lockManager.acquireLockOnDemand();
simulateLockSuccess();
simulateLockDemand();
lockManager.onSaveInProgress(new SaveInProgressEvent(path));
verify(lockService,
times(1)).releaseLock(any(Path.class),
any(ParameterizedCommand.class));
}
@Test
public void releaseLockOnUpdate() {
lockManager.acquireLockOnDemand();
simulateLockSuccess();
simulateLockDemand();
lockManager.onResourceUpdated(new ResourceUpdatedEvent(path,
"",
new SessionInfoImpl(user)));
verify(lockService,
times(1)).releaseLock(any(Path.class),
any(ParameterizedCommand.class));
}
@Test
public void reloadEditorOnUpdateFromDifferentUser() {
lockManager.onResourceUpdated(new ResourceUpdatedEvent(path,
"",
new SessionInfoImpl(user)));
assertEquals(0,
reloads);
lockManager.onResourceUpdated(new ResourceUpdatedEvent(path,
"",
new SessionInfoImpl(new UserImpl("differentUser"))));
assertEquals(1,
reloads);
}
@Test
public void releaseOwnedLockOnly() {
lockManager.acquireLockOnDemand();
simulateLockFailure();
simulateLockDemand();
lockManager.onResourceUpdated(new ResourceUpdatedEvent(path,
"",
new SessionInfoImpl(user)));
verify(lockService,
never()).releaseLock(any(Path.class),
any(ParameterizedCommand.class));
}
@Test
public void requestAcquireLockOnDemandNoMoreThanOnce() {
lockManager.acquireLockOnDemand();
simulateLockNoResponse();
simulateLockDemand();
simulateLockDemand();
verify(lockService,
times(1)).acquireLock(any(Path.class),
any(ParameterizedCommand.class));
}
@Test
public void acquireLock() {
lockManager.acquireLock();
verify(lockService,
times(1)).acquireLock(any(Path.class),
any(ParameterizedCommand.class));
}
@Test
public void requestAcquireLockNoMoreThanOnce() {
simulateLockNoResponse();
lockManager.acquireLock();
lockManager.acquireLock();
verify(lockService,
times(1)).acquireLock(any(Path.class),
any(ParameterizedCommand.class));
}
@Test
public void requestAcquireLockNoMoreThanOnceForSameUser() {
simulateLockSuccess();
lockManager.acquireLock();
lockManager.acquireLock();
verify(lockService,
times(1)).acquireLock(any(Path.class),
any(ParameterizedCommand.class));
}
@Test
public void acquireLockFiresChangeTitleEvent() {
simulateLockSuccess();
lockManager.acquireLock();
verify(changeTitleEvent,
times(1)).fire(any(ChangeTitleWidgetEvent.class));
lockManager.acquireLock();
verify(changeTitleEvent,
times(2)).fire(any(ChangeTitleWidgetEvent.class));
}
private void simulateLockDemand() {
EventListener listener = lockManager.acquireLockOnDemand(widget.getElement());
listener.onBrowserEvent(event);
}
private void simulateLockFailure() {
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
final Object[] args = invocation.getArguments();
LockInfo lockInfo = new LockInfo(true,
"somebody",
path);
final LockResult failed = LockResult.failed(lockInfo);
((ParameterizedCommand<LockResult>) args[1]).execute(failed);
return null;
}
}).when(lockService).acquireLock(any(Path.class),
any(ParameterizedCommand.class));
}
private void simulateLockSuccess() {
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
final Object[] args = invocation.getArguments();
final LockResult acquired = LockResult.acquired(path,
user.getIdentifier());
((ParameterizedCommand<LockResult>) args[1]).execute(acquired);
return null;
}
}).when(lockService).acquireLock(any(Path.class),
any(ParameterizedCommand.class));
}
private void simulateLockError() {
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
final Object[] args = invocation.getArguments();
final LockResult acquired = LockResult.error();
((ParameterizedCommand<LockResult>) args[1]).execute(acquired);
return null;
}
}).when(lockService).acquireLock(any(Path.class),
any(ParameterizedCommand.class));
}
private void simulateLockNoResponse() {
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return null;
}
}).when(lockService).acquireLock(any(Path.class),
any(ParameterizedCommand.class));
}
private void mockTimer() throws Exception {
final Timer mockTimer = new Timer() {
@Override
public void run() {
target.getReloadRunnable().run();
}
@Override
public void schedule(int delayMillis) {
run();
}
};
final Field reloadTimer = LockManagerImpl.class.getDeclaredField("reloadTimer");
reloadTimer.setAccessible(true);
reloadTimer.set(lockManager,
mockTimer);
}
}