public void ContinueLoginAndSchedule() { NotifyLoading(true); SimvaApi <IStudentsApi> .ContinueLogin() .Then(simvaController => { this.auth = simvaController.AuthorizationInfo; this.simvaController = simvaController; return(UpdateSchedule()); }) .Then(schedule => { var result = new AsyncCompletionSource(); StartCoroutine(AsyncCoroutine(LaunchActivity(schedule.Next), result)); return(result); }) .Catch(error => { NotifyLoading(false); NotifyManagers(error.Message); }) .Finally(() => { OpenIdUtility.tokenLogin = false; }); }
private IAsyncOperation <string> DownloadAsTextAsync(string url) { var op = new AsyncCompletionSource <string>(); var webClient = new WebClient(); webClient.DownloadStringCompleted += (sender, args) => { webClient.Dispose(); if (args.Error != null) { Console.WriteLine("Download failed: " + args.Error.Message); op.SetException(args.Error); } else { Console.WriteLine("Download completed."); op.SetResult(args.Result); } }; webClient.DownloadProgressChanged += (sender, args) => { Console.WriteLine("Download progress: " + args.ProgressPercentage + "%."); op.TrySetProgress(args.ProgressPercentage / 100f); }; Console.WriteLine("Downloading " + url + "."); webClient.DownloadStringAsync(new Uri(url)); return(op.Operation); }
public IAsyncOperation Continue(string activityId, bool completed) { NotifyLoading(true); return(API.Api.SetCompletion(activityId, API.AuthorizationInfo.Username, completed) .Then(() => { backupActivity = GetActivity(CurrentActivityId); string activityType = backupActivity.Type; if (activityType.Equals("gameplay", StringComparison.InvariantCultureIgnoreCase) && backupActivity.Details != null && backupActivity.Details.ContainsKey("backup") && (bool)backupActivity.Details["backup"]) { string traces = SimvaBridge.Load(((TrackerAssetSettings)TrackerAsset.Instance.Settings).BackupFile); Instantiate(Resources.Load("SimvaBackupPopup")); backupOperation = SaveActivity(CurrentActivityId, traces, true); backupOperation.Then(() => { afterBackup = true; }); } return UpdateSchedule(); }) .Then(schedule => { NotifyLoading(false); var result = new AsyncCompletionSource(); StartCoroutine(AsyncCoroutine(LaunchActivity(schedule.Next), result)); return result; }) .Catch(error => { NotifyLoading(false); NotifyManagers(error.Message); })); }
public static IAsyncOperation <AuthorizationInfo> GetToken(string tokenUrl, string formUrlEncoded, string clientId) { var result = new AsyncCompletionSource <AuthorizationInfo>(); UnityWebRequest uwr = UnityWebRequest.Post(tokenUrl, ""); byte[] bytes = Encoding.UTF8.GetBytes(formUrlEncoded); UploadHandlerRaw uH = new UploadHandlerRaw(bytes); uH.contentType = "application/x-www-form-urlencoded"; uwr.uploadHandler = uH; uwr.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded"); Observable.FromCoroutine(() => DoRequest(result, uwr)).Subscribe(); var wrapper = new AsyncCompletionSource <AuthorizationInfo>(); result.Then(authInfo => { authInfo.ClientId = clientId; wrapper.SetResult(authInfo); }).Catch(ex => wrapper.SetException(ex)); return(wrapper); }
public IAsyncOperation <string[]> CreateBatchUsers(int number) { var result = new AsyncCompletionSource <string[]>(); var listOfIds = new string[number]; var amountDone = 0; for (int i = 0; i < number; i++) { var newUser = GenerateRandomBase58Key(4); listOfIds[i] = newUser; Register(newUser, newUser + "@simva.e-ucm.es", newUser, false) .Then(registered => { lock (listOfIds) { amountDone++; result.SetProgress(amountDone / (float)number); } if (amountDone == number) { result.SetResult(listOfIds.ToArray()); } }); } return(result); }
public static IAsyncOperation <AuthorizationInfo> LoginWithROPC(string username, string password, string authUrl, string tokenUrl, string clientId, string audience, string scope = null) { var result = new AsyncCompletionSource <AuthorizationInfo>(); var port = UnityEngine.Random.Range(25525, 65535); var url = authUrl; var formUrlEncoded = "grant_type=password" + "&username="******"&password="******"&client_id=" + clientId; if (!string.IsNullOrEmpty(scope)) { formUrlEncoded += "&scope=" + scope; } if (!string.IsNullOrEmpty(audience)) { formUrlEncoded += "&audience=" + audience; } return(GetToken(tokenUrl, formUrlEncoded, clientId)); }
public async Task ThenAll_CompletesWhenCancelled() { // Arrange var cs = new CancellationTokenSource(); var op1 = AsyncResult.CompletedOperation; var op2 = new AsyncCompletionSource(); var op3 = new AsyncCompletionSource(); var op = op1.ThenAll(() => new IAsyncOperation[] { op2, op3 }).WithCancellation(cs.Token); cs.Cancel(); // Act try { await op; } catch (OperationCanceledException) { } // Assert Assert.True(op.IsCanceled); Assert.True(op2.IsCanceled); Assert.True(op3.IsCanceled); }
private static IAsyncOperation <AuthorizationInfo> DoAuthorizationRequest(string clientId, UnityWebRequest uwr) { var wrapper = new AsyncCompletionSource <AuthorizationInfo>(); RequestsUtil.DoRequest <AuthorizationInfo>(uwr) .Then(authInfo => { authInfo.ClientId = clientId; wrapper.SetResult(authInfo); return(wrapper); }) .Catch(ex => { if (uwr.isHttpError) { var apiEx = (ApiException)ex; var msg = (string)apiEx.ErrorContent; try { var authError = JsonConvert.DeserializeObject <AuthorizationError>(msg); msg = authError.ErrorDescription; } catch { } wrapper.SetException(new ApiException((int)uwr.responseCode, msg)); } else { wrapper.SetException(ex); } }) .AddProgressCallback(wrapper.SetProgress); return(wrapper); }
private IAsyncOperation <Texture2D> LoadTextureAsync() { var result = new AsyncCompletionSource <Texture2D>(); Texture2D tex = null; switch (type) { case ResourceManager.LoadingType.ResourcesLoad: var resourceRequest = Resources.LoadAsync <Texture2D>(path); resourceRequest.completed += done => { tex = resourceRequest.asset as Texture2D; if (tex == null) { Debug.Log("No se pudo cargar: " + this.path); } result.SetResult(tex); }; break; case ResourceManager.LoadingType.SystemIO: tex = ReadFromFile(path); result.SetResult(tex); break; } return(result); }
public IAsyncOperation ContinueOAuth(string clientId) { var scopes = new string[] { }; var tokenUrl = TokenPath ?? "https://sso.simva.e-ucm.es/auth/realms/simva/protocol/openid-connect/token"; var authUrl = AuthPath ?? "https://sso.simva.e-ucm.es/auth/realms/simva/protocol/openid-connect/auth"; var done = new AsyncCompletionSource(); try { OpenIdUtility.TryContinueLogin(tokenUrl, clientId) .Then(authInfo => { AuthorizationInfo = authInfo; done.SetCompleted(); }); } catch (ApiException ex) { done.SetException(new ApiException(ex.ErrorCode, "Failed to renew AuthorizationInfo: " + ex.Message)); } return(done); }
/// <summary> /// Obtains your own user. Based on the current auth header obtains the user /// </summary> /// <returns>User</returns> public IAsyncOperation <User> GetMe() { var path = "/users/me"; path = path.Replace("{format}", "json"); var queryParams = new Dictionary <String, String>(); var headerParams = new Dictionary <String, String>(); var formParams = new Dictionary <String, String>(); var fileParams = new Dictionary <String, String>(); String postBody = null; // authentication setting, if any String[] authSettings = new String[] { "OAuth2" }; var result = new AsyncCompletionSource <User>(); // make the HTTP request ApiClient.CallApi(path, UnityWebRequest.kHttpVerbGET, queryParams, postBody, headerParams, formParams, fileParams, authSettings) .Then(webRequest => { var uniWebRequest = (UnityWebRequest)webRequest; var headers = uniWebRequest.GetResponseHeaders().Select(kv => string.Format("{0}={1}", kv.Key, kv.Value)).ToList(); var data = (User)ApiClient.Deserialize(webRequest.downloadHandler.text, typeof(User), headers); result.SetResult(data); }) .Catch(error => { var apiEx = (ApiException)error; result.SetException(new ApiException(apiEx.ErrorCode, "Error calling GetMe: " + apiEx.Message, apiEx.ErrorContent)); }); return(result); }
public IAsyncOperation InitOAuth(string clientId, string clientSecret = null, string realm = null, string appName = null, string scopeSeparator = ":", bool usePKCE = false, Dictionary <string, string> aditionalQueryStringParams = null, bool scope_offline = false) { String[] scopes = null; if (scope_offline) { scopes = new string[] { "offline_access" }; } else { scopes = new string[] { }; } var tokenUrl = TokenPath ?? "https://sso.simva.e-ucm.es/auth/realms/simva/protocol/openid-connect/token"; var authUrl = AuthPath ?? "https://sso.simva.e-ucm.es/auth/realms/simva/protocol/openid-connect/auth"; var done = new AsyncCompletionSource(); OpenIdUtility.LoginWithAccessCode(authUrl, tokenUrl, clientId, null, string.Join(scopeSeparator, scopes), usePKCE) .Then(authInfo => { AuthorizationInfo = authInfo; done.SetCompleted(); }) .Catch(error => { done.SetException(new ApiException(500, error.Message)); }); return(done); }
private IAsyncOperation <AdventureData> LoadDescriptor() { var done = new AsyncCompletionSource <AdventureData>(); done.SetProgress(0); Loader.LoadAdventureDataAsync(ResourceManager, new List <Incidence>()) .Then(adventureData => { var descriptorAssets = new List <string>(); done.SetProgress(0.1f); Debug.Log("Setting progress 10"); /*foreach (var cursor in adventureData.getCursors()) * { * descriptorAssets.Add(cursor.getPath()); * } * foreach (var button in adventureData.getButtons()) * { * descriptorAssets.Add(button.getPath()); * }*/ var cachePromise = ResourceManager.CacheAssets(descriptorAssets); cachePromise.AddProgressCallback(p => done.SetProgress(p)); cachePromise.Then(() => { Debug.Log("Done Caching 100"); done.SetProgress(1f); done.SetResult(adventureData); }); }); return(done); }
public static IAsyncOperation <UnityWebRequest> DoRequestInBackground(UnityWebRequest webRequest) { var result = new AsyncCompletionSource <UnityWebRequest>(); Observable.FromCoroutine(() => DoRequest(result, webRequest, true)).Subscribe(); return(result); }
/// <summary> /// Asynchronously loads a <see cref="Texture2D"/> from the specified URL. /// </summary> public IAsyncOperation <Texture2D> LoadTextureAsync(string textureUrl) { var result = new AsyncCompletionSource <Texture2D>(); StartCoroutine(LoadTextureInternal(result, textureUrl)); return(result.Operation); }
public IAsyncOperation <string> DoSignupApiCall(string url) { var result = new AsyncCompletionSource <string>(); Timing.RunCoroutine(_InternalApiCall(url, result)); return(result); }
private IAsyncOperation <T> LoadAsync(string path, AssetBundle assetBundle, IEnumerator itor) { InitAssetInfo(path); asc = new AsyncCompletionSource <T>(); Chain.Start() .Coroutine(itor); return(asc); }
public static IAsyncOperation <AuthorizationInfo> LoginWithAccessCode(string authUrl, string tokenUrl, string clientId, string audience = null, string scope = null, bool usePKCE = false, string codeChallengeMethod = "S256") { var result = new AsyncCompletionSource <AuthorizationInfo>(); var port = UnityEngine.Random.Range(25525, 65535); var url = authUrl + "?" + "response_type=code" + "&client_id=" + clientId; string codeVerifier = null, codeChallenge = null; if (usePKCE) { GeneratePKCE(out codeVerifier, out codeChallenge); url += "&code_challenge=" + codeChallenge + "&code_challenge_method=" + codeChallengeMethod; } if (!string.IsNullOrEmpty(scope)) { url += "&scope=" + scope; } if (!string.IsNullOrEmpty(audience)) { url += "&audience=" + audience; } var redirectUri = string.Empty; ListenForCode(port, out redirectUri) .Then(loginResponse => { if (loginResponse.IsError) { result.SetException(new ApiException(500, loginResponse.Error + ": " + loginResponse.ErrorDescription)); } else { GetToken(tokenUrl, clientId, loginResponse.Code, redirectUri, codeVerifier) .Then(token => { result.SetResult(token); }) .Catch(ex => result.SetException(ex)); } }); url += "&redirect_uri=" + redirectUri; Debug.Log(redirectUri); Debug.Log(url); OpenBrowser(url); return(result); }
public IAsyncOperation <Texture2D> getImageAsync(string uri, bool loadFromDefaults) { var result = new AsyncCompletionSource <Texture2D>(); if (string.IsNullOrEmpty(uri)) { result.SetResult(null); } else { if (images.ContainsKey(uri)) { result.SetResult(images[uri].Texture); } else { var holder = new Texture2DHolder(fixPath(uri), type); holder.LoadAsync() .Then(done => { Debug.Log("Done loading " + uri); if (done) { if (!images.ContainsKey(uri)) { images.Add(uri, holder); } result.SetResult(holder.Texture); } else if (loadFromDefaults) { // Load from defaults holder = new Texture2DHolder(defaultPath(uri), type); if (holder.Loaded()) { Debug.Log(uri + " loaded from defaults..."); if (!images.ContainsKey(uri)) { images.Add(uri, holder); } result.SetResult(holder.Texture); } else { Debug.LogWarning("Unable to load " + uri); result.SetResult(null); } } else { result.SetResult(null); } }); } } return(result); }
private static IAsyncOperation <KeyValuePair <int, T> > ThenIndex <T>(int index, IAsyncOperation <T> promise) { var result = new AsyncCompletionSource <KeyValuePair <int, T> >(); promise.Done(t => { result.SetResult(new KeyValuePair <int, T>(index, t)); }); return(result); }
/// <summary> /// sets the result for the activity Set the completion status of the activity for a student /// </summary> /// <param name="id">The test ID</param> /// <param name="user">the user to set its result (if logged in student , user is not needed) </param> /// <returns></returns> public IAsyncOperation SetResult(string id, string user, object body) { // verify the required parameter 'id' is set if (id == null) { throw new ApiException(400, "Missing required parameter 'id' when calling SetResult"); } var path = "/activities/{id}/result"; path = path.Replace("{format}", "json"); path = path.Replace("{" + "id" + "}", ApiClient.ParameterToString(id)); var queryParams = new Dictionary <String, String>(); var headerParams = new Dictionary <String, String>(); var formParams = new Dictionary <String, String>(); var fileParams = new Dictionary <String, String>(); String postBody = ApiClient.Serialize(body); if (user != null) { queryParams.Add("user", ApiClient.ParameterToString(user)); // query parameter } // authentication setting, if any String[] authSettings = new String[] { "OAuth2" }; var result = new AsyncCompletionSource(); // make the HTTP request var callApi = ApiClient.CallApi(path, UnityWebRequest.kHttpVerbPOST, queryParams, postBody, headerParams, formParams, fileParams, authSettings); callApi.AddProgressCallback(p => { UnityEngine.Debug.Log("SetResultProgress: " + p); if (!result.IsCompleted && !result.IsCanceled) { result.SetProgress(p); } }); callApi.Then(webRequest => { result.SetCompleted(); }) .Catch(error => { var apiEx = (ApiException)error; result.SetException(new ApiException(apiEx.ErrorCode, "Error calling SetResult: " + apiEx.Message, apiEx.ErrorContent)); }) ; return(result); }
public IAsyncOperation CacheAssets(IEnumerable <string> assets) { Debug.Log("CachingAssets: " + assets.Count()); var result = new AsyncCompletionSource(); var i = 0; var total = assets.Count(); System.Action step = () => { Debug.Log("Step: " + i + " (" + total + ")"); i++; result.SetProgress(Mathf.Clamp01(i / (float)total)); if (i == total) { result.SetCompleted(); } }; foreach (var asset in assets) { if (asset.EndsWith("eaa.xml") || asset.EndsWith(".eaa")) { Debug.Log("Loading Animation Async: " + asset); Loader.LoadAnimationAsync(asset, this, new List <Incidence>()) .Then(anim => { total += anim.getFrames().Count; foreach (var frame in anim.getFrames()) { getImageAsync(frame.getImageAbsolutePath()).Then(step); } step(); }); } else if (asset.EndsWith(".png") || asset.EndsWith(".jpg") || asset.EndsWith(".ico")) { Debug.Log("Loading Image Async: " + asset); getImageAsync(asset).Then(step); } else { step(); } //TODO end the rest of file types } if (total == 0) { result.SetCompleted(); } return(result); }
public static IAsyncOperation <AuthorizationInfo> GetToken(string tokenUrl, string clientId, string authCode, string redirect_uri, string codeVerifier = null) { var result = new AsyncCompletionSource <AuthorizationInfo>(); var form = new Dictionary <string, string>() { { "grant_type", "authorization_code" }, { "code", authCode }, { "redirect_uri", redirect_uri }, { "client_id", clientId }, }; //Debug.Log(JsonConvert.SerializeObject(form, Formatting.Indented)); if (!string.IsNullOrEmpty(codeVerifier)) { form.Add("code_verifier", codeVerifier); Debug.Log("A2 - Code Verifier: " + codeVerifier); } UnityWebRequest uwr = UnityWebRequest.Post(tokenUrl, form); Observable.FromCoroutine(() => DoRequest(result, uwr)).Subscribe(); var wrapper = new AsyncCompletionSource <AuthorizationInfo>(); result.Then(authInfo => { authInfo.ClientId = clientId; wrapper.SetResult(authInfo); return(wrapper); }) .Catch(ex => { if (uwr.isHttpError) { var apiEx = (ApiException)ex; var msg = (string)apiEx.ErrorContent; try { var authError = JsonConvert.DeserializeObject <AuthorizationError>(msg); msg = authError.ErrorDescription; } catch { } wrapper.SetException(new ApiException((int)uwr.responseCode, msg)); } else { wrapper.SetException(ex); } }); return(wrapper); }
public IAsyncOperation <string> UpgradeAsync(string path) { var result = new AsyncCompletionSource <string>(); GetFileVersionAsync(path, resourceManager) .Then(version => { Dictionary <int, ITransformer> transformers = null; foreach (var upgradableFile in orderedTransformers.Keys) { if (Regex.IsMatch(path, upgradableFile)) { transformers = orderedTransformers[upgradableFile]; break; } } if (transformers == null) { result.SetResult(null); } else { var maxVersion = transformers.Values.Max(t => t.DestinationVersion); resourceManager.getTextAsync(path) .Then(input => { while (version < maxVersion) { if (!transformers.ContainsKey(version)) { incidences.Add(new Incidence(Incidence.XML_INCIDENCE, Incidence.XML_INCIDENCE, path, Incidence.IMPORTANCE_CRITICAL, "Upgrader not found to upgrade from version " + version + " towards " + maxVersion, false, new UpgraderVersionNotFoundException() { TargetFile = path, TargetVersion = version, MaxVersion = maxVersion })); result.SetResult(null); } input = transformers[version].Upgrade(input, path, resourceManager); version = transformers[version].DestinationVersion; } result.SetResult(input); }); } }); return(result); }
public IAsyncOperation <bool> LoadAsync() { var result = new AsyncCompletionSource <bool>(); LoadTextureAsync() .Then(texture => { tex = texture; loaded = tex != null; result.SetResult(tex); }); return(result); }
public static IAsyncOperation <T> DoRequest <T>(UnityWebRequest webRequest) { var result = new AsyncCompletionSource <T>(); DoRequest(webRequest) .Then(wr => { result.SetResult(JsonConvert.DeserializeObject <T>(wr.downloadHandler.text)); }) .Catch(result.SetException) .AddProgressCallback(result.SetProgress); return(result); }
private static IAsyncOperation <int> GetFileVersionAsync(string path, ResourceManager resourceManager) { UnityEngine.Debug.Log("Getting File Version Async"); var result = new AsyncCompletionSource <int>(); resourceManager.getTextAsync(path) .Then(text => { UnityEngine.Debug.Log("Done Getting File Version Async"); result.SetResult(ExtractFileVersion(text)); }); return(result); }
public IAsyncOperation <bool> NeedsUpgradeAsync(string path) { UnityEngine.Debug.Log("Checking Upgrade Async"); var result = new AsyncCompletionSource <bool>(); GetFileVersionAsync(path, resourceManager) .Then(version => { UnityEngine.Debug.Log("Done Checking Upgrade Async"); result.SetResult(CheckUpgraders(version, path)); }); return(result); }
private IAsyncOperation <ResourceRequest> LoadServerURL() { var rACS = new AsyncCompletionSource <ResourceRequest>(); var rCoroutineHandler = CoroutineManager.Instance.StartHandler(LoadServerURL_Async(rACS)); rACS.AddCompletionCallback((rContinuation) => { if (rContinuation.IsCanceled || rContinuation.IsFaulted) { CoroutineManager.Instance.Stop(rCoroutineHandler); } }); return(rACS.Operation); }
public static IAsyncOperation <Chapter> LoadChapterAsync(string filename, ResourceManager resourceManager, List <Incidence> incidences) { var result = new AsyncCompletionSource <Chapter>(); var chapterHandler = new ChapterHandler(new Chapter(), resourceManager, incidences); chapterHandler.ParseAsync(filename) .Then(chapter => { result.SetResult(chapter); }); return(result); }
public void BeginRead_WhenCompletedAsynchronously_CallsCallbackAndCompletesResult() { // Arrange object expectedState = new object(); ExpectedAsyncResult expectedResult = new ExpectedAsyncResult { AsyncState = expectedState, CompletedSynchronously = false, IsCompleted = true }; bool callbackCalled = false; IAsyncResult callbackResult = null; Stream product = null; AsyncCallback callback = (ar) => { callbackResult = ar; AssertEqual(expectedResult, ar); callbackCalled = true; }; Mock<CloudBlobStream> innerStreamMock = CreateMockInnerStream(); AsyncCompletionSource completion = new AsyncCompletionSource(); innerStreamMock .SetupBeginRead() .ReturnsCompletingAsynchronously(completion); innerStreamMock .SetupEndRead() .Returns(-1); CloudBlobStream innerStream = innerStreamMock.Object; product = CreateProductUnderTest(innerStream); byte[] buffer = new byte[0]; int offset = 123; int count = 456; IAsyncResult result = product.BeginRead(buffer, offset, count, callback, expectedState); // Act completion.Complete(); // Assert Assert.True(callbackCalled); // An AsyncCallback must be called with the same IAsyncResult instance as the Begin method returned. Assert.Same(result, callbackResult); AssertEqual(expectedResult, result, disposeActual: true); }
public void EndWrite_WhenInnerStreamThrows_PropogatesException() { // Arrange Exception expectedException = new Exception(); Mock<CloudBlobStream> innerStreamMock = CreateMockInnerStream(); AsyncCompletionSource completion = new AsyncCompletionSource(); innerStreamMock .SetupBeginWrite() .ReturnsCompletingAsynchronously(completion); innerStreamMock .SetupEndWrite() .Throws(expectedException); CloudBlobStream innerStream = innerStreamMock.Object; Stream product = CreateProductUnderTest(innerStream); byte[] buffer = new byte[0]; int offset = 123; int count = 456; AsyncCallback callback = null; object state = null; IAsyncResult result = product.BeginWrite(buffer, offset, count, callback, state); completion.Complete(); // Act & Assert Exception exception = Assert.Throws<Exception>(() => product.EndWrite(result)); Assert.Same(expectedException, exception); }
public void EndWrite_DuringCallback_DelegatesToInnerStreamEndWrite() { // Arrange Mock<CloudBlobStream> innerStreamMock = CreateMockInnerStream(); AsyncCompletionSource completion = new AsyncCompletionSource(); innerStreamMock .SetupBeginWrite() .ReturnsCompletingAsynchronously(completion); innerStreamMock .Setup(s => s.EndWrite(It.Is<IAsyncResult>((ar) => ar == completion.AsyncResult))) .Verifiable(); CloudBlobStream innerStream = innerStreamMock.Object; Stream product = CreateProductUnderTest(innerStream); byte[] buffer = new byte[0]; int offset = 123; int count = 456; bool callbackCalled = false; AsyncCallback callback = (ar) => { product.EndWrite(ar); callbackCalled = true; }; object state = null; IAsyncResult result = product.BeginWrite(buffer, offset, count, callback, state); // Act completion.Complete(); // Assert Assert.True(callbackCalled); innerStreamMock.Verify(); }
public void EndRead_DelegatesToInnerStreamEndRead() { // Arrange int expectedBytesRead = 789; Mock<CloudBlobStream> innerStreamMock = CreateMockInnerStream(); AsyncCompletionSource completion = new AsyncCompletionSource(); innerStreamMock .SetupBeginRead() .ReturnsCompletingAsynchronously(completion); innerStreamMock .Setup(s => s.EndRead(It.Is<IAsyncResult>(ar => ar == completion.AsyncResult))) .Returns(expectedBytesRead) .Verifiable(); CloudBlobStream innerStream = innerStreamMock.Object; Stream product = CreateProductUnderTest(innerStream); byte[] buffer = new byte[0]; int offset = 123; int count = 456; AsyncCallback callback = null; object state = null; IAsyncResult result = product.BeginRead(buffer, offset, count, callback, state); completion.Complete(); // Act int bytesRead = product.EndRead(result); // Assert Assert.Equal(expectedBytesRead, bytesRead); innerStreamMock.Verify(); }