summaryrefslogtreecommitdiff
path: root/updater/testUI/build.gradle
diff options
context:
space:
mode:
Diffstat (limited to 'updater/testUI/build.gradle')
-rwxr-xr-xupdater/testUI/build.gradle344
1 files changed, 344 insertions, 0 deletions
diff --git a/updater/testUI/build.gradle b/updater/testUI/build.gradle
new file mode 100755
index 000000000000..2c86712964bc
--- /dev/null
+++ b/updater/testUI/build.gradle
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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.
+ */
+import java.nio.charset.Charset
+
+apply plugin: "application"
+
+project.mainClassName = "com.intellij.updater.Runner"
+
+defaultTasks "testSuite"
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compile files("../../lib/log4j.jar")
+ testCompile group: "junit", name: "junit", version: "3.+"
+}
+
+sourceSets {
+ main {
+ java { srcDir "../src" }
+ resources { srcDir "../src" }
+ }
+ test {
+ java { srcDir "../tests" }
+ resources { srcDir "../tests" }
+ }
+}
+
+
+test {
+ testLogging {
+ showStandardStreams = true
+ showStackTraces = true
+ exceptionFormat = "full"
+ }
+}
+
+//---
+
+// Task : Tests updater create + install in the default normal case.
+// Scope: large test.
+// Running this will display the install patcher UI.
+task testUI1(dependsOn: jar) << {
+ println "## Running UI test 1"
+ println "## Jar file: " + jar.archivePath.getAbsolutePath()
+
+ // Create a temp dir inside the gradle build/tmp dir
+ //noinspection GroovyAssignabilityCheck
+ def buildTmpDir = new File(project.buildDir, "tmp");
+ def tmpDir = _createTempDir(buildTmpDir)
+ def logDir = _createTempDir(buildTmpDir)
+
+ try {
+ // create a "from version 1" and "to version 2" directories
+ def dataDir1 = _createTestData(tmpDir, "1")
+ assert _mkFile(dataDir1, "plugins", "v1", "myplugin.jar").exists()
+ assert !_mkFile(dataDir1, "plugins", "v2", "myplugin.jar").exists()
+ assert _getFileContent(_mkFile(dataDir1, "build.txt")).equals("AI-123.45678-1")
+
+ def dataDir2 = _createTestData(tmpDir, "2")
+ assert !_mkFile(dataDir2, "plugins", "v1", "myplugin.jar").exists()
+ assert _mkFile(dataDir2, "plugins", "v2", "myplugin.jar").exists()
+ assert _getFileContent(_mkFile(dataDir2, "build.txt")).equals("AI-123.45678-2")
+
+ def patch = _createFileContent(tmpDir, "patch.jar", "patch jar placeholder");
+ patch.delete()
+ assert !patch.exists()
+
+ def logFullFile = _mkFile(logDir, "idea_updater.log")
+ def logErrorFile = _mkFile(logDir, "idea_updater_error.log")
+ assert !logFullFile .exists()
+ assert !logErrorFile.exists()
+
+ // call updater jar to create a diff, resulting in a patch jar.
+ println "## Invoking updater <create>"
+ javaexec {
+ classpath jar.archivePath
+ classpath "../../lib/log4j.jar"
+ main = "com.intellij.updater.Runner"
+ args "create"
+ args "AI-123.45678-1"
+ args "AI-123.45678-2"
+ args dataDir1.getAbsolutePath()
+ args dataDir2.getAbsolutePath()
+ args patch.getAbsolutePath()
+ args logDir.getAbsolutePath()
+ }
+ assert patch.exists()
+
+ assert logFullFile .exists()
+ assert logErrorFile.exists() // should exist and be empty
+ assert _getFileContent(logErrorFile).equals(null)
+
+
+ // that patch jar is self-executable. use it to update dir1 into dir2 in-place.
+ println "## Invoking updater <install>"
+ javaexec {
+ classpath patch
+ classpath "../../lib/log4j.jar"
+ main = "com.intellij.updater.Runner"
+ args "install"
+ args "--exit0"
+ args dataDir1.getAbsolutePath()
+ args logDir.getAbsolutePath()
+ }
+ // build.txt should have changed to v2
+ assert _getFileContent(_mkFile(dataDir1, "build.txt")).equals("AI-123.45678-2")
+ // plugin v1 should have been replaced by pluging v2 in the dataDir1 directory.
+ assert !_mkFile(dataDir1, "plugins", "v1", "myplugin.jar").exists()
+ assert _mkFile(dataDir1, "plugins", "v2", "myplugin.jar").exists()
+
+ assert logFullFile .exists()
+ assert logErrorFile.exists() // should exist and be empty
+ assert _getFileContent(logErrorFile).equals(null)
+
+ } finally {
+ // Cleanup on exit
+ tmpDir.deleteDir()
+ logDir.deleteDir()
+ }
+}
+
+// Task : Tests updater create + install with 2 open files.
+// Scope: large *interactive* test.
+// On Windows, the opened files are locked and can't be deleted/overwritten.
+// On Linux/Mac, they should be writable & deletable.
+//
+// Running this will display the install patcher UI, which will fail at
+// first on Windows. After 5 seconds the open files will be closed.
+// Hitting "retry" in the UI after this point should perform the whole
+// install operation again.
+task testUI2(dependsOn: jar) << {
+ println "## Running UI test 2"
+ println "## Jar file: " + jar.archivePath.getAbsolutePath()
+
+ // Create a temp dir inside the gradle build/tmp dir
+ //noinspection GroovyAssignabilityCheck
+ def buildTmpDir = new File(project.buildDir, "tmp");
+ def tmpDir = _createTempDir(buildTmpDir)
+ def logDir = _createTempDir(buildTmpDir)
+ def closeableFiles = []
+
+ try {
+ // create a "from version 1" and "to version 2" directories
+ def dataDir1 = _createTestData(tmpDir, "1")
+ assert _mkFile(dataDir1, "plugins", "v1", "myplugin.jar").exists()
+ assert !_mkFile(dataDir1, "plugins", "v2", "myplugin.jar").exists()
+ assert _getFileContent(_mkFile(dataDir1, "build.txt")).equals("AI-123.45678-1")
+
+ def dataDir2 = _createTestData(tmpDir, "2")
+ assert !_mkFile(dataDir2, "plugins", "v1", "myplugin.jar").exists()
+ assert _mkFile(dataDir2, "plugins", "v2", "myplugin.jar").exists()
+ assert _getFileContent(_mkFile(dataDir2, "build.txt")).equals("AI-123.45678-2")
+
+ def patch = _createFileContent(tmpDir, "patch.jar", "patch jar placeholder");
+ patch.delete()
+ assert !patch.exists()
+
+ def logFullFile = _mkFile(logDir, "idea_updater.log")
+ def logErrorFile = _mkFile(logDir, "idea_updater_error.log")
+ assert !logFullFile .exists()
+ assert !logErrorFile.exists()
+
+ // keep a couple files open, preventing them from being deleted or replaced on Windows
+ closeableFiles << _openFile(_mkFile(dataDir1, "build.txt"))
+ closeableFiles << _openFile(_mkFile(dataDir1, "plugins", "v1", "myplugin.jar"))
+
+ // call updater jar to create a diff, resulting in a patch jar.
+ println "## Invoking updater <create>"
+ javaexec {
+ classpath jar.archivePath
+ classpath "../../lib/log4j.jar"
+ main = "com.intellij.updater.Runner"
+ args "create"
+ args "AI-123.45678-1"
+ args "AI-123.45678-2"
+ args dataDir1.getAbsolutePath()
+ args dataDir2.getAbsolutePath()
+ args patch.getAbsolutePath()
+ args logDir.getAbsolutePath()
+ }
+ assert patch.exists()
+
+ assert logFullFile .exists()
+ assert logErrorFile.exists() // should exist and be empty
+ assert _getFileContent(logErrorFile).equals(null)
+
+ Thread.start {
+ sleep(5 * 1000) // 5 seconds
+ synchronized(closeableFiles) {
+ println "##"
+ println "## Closing pending open files --> now click 'Retry' in Updater UI."
+ println "##"
+ closeableFiles.each { it.close() }
+ closeableFiles.clear()
+ }
+ }
+
+ // that patch jar is self-executable. use it to update dir1 into dir2 in-place.
+ println "## Invoking updater <install>"
+ println "##"
+ println "## Note: on Windows some files will be locked for 5 seconds and the installer"
+ println "## window should display a 'Retry' button. This code will wait 5 seconds"
+ println "## then unlock the files, at which point you would click that 'Retry'"
+ println "## button and the install should continue correctly."
+ println "##"
+
+ javaexec {
+ classpath patch
+ classpath "../../lib/log4j.jar"
+ main = "com.intellij.updater.Runner"
+ args "install"
+ args "--exit0"
+ args dataDir1.getAbsolutePath()
+ args logDir.getAbsolutePath()
+ }
+ // build.txt should have changed to v2
+ assert _getFileContent(_mkFile(dataDir1, "build.txt")).equals("AI-123.45678-2")
+ // plugin v1 should have been replaced by pluging v2 in the dataDir1 directory.
+ assert !_mkFile(dataDir1, "plugins", "v1", "myplugin.jar").exists()
+ assert _mkFile(dataDir1, "plugins", "v2", "myplugin.jar").exists()
+
+ assert logFullFile .exists()
+ // the log error file should exist and should not be empty on Windows.
+ assert logErrorFile.exists()
+ if (System.getProperty("os.name").startsWith("Windows")) {
+ assert _getFileContent(logErrorFile) != null
+ } else {
+ assert _getFileContent(logErrorFile).equals(null)
+ }
+
+ } finally {
+ // Cleanup on exit
+ synchronized(closeableFiles) {
+ closeableFiles.each { it.close() }
+ closeableFiles.clear()
+ }
+ tmpDir.deleteDir()
+ logDir.deleteDir()
+ }
+}
+
+// Task: Test suite to run both tests above.
+task testSuite(dependsOn: [testUI1, testUI2]) << {
+}
+
+// ---- Helper methods
+
+// Convention: all local helper methods start with an underscore to clearly
+// differentiate them from groovy/gradle methods.
+
+
+// Creates a temp dir with a random name in the build/tmp directory.
+File _createTempDir(File parent) {
+ def d = File.createTempFile("test", "", parent)
+ d.delete()
+ d.mkdirs()
+ return d
+}
+
+// Creates a new directory with the specific name in the specified parent directory.
+File _createDir(File parent, String name) {
+ def d = new File(parent, name)
+ d.mkdirs()
+ return d
+}
+
+// Creates a new file with the specified name, in the specified parent directory with the given UTF-8 content.
+File _createFileContent(File parentDir, String fileName, String fileContent) throws IOException {
+ File f = new File(parentDir, fileName)
+ OutputStreamWriter fw = new OutputStreamWriter(new FileOutputStream(f), Charset.forName("UTF-8"))
+ try {
+ fw.write(fileContent)
+ } finally {
+ fw.close()
+ }
+ return f
+}
+
+// Opens a file for writing (thus locking it on Windows) but does not close it.
+// Caller should call Closeable.close() on the returned Closeable object.
+Closeable _openFile(File file) throws IOException {
+ if (!file.exists()) throw new IOException("File not found, expected file: " + file.getName())
+ // We need to actually write to the file but not change its content so just read it
+ // then write the same thing back to it, without closing it.
+ String content = _getFileContent(file)
+ FileWriter fw = new FileWriter(file, false /*append*/)
+ fw.append(content)
+ fw.flush()
+ println("## Open file " + file.getName());
+ return fw // file is not closed
+}
+
+// Returns the first line of the file.
+// Returns null if the file exists and is empty.
+// Throws IOException if file does not exist.
+String _getFileContent(File file) throws IOException {
+ if (!file.exists()) throw new IOException("File not found, expected file: " + file.getName())
+ BufferedReader br = new BufferedReader(new FileReader(file))
+ try {
+ return br.readLine()
+ } finally {
+ br.close()
+ }
+}
+
+// Creates a new File() object with the concatenated name segments.
+File _mkFile(File base, String...segments) {
+ for(String segment : segments) {
+ base = new File(base, segment)
+ }
+ return base
+}
+
+// Creates a mock test data for an idea-based IDE.
+File _createTestData(File tmpDir, String value) {
+ File root = _createDir(tmpDir, "idea-ide-" + value)
+ File bin = _createDir(root, "bin")
+ File lib = _createDir(root, "lib")
+ File plugins = _createDir(root, "plugins")
+ File myplugin = _createDir(plugins, "v" + value)
+
+ _createFileContent(root, "build.txt", "AI-123.45678-" + value);
+ _createFileContent(bin, "idea.exe", "binary file " + value);
+ _createFileContent(lib, "idea.jar", "some jar file " + value);
+ _createFileContent(myplugin, "myplugin.jar", "some jar file " + value);
+
+ return root
+}