浏览代码

Ensure Upload is properly reset after an upload is interrupted (#10522)

Fixes #9635
tags/8.4.0.alpha1
Anna Koskinen 6 年前
父节点
当前提交
b45f30685d

+ 1
- 0
client/src/main/java/com/vaadin/client/ui/VUpload.java 查看文件

@@ -222,6 +222,7 @@ public class VUpload extends SimplePanel {
* file. A new target frame is created later."
*/
cleanTargetFrame();
rebuildPanel();
submitted = false;
}
}

+ 208
- 0
uitest/src/main/java/com/vaadin/tests/components/upload/InterruptUpload.java 查看文件

@@ -0,0 +1,208 @@
package com.vaadin.tests.components.upload;

import java.io.OutputStream;

import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Button;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.ProgressBar;
import com.vaadin.ui.UI;
import com.vaadin.ui.Upload;
import com.vaadin.ui.Upload.FailedEvent;
import com.vaadin.ui.Upload.FinishedEvent;
import com.vaadin.ui.Upload.Receiver;
import com.vaadin.ui.Upload.StartedEvent;
import com.vaadin.ui.Upload.SucceededEvent;
import com.vaadin.ui.Window;

public class InterruptUpload extends AbstractTestUI {

private Upload sample;
private UploadInfoWindow uploadInfoWindow;

@Override
protected void setup(VaadinRequest request) {
LineBreakCounter lineBreakCounter = new LineBreakCounter();
lineBreakCounter.setSlow(true);

sample = new Upload(null, lineBreakCounter);
sample.setImmediateMode(true);
sample.setButtonCaption("Upload File");

uploadInfoWindow = new UploadInfoWindow(sample, lineBreakCounter);

sample.addStartedListener(event -> {
if (uploadInfoWindow.getParent() == null) {
UI.getCurrent().addWindow(uploadInfoWindow);
}
uploadInfoWindow.setClosable(false);
});
sample.addFinishedListener(event -> uploadInfoWindow.setClosable(true));

addComponent(sample);
}

private static class UploadInfoWindow extends Window
implements Upload.StartedListener, Upload.ProgressListener,
Upload.FailedListener, Upload.SucceededListener,
Upload.FinishedListener {
private final Label state = new Label();
private final Label result = new Label();
private final Label fileName = new Label();
private final Label textualProgress = new Label();

private final ProgressBar progressBar = new ProgressBar();
private final Button cancelButton;
private final LineBreakCounter counter;

private UploadInfoWindow(final Upload upload,
final LineBreakCounter lineBreakCounter) {
super("Status");
counter = lineBreakCounter;

addStyleName("upload-info");

setResizable(false);
setDraggable(false);

final FormLayout uploadInfoLayout = new FormLayout();
setContent(uploadInfoLayout);
uploadInfoLayout.setMargin(true);

final HorizontalLayout stateLayout = new HorizontalLayout();
stateLayout.setSpacing(true);
stateLayout.addComponent(state);

cancelButton = new Button("Cancel");
cancelButton.addClickListener(event -> upload.interruptUpload());
cancelButton.setVisible(false);
cancelButton.setStyleName("small");
stateLayout.addComponent(cancelButton);

stateLayout.setCaption("Current state");
state.setValue("Idle");
uploadInfoLayout.addComponent(stateLayout);

fileName.setCaption("File name");
uploadInfoLayout.addComponent(fileName);

result.setCaption("Line breaks counted");
uploadInfoLayout.addComponent(result);

progressBar.setCaption("Progress");
progressBar.setVisible(false);
uploadInfoLayout.addComponent(progressBar);

textualProgress.setVisible(false);
uploadInfoLayout.addComponent(textualProgress);

upload.addStartedListener(this);
upload.addProgressListener(this);
upload.addFailedListener(this);
upload.addSucceededListener(this);
upload.addFinishedListener(this);

}

@Override
public void uploadFinished(final FinishedEvent event) {
state.setValue("Idle");
progressBar.setVisible(false);
textualProgress.setVisible(false);
cancelButton.setVisible(false);
UI.getCurrent().setPollInterval(-1);
}

@Override
public void uploadStarted(final StartedEvent event) {
// this method gets called immediately after upload is started
progressBar.setValue(0f);
progressBar.setVisible(true);
UI.getCurrent().setPollInterval(500);
textualProgress.setVisible(true);
// updates to client
state.setValue("Uploading");
fileName.setValue(event.getFilename());

cancelButton.setVisible(true);
}

@Override
public void updateProgress(final long readBytes,
final long contentLength) {
// this method gets called several times during the update
progressBar.setValue(readBytes / (float) contentLength);
textualProgress.setValue(
"Processed " + readBytes + " bytes of " + contentLength);
result.setValue(counter.getLineBreakCount() + " (counting...)");
}

@Override
public void uploadSucceeded(final SucceededEvent event) {
result.setValue(counter.getLineBreakCount() + " (total)");
}

@Override
public void uploadFailed(final FailedEvent event) {
result.setValue(
counter.getLineBreakCount() + " (counting interrupted at "
+ Math.round(100 * progressBar.getValue()) + "%)");
}
}

private static class LineBreakCounter implements Receiver {
private int counter;
private int total;
private boolean sleep;

/**
* return an OutputStream that simply counts lineends
*/
@Override
public OutputStream receiveUpload(final String filename,
final String MIMEType) {
counter = 0;
total = 0;
return new OutputStream() {
private static final int searchedByte = '\n';

@Override
public void write(final int b) {
total++;
if (b == searchedByte) {
counter++;
}
if (sleep && total % 1000 == 0) {
try {
Thread.sleep(100);
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
}
};
}

private int getLineBreakCount() {
return counter;
}

private void setSlow(boolean value) {
sleep = value;
}
}

@Override
protected Integer getTicketNumber() {
return 9635;
}

@Override
public String getDescription() {
return "Interrupting an upload shouldn't prevent uploading that same file immediately afterwards.";
}

}

+ 112
- 0
uitest/src/test/java/com/vaadin/tests/components/upload/InterruptUploadTest.java 查看文件

@@ -0,0 +1,112 @@
package com.vaadin.tests.components.upload;

import static org.junit.Assert.assertTrue;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.internal.WrapsElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.LocalFileDetector;
import org.openqa.selenium.remote.RemoteWebElement;

import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.testbench.elements.LabelElement;
import com.vaadin.testbench.elements.WindowElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
import com.vaadin.tests.util.LoremIpsum;

public class InterruptUploadTest extends MultiBrowserTest {

@Override
public List<DesiredCapabilities> getBrowsersToTest() {
// PhantomJS fails to upload files for unknown reasons
return getBrowsersExcludingPhantomJS();
}

@Test
public void testInterruptUpload() throws Exception {
openTestURL();

File tempFile = createTempFile();
fillPathToUploadInput(tempFile.getPath());

waitForElementPresent(By.className("v-window"));

$(ButtonElement.class).caption("Cancel").first().click();

String expected = " (counting interrupted at ";
String actual = $(LabelElement.class).caption("Line breaks counted")
.first().getText();
assertTrue("Line break count note does not match expected (was: "
+ actual + ")", actual.contains(expected));

$(WindowElement.class).first().close();
waitForElementNotPresent(By.className("v-window"));

tempFile = createTempFile();
fillPathToUploadInput(tempFile.getPath());

waitForElementPresent(By.className("v-window"));
$(ButtonElement.class).caption("Cancel").first().click();
}

/**
* @return The generated temp file handle
* @throws IOException
*/
private File createTempFile() throws IOException {
File tempFile = File.createTempFile("TestFileUpload", ".txt");
BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile));
writer.write(getTempFileContents());
writer.close();
tempFile.deleteOnExit();
return tempFile;
}

private String getTempFileContents() {
StringBuilder sb = new StringBuilder("This is a big test file!");
for (int i = 0; i < 70; ++i) {
sb.append("\n");
sb.append(LoremIpsum.get());
}
return sb.toString();
}

private void fillPathToUploadInput(String tempFileName) throws Exception {
// create a valid path in upload input element. Instead of selecting a
// file by some file browsing dialog, we use the local path directly.
WebElement input = getInput();
setLocalFileDetector(input);
input.sendKeys(tempFileName);
}

private WebElement getInput() {
return getDriver().findElement(By.className("gwt-FileUpload"));
}

private void setLocalFileDetector(WebElement element) throws Exception {
if (getRunLocallyBrowser() != null) {
return;
}

if (element instanceof WrapsElement) {
element = ((WrapsElement) element).getWrappedElement();
}
if (element instanceof RemoteWebElement) {
((RemoteWebElement) element)
.setFileDetector(new LocalFileDetector());
} else {
throw new IllegalArgumentException(
"Expected argument of type RemoteWebElement, received "
+ element.getClass().getName());
}
}

}

正在加载...
取消
保存