Add Dev tests and fix hard coded paths (#192)

* Added Dev tests and fixed hard coded paths, fixes #183

* Fixed Path dependency in 5.2 Package

* Removed mxcl/Path dependency

* Removed mxcl/Path dependency, Added confirmation of file existence in Init test

* Added sdk install head of init command test

* Moved carton sdk install to static setup method for tests

* Moved carton sdk install to static setup method for tests

* Moved carton sdk install to static setup method for tests

* Moved carton sdk install to static setup method for tests

* Moved carton sdk install to static setup method for tests

* changed order of actions for github automations to support testing

* modified test run to exclude release

* changed sdk install to run per test

* adjusted github workflows to create carton sdk folders

* adjusted github workflows to use /home/runner instead of root

* adjusted test to wait for sdk installation

* adjusted ubuntu tests for passing

* adjusted Dockerfile to run tests

* added tmate session for debugging

* Removed tmate session, added directory creation for carton sdk and sym link

* Adjusted order of commands for runner

* Fixed mkdir from worker to runner

* Added more terminal output for debugging

* Added more terminal output for debugging

* Added more terminal output for debugging

* Added more terminal output for debugging

* Added more terminal output for debugging

* Fixed hard coded paths

* Removed test investigation fixtures

* Removed test investigation fixtures

Co-authored-by: thecb4 <cavelle@tehcb4.io>
This commit is contained in:
thecb4 2020-12-24 03:49:28 -05:00 committed by GitHub
parent 0ac284a2cf
commit d7352b5a25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 291 additions and 88 deletions

View File

@ -99,7 +99,6 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Build on Ubuntu 20.04 with Swift 5.3
run: |
swift test -c release --enable-test-discovery

View File

@ -6,6 +6,7 @@ LABEL org.opencontainers.image.source https://github.com/swiftwasm/carton
RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true && apt-get -q update && \
apt-get -q install -y \
build-essential \
libsqlite3-0 \
libsqlite3-dev \
curl unzip \
@ -23,6 +24,7 @@ COPY . carton/
RUN cd carton && \
./install_ubuntu_deps.sh && \
swift test -c release --enable-test-discovery && \
swift build -c release && \
cd TestApp && ../.build/release/carton test && cd .. && \
mv .build/release/carton /usr/bin && \

View File

@ -37,15 +37,6 @@
"version": "0.11.0"
}
},
{
"package": "Path.swift",
"repositoryURL": "https://github.com/mxcl/Path.swift.git",
"state": {
"branch": null,
"revision": "f062ed9ce3729fb3ba3f43573136d2a0e0c6d209",
"version": "1.0.0"
}
},
{
"package": "routing-kit",
"repositoryURL": "https://github.com/vapor/routing-kit.git",

View File

@ -35,7 +35,6 @@ let package = Package(
.package(url: "https://github.com/apple/swift-crypto.git", from: "1.1.0"),
.package(url: "https://github.com/JohnSundell/Splash.git", from: "0.14.0"),
.package(url: "https://github.com/swiftwasm/WasmTransformer", .upToNextMinor(from: "0.0.2")),
.package(url: "https://github.com/mxcl/Path.swift.git", .exact("1.0.0")),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module
@ -110,11 +109,10 @@ let package = Package(
"CartonHelpers",
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "Path", package: "Path.swift"),
]
),
.testTarget(
name: "CartonCLITests",
name: "CartonCommandTests",
dependencies: [
"CartonCLI",
]

View File

@ -106,7 +106,7 @@ let package = Package(
]
),
.testTarget(
name: "CartonCLITests",
name: "CartonCommandTests",
dependencies: [
"CartonCLI",
]

View File

@ -172,10 +172,11 @@ public final class Toolchain {
let package = try self.package.get()
let targetPaths = package.targets.compactMap { target -> String? in
guard let path = target.path else {
switch target.type {
case .regular:
return "Sources/\(target.name)"
return RelativePath("Sources").appending(component: target.name).pathString
case .test, .system:
return nil
}

View File

@ -169,7 +169,7 @@ public class ToolchainSystem {
#if os(macOS)
let platformSuffixes = ["osx", "catalina", "macos"]
#elseif os(Linux)
let releaseFile = AbsolutePath("/etc/lsb-release")
let releaseFile = AbsolutePath("/etc").appending(component: "lsb-release")
guard fileSystem.isFile(releaseFile) else {
throw ToolchainError.unsupportedOperatingSystem
}

View File

@ -39,7 +39,10 @@ struct HashArchive: ParsableCommand {
let terminal = InteractiveWriter.stdout
let cwd = localFileSystem.currentWorkingDirectory!
let staticPath = AbsolutePath(cwd, "static")
let dotFilesStaticPath = AbsolutePath(localFileSystem.homeDirectory, ".carton/static")
let dotFilesStaticPath = localFileSystem.homeDirectory.appending(
components: ".carton",
"static"
)
try localFileSystem.createDirectory(dotFilesStaticPath, recursive: true)
let hashes = try ["dev", "bundle", "test"].map { entrypoint -> (String, String) in
@ -85,7 +88,10 @@ struct HashArchive: ParsableCommand {
"""
try localFileSystem.writeFileContents(
AbsolutePath(cwd, RelativePath("Sources/carton/Server/StaticArchive.swift")),
AbsolutePath(
cwd,
RelativePath("Sources").appending(components: "carton", "Server", "StaticArchive.swift")
),
bytes: ByteString(encodingAsUTF8: hashesFileContent)
)
}

View File

@ -1,63 +0,0 @@
// Copyright 2020 Carton contributors
//
// 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.
//
// Created by Cavelle Benjamin on Dec/20/20.
//
@testable import CartonCLI
import XCTest
final class DevCommandTests: XCTestCase {
func testDefaultArgumentParsing() throws {
// given
let arguments: [String] = []
// when
AssertParse(Dev.self, arguments) { command in
// then
XCTAssertNotNil(command)
}
}
func testHelpString() throws {
// given
let expectation =
"""
OVERVIEW: Watch the current directory, host the app, rebuild on change.
USAGE: carton dev [--product <product>] [--destination <destination>] [--custom-index-page <custom-index-page>] [--release] [--verbose] [--port <port>] [--skip-auto-open]
OPTIONS:
--product <product> Specify name of an executable product in development.
--destination <destination>
This option has no effect and will be removed in a
future version of `carton`
--custom-index-page <custom-index-page>
Specify a path to a custom `index.html` file to be
used for your app.
--release When specified, build in the release mode.
-v, --verbose Don't clear terminal window after files change.
-p, --port <port> Set the HTTP port the development server will run on.
(default: 8080)
--skip-auto-open Skip automatically opening app in system browser.
--version Show the version.
-h, --help Show help information.
"""
// when
// then
AssertExecuteCommand(command: "carton dev -h", expected: expectation)
}
}

View File

@ -177,18 +177,24 @@ public func AssertHelp<T: ParsableCommand, U: ParsableCommand>(
)
}
public class EmptyTest: XCTestCase {}
extension EmptyTest: Testable {}
public extension XCTest {
var debugURL: URL {
let bundleURL = Bundle(for: type(of: self)).bundleURL
static var debugURL: URL {
let bundleURL = Bundle(for: EmptyTest.self).bundleURL
return bundleURL.lastPathComponent.hasSuffix("xctest")
? bundleURL.deletingLastPathComponent()
: bundleURL
}
func AssertExecuteCommand(
static func AssertExecuteCommand(
command: String,
cwd: URL? = nil, // To allow for testing of file based output
expected: String? = nil,
exitCode: ExitCode = .success,
debug: Bool = false,
file: StaticString = #file, line: UInt = #line
) {
let splitCommand = command.split(separator: " ")
@ -210,6 +216,10 @@ public extension XCTest {
}
process.arguments = arguments
if let workingDirectory = cwd {
process.currentDirectoryURL = workingDirectory
}
let output = Pipe()
process.standardOutput = output
let error = Pipe()
@ -229,6 +239,8 @@ public extension XCTest {
let outputActual = String(data: outputData, encoding: .utf8)!
.trimmingCharacters(in: .whitespacesAndNewlines)
if debug { print(outputActual) }
let errorData = error.fileHandleForReading.readDataToEndOfFile()
let errorActual = String(data: errorData, encoding: .utf8)!
.trimmingCharacters(in: .whitespacesAndNewlines)
@ -244,4 +256,70 @@ public extension XCTest {
XCTAssertEqual(process.terminationStatus, exitCode.rawValue, file: file, line: line)
}
func AssertExecuteCommand(
command: String,
cwd: URL? = nil, // To allow for testing of file based output
expected: String? = nil,
exitCode: ExitCode = .success,
debug: Bool = false,
file: StaticString = #file, line: UInt = #line
) {
let splitCommand = command.split(separator: " ")
let arguments = splitCommand.dropFirst().map(String.init)
let commandName = String(splitCommand.first!)
let commandURL = XCTest.debugURL.appendingPathComponent(commandName)
guard (try? commandURL.checkResourceIsReachable()) ?? false else {
XCTFail("No executable at '\(commandURL.standardizedFileURL.path)'.",
file: file, line: line)
return
}
let process = Process()
if #available(macOS 10.13, *) {
process.executableURL = commandURL
} else {
process.launchPath = commandURL.path
}
process.arguments = arguments
if let workingDirectory = cwd {
process.currentDirectoryURL = workingDirectory
}
let output = Pipe()
process.standardOutput = output
let error = Pipe()
process.standardError = error
if #available(macOS 10.13, *) {
guard (try? process.run()) != nil else {
XCTFail("Couldn't run command process.", file: file, line: line)
return
}
} else {
process.launch()
}
process.waitUntilExit()
let outputData = output.fileHandleForReading.readDataToEndOfFile()
let outputActual = String(data: outputData, encoding: .utf8)!
.trimmingCharacters(in: .whitespacesAndNewlines)
if debug { print(outputActual) }
let errorData = error.fileHandleForReading.readDataToEndOfFile()
let errorActual = String(data: errorData, encoding: .utf8)!
.trimmingCharacters(in: .whitespacesAndNewlines)
if let expected = expected {
AssertEqualStringsIgnoringTrailingWhitespace(
expected,
errorActual + outputActual,
file: file,
line: line
)
}
}
}

View File

@ -0,0 +1,24 @@
// Copyright 2020 Carton contributors
//
// 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.
//
// Created by Cavelle Benjamin on Dec/20/20.
//
@testable import CartonCLI
import XCTest
extension DevCommandTests: Testable {}
// Dev Command stub
final class DevCommandTests: XCTestCase {}

View File

@ -0,0 +1,76 @@
// Copyright 2020 Carton contributors
//
// 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.
//
// Created by Cavelle Benjamin on Dec/20/20.
//
@testable import CartonCLI
import TSCBasic
import XCTest
extension InitCommandTests: Testable {}
final class InitCommandTests: XCTestCase {
func testWithNoArguments() throws {
// given I've created a directory
let package = "wasp"
let packageDirectory = testFixturesDirectory.appending(component: package)
// it's ok if there is nothing to delete
do { try packageDirectory.delete() } catch {}
try packageDirectory.mkdir()
XCTAssertTrue(packageDirectory.exists, "Did not create \(package) directory")
AssertExecuteCommand(
command: "carton init",
cwd: packageDirectory.url
)
// Confirm that the files are actually in the folder
XCTAssertTrue(packageDirectory.ls().contains("Package.swift"), "Package.swift does not exist")
XCTAssertTrue(packageDirectory.ls().contains("README.md"), "README.md does not exist")
XCTAssertTrue(packageDirectory.ls().contains(".gitignore"), ".gitignore does not exist")
XCTAssertTrue(packageDirectory.ls().contains("Sources"), "Sources does not exist")
XCTAssertTrue(
packageDirectory.ls().contains("Sources/\(package)"),
"Sources/\(package) does not exist"
)
XCTAssertTrue(
packageDirectory.ls().contains("Sources/\(package)/main.swift"),
"Sources/\(package)/main.swift does not exist"
)
XCTAssertTrue(packageDirectory.ls().contains("Tests"), "Tests does not exist")
XCTAssertTrue(
packageDirectory.ls().contains("Tests/LinuxMain.swift"),
"Tests/LinuxMain.swift does not exist"
)
XCTAssertTrue(
packageDirectory.ls().contains("Tests/\(package)Tests"),
"Tests/\(package)Tests does not exist"
)
XCTAssertTrue(
packageDirectory.ls().contains("Tests/\(package)Tests/\(package)Tests.swift"),
"Tests/\(package)Tests/\(package)Tests.swift does not exist"
)
XCTAssertTrue(
packageDirectory.ls().contains("Tests/\(package)Tests/XCTestManifests.swift"),
"Tests/\(package)Tests/XCTestManifests.swift does not exist"
)
// finally, clean up
try packageDirectory.delete()
}
}

View File

@ -0,0 +1,91 @@
// Copyright 2020 Carton contributors
//
// 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.
//
// Created by Cavelle Benjamin on Dec/20/20.
//
import Foundation
import TSCBasic
public protocol Testable {
var productsDirectory: AbsolutePath { get }
var testFixturesDirectory: AbsolutePath { get }
var packageDirectory: AbsolutePath { get }
}
public extension Testable {
/// Returns path to the built products directory.
var productsDirectory: AbsolutePath {
#if os(macOS)
for bundle in Bundle.allBundles where bundle.bundlePath.hasSuffix(".xctest") {
return AbsolutePath(bundle.bundleURL.deletingLastPathComponent().path)
}
fatalError("couldn't find the products directory")
#else
return AbsolutePath(Bundle.main.bundleURL.path)
#endif
}
var testFixturesDirectory: AbsolutePath {
packageDirectory.appending(components: "Tests", "Fixtures")
}
var packageDirectory: AbsolutePath {
// necessary if you are using xcode
if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil {
return productsDirectory
.parentDirectory
.parentDirectory
.parentDirectory
.parentDirectory
.parentDirectory
}
return productsDirectory
.parentDirectory
.parentDirectory
.parentDirectory
}
}
extension AbsolutePath {
func mkdir() throws {
_ = try FileManager.default.createDirectory(
atPath: pathString,
withIntermediateDirectories: true
)
}
func delete() throws {
_ = try FileManager.default.removeItem(atPath: pathString)
}
var url: URL {
URL(fileURLWithPath: pathString)
}
var exists: Bool {
FileManager.default.fileExists(atPath: pathString)
}
func ls() -> [String] {
guard let paths = try? FileManager.default.subpathsOfDirectory(atPath: pathString)
else { return [] }
return paths
}
static var home: AbsolutePath {
AbsolutePath(FileManager.default.homeDirectoryForCurrentUser.path)
}
}