diff --git a/RAD.xcodeproj/project.pbxproj b/RAD.xcodeproj/project.pbxproj index d1c1ec5..764f014 100644 --- a/RAD.xcodeproj/project.pbxproj +++ b/RAD.xcodeproj/project.pbxproj @@ -240,6 +240,8 @@ FFC50CBB2181DACF00748BA9 /* TimezonedDate+ObjectConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC50CBA2181DACF00748BA9 /* TimezonedDate+ObjectConvertible.swift */; }; FFD0D71820F8CEF6009FD005 /* Date+Now.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFD0D71720F8CEF6009FD005 /* Date+Now.swift */; }; FFD0D71A20F8D6B7009FD005 /* DateComponents+NegativeOperator.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFD0D71920F8D6B7009FD005 /* DateComponents+NegativeOperator.swift */; }; + FFE53A8D21AE876F00FA5DF4 /* SanityCheckTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE53A8C21AE876F00FA5DF4 /* SanityCheckTestCase.swift */; }; + FFE53A8F21AE8A0600FA5DF4 /* XCTestCase+Resource.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE53A8E21AE8A0600FA5DF4 /* XCTestCase+Resource.swift */; }; FFE8B56A20E6599C0038A53B /* NetworkScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE8B56920E6599C0038A53B /* NetworkScheduler.swift */; }; FFE8B56E20E659DE0038A53B /* RequestBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE8B56D20E659DE0038A53B /* RequestBuilder.swift */; }; FFE8B57220E6604B0038A53B /* URLRequest+HttpMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE8B57120E6604B0038A53B /* URLRequest+HttpMethod.swift */; }; @@ -507,6 +509,8 @@ FFC50CBA2181DACF00748BA9 /* TimezonedDate+ObjectConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TimezonedDate+ObjectConvertible.swift"; sourceTree = ""; }; FFD0D71720F8CEF6009FD005 /* Date+Now.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Now.swift"; sourceTree = ""; }; FFD0D71920F8D6B7009FD005 /* DateComponents+NegativeOperator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateComponents+NegativeOperator.swift"; sourceTree = ""; }; + FFE53A8C21AE876F00FA5DF4 /* SanityCheckTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SanityCheckTestCase.swift; sourceTree = ""; }; + FFE53A8E21AE8A0600FA5DF4 /* XCTestCase+Resource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCTestCase+Resource.swift"; sourceTree = ""; }; FFE8B56920E6599C0038A53B /* NetworkScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkScheduler.swift; sourceTree = ""; }; FFE8B56D20E659DE0038A53B /* RequestBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestBuilder.swift; sourceTree = ""; }; FFE8B57120E6604B0038A53B /* URLRequest+HttpMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLRequest+HttpMethod.swift"; sourceTree = ""; }; @@ -652,6 +656,7 @@ FF2EBFE82183455C00BDDE4C /* EntitiesTests */, FF2193E9217EFFF8003417FF /* OperationTests */, FF4A048721906240003A466B /* SchedulingTests */, + FFE53A8C21AE876F00FA5DF4 /* SanityCheckTestCase.swift */, ); path = ModelTests; sourceTree = ""; @@ -798,6 +803,7 @@ children = ( FF380EF6217DC7E70029A4D2 /* XCTest+OptionalEqual.swift */, FF380EF8217DC80C0029A4D2 /* XCTest+MessageOption.swift */, + FFE53A8E21AE8A0600FA5DF4 /* XCTestCase+Resource.swift */, FF41629521AC3C3B0075D3DF /* XCTestCase+Wait.swift */, ); path = XCTest; @@ -1524,10 +1530,12 @@ FFA0C1AD2191EC0D00D684AA /* AnalyticsDebuggerExtractPayloadTestCase.swift in Sources */, FF84B9122187595800D48755 /* SaveOperationTestCase.swift in Sources */, FF380EF7217DC7E70029A4D2 /* XCTest+OptionalEqual.swift in Sources */, + FFE53A8D21AE876F00FA5DF4 /* SanityCheckTestCase.swift in Sources */, FF219451217F626F003417FF /* ParseJSONOperationTestSuite.swift in Sources */, FF31AFB121A3044900F7A252 /* SuccessCodeClassCleanupTestCase.swift in Sources */, FF5D6F7E218C57EB00A3B8FF /* RangeCreationExpectationBuilder.swift in Sources */, FF380EFB217DC8550029A4D2 /* Inversable.swift in Sources */, + FFE53A8F21AE8A0600FA5DF4 /* XCTestCase+Resource.swift in Sources */, FF154FAB2180A5E300E60011 /* DispatchQueue+Queues.swift in Sources */, FF21944A217F56B8003417FF /* WaitOperationTestCase.swift in Sources */, FF380EF4217DBBAD0029A4D2 /* DateComponentsTestCase.swift in Sources */, diff --git a/RADTests/Extension/XCTest/XCTestCase+Resource.swift b/RADTests/Extension/XCTest/XCTestCase+Resource.swift new file mode 100644 index 0000000..e47f06a --- /dev/null +++ b/RADTests/Extension/XCTest/XCTestCase+Resource.swift @@ -0,0 +1,36 @@ +// +// XCTestCase+Resource.swift +// RADTests +// +// Copyright 2018 NPR +// +// 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. +// + +import XCTest +import AVFoundation + +extension XCTestCase { + func findResource( + name: String, + extension: String = "mp3", + file: StaticString = #file, + line: UInt = #line + ) -> AVPlayerItem! { + guard let url = Bundle.testBundle.url( + forResource: name, withExtension: `extension` + ) else { + XCTFail("Resource is not available", file: file, line: line) + return nil + } + return AVPlayerItem(url: url) + } +} diff --git a/RADTests/Tests/AnalyticsTestCase.swift b/RADTests/Tests/AnalyticsTestCase.swift index 3fbd1cb..749ca8c 100644 --- a/RADTests/Tests/AnalyticsTestCase.swift +++ b/RADTests/Tests/AnalyticsTestCase.swift @@ -79,21 +79,6 @@ class AnalyticsTestCase: OperationTestCase { wait(for: .seconds(5)) } - func findResource( - name: String, - extension: String = "mp3", - file: StaticString = #file, - line: UInt = #line - ) -> AVPlayerItem! { - guard let url = Bundle.testBundle.url( - forResource: name, withExtension: `extension` - ) else { - XCTFail("Resource is not available", file: file, line: line) - return nil - } - return AVPlayerItem(url: url) - } - func play( item: AVPlayerItem?, for time: TimeInterval, diff --git a/RADTests/Tests/ModelTests/SanityCheckTestCase.swift b/RADTests/Tests/ModelTests/SanityCheckTestCase.swift new file mode 100644 index 0000000..45041fb --- /dev/null +++ b/RADTests/Tests/ModelTests/SanityCheckTestCase.swift @@ -0,0 +1,124 @@ +// +// SanityCheckTestCase.swift +// RADTests +// +// Copyright 2018 NPR +// +// 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. +// + +import XCTest +import AVFoundation +@testable import RAD + +class SanityCheckTestCase: XCTestCase { + private var analytics: Analytics? + private var player: AVPlayer? + + func testSanityCheck() { + configureAnalytics() + playASong() + cleanObjects() + configureAnalytics() + checkForUnlockedObjects() + } + + private func configureAnalytics() { + analytics = Analytics() + let player = AVPlayer(playerItem: nil) + self.player = player + analytics?.observePlayer(player) + } + + private func playASong() { + let item = findResource(name: "1_000Events") + player?.replaceCurrentItem(with: item) + player?.play() + + let stopExpectation = self.expectation(description: "Player did stop.") + DispatchQueue.concurrent.asyncAfter( + deadline: .now() + .seconds(3), execute: { + self.player?.pause() + self.player?.replaceCurrentItem(with: nil) + stopExpectation.fulfill() + }) + + wait(for: [stopExpectation], timeout: .seconds(5)) + } + + private func cleanObjects() { + player = nil + analytics = nil + } + + private func checkForUnlockedObjects() { + wait( + for: [radObjectsExpectation(), + sessionIDObjectsExpectation(), + itemSessionObjectsExpectation()], + timeout: .seconds(20)) + } + + private func radObjectsExpectation() -> XCTestExpectation { + let radExpectation = self.expectation( + description: "Rad objects checked.") + analytics?.debugger.objects(for: .rad, completion: { objects in + let lockedObjects = objects.filter({ object in + guard let isLocked = object["isLocked"] as? Bool else { + return false + } + return isLocked + }) + XCTAssert( + lockedObjects.count == 0, + "There locked Rad objects in database.") + radExpectation.fulfill() + }) + return radExpectation + } + + private func sessionIDObjectsExpectation() -> XCTestExpectation { + let sessionIDExpectation = self.expectation( + description: "Session ID objects checked.") + analytics?.debugger.objects( + for: .itemSessionId, completion: { objects in + let lockedObjects = objects.filter({ object in + guard let isLocked = object["isLocked"] as? Bool else { + return false + } + return isLocked + }) + XCTAssert( + lockedObjects.count == 0, + "There locked Session ID objects in database.") + sessionIDExpectation.fulfill() + }) + return sessionIDExpectation + } + + private func itemSessionObjectsExpectation() -> XCTestExpectation { + let itemSessionExpectation = self.expectation( + description: "Item session objects checked.") + analytics?.debugger.objects(for: .rad, completion: { objects in + let lockedObjects = objects.filter({ object in + guard let isActive = object["isActive"] as? Bool else { + return false + } + return isActive + }) + XCTAssert( + lockedObjects.count == 0, + "There locked Rad objects in database.") + itemSessionExpectation.fulfill() + }) + return itemSessionExpectation + } +}