NSURL书签在Xcode服务器上的单元测试中失败

NSURL书签在Xcode服务器上的单元测试中失败,xcode,cocoa,unit-testing,appstore-sandbox,xcode-server,Xcode,Cocoa,Unit Testing,Appstore Sandbox,Xcode Server,在我的应用程序的单元测试中,我创建了一个文档范围为NSURL书签。这些测试在我的机器上一直正常工作(现在仍然如此),但在Xcode服务器bot上运行时失败。我不会对单元测试包进行代码设计 - (void)testBookmarks { // Create testing directory NSFileManager *fm = [NSFileManager defaultManager]; NSString *sourceDir = [fm currentDirecto

在我的应用程序的单元测试中,我创建了一个文档范围为
NSURL
书签。这些测试在我的机器上一直正常工作(现在仍然如此),但在Xcode服务器bot上运行时失败。我不会对单元测试包进行代码设计

- (void)testBookmarks
{
    // Create testing directory
    NSFileManager *fm = [NSFileManager defaultManager];
    NSString *sourceDir = [fm currentDirectoryPath];
    NSString *testingDir = [sourceDir stringByAppendingPathComponent:@"~testing dir"];

    if ([fm fileExistsAtPath:testingDir]) {
        [fm removeItemAtPath:testingDir error:NULL];
    }

    [fm createDirectoryAtPath:testingDir
  withIntermediateDirectories:NO
                   attributes:nil
                        error:NULL];

    // Create file to create bookmark to
    NSString *bookmarkedFilePath = [testingDir stringByAppendingPathComponent:@"fileToBookmark.txt"];
    [fm createFileAtPath:bookmarkedFilePath
                contents:nil
              attributes:nil];
    NSURL *originalURL = [NSURL fileURLWithPath:bookmarkedFilePath];

    // Create file to create bookmark relative to
    NSString *relativeFilePath = [testingDir stringByAppendingPathComponent:@"relativeToFile.txt"];
    [fm createFileAtPath:relativeFilePath
                contents:nil
              attributes:nil];

    // Create a document-scoped bookmark
    NSError *docScopedError = nil;
    NSURL *relativeToURL = [NSURL fileURLWithPath:relativeFilePath];
    NSData *bookmark = [originalURL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
                             includingResourceValuesForKeys:nil
                                              relativeToURL:relativeToURL
                                                      error:&docScopedError];

    // Assert everything went well
    XCTAssertNil(docScopedError, @"Error while creating document-scoped bookmark from URL:\n%@\nrelative to: %@",
                 originalURL, relativeToURL);
    XCTAssertNotNil(bookmark, @"No bookmark created to URL:\n%@\nrelative to: %@",
                 originalURL, relativeToURL);
}
这两个断言都失败了,并且记录的消息验证了这两个URL都不是nil,并且我能够验证这两个文件是否都存在于磁盘上。它们都包含在Git checkout目录中,帐户可以完全访问该目录。
relativeToUrl
指向在测试之前创建的文件

生成的
n错误
包含以下信息:

“错误域=NSCOCAERRORDOMAIN Code=256“无法打开文件。”(安全策略不允许的项目URL)UserInfo=0x10691c6d0{NSDebugDescription=安全策略不允许的项目URL}”

它可能引用什么安全策略,我将如何更新它?同样,所有这些都可以在我本地的开发机器上正常工作

更新

我创建了一个演示项目,并将其推到了。您可以随意创建自己的Xcode Bot,从那里拉过来看看是否可以复制。我能够用干净的OS X、Xcode和服务器安装进行复制。

以下是我从与DTS团队成员的讨论中学到的(到目前为止)

  • 安全范围的书签不适用于非沙盒(和非代码签名)应用程序。我的单元测试没有签名或沙盒(这样做会带来其他问题),但不管怎样,它们都可以工作。当下一个OSX版本发布时,它们可能会崩溃,但时间会证明这一点

  • 显然,安全作用域机制认为某些目录是禁止访问的。我将在下面列出一个列表(由于缺少文档),并在发现更多异常时进行更新(请执行相同操作)

  • 我的单元测试在签出位置内创建了一个目录,并为其中一个文件创建了书签。由于我的本地Xcode签出在
    ~/Source code
    中,所以工作正常。但是,Xcode服务器签出到
    /Library/Developer/Xcode服务器/Caches/…
    ,这就是问题的原因

    我用我的实现更新了我的示例GitHub项目,该实现可以解决这个问题。简而言之,我的单元测试中有以下代码:

    NSString *envVarTestingDir = [[NSProcessInfo processInfo].environment objectForKey:@"UNIT_TESTING_DIR"];
    NSString *sourceRelativeDir = [[fm currentDirectoryPath] stringByAppendingPathComponent:@"~testing dir"];
    NSString *testingDirPath = [envVarTestingDir length] > 0 ? envVarTestingDir : sourceRelativeDir;
    
    然后,我有一个单独的CI构建方案,它将
    UNIT\u TESTING\u DIR
    环境变量定义为
    /Users/Shared/~TESTING DIR
    ,因为这是一个全局可访问的位置。这样,我可以让本地构建写入到首选位置,但CI构建不会失败。赢/赢

    PS

    显然,Xcode服务器将
    NSHomeDirectory()
    返回的目录重新分配为
    /var/\u xcsbuildd
    ,这是不允许的


    您的捆绑包有哪些权利?第一行中的路径,如何将其添加到沙盒中?这些是单元测试,没有沙盒,也没有代码签名。您可以将iCloud Drive添加到禁止使用的目录列表中:-/我的解决方法是首先尝试使用安全范围保存URL,如果失败(例如,由于URL指向iCloud Drive),请在没有安全作用域的情况下重试。这似乎很有效。@mage先生很有趣,谢谢!我去更新了上面的列表,但它已经包含在
    ~/Library
    下了,对吗?哦,对了!不过,您可能想提一下,以防其他人忘记iCloud驱动器是
    ~/Library
    ;-)的一部分
    NSString *envVarTestingDir = [[NSProcessInfo processInfo].environment objectForKey:@"UNIT_TESTING_DIR"];
    NSString *sourceRelativeDir = [[fm currentDirectoryPath] stringByAppendingPathComponent:@"~testing dir"];
    NSString *testingDirPath = [envVarTestingDir length] > 0 ? envVarTestingDir : sourceRelativeDir;