An amazing project that generates micro reports from tournament results
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

306 lines
12 KiB

////////////////////////////////////////////////////////////////////////////
//
// Copyright 2017 Realm Inc.
//
// 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 RealmSwift
class SwiftPermissionsAPITests: SwiftSyncTestCase {
var userA: SyncUser!
var userB: SyncUser!
var userC: SyncUser!
override func setUp() {
super.setUp()
let baseName = UUID().uuidString
userA = try! synchronouslyLogInUser(for: .usernamePassword(username: baseName + "a", password: "a", register: true),
server: SwiftSyncTestCase.authServerURL())
userB = try! synchronouslyLogInUser(for: .usernamePassword(username: baseName + "b", password: "a", register: true),
server: SwiftSyncTestCase.authServerURL())
userC = try! synchronouslyLogInUser(for: .usernamePassword(username: baseName + "c", password: "a", register: true),
server: SwiftSyncTestCase.authServerURL())
}
override func tearDown() {
userA.logOut()
userB.logOut()
userC.logOut()
super.tearDown()
}
private func checkPermissionCount(results: SyncPermissionResults,
expected: Int,
file: StaticString = #file,
line: UInt = #line) {
let ex = expectation(description: "Checking permission count")
let token = results.observe { (change) in
if case let .error(theError) = change {
XCTFail("Notification returned error '\(theError)' when running test at \(file):\(line)")
return
}
if results.count == expected {
ex.fulfill()
}
}
waitForExpectations(timeout: 2.0, handler: nil)
token.invalidate()
}
private func get(permission: SyncPermission,
from results: SyncPermissionResults,
file: StaticString = #file,
line: UInt = #line) -> SyncPermission? {
let ex = expectation(description: "Retrieving permission")
var finalValue: SyncPermission?
let token = results.observe { (change) in
if case let .error(theError) = change {
XCTFail("Notification returned error '\(theError)' when running test at \(file):\(line)")
return
}
for result in results where result == permission {
finalValue = result
ex.fulfill()
return
}
}
waitForExpectations(timeout: 2.0, handler: nil)
token.invalidate()
return finalValue
}
/// Ensure the absence of a permission from a results after an elapsed time interval.
/// This method is intended to be used to check that a permission never becomes
/// present within a results to begin with.
private func ensureAbsence(of permission: SyncPermission,
from results: SyncPermissionResults,
after wait: Double = 0.5,
file: StaticString = #file,
line: UInt = #line) {
let ex = expectation(description: "Looking for permission")
var isPresent = false
let token = results.observe { (change) in
if case let .error(theError) = change {
XCTFail("Notification returned error '\(theError)' when running test at \(file):\(line)")
return
}
isPresent = results.contains(permission)
}
DispatchQueue.main.asyncAfter(deadline: .now() + wait) {
ex.fulfill()
}
waitForExpectations(timeout: wait + 1.0, handler: nil)
token.invalidate()
XCTAssertFalse(isPresent, "Permission '\(permission)' was spuriously present (\(file):\(line))")
}
private func tildeSubstitutedURL(for url: URL, user: SyncUser) -> URL {
XCTAssertNotNil(user.identity)
let identity = user.identity!
return URL(string: url.absoluteString.replacingOccurrences(of: "~", with: identity))!
}
/// Setting a permission should work, and then that permission should be able to be retrieved.
func testSettingPermissions() {
// First, there should be no permissions.
let ex = expectation(description: "No permissions for newly created user.")
var results: SyncPermissionResults!
userB.retrievePermissions { (r, error) in
XCTAssertNil(error)
XCTAssertNotNil(r)
results = r
ex.fulfill()
}
waitForExpectations(timeout: 2.0, handler: nil)
checkPermissionCount(results: results, expected: 0)
// Open a Realm for user A.
let uuid = UUID().uuidString
let url = SwiftSyncTestCase.uniqueRealmURL(customName: uuid)
_ = try! synchronouslyOpenRealm(url: url, user: userA)
// Give user B read permissions to that Realm.
let p = SyncPermission(realmPath: tildeSubstitutedURL(for: url, user: userA).path,
identity: userB.identity!,
accessLevel: .read)
// Set the permission.
let ex2 = expectation(description: "Setting a permission should work.")
userA.apply(p) { (error) in
XCTAssertNil(error)
ex2.fulfill()
}
waitForExpectations(timeout: 2.0, handler: nil)
// Now retrieve the permissions again and make sure the new permission is properly set.
let ex3 = expectation(description: "One permission in results after setting the permission.")
userB.retrievePermissions { (r, error) in
XCTAssertNil(error)
XCTAssertNotNil(r)
results = r
ex3.fulfill()
}
waitForExpectations(timeout: 2.0, handler: nil)
// Expected permission: applies to user B, but for user A's Realm.
let finalValue = get(permission: p, from: results)
XCTAssertNotNil(finalValue, "Did not find the permission \(p)")
// Check getting permission by its index.
let index = results.index(of: p)
XCTAssertNotNil(index)
XCTAssertTrue(p == results[index!])
}
/// Observing permission changes should work.
func testObservingPermissions() {
// Get a reference to the permission results.
let ex = expectation(description: "Retrieve permission results.")
var results: SyncPermissionResults!
userB.retrievePermissions { (r, error) in
XCTAssertNil(error)
XCTAssertNotNil(r)
results = r
ex.fulfill()
}
waitForExpectations(timeout: 2.0, handler: nil)
// Open a Realm for user A.
let uuid = UUID().uuidString
let url = SwiftSyncTestCase.uniqueRealmURL(customName: uuid)
_ = try! synchronouslyOpenRealm(url: url, user: userA)
// Register notifications.
let noteEx = expectation(description: "Notification should fire")
let token = results.observe { (change) in
if case .error = change {
XCTFail("Should not return an error")
return
}
if results.count > 0 {
noteEx.fulfill()
}
}
// Give user B read permissions to that Realm.
let p = SyncPermission(realmPath: tildeSubstitutedURL(for: url, user: userA).path,
identity: userB.identity!,
accessLevel: .read)
// Set the permission.
let ex2 = expectation(description: "Setting a permission should work.")
userA.apply(p) { (error) in
XCTAssertNil(error)
ex2.fulfill()
}
waitForExpectations(timeout: 2.0, handler: nil)
// Wait for the notification to be fired.
wait(for: [noteEx], timeout: 2.0)
token.invalidate()
let finalValue = get(permission: p, from: results)
XCTAssertNotNil(finalValue, "Did not find the permission \(p)")
}
/// User should not be able to change a permission for a Realm they don't own.
func testSettingUnownedRealmPermission() {
// Open a Realm for user A.
let uuid = UUID().uuidString
let url = SwiftSyncTestCase.uniqueRealmURL(customName: uuid)
_ = try! synchronouslyOpenRealm(url: url, user: userA)
// Try to have user B give user C permissions to that Realm.
let p = SyncPermission(realmPath: url.path, identity: userC.identity!, accessLevel: .read)
// Attempt to set the permission.
let ex2 = expectation(description: "Setting an invalid permission should fail.")
userB.apply(p) { (error) in
XCTAssertNotNil(error)
ex2.fulfill()
}
waitForExpectations(timeout: 2.0, handler: nil)
// Now retrieve the permissions again and make sure the new permission was not set.
var results: SyncPermissionResults!
let ex3 = expectation(description: "Retrieving the results should work.")
userB.retrievePermissions { (r, error) in
XCTAssertNil(error)
XCTAssertNotNil(r)
results = r
ex3.fulfill()
}
waitForExpectations(timeout: 2.0, handler: nil)
ensureAbsence(of: p, from: results)
}
// MARK: - Offer/response
func testPermissionOffer() {
_ = try! synchronouslyOpenRealm(url: realmURL, user: userA)
var token: String?
// Create an offer.
let ex = expectation(description: "A new permission offer will be processed by the server.")
userA.createOfferForRealm(at: realmURL, accessLevel: .write) { (t, error) in
XCTAssertNil(error)
XCTAssertNotNil(t)
token = t
ex.fulfill()
}
waitForExpectations(timeout: 10.0, handler: nil)
XCTAssertGreaterThan(token!.lengthOfBytes(using: .utf8), 0)
}
func testPermissionOfferResponse() {
_ = try! synchronouslyOpenRealm(url: realmURL, user: userA)
var token: String?
// Create an offer.
let ex = expectation(description: "A new permission offer will be processed by the server.")
userA.createOfferForRealm(at: realmURL, accessLevel: .write) { (t, error) in
XCTAssertNil(error)
XCTAssertNotNil(t)
token = t
ex.fulfill()
}
waitForExpectations(timeout: 10.0, handler: nil)
guard let theToken = token else {
XCTFail("We expected an offer token, but did not get one. Aborting the test.")
return
}
XCTAssertGreaterThan(theToken.lengthOfBytes(using: .utf8), 0)
// Accept the offer.
let ex2 = expectation(description: "A permission offer response will be processed by the server.")
var url: URL?
userB.acceptOffer(forToken: theToken) { (u, error) in
XCTAssertNil(error)
XCTAssertNotNil(u)
url = u
ex2.fulfill()
}
waitForExpectations(timeout: 10.0, handler: nil)
guard let theURL = url else {
XCTFail("We expected a Realm URL, but did not get one. Aborting the test.")
return
}
XCTAssertEqual(theURL.path, tildeSubstitutedURL(for: realmURL, user: userA).path)
do {
_ = try synchronouslyOpenRealm(url: theURL, user: userB)
} catch {
XCTFail("Was not able to successfully open the Realm with user B after accepting the offer.")
}
}
}