blob: 2c86712964bcff7f0c67fa113c405cd9070db044 [file] [log] [blame]
/*
* 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
}