org.gradle.internal.snapshot.impl.DefaultFileSystemSnapshotterTest.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2017 the original author or authors.
*
* 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.gradle.internal.snapshot.impl
import org.gradle.api.Action
import org.gradle.api.file.FileCollection
import org.gradle.api.internal.cache.StringInterner
import org.gradle.api.internal.file.FileCollectionInternal
import org.gradle.api.internal.file.TemporaryFileProvider
import org.gradle.api.internal.file.TestFiles
import org.gradle.api.internal.file.collections.DefaultSingletonFileTree
import org.gradle.api.internal.file.collections.DirectoryFileTree
import org.gradle.api.internal.file.collections.FileTreeAdapter
import org.gradle.api.internal.file.collections.GeneratedSingletonFileTree
import org.gradle.api.resources.MissingResourceException
import org.gradle.api.resources.ReadableResource
import org.gradle.api.resources.ResourceException
import org.gradle.api.resources.internal.LocalResourceAdapter
import org.gradle.api.tasks.util.PatternFilterable
import org.gradle.api.tasks.util.PatternSet
import org.gradle.internal.Factory
import org.gradle.internal.file.FileType
import org.gradle.internal.hash.TestFileHasher
import org.gradle.internal.snapshot.DirectorySnapshot
import org.gradle.internal.snapshot.FileSystemLocationSnapshot
import org.gradle.internal.snapshot.FileSystemSnapshot
import org.gradle.internal.snapshot.FileSystemSnapshotVisitor
import org.gradle.internal.snapshot.RegularFileSnapshot
import org.gradle.internal.snapshot.WellKnownFileLocations
import org.gradle.test.fixtures.file.TestFile
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.junit.Rule
import spock.lang.Specification
import javax.annotation.Nullable
class DefaultFileSystemSnapshotterTest extends Specification {
@Rule
TestNameTestDirectoryProvider tmpDir = new TestNameTestDirectoryProvider()
def fileHasher = new TestFileHasher()
def fileSystemMirror = new DefaultFileSystemMirror(Stub(WellKnownFileLocations))
def snapshotter = new DefaultFileSystemSnapshotter(fileHasher, new StringInterner(), TestFiles.fileSystem(), fileSystemMirror)
def "fetches details of a file and caches the result"() {
def f = tmpDir.createFile("f")
expect:
def snapshot = snapshotter.snapshot(f)
snapshot.absolutePath == f.path
snapshot.name == "f"
snapshot.type == FileType.RegularFile
snapshot.isContentAndMetadataUpToDate(new RegularFileSnapshot(f.path, f.absolutePath, fileHasher.hash(f), TestFiles.fileSystem().stat(f).lastModified))
def snapshot2 = snapshotter.snapshot(f)
snapshot2.is(snapshot)
}
def "fetches details of a directory and caches the result"() {
def d = tmpDir.createDir("d")
expect:
def snapshot = snapshotter.snapshot(d)
snapshot.absolutePath == d.path
snapshot.name == "d"
snapshot.type == FileType.Directory
def snapshot2 = snapshotter.snapshot(d)
snapshot2.is(snapshot)
}
def "fetches details of a missing file and caches the result"() {
def f = tmpDir.file("f")
expect:
def snapshot = snapshotter.snapshot(f)
snapshot.absolutePath == f.path
snapshot.name == "f"
snapshot.type == FileType.Missing
def snapshot2 = snapshotter.snapshot(f)
snapshot2.is(snapshot)
}
def "fetches details of a directory hierarchy and caches the result"() {
def d = tmpDir.createDir("d")
d.createFile("f1")
d.createFile("d1/f2")
d.createDir("d2")
expect:
def snapshot = snapshotter.snapshot(d)
getSnapshotInfo(snapshot) == [d.path, 5]
def snapshot2 = snapshotter.snapshot(d)
snapshot2.is(snapshot)
}
def "fetches details of an empty directory and caches the result"() {
def d = tmpDir.createDir("d")
expect:
def snapshot = snapshotter.snapshot(d)
getSnapshotInfo(snapshot) == [d.absolutePath, 1]
def snapshot2 = snapshotter.snapshot(d)
snapshot2.is(snapshot)
}
def "fetches details of a directory tree with no patterns and caches the result"() {
def d = tmpDir.createDir("d")
d.createFile("f1")
d.createFile("d1/f2")
d.createDir("d2")
def tree = dirTree(d)
expect:
def snapshot = snapshotter.snapshotDirectoryTree(tree.getDir(), tree.getPatterns())
getSnapshotInfo(snapshot) == [d.path, 5]
def snapshot2 = snapshotter.snapshotDirectoryTree(tree.getDir(), tree.getPatterns())
snapshot2.is(snapshot)
def snapshot3 = snapshotter.snapshotDirectoryTree(tree.getDir(), tree.getPatterns())
snapshot3.is(snapshot)
}
def "fetches details of a directory tree with patterns patterns and does not cache the result"() {
def d = tmpDir.createDir("d")
d.createFile("f1")
d.createFile("d1/f2")
d.createFile("d1/f1")
d.createDir("d2")
d.createFile("d2/f1")
d.createFile("d2/f2")
def patterns = TestFiles.patternSetFactory.create()
patterns.include "**/*1"
def emptyPatterns = new PatternSet()
expect:
def snapshot = snapshotter.snapshotDirectoryTree(d, patterns)
getSnapshotInfo(snapshot) == [d.path, 6]
def snapshot2 = snapshotter.snapshotDirectoryTree(d, patterns)
!snapshot2.is(snapshot)
def snapshot3 = snapshotter.snapshotDirectoryTree(d, emptyPatterns)
!snapshot3.is(snapshot)
getSnapshotInfo(snapshot3) == [d.path, 8]
def snapshot4 = snapshotter.snapshotDirectoryTree(d, emptyPatterns)
!snapshot4.is(snapshot)
snapshot4.is(snapshot3)
}
def "reuses cached unfiltered trees when looking for details of a filtered tree"() {
given: "An existing snapshot"
def d = tmpDir.createDir("d")
d.createFile("f1")
d.createFile("d1/f2")
d.createFile("d1/f1")
snapshotter.snapshotDirectoryTree(d, new PatternSet())
and: "A filtered tree over the same directory"
def patterns = TestFiles.patternSetFactory.create()
patterns.include "**/*1"
when:
def snapshot = snapshotter.snapshotDirectoryTree(d, patterns)
def relativePaths = [] as Set
snapshot.accept(new FileSystemSnapshotVisitor() {
private Deque relativePath = new ArrayDeque()
private boolean seenRoot = false
@Override
boolean preVisitDirectory(DirectorySnapshot directorySnapshot) {
if (!seenRoot) {
seenRoot = true
} else {
relativePath.addLast(directorySnapshot.name)
relativePaths.add(relativePath.join("/"))
}
return true
}
@Override
void visit(FileSystemLocationSnapshot fileSnapshot) {
relativePath.addLast(fileSnapshot.name)
relativePaths.add(relativePath.join("/"))
relativePath.removeLast()
}
@Override
void postVisitDirectory(DirectorySnapshot directorySnapshot) {
if (relativePath.isEmpty()) {
seenRoot = false
} else {
relativePath.removeLast()
}
}
})
then: "The filtered tree uses the cached state"
relativePaths == ["d1", "d1/f1", "f1"] as Set
}
def "snapshots a non-existing directory"() {
given:
def d = tmpDir.file("dir")
when:
def snapshot = snapshotter.snapshotDirectoryTree(d, new PatternSet())
then:
getSnapshotInfo(snapshot) == [null, 0]
}
def "snapshots file as directory tree"() {
given:
def d = tmpDir.createFile("fileAsTree")
when:
def snapshot = snapshotter.snapshotDirectoryTree(d, new PatternSet())
then:
getSnapshotInfo(snapshot) == [null, 1]
snapshot.accept(new FileSystemSnapshotVisitor() {
@Override
boolean preVisitDirectory(DirectorySnapshot directorySnapshot) {
throw new UnsupportedOperationException()
}
@Override
void visit(FileSystemLocationSnapshot fileSnapshot) {
assert fileSnapshot.absolutePath == d.getAbsolutePath()
assert fileSnapshot.name == d.name
}
@Override
void postVisitDirectory(DirectorySnapshot directorySnapshot) {
throw new UnsupportedOperationException()
}
})
}
def "snapshots a singletonFileTree as RegularFileSnapshot"() {
given:
def tempDir = tmpDir.createDir('tmpDir')
def file = tempDir.file('testFile')
file.text = "content"
when:
def tree = new FileTreeAdapter(new DefaultSingletonFileTree(file), TestFiles.patternSetFactory)
then:
assertSingleFileTree(tree)
assertSingleFileTree(tree.matching(new Action() {
@Override
void execute(PatternFilterable patternFilterable) {
patternFilterable.include(file.name)
}
}))
assertEmptyTree(tree.matching(new Action() {
@Override
void execute(PatternFilterable patternFilterable) {
patternFilterable.exclude(file.name)
}
}))
when:
def singleFileTree = TestFiles.fileOperations(tempDir).fileTree(file)
then:
assertSingleFileTree(singleFileTree)
assertSingleFileTree(singleFileTree.matching { include(file.name) })
assertEmptyTree(singleFileTree.matching { exclude(file.name) })
when:
def fromConfigurableFiles = TestFiles.fileOperations(tempDir).configurableFiles(file).asFileTree
then:
assertSingleFileTree(fromConfigurableFiles)
assertSingleFileTree(fromConfigurableFiles.matching { include(file.name) })
assertEmptyTree(fromConfigurableFiles.matching { exclude(file.name) })
}
def "snapshots archive trees as RegularFileSnapshot"() {
given:
def tempDir = tmpDir.createDir('tmpDir')
def archiveBaseDir = tempDir.createDir('archiveBase')
def file = archiveBaseDir.createFile('file.txt')
file.text = "content"
when:
TestFile zip = tempDir.file('archive.zip')
archiveBaseDir.zipTo(zip)
def zipTree = TestFiles.fileOperations(tempDir, testFileProvider()).zipTree(zip)
def snapshots = snapshotter.snapshot(zipTree)
then:
assertSingleFileSnapshot(snapshots)
when:
TestFile tar = tempDir.file('archive.tar')
archiveBaseDir.tarTo(tar)
def tarTree = TestFiles.fileOperations(tempDir, testFileProvider()).tarTree(tar)
snapshots = snapshotter.snapshot(tarTree)
then:
assertSingleFileSnapshot(snapshots)
when:
def tarDir = tmpDir.createDir('tarDir')
TestFile emptyTar = tempDir.file('emptyArchive.tar')
tarDir.tarTo(emptyTar)
def emtpyTarTree = TestFiles.fileOperations(tempDir, testFileProvider()).tarTree(tar)
snapshots = snapshotter.snapshot(emtpyTarTree)
then:
assertSingleFileSnapshot(snapshots)
when:
def tgzDir = tmpDir.createDir('tgzDir')
TestFile tgz = tempDir.file('emptyArchive.tgz')
tgzDir.tgzTo(tgz)
def localResource = new LocalResourceAdapter(TestFiles.fileRepository().localResource(tgz))
def emtpyTgzTree = TestFiles.fileOperations(tempDir, testFileProvider()).tarTree(localResource)
snapshots = snapshotter.snapshot(emtpyTgzTree)
then:
assertSingleFileSnapshot(snapshots)
when:
def readableResource = new ReadableResource() {
@Override
InputStream read() throws MissingResourceException, ResourceException {
return tgz.newInputStream()
}
@Override
String getDisplayName() {
return tgz.getName()
}
@Override
URI getURI() {
return tgz.toURI()
}
@Override
String getBaseName() {
return tgz.getName()
}
}
def recourceTarTree = TestFiles.fileOperations(tempDir, testFileProvider()).tarTree(readableResource)
snapshots = snapshotter.snapshot(recourceTarTree)
then:
assert snapshots.size() == 1
assert getSnapshotInfo(snapshots[0]) == [null, 0]
}
def "snapshots a generated singletonFileTree as RegularFileSnapshot"() {
given:
def file = tmpDir.createFile('testFile')
def tempDir = tmpDir.createDir('tmpDir')
Factory factory = new Factory() {
@Override
File create() {
return tempDir
}
}
def action = new Action() {
@Override
void execute(OutputStream outputStream) {
outputStream.write("content".getBytes())
}
}
when:
def tree = new FileTreeAdapter(new GeneratedSingletonFileTree(factory, file.name, action))
then:
assertSingleFileTree(tree)
assertSingleFileTree(tree.matching { include file.name })
assertEmptyTree(tree.matching { exclude file.name })
}
private static DirectoryFileTree dirTree(File dir) {
TestFiles.directoryFileTreeFactory().create(dir)
}
private TemporaryFileProvider testFileProvider() {
new TemporaryFileProvider() {
@Override
File newTemporaryFile(String... path) {
return tmpDir.createFile(path)
}
@Override
File createTemporaryFile(String prefix, @Nullable String suffix, @Nullable String... path) {
return null
}
@Override
File createTemporaryDirectory(@Nullable String prefix, @Nullable String suffix, @Nullable String... path) {
return tmpDir.createDir(path)
}
}
}
void assertSingleFileSnapshot(snapshots) {
assert snapshots.size() == 1
assert getSnapshotInfo(snapshots[0]) == [null, 1]
}
void assertEmptyTree(FileCollection fileCollection) {
def snapshots = snapshotter.snapshot((FileCollectionInternal) fileCollection)
assert snapshots.size() == 1
assert snapshots[0] == FileSystemSnapshot.EMPTY
assert fileCollection.files.empty
}
void assertSingleFileTree(FileCollection fileCollection) {
assert fileCollection.files.size() == 1
def file = fileCollection.files[0]
def snapshots = snapshotter.snapshot((FileCollectionInternal) fileCollection)
assertSingleFileSnapshot(snapshots)
assert snapshots[0].absolutePath == file.absolutePath
}
private static List getSnapshotInfo(FileSystemSnapshot tree) {
String rootPath = null
int count = 0
tree.accept(new FileSystemSnapshotVisitor() {
@Override
boolean preVisitDirectory(DirectorySnapshot directorySnapshot) {
if (rootPath == null) {
rootPath = directorySnapshot.absolutePath
}
count++
return true
}
@Override
void visit(FileSystemLocationSnapshot fileSnapshot) {
count++
}
@Override
void postVisitDirectory(DirectorySnapshot directorySnapshot) {
}
})
return [rootPath, count]
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy