Skip to content
This repository has been archived by the owner on Jan 17, 2019. It is now read-only.

Commit

Permalink
Write stdout/stderr directly, replace Xcode reporter
Browse files Browse the repository at this point in the history
  • Loading branch information
plu committed Feb 20, 2017
1 parent e5227a5 commit dc69f3b
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 108 deletions.
2 changes: 1 addition & 1 deletion Dependencies/FBSimulatorControl
Submodule FBSimulatorControl updated 44 files
+1 −0 .gitignore
+14 −1 FBControlCore/Configuration/FBProcessLaunchConfiguration+Helpers.h
+23 −8 FBControlCore/Configuration/FBProcessLaunchConfiguration+Helpers.m
+1 −1 FBControlCore/Diagnostics/FBDiagnostic.m
+3 −0 FBControlCore/FBControlCore.h
+5 −9 FBControlCore/Tasks/FBTask.m
+32 −0 FBControlCore/Utility/FBFileWriter.h
+59 −0 FBControlCore/Utility/FBFileWriter.m
+53 −0 FBControlCore/Utility/FBPipeReader.h
+53 −0 FBControlCore/Utility/FBPipeReader.m
+81 −0 FBControlCore/Utility/FBSocketReader.h
+209 −0 FBControlCore/Utility/FBSocketReader.m
+30 −0 FBSimulatorControl.xcodeproj/project.pbxproj
+9 −3 FBSimulatorControl/Diagnostics/FBSimulatorDiagnostics.m
+42 −3 FBSimulatorControl/Strategies/FBAgentLaunchStrategy.h
+54 −25 FBSimulatorControl/Strategies/FBAgentLaunchStrategy.m
+1 −1 FBSimulatorControl/Strategies/FBApplicationLaunchStrategy.m
+1 −2 FBSimulatorControl/Strategies/FBSimulatorTestRunStrategy.m
+59 −15 FBSimulatorControlTests/Tests/Integration/FBSimulatorDiagnosticsTests.m
+5 −0 FBSimulatorControlTests/Tests/Integration/FBSimulatorFramebufferTests.m
+23 −0 FBSimulatorControlTests/Tests/Integration/FBSimulatorTestInjectionTests.m
+10 −0 PrivateHeaders/CoreSimulator/CoreSimulator+BlockDefines.h
+3 −2 PrivateHeaders/CoreSimulator/SimDevice.h
+3 −3 XCTestBootstrap/Strategies/FBXCTestRunStrategy.h
+18 −14 XCTestBootstrap/Strategies/FBXCTestRunStrategy.m
+6 −4 XCTestBootstrapTests/Tests/FBXCTestRunStrategyTests.m
+14 −0 fbsimctl/FBSimulatorControlKit/Sources/Bridging.swift
+17 −3 fbsimctl/FBSimulatorControlKit/Sources/Command.swift
+9 −2 fbsimctl/FBSimulatorControlKit/Sources/CommandParsers.swift
+17 −7 fbsimctl/FBSimulatorControlKit/Sources/CommandRunners.swift
+98 −0 fbsimctl/FBSimulatorControlKit/Sources/HidRelay.swift
+8 −7 fbsimctl/FBSimulatorControlKitTests/Tests/Unit/CommandParsersTests.swift
+10 −0 fbsimctl/cli-tests/supports_metal.swift
+8 −0 fbsimctl/cli-tests/tests.py
+7 −0 fbsimctl/cli-tests/util.py
+5 −1 fbsimctl/fbsimctl.xcodeproj/project.pbxproj
+1 −0 fbxctest/FBXCTestKit/Configuration/FBXCTestConfiguration.h
+4 −0 fbxctest/FBXCTestKit/Configuration/FBXCTestConfiguration.m
+8 −0 fbxctest/FBXCTestKit/Reporters/FBJSONTestReporter.m
+2 −0 fbxctest/FBXCTestKit/Reporters/FBXCTestReporter.h
+19 −85 fbxctest/FBXCTestKit/Runners/FBLogicTestRunner.m
+58 −0 fbxctest/FBXCTestKit/Utility/FBLogicTestProcess.h
+168 −0 fbxctest/FBXCTestKit/Utility/FBLogicTestProcess.m
+8 −0 fbxctest/fbxctest.xcodeproj/project.pbxproj
4 changes: 1 addition & 3 deletions PXCTestKit/Command/RunTests/RunTestsReporters.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,12 @@ final class RunTestsReporters {
func addReporter(for simulator: FBSimulator, name: String, testTargetName: String) throws -> FBTestManagerTestReporter {
// `name` might be equal to `testTargetName`, unless tests are partitioned, then `name` is something like "testTargetName/partition-n"
let consoleReporter = reporterType.init(simulatorIdentifier: simulator.identifier, testTargetName: name, consoleOutput: consoleOutput)
let xcodeReportURL = fileManager.urlFor(simulatorConfiguration: simulator.configuration!, target: name).appendingPathComponent("test.log")
let xcodeReporter = try XcodeReporter(simulatorIdentifier: simulator.identifier, testTargetName: name, fileURL: xcodeReportURL)
let testReporter = TestReporter(simulatorIdentifier: simulator.identifier, testTargetName: name)

consoleReporters.append(consoleReporter)
testReporters.append(testReporter)

return TestReporterAdapter(reporters: [consoleReporter, testReporter, xcodeReporter])
return TestReporterAdapter(reporters: [consoleReporter, testReporter])
}

func finishReporting(consoleOutput: ConsoleOutput) throws {
Expand Down
37 changes: 30 additions & 7 deletions PXCTestKit/Command/RunTests/RunTestsWorker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,23 @@ final class RunTestsWorker {
}
}

func extractDiagnostics(fileManager: RunTestsFileManager) throws {
let launchedProcessLogs = simulator.simulatorDiagnostics.launchedProcessLogs()
for application in applications {
guard let diagnostics = launchedProcessLogs.first(where: { $0.0.processName == application.name })?.value else { continue }
let destinationPath = fileManager.urlFor(worker: self).path
try diagnostics.writeOut(toDirectory: destinationPath)
func cleanUpLogFiles(fileManager: RunTestsFileManager) throws {
let logFilesPath = fileManager.urlFor(worker: self).path
for logFilePath in FBFileFinder.contentsOfDirectory(withBasePath: logFilesPath) {
let temporaryFilePath = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString).path
guard
let reader = FileReader(path: logFilePath),
let writer = FileWriter(path: temporaryFilePath)
else { continue }
for line in reader {
writer.write(string: line.replacingOccurrences(of: "XCTestOutputBarrier", with: ""))
}
try FileManager.default.removeItem(atPath: logFilePath)
try FileManager.default.moveItem(atPath: temporaryFilePath, toPath: logFilePath)
}
}

func extractDiagnostics(fileManager: RunTestsFileManager) throws {
for error in errors {
for crash in error.crashes {
let destinationPath = fileManager.urlFor(worker: self).path
Expand All @@ -53,16 +63,25 @@ final class RunTestsWorker {
}

func startTests(context: RunTestsContext, reporters: RunTestsReporters) throws {
let workingDirectoryURL = context.fileManager.urlFor(worker: self)
let testsToRun = context.testsToRun[name] ?? Set<String>()
let testEnvironment = Environment.injectPrefixedVariables(
from: context.environment,
into: testLaunchConfiguration.testEnvironment,
workingDirectoryURL: context.fileManager.urlFor(worker: self)
workingDirectoryURL: workingDirectoryURL
)

let bundleName = self.testLaunchConfiguration.applicationLaunchConfiguration!.bundleName!
let outputPath = workingDirectoryURL.appendingPathComponent("\(bundleName).log").path

let applicationLaunchConfiguration = self.testLaunchConfiguration
.applicationLaunchConfiguration!
.withOutput(try FBProcessOutputConfiguration(stdOut: outputPath, stdErr: outputPath))

let testLaunchConfigurartion = self.testLaunchConfiguration
.withTestsToRun(self.testLaunchConfiguration.testsToRun.union(testsToRun))
.withTestEnvironment(testEnvironment)
.withApplicationLaunchConfiguration(applicationLaunchConfiguration)

let reporter = try reporters.addReporter(for: simulator, name: name, testTargetName: targetName)

Expand Down Expand Up @@ -135,6 +154,10 @@ extension Sequence where Iterator.Element == RunTestsWorker {
try worker.extractDiagnostics(fileManager: context.fileManager)
}

for worker in self {
try worker.cleanUpLogFiles(fileManager: context.fileManager)
}

return flatMap { $0.errors }
}

Expand Down
75 changes: 75 additions & 0 deletions PXCTestKit/FileReader.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//
// FileReader.swift
// pxctest
//
// Created by Johannes Plunien on 20/02/2017.
// Copyright © 2017 Johannes Plunien. All rights reserved.
//

import Foundation

final class FileReader {

private var buffer: Data
private let chunkSize: Int
private let encoding: String.Encoding
private var eof: Bool
private var fileHandle: FileHandle?
private let delimiter: Data

init?(path: String, delimiter: String = "\n", encoding: String.Encoding = .utf8, chunkSize: Int = 4096) {
guard
let fileHandle = FileHandle(forReadingAtPath: path),
let delimiter = delimiter.data(using: encoding)
else { return nil }

self.buffer = Data(capacity: chunkSize)
self.chunkSize = chunkSize
self.delimiter = delimiter
self.encoding = encoding
self.eof = false
self.fileHandle = fileHandle
}

deinit {
fileHandle?.closeFile()
fileHandle = nil
}

func nextLine() -> String? {
guard let fileHandle = fileHandle else {
return nil
}

while !eof {
if let range = buffer.range(of: delimiter) {
let line = String(data: buffer.subdata(in: 0..<range.upperBound), encoding: encoding)
buffer.removeSubrange(0..<range.upperBound)
return line
}
let tmpData = fileHandle.readData(ofLength: chunkSize)
if tmpData.count > 0 {
buffer.append(tmpData)
} else {
eof = true
if buffer.count > 0 {
let line = String(data: buffer as Data, encoding: encoding)
buffer.count = 0
return line
}
}
}
return nil
}

}

extension FileReader: Sequence {

func makeIterator() -> AnyIterator<String> {
return AnyIterator {
return self.nextLine()
}
}

}
35 changes: 35 additions & 0 deletions PXCTestKit/FileWriter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// FileWriter.swift
// pxctest
//
// Created by Johannes Plunien on 20/02/2017.
// Copyright © 2017 Johannes Plunien. All rights reserved.
//

import Foundation

final class FileWriter {

private let encoding: String.Encoding
private var fileHandle: FileHandle?

init?(path: String, encoding: String.Encoding = .utf8) {
FileManager.default.createFile(atPath: path, contents: nil, attributes: nil)

guard let fileHandle = FileHandle(forWritingAtPath: path) else { return nil }

self.encoding = encoding
self.fileHandle = fileHandle
}

deinit {
fileHandle?.closeFile()
fileHandle = nil
}

func write(string: String) {
guard let data = string.data(using: encoding) else { return }
fileHandle?.write(data)
}

}
85 changes: 0 additions & 85 deletions PXCTestKit/Reporter/XcodeReporter.swift

This file was deleted.

23 changes: 15 additions & 8 deletions PXCTestKitTests/Command/RunTests/RunTestsCommandTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ class RunTestsCommandTests: XCTestCase {
["SampleTests", "SampleUITests"].forEach { (target) in
result.context.simulatorConfigurations.forEach { (simulatorConfiguration) in
let url = result.context.fileManager.urlFor(simulatorConfiguration: simulatorConfiguration, target: target)
XCTAssertFileSizeGreaterThan(url.appendingPathComponent("Sample.log").path, 0)
XCTAssertFileSizeGreaterThan(url.appendingPathComponent("test.log").path, 0)
XCTAssertFileSizeGreaterThan(url.appendingPathComponent(logFileName(for: target)).path, 0)
}
}
}
Expand All @@ -78,8 +77,7 @@ class RunTestsCommandTests: XCTestCase {
["SampleTests", "SampleUITests"].forEach { (target) in
result.context.simulatorConfigurations.forEach { (simulatorConfiguration) in
let url = result.context.fileManager.urlFor(simulatorConfiguration: simulatorConfiguration, target: target)
XCTAssertFileSizeGreaterThan(url.appendingPathComponent("Sample.log").path, 0)
XCTAssertFileSizeGreaterThan(url.appendingPathComponent("test.log").path, 0)
XCTAssertFileSizeGreaterThan(url.appendingPathComponent(logFileName(for: target)).path, 0)
}
}
}
Expand All @@ -104,7 +102,6 @@ class RunTestsCommandTests: XCTestCase {
result.context.simulatorConfigurations.forEach { (simulatorConfiguration) in
let url = result.context.fileManager.urlFor(simulatorConfiguration: simulatorConfiguration, target: "SuccessfulTests")
XCTAssertFileSizeGreaterThan(url.appendingPathComponent("Sample.log").path, 0)
XCTAssertFileSizeGreaterThan(url.appendingPathComponent("test.log").path, 0)
}
}

Expand All @@ -126,8 +123,7 @@ class RunTestsCommandTests: XCTestCase {
["SampleTests", "SampleUITests", "SuccessfulTests"].forEach { (target) in
result.context.simulatorConfigurations.forEach { (simulatorConfiguration) in
let url = result.context.fileManager.urlFor(simulatorConfiguration: simulatorConfiguration, target: target)
XCTAssertFileSizeGreaterThan(url.appendingPathComponent("Sample.log").path, 0)
XCTAssertFileSizeGreaterThan(url.appendingPathComponent("test.log").path, 0)
XCTAssertFileSizeGreaterThan(url.appendingPathComponent(logFileName(for: target)).path, 0)
}
}
}
Expand All @@ -149,11 +145,22 @@ class RunTestsCommandTests: XCTestCase {
result.context.simulatorConfigurations.forEach { (simulatorConfiguration) in
let url = result.context.fileManager.urlFor(simulatorConfiguration: simulatorConfiguration, target: "CrashTests")
XCTAssertFileSizeGreaterThan(url.appendingPathComponent("Crash.log").path, 0)
XCTAssertFileSizeGreaterThan(url.appendingPathComponent("test.log").path, 0)
XCTAssertDirectoryContainsFileThatHasSuffix(url.path, ".crash")
}
}

// MARK: -

func logFileName(for target: String) -> String {
switch target {
case "SampleTests": return "Sample.log"
case "SuccessfulTests": return "Sample.log"
case "SampleUITests": return "SampleUITests-Runner.log"
default:
preconditionFailure("Unsupported target: \(target)")
}
}

}

extension RunTestsCommandTests {
Expand Down
28 changes: 28 additions & 0 deletions PXCTestKitTests/FileReaderTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// FileReaderTests.swift
// pxctest
//
// Created by Johannes Plunien on 20/02/2017.
// Copyright © 2017 Johannes Plunien. All rights reserved.
//

import XCTest
@testable import PXCTestKit

class FileReaderTests: XCTestCase {

func testNextLine() {
var expectedLines = Array([
"this\n",
"is\n",
"some\n",
"text\n",
"lastline\n",
].reversed())
let reader = FileReader(path: fixtures.textFilePath)!
for line in reader {
XCTAssertEqual(line, expectedLines.popLast())
}
}

}
5 changes: 5 additions & 0 deletions PXCTestKitTests/Fixtures/something.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
this
is
some
text
lastline
4 changes: 4 additions & 0 deletions PXCTestKitTests/Helper/Fixtures.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ final class Fixtures {
return bundle.url(forResource: "runtime", withExtension: "json")!
}

var textFilePath: String {
return bundle.path(forResource: "something", ofType: "txt")!
}

// MARK: - Sample.app

var sampleAppTestRun: URL {
Expand Down
Loading

8 comments on commit dc69f3b

@davetobin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@plu Thanks for these changes. Just a few questions. I have tried running with these changes and there is now no delay after testings but I don't know where the log files are written to. I have specified '--output /Users/dave/Desktop/Logs' but I no longer get any files generated under 'iPhone 6s' directory. I only get the junit file in Users/dave/Desktop/Logs and the directory structure down to 'iPhone 6s' directory but it contains no files.

Also, is it possible to generate a junit xml file per device like previously?

@plu
Copy link
Owner Author

@plu plu commented on dc69f3b Feb 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, is it possible to generate a junit xml file per device like previously?

Unfortunately I did not add an option for this, so the new behaviour is kind of set in stone (or code). But pull requests are welcome. The new junit.xml contains namespaces, so Jenkins will pick that up and show it nicely per target and device.

I don't know where the log files are written to.

There should be something in /Users/dave/Desktop/Logs per device and per test target. Inside you should find a log file named like your Application.

What kind of tests are you running there, just XCTest or some XCUITest ones?

@davetobin
Copy link
Contributor

@davetobin davetobin commented on dc69f3b Feb 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately I did not add an option for this, so the new behaviour is kind of set in stone (or code). But pull requests are welcome. The new junit.xml contains namespaces, so Jenkins will pick that up and show it nicely per target and device.

That's ok, we will be using Jenkins anyway.

There should be something in /Users/dave/Desktop/Logs per device and per test target. Inside you should find a log file named like your Application.

I get this: /Users/dave/Desktop/Logs/UITests/iOS 10.2/iPhone 6s
but previous to these changes it contained app.log and test.log but now it is empty after testing.

What kind of tests are you running there, just XCTest or some XCUITest ones?

I'm running a XCUITest scheme.

@plu
Copy link
Owner Author

@plu plu commented on dc69f3b Feb 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, that's strange. Now it should contain only one log file (app.log) which should have exactly the same content as you'd see in the Xcode console. I'll try to reproduce the problem.

@plu
Copy link
Owner Author

@plu plu commented on dc69f3b Feb 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've created a ticket and try to look at it tomorrow: #23

@davetobin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, great. Thanks

@plu
Copy link
Owner Author

@plu plu commented on dc69f3b Feb 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, one more question: Can you please show me the output of pxctest version? So I can see on which commit you were, will make reproducing the issue easier, hopefully. Thanks!

@davetobin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pxctest 0.3.1 (dc69f3b)

Appreciate the help with this.

Please sign in to comment.