@@ -1883,4 +1883,143 @@ final class EnumeratorTests: NextcloudFileProviderKitTestCase {
18831883 )
18841884 }
18851885 }
1886+
1887+ func testLockChangeInNestedFileDetectedDuringWorkingSetEnumeration( ) async throws {
1888+ let db = Self . dbManager. ncDatabase ( )
1889+ debugPrint ( db)
1890+
1891+ let remoteChildFolder = MockRemoteItem (
1892+ identifier: " childFolder " ,
1893+ versionIdentifier: " CHILD_V1 " ,
1894+ name: " childFolder " ,
1895+ remotePath: Self . account. davFilesUrl + " /folder/childFolder " ,
1896+ directory: true ,
1897+ account: Self . account. ncKitAccount,
1898+ username: Self . account. username,
1899+ userId: Self . account. id,
1900+ serverUrl: Self . account. serverUrl
1901+ )
1902+
1903+ let remoteNestedFile = MockRemoteItem (
1904+ identifier: " nestedFile " ,
1905+ versionIdentifier: " FILE_V1 " ,
1906+ name: " nestedFile.txt " ,
1907+ remotePath: Self . account. davFilesUrl + " /folder/childFolder/nestedFile.txt " ,
1908+ locked: true ,
1909+ lockOwner: " otherUser " ,
1910+ lockTimeOut: Date . now. advanced ( by: 1_000_000 ) ,
1911+ account: Self . account. ncKitAccount,
1912+ username: Self . account. username,
1913+ userId: Self . account. id,
1914+ serverUrl: Self . account. serverUrl
1915+ )
1916+
1917+ remoteFolder. children = [ remoteChildFolder]
1918+ remoteChildFolder. parent = remoteFolder
1919+ remoteChildFolder. children = [ remoteNestedFile]
1920+ remoteNestedFile. parent = remoteChildFolder
1921+
1922+ let remoteInterface = MockRemoteInterface ( account: Self . account, rootItem: rootItem)
1923+
1924+ var folderMetadata = remoteFolder. toItemMetadata ( account: Self . account)
1925+ folderMetadata. visitedDirectory = true
1926+ Self . dbManager. addItemMetadata ( folderMetadata)
1927+
1928+ var childFolderMetadata = remoteChildFolder. toItemMetadata ( account: Self . account)
1929+ childFolderMetadata. visitedDirectory = true
1930+ Self . dbManager. addItemMetadata ( childFolderMetadata)
1931+
1932+ var nestedFileMetadata = remoteNestedFile. toItemMetadata ( account: Self . account)
1933+ nestedFileMetadata. downloaded = true
1934+ nestedFileMetadata. lock = false
1935+ nestedFileMetadata. lockOwner = " "
1936+ nestedFileMetadata. lockTimeOut = nil
1937+ Self . dbManager. addItemMetadata ( nestedFileMetadata)
1938+
1939+ let anchorDate = Date ( ) . addingTimeInterval ( - 300 )
1940+ let formatter = ISO8601DateFormatter ( )
1941+ let anchor = try NSFileProviderSyncAnchor ( XCTUnwrap ( formatter. string ( from: anchorDate) . data ( using: . utf8) ) )
1942+
1943+ let enumerator = try Enumerator (
1944+ enumeratedItemIdentifier: . workingSet,
1945+ account: Self . account,
1946+ remoteInterface: remoteInterface,
1947+ dbManager: Self . dbManager,
1948+ log: FileProviderLogMock ( )
1949+ )
1950+
1951+ let observer = MockChangeObserver ( enumerator: enumerator)
1952+ try await observer. enumerateChanges ( from: anchor)
1953+
1954+ XCTAssertNil ( observer. error)
1955+
1956+ let dbNestedFile = try XCTUnwrap (
1957+ Self . dbManager. itemMetadata ( ocId: remoteNestedFile. identifier)
1958+ )
1959+ XCTAssertTrue (
1960+ dbNestedFile. lock,
1961+ " Lock change on nested file should be detected during working set enumeration "
1962+ )
1963+ XCTAssertEqual ( dbNestedFile. lockOwner, " otherUser " )
1964+
1965+ let nestedFileReported = observer. changedItems. contains {
1966+ $0. itemIdentifier. rawValue == remoteNestedFile. identifier
1967+ }
1968+ XCTAssertTrue (
1969+ nestedFileReported,
1970+ " Nested file with lock change should be reported as changed "
1971+ )
1972+ }
1973+
1974+ func testLockTokenPreservedDuringTargetDepthRead( ) async throws {
1975+ let db = Self . dbManager. ncDatabase ( )
1976+ debugPrint ( db)
1977+
1978+ let remoteFile = MockRemoteItem (
1979+ identifier: " lockedFile " ,
1980+ versionIdentifier: " V1 " ,
1981+ name: " lockedFile.txt " ,
1982+ remotePath: Self . account. davFilesUrl + " /lockedFile.txt " ,
1983+ locked: true ,
1984+ lockOwner: Self . account. username,
1985+ lockTimeOut: Date . now. advanced ( by: 1_000_000 ) ,
1986+ account: Self . account. ncKitAccount,
1987+ username: Self . account. username,
1988+ userId: Self . account. id,
1989+ serverUrl: Self . account. serverUrl
1990+ )
1991+
1992+ rootItem. children = [ remoteFile]
1993+ remoteFile. parent = rootItem
1994+
1995+ let remoteInterface = MockRemoteInterface ( account: Self . account, rootItem: rootItem)
1996+
1997+ var fileMetadata = remoteFile. toItemMetadata ( account: Self . account)
1998+ fileMetadata. lockToken = " local-lock-token-123 "
1999+ fileMetadata. downloaded = true
2000+ Self . dbManager. addItemMetadata ( fileMetadata)
2001+
2002+ let preRead = try XCTUnwrap ( Self . dbManager. itemMetadata ( ocId: " lockedFile " ) )
2003+ XCTAssertEqual ( preRead. lockToken, " local-lock-token-123 " )
2004+
2005+ let ( metadatas, _, _, _, _, readError) = await Enumerator . readServerUrl (
2006+ Self . account. davFilesUrl + " /lockedFile.txt " ,
2007+ account: Self . account,
2008+ remoteInterface: remoteInterface,
2009+ dbManager: Self . dbManager,
2010+ depth: . target,
2011+ log: FileProviderLogMock ( )
2012+ )
2013+
2014+ XCTAssertNil ( readError)
2015+ XCTAssertNotNil ( metadatas)
2016+
2017+ let postRead = try XCTUnwrap ( Self . dbManager. itemMetadata ( ocId: " lockedFile " ) )
2018+ XCTAssertEqual (
2019+ postRead. lockToken,
2020+ " local-lock-token-123 " ,
2021+ " lockToken must be preserved across target-depth reads "
2022+ )
2023+ XCTAssertTrue ( postRead. downloaded, " downloaded state must be preserved " )
2024+ }
18862025}
0 commit comments