Skip to content

For testing Foundation on Android #1189

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 12, 2017
Merged

For testing Foundation on Android #1189

merged 1 commit into from
Oct 12, 2017

Conversation

johnno1962
Copy link
Contributor

@johnno1962 johnno1962 commented Aug 25, 2017

Changes I had to make to be able to test Foundation on Android. Results are good considering the differrences of the platform to vanilla Linux:

 Executed 956 tests, with 15 failures (0 unexpected) in 20.926 (20.926) seconds

There seems to be some problem with TestNSAttributedString.test_enumerateAttributes. An invalid dictionary is returned from CFAttributedStringGetAttributesAndLongestEffectiveRange. I couldn’t puzzle out more than that. I’ve also disabled TestURLSession.test_cancelTask as it seems to result in intermmittent crashes though I’m running Foundation from a week ago and I see related commits. Other changes (to TestNSNumber.swift for example) might be useful for other 32 bit platforms.

Thanks!

@xwu
Copy link
Contributor

xwu commented Aug 26, 2017

I’ve looked into the NDK options and they are very limited like they are for any UNIX. On my device there is no /usr/share/zoneinfo/ database but a single file in a proprietary format known only to Java.

From a cursory reading, the single file is simply a concatenated version of the standard files on other platforms; if reading this file directly from the NDK is impossible, then it is important to work out what the proper fallback should be. (See below.)

Answering your reservations one by one UTC and GMT are synonnyms for all intents an purposes in this context and GMT needs to be rewritten to GMT+0000 as this is the only format

GMT being rewritten as GMT+0000 is certainly fine. If UTC and GMT are not treated as synonyms on all other platforms, then they should not be synonyms for Android. If, on the other hand, they are synonyms on all other platforms, then it should be fine here too--however, in that case, it should be handled in CFTimeZone.c uniformly for all platforms.

CFTimeZone.c understands without acces to a database by name. I’d rather not try to alter CFTimeZone.c as it is sourced differently from the swift and swift is a higher level language.

If CFTimeZone.c is where the guts of time zone processing are implemented, and if that's what's not implemented for Android, then clearly that's the correct place to patch if you're providing the corresponding functionality. If you're just logging an error, then clearly it's acceptable to throw that into the Swift initializer.

An invalid Timezone should be fatal when you are debugging but a foundation library should not crash peoples apps out in the field IMO so I’ve opted for the latter.

That's fine on reconsideration; this is a failable initializer and logging and returning nil pretty much upholds the semantic contract of the initializer.

I’ve introduced a pseudo timezone “System” which people can use to format dates to the timezone of the device.

This is a functionality change that shouldn't be part of an Android-specific patch. TimeZone.current is the intended spelling for accessing the system time zone.

if localtime_r(&now, &info) != nil &&
(tzName == "System" || tzName == String(cString: info.tm_zone)) {
(info.tm_gmtoff < 0 ? "-" : "+").withCString {
tzName = String(format: "GMT%s%02d%02d",
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a valiant effort but very much incorrect. An NSTimeZone instance for a particular time zone will have different offsets from GMT depending on the date and time; it is not equivalent to a fixed GMT offset. When you don't have the information to instantiate the requested time zone, the correct result can only be nil.

@johnno1962
Copy link
Contributor Author

johnno1962 commented Aug 27, 2017

I’ve pushed a new simpler version implementing “TimeZone.current” instead of a “System” timezone. It still has it’s limitations in that it simulates a proper timezone with a fixed GMT offset but it’s the best I can do until ICU is able to parse Android's /system/usr/share/zoneinfo/tzdata. I’d be quite reluctant to start making modifications to the very complex CFTimeZone.c and risk breaking other platforms.

Copy link
Contributor

@parkera parkera left a comment

Choose a reason for hiding this comment

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

Why are so many tests related to numbers commented out for Android?

I'm also a bit concerned with just removing tests for Android that seem to be related to ICU support.

var values = [
TimeZone(identifier: "UTC")!,
TimeZone.current
]
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess the problem here is that Android doesn't come with a reasonable ICU?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed, options are very limited for Android date/time conversion from C

XCTAssertEqual(Decimal(186243*15673), Decimal(186243) * Decimal(15673))
#endif
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this not possible on Android?

Copy link
Contributor

Choose a reason for hiding this comment

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

If it's a 32-bit vs 64-bit thing, can we express that differently so it works on other 32 bit platforms?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Couldn't get it to compile for some reason even though there is Decimal.init(_ value: Int64)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Error was:

/home/johnno/swifty-robot-environment/util/prepare_environment/test-foundation/Sources/TestDecimal.swift:280:38: error: arithmetic operation '186243 * 15673' (on type 'Int') results in an overflow
        XCTAssertEqual(Decimal(186243*15673), Decimal(186243) * Decimal(15673))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Was able to fix this: Decimal(Int64(186243)*Int64(15673)). I had a second look and can’t see how the other commenting out could be avoided.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is an incorrect use of these initializers. Int64(15673) creates a value of type Int from the literal and then converts it to a value of type Int64; indeed, consideration has been given to making this usage with literals a compiler warning. You want to write instead Decimal(186243 * 15673 as Int64).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks @xwu. Resolved.

@johnno1962
Copy link
Contributor Author

johnno1962 commented Aug 28, 2017

If you’re interested, the only failures are now:

Sources/TestNSCache.swift:76: error: TestNSCache.test_setWithMutableKeys : XCTAssertEqual failed: ("nil") is not equal to ("Optional(value)") - should be equal to value when using first key
Sources/TestDecimal.swift:349: error: TestDecimal.test_Misc : XCTAssertEqual failed: ("26.99999999999999488") is not equal to ("27") - 27 == 3^3
Sources/TestDecimal.swift:349: error: TestDecimal.test_Misc : XCTAssertEqual failed: ("80.99999999999997952") is not equal to ("81") - 81 == 3^4
Sources/TestFileManager.swift:524: error: TestFileManager.test_homedirectoryForUser : XCTAssertNil failed: "<CFURL 0xb8cbdfd0 [0xb617e004]>{string = file:///data/local/tmp/, encoding = 134217984, base = (null)}" - 
Sources/TestNSLocale.swift:119: error: TestNSLocale.test_localeProperties : failed - Locale lookup unavailable on Android
Sources/TestNSString.swift:888: error: TestNSString.test_expandingTildeInPath : XCTAssertEqual failed: ("/data/local/tmp") is not equal to ("~823F454B-ECB1-40DB-B1D5-012A0A1C615F") - Return copy of receiver if home directory could no be resolved.
TimeZone database not available on Android
Sources/TestTimeZone.swift:176: error: TestTimeZone.test_initializingTimeZoneWithAbbreviation : XCTAssertEqual failed: ("nil") is not equal to ("Optional("America/Halifax")") - expected identifier "America/Halifax" is not equal to "nil"
Sources/TestTimeZone.swift:125: error: TestTimeZone.test_localizedName : failed - Named timezones not available on Android
Sources/TestURL.swift:396: error: TestURL.test_URLByResolvingSymlinksInPath : XCTAssertEqual failed: ("file:///tmp") is not equal to ("file:///tmp/") - URLByResolvingSymlinksInPath removes extraneous path components and resolve symlinks.
Sources/TestURL.swift:431: error: TestURL.test_URLByResolvingSymlinksInPath : XCTAssertEqual failed: ("file:///tmp") is not equal to ("file:///tmp/") - 
429
Sources/TestURLSession.swift:216: error: TestURLSession.test_cancelTask : failed - Intermittent failures on Android
Sources/TestURLSession.swift:471: error: TestURLSession.test_concurrentRequests : failed - 640 tasks causes other tests to fail on Android
Sources/TestXMLParser.swift:136: error: TestXMLParser.test_withDataEncodings : XCTAssertEqual failed: ("[]") is not equal to ("[TestFoundation.XMLParserDelegateEvent.startDocument, TestFoundation.XMLParserDelegateEvent.didStartElement("test", nil, nil, ["attribute": "value"]), TestFoundation.XMLParserDelegateEvent.didStartElement("foo", nil, nil, [:]), TestFoundation.XMLParserDelegateEvent.foundCharacters("bar"), TestFoundation.XMLParserDelegateEvent.didEndElement("foo", nil, nil), TestFoundation.XMLParserDelegateEvent.didEndElement("test", nil, nil)]") - 
Sources/TestNSAttributedString.swift:160: error: TestNSAttributedString.test_enumerateAttributes : failed - Intermittent failures on Android
*** NSClassFromString(TestFoundation.SwiftClass.InnerClass): nested class names not yet supported
Sources/TestJSONEncoder.swift:483: error: TestJSONEncoder.test_encodingTopLevelSingleValueStruct : XCTAssertEqual failed: ("(TopLevelArrayWrapper in _845CC7E595F11E7F77C76EC5CBA6E9D7)<(Timestamp in _845CC7E595F11E7F77C76EC5CBA6E9D7)>(value: TestFoundation.(Timestamp in _845CC7E595F11E7F77C76EC5CBA6E9D7)(value: 2147483647.0))") is not equal to ("(TopLevelArrayWrapper in _845CC7E595F11E7F77C76EC5CBA6E9D7)<(Timestamp in _845CC7E595F11E7F77C76EC5CBA6E9D7)>(value: TestFoundation.(Timestamp in _845CC7E595F11E7F77C76EC5CBA6E9D7)(value: 3141592653.0))") - (TopLevelArrayWrapper in _845CC7E595F11E7F77C76EC5CBA6E9D7)<(Timestamp in _845CC7E595F11E7F77C76EC5CBA6E9D7)> did not round-trip to an equal value.

@@ -103,7 +103,7 @@ class TestNSData: XCTestCase {

func test_writeToURLOptions() {
let saveData = try! Data(contentsOf: Bundle.main.url(forResource: "Test", withExtension: "plist")!)
let savePath = URL(fileURLWithPath: "/var/tmp/Test.plist")
let savePath = URL(fileURLWithPath: NSTemporaryDirectory()+"Test1.plist")
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Can you please put spaces before and after the operator? Also, why have you renamed the output file?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Had to rename output file as bundle resources dir and tmp directory are the same the way the tests run on Android. Deleting Test.plist makes the next run of tests fail.

tzName = "GMT+0000"
}
else if !(tzName.hasPrefix("GMT+") || tzName.hasPrefix("GMT-")) {
NSLog("TimeZone database not available on Android")
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: it should be spelled "Time zone".

#if os(Android)
var now = time(nil), info = tm()
if localtime_r(&now, &info) != nil {
// NOTE: this is not a real timezone but a fixed offset from GMT.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: again, "time zone".

@alblue
Copy link
Contributor

alblue commented Oct 5, 2017

@johnno1962 there are a number of different changes here, including some purely stylistic ones. Can you separate them into individual PRs that can be merged independently? For example, your changes for if os(Linux) || os(Android) changes - are these something that can be submitted as a separate PR rebased against master?

@johnno1962
Copy link
Contributor Author

johnno1962 commented Oct 5, 2017

Not sure I follow you. These are the minimum changes for tests to run on Android, the only stylistic changes I can see are changing XCTAssertTrue to XCTAssertEqual in a couple of places to aid debugging. I reverted the if os(Linux) || os(Android) changes in the finish as I use a compiler which treats Android as a synonym for Linux if you test for it so the number of changes is down from 70 odd files to 18. The only thing is perhaps out of place here is the NSTimeZone changes which I can separate out if you like. Let me rebase and squash and see if you’re happy with it.

@alblue
Copy link
Contributor

alblue commented Oct 5, 2017

@johnno1962 yeah, maybe a squash will help show where we are with this :)

@johnno1962
Copy link
Contributor Author

OK, rebase should be good to go now.

@alblue
Copy link
Contributor

alblue commented Oct 5, 2017

@swift-ci please test

@alblue
Copy link
Contributor

alblue commented Oct 5, 2017

Generally speaking the changes look OK - there are several where the Android specific tests are stubbed out (looks like the threading and timezone naming ones), something to deal with the fact that /data is a suitable path for Android and not /tmp or /usr, and a few minor formatting issues (e.g. XCTAssert(a=b) to XCTAssertEqual(a,b) and so on). The only other thing is some >Int32 sized variables which have been stubbed out with if !arm which I assume is shorthand for 'if 32 bit'.

Provided the tests pass I think this is probably good to go...

@alblue
Copy link
Contributor

alblue commented Oct 11, 2017

@johnno1962 can you rebase and fix the conflicts please?

@johnno1962
Copy link
Contributor Author

Rebased, beginning to feel like we’ll not be able to keep this open much longer.

@alblue
Copy link
Contributor

alblue commented Oct 11, 2017

@swift-ci please test

@johnno1962
Copy link
Contributor Author

johnno1962 commented Oct 11, 2017

Random typo fixed.. you’ll need to test again

@alblue
Copy link
Contributor

alblue commented Oct 11, 2017

@swift-ci please test again

@alblue alblue dismissed parkera’s stale review October 11, 2017 19:47

Issues have been addressed

@alblue
Copy link
Contributor

alblue commented Oct 11, 2017

@swift-ci please test

@alblue
Copy link
Contributor

alblue commented Oct 11, 2017

Hmm. Failure is in libdispatch:

src/libdispatch.so: error: undefined reference to '__atomic_fetch_sub_4'
src/libdispatch.so: error: undefined reference to '__atomic_load_4'
src/libdispatch.so: error: undefined reference to '__atomic_fetch_add_4'
src/libdispatch.so: error: undefined reference to '__atomic_compare_exchange_4'
src/libdispatch.so: error: undefined reference to '__atomic_fetch_or_4'
src/libdispatch.so: error: undefined reference to '__atomic_fetch_and_4'
src/libdispatch.so: error: undefined reference to '__atomic_store_4'
src/libdispatch.so: error: undefined reference to '__atomic_exchange_4'
clang-5.0: error: linker command failed with exit code 1 (use -v to see invocation)

@alblue
Copy link
Contributor

alblue commented Oct 11, 2017

@swift-ci please clean test

@alblue
Copy link
Contributor

alblue commented Oct 11, 2017 via email

@johnno1962
Copy link
Contributor Author

Is this anything to do with #1206? Can’t be the first time tests have been run since then.

@parkera
Copy link
Contributor

parkera commented Oct 11, 2017

cc @shahmishal

@alblue
Copy link
Contributor

alblue commented Oct 11, 2017 via email

@shahmishal
Copy link
Member

We are seeing this on master branch:

https://ci.swift.org/job/oss-swift-incremental-RA-linux-ubuntu-16_04-long-test/407/
https://ci.swift.org/job/oss-swift-incremental-RA-linux-ubuntu-16_10-long-test/408/
https://ci.swift.org/job/oss-swift-incremental-RA-linux-ubuntu-14_04-long-test/1063/

This started after following commits:

Git (apple/swift-llvm.git)

  • Add section headers to SpecialCaseLists
  • [llvm-cov] Improve const-correctness of filters. NFC.
  • [llvm-cov] Create directory structure when filtering using -name*=
  • [llvm-cov] Hide files with no coverage from the index when filtering by
  • [llvm-cov] Fix showing title when filtering and not outputting to a
  • [ProfileData] Fix data racing in merging indexed profiles
  • Check for overflows when calculating the offset in GetGEPCost.
  • Convert an APInt to int64_t properly in TTI::getGEPCost().
  • [Dominators] Invalidate DFS numbers upon edge deletions
  • Don't move llvm.localescape outside the entry block in the GCOV

Git (apple/swift-clang.git)

  • [Driver] Disable static C++ library support on Fuchsia
  • Enable AddressSanitizer for Fuchsia targets
  • [Driver][Fuchsia] Pass --hash-style=gnu to the linker
  • Cleanup and generalize -shared-libasan.
  • [Driver] Fix -static-libsan / -shared-libsan on Darwin
  • Allow specifying sanitizers in blacklists
  • [Preprocessor] Preserve #pragma clang assume_nonnull in preprocessed
  • Fix templated type alias completion when using global completion cache
  • Use EmitPointerWithAlignment to get alignment information of the pointer

Git (apple/swift-corelibs-foundation.git)

  • Implemented FileManager.attributesOfFileSystem()
  • Fallback to statvfs in Linux for filesystem attributes
  • Fixed FileManager.attributesOfFileSystem tests
  • Fixed FileManager.attributesOfFileSystem tests (+1 squashed commit)

Git (apple/swift-compiler-rt.git)

  • [ubsan] Add a static runtime on Darwin
  • [ubsan] Fix Asan internal alloc corruption in PR33221 test.
  • cmake: Fix one more usage of append()
  • Use list(APPEND) instead of append()
  • [ubsan] Save binary name before parsing options
  • [ubsan] Make ubsan version of __sanitizer_print_stack_trace consistent
  • [compiler-rt] Cleanup decorators

@alblue
Copy link
Contributor

alblue commented Oct 12, 2017 via email

@shahmishal
Copy link
Member

@alblue, @gottesmm reverted the commit which caused the issue.

@swift-ci test

@alblue
Copy link
Contributor

alblue commented Oct 12, 2017

@shahmishal @gottesmm can you clarify which commit was reverted, so that we know what it was?

@gottesmm
Copy link
Contributor

This is the linux failures from yesterday? A clang commit was cherry-picked that broke lowering of atomic intrinsics. So we were emitting calls to the intrinsics instead of just using builtin llvm instructions.

@alblue
Copy link
Contributor

alblue commented Oct 12, 2017

Thanks!

@alblue
Copy link
Contributor

alblue commented Oct 12, 2017

@swift-ci please test and merge

@swift-ci swift-ci merged commit d94be7e into swiftlang:master Oct 12, 2017
@johnno1962
Copy link
Contributor Author

johnno1962 commented Oct 13, 2017

Tnanks @alblue 👍 👍, we’re on a roll! #1198 would be next (preferably before #1216 to minimise conflicts as the latter is quite a refactoring) then I can rebase and clean up #1113 and we’re done. Re: all the boilerplate importing the right foundation in these files I’d recommend a @_exported import something like the following in main.swift and all the other imports could be removed but that’s a PR for anther day:

#if DEPLOYMENT_RUNTIME_OBJC || os(Linux)
@_exported import Foundation
@_exported import XCTest
#else
@_exported import SwiftFoundation
@_exported import SwiftXCTest
#endif

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants