diff --git a/TinCan/RemoteLRS.cs b/TinCan/RemoteLRS.cs index eeabe34..24ff5cc 100644 --- a/TinCan/RemoteLRS.cs +++ b/TinCan/RemoteLRS.cs @@ -1,1264 +1,1264 @@ -/* - Copyright 2014 Rustici Software - - 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. -*/ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using Newtonsoft.Json.Linq; -using TinCan.Documents; -using TinCan.LRSResponses; - -namespace TinCan -{ - public class RemoteLRS : ILRS - { - public Uri endpoint { get; set; } - public TCAPIVersion version { get; set; } - public String auth { get; set; } - public Dictionary extended { get; set; } - - public void SetAuth(String username, String password) - { - auth = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(username + ":" + password)); - } - - public RemoteLRS() { } - public RemoteLRS(Uri endpoint, TCAPIVersion version, String username, String password) - { - this.endpoint = endpoint; - this.version = version; - this.SetAuth(username, password); - } - public RemoteLRS(String endpoint, TCAPIVersion version, String username, String password) : this(new Uri(endpoint), version, username, password) { } - public RemoteLRS(String endpoint, String username, String password) : this(endpoint, TCAPIVersion.latest(), username, password) { } - - private class MyHTTPRequest - { - public String method { get; set; } - public String resource { get; set; } - public Dictionary queryParams { get; set; } - public Dictionary headers { get; set; } - public String contentType { get; set; } - public byte[] content { get; set; } - } - - private class MyHTTPResponse - { - public HttpStatusCode status { get; set; } - public String contentType { get; set; } - public byte[] content { get; set; } - public DateTime lastModified { get; set; } - public String etag { get; set; } - public Exception ex { get; set; } - - public MyHTTPResponse() { } - public MyHTTPResponse(HttpWebResponse webResp) - { - status = webResp.StatusCode; - contentType = webResp.ContentType; - etag = webResp.Headers.Get("Etag"); - lastModified = webResp.LastModified; - - using (var stream = webResp.GetResponseStream()) - { - content = ReadFully(stream, (int)webResp.ContentLength); - } - } - } - - private HttpWebRequest PreprocessRequest(MyHTTPRequest req) - { - String url; - if (req.resource.StartsWith("http", StringComparison.InvariantCultureIgnoreCase)) - { - url = req.resource; - } - else - { - url = endpoint.ToString(); - if (!url.EndsWith("/") && !req.resource.StartsWith("/")) - { - url += "/"; - } - url += req.resource; - } - - if (req.queryParams != null) - { - String qs = ""; - foreach (KeyValuePair entry in req.queryParams) - { - if (qs != "") - { - qs += "&"; - } - qs += HttpUtility.UrlEncode(entry.Key) + "=" + HttpUtility.UrlEncode(entry.Value); - } - if (qs != "") - { - url += "?" + qs; - } - } - - // TODO: handle special properties we recognize, such as content type, modified since, etc. - var webReq = (HttpWebRequest)WebRequest.Create(url); - webReq.Method = req.method; - - webReq.Headers.Add("X-Experience-API-Version", version.ToString()); - if (auth != null) - { - webReq.Headers.Add("Authorization", auth); - } - if (req.headers != null) - { - foreach (KeyValuePair entry in req.headers) - { - webReq.Headers.Add(entry.Key, entry.Value); - } - } - - if (req.contentType != null) - { - webReq.ContentType = req.contentType; - } - else - { - webReq.ContentType = "application/octet-stream"; - } - - if (req.content != null) - { - webReq.ContentLength = req.content.Length; - using (var stream = webReq.GetRequestStream()) - { - stream.Write(req.content, 0, req.content.Length); - } - } - - return webReq; - } - - private MyHTTPResponse MakeSyncRequest(MyHTTPRequest req) - { - HttpWebRequest webReq = PreprocessRequest(req); - MyHTTPResponse resp; - - try - { - using (var webResp = (HttpWebResponse)webReq.GetResponse()) - { - resp = new MyHTTPResponse(webResp); - } - } - catch (WebException ex) - { - if (ex.Response != null) - { - using (var webResp = (HttpWebResponse)ex.Response) - { - resp = new MyHTTPResponse(webResp); - } - } - else - { - resp = new MyHTTPResponse(); - resp.content = Encoding.UTF8.GetBytes("Web exception without '.Response'"); - } - resp.ex = ex; - } - - return resp; - } - - private async Task MakeAsyncRequest(MyHTTPRequest req) - { - HttpWebRequest webReq = PreprocessRequest(req); - MyHTTPResponse resp; - - try - { - using (var webResp = await webReq.GetResponseAsync()) - { - resp = new MyHTTPResponse((HttpWebResponse)webResp); - } - } - catch (WebException ex) - { - if (ex.Response != null) - { - using (var webResp = (HttpWebResponse)ex.Response) - { - resp = new MyHTTPResponse(webResp); - } - } - else - { - resp = new MyHTTPResponse(); - resp.content = Encoding.UTF8.GetBytes("Web exception without '.Response'"); - } - resp.ex = ex; - } - - return resp; - } - - /// - /// See http://www.yoda.arachsys.com/csharp/readbinary.html no license found - /// - /// Reads data from a stream until the end is reached. The - /// data is returned as a byte array. An IOException is - /// thrown if any of the underlying IO calls fail. - /// - /// The stream to read data from - /// The initial buffer length - private static byte[] ReadFully(Stream stream, int initialLength) - { - // If we've been passed an unhelpful initial length, just - // use 32K. - if (initialLength < 1) - { - initialLength = 32768; - } - - byte[] buffer = new byte[initialLength]; - int read = 0; - - int chunk; - while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0) - { - read += chunk; - - // If we've reached the end of our buffer, check to see if there's - // any more information - if (read == buffer.Length) - { - int nextByte = stream.ReadByte(); - - // End of stream? If so, we're done - if (nextByte == -1) - { - return buffer; - } - - // Nope. Resize the buffer, put in the byte we've just - // read, and continue - byte[] newBuffer = new byte[buffer.Length * 2]; - Array.Copy(buffer, newBuffer, buffer.Length); - newBuffer[read] = (byte)nextByte; - buffer = newBuffer; - read++; - } - } - // Buffer is now too big. Shrink it. - byte[] ret = new byte[read]; - Array.Copy(buffer, ret, read); - return ret; - } - - private MyHTTPResponse GetDocument(String resource, Dictionary queryParams, Document document) - { - var req = new MyHTTPRequest(); - req.method = "GET"; - req.resource = resource; - req.queryParams = queryParams; - - var res = MakeSyncRequest(req); - if (res.status == HttpStatusCode.OK) - { - document.content = res.content; - document.contentType = res.contentType; - document.timestamp = res.lastModified; - document.etag = res.etag; - } - - return res; - } - private ProfileKeysLRSResponse GetProfileKeys(String resource, Dictionary queryParams) - { - var r = new ProfileKeysLRSResponse(); - - var req = new MyHTTPRequest(); - req.method = "GET"; - req.resource = resource; - req.queryParams = queryParams; - - var res = MakeSyncRequest(req); - if (res.status != HttpStatusCode.OK) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - r.success = true; - - var keys = JArray.Parse(Encoding.UTF8.GetString(res.content)); - if (keys.Count > 0) { - r.content = new List(); - foreach (JToken key in keys) { - r.content.Add((String)key); - } - } - - return r; - } - private LRSResponse SaveDocument(String resource, Dictionary queryParams, Document document) - { - var r = new LRSResponse(); - - var req = new MyHTTPRequest(); - req.method = "PUT"; - req.resource = resource; - req.queryParams = queryParams; - req.contentType = document.contentType; - req.content = document.content; - - var res = MakeSyncRequest(req); - if (res.status != HttpStatusCode.NoContent) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - r.success = true; - - return r; - } - private LRSResponse DeleteDocument(String resource, Dictionary queryParams) - { - var r = new LRSResponse(); - - var req = new MyHTTPRequest(); - req.method = "DELETE"; - req.resource = resource; - req.queryParams = queryParams; - - var res = MakeSyncRequest(req); - if (res.status != HttpStatusCode.NoContent) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - r.success = true; - - return r; - } - private StatementLRSResponse GetStatement(Dictionary queryParams) - { - var r = new StatementLRSResponse(); - - var req = new MyHTTPRequest(); - req.method = "GET"; - req.resource = "statements"; - req.queryParams = queryParams; - - var res = MakeSyncRequest(req); - if (res.status != HttpStatusCode.OK) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - r.success = true; - r.content = new Statement(new Json.StringOfJSON(Encoding.UTF8.GetString(res.content))); - - return r; - } - - private async Task GetDocumentAsync(String resource, Dictionary queryParams, Document document) - { - var req = new MyHTTPRequest(); - req.method = "GET"; - req.resource = resource; - req.queryParams = queryParams; - - var res = await MakeAsyncRequest(req); - if (res.status == HttpStatusCode.OK) - { - document.content = res.content; - document.contentType = res.contentType; - document.timestamp = res.lastModified; - document.etag = res.etag; - } - - return res; - } - private async Task GetProfileKeysAsync(String resource, Dictionary queryParams) - { - var r = new ProfileKeysLRSResponse(); - - var req = new MyHTTPRequest(); - req.method = "GET"; - req.resource = resource; - req.queryParams = queryParams; - - var res = await MakeAsyncRequest(req); - if (res.status != HttpStatusCode.OK) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - r.success = true; - - var keys = JArray.Parse(Encoding.UTF8.GetString(res.content)); - if (keys.Count > 0) - { - r.content = new List(); - foreach (JToken key in keys) - { - r.content.Add((String)key); - } - } - - return r; - } - private async Task SaveDocumentAsync(String resource, Dictionary queryParams, Document document) - { - var r = new LRSResponse(); - - var req = new MyHTTPRequest(); - req.method = "PUT"; - req.resource = resource; - req.queryParams = queryParams; - req.contentType = document.contentType; - req.content = document.content; - - var res = await MakeAsyncRequest(req); - if (res.status != HttpStatusCode.NoContent) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - r.success = true; - - return r; - } - private async Task DeleteDocumentAsync(String resource, Dictionary queryParams) - { - var r = new LRSResponse(); - - var req = new MyHTTPRequest(); - req.method = "DELETE"; - req.resource = resource; - req.queryParams = queryParams; - - var res = await MakeAsyncRequest(req); - if (res.status != HttpStatusCode.NoContent) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - r.success = true; - - return r; - } - private async Task GetStatementAsync(Dictionary queryParams) - { - var r = new StatementLRSResponse(); - - var req = new MyHTTPRequest(); - req.method = "GET"; - req.resource = "statements"; - req.queryParams = queryParams; - - MyHTTPResponse res = await MakeAsyncRequest(req); - - if (res.status != HttpStatusCode.OK) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - r.success = true; - r.content = new Statement(new Json.StringOfJSON(Encoding.UTF8.GetString(res.content))); - - return r; - } - - public AboutLRSResponse About() - { - var r = new AboutLRSResponse(); - - var req = new MyHTTPRequest(); - req.method = "GET"; - req.resource = "about"; - - var res = MakeSyncRequest(req); - if (res.status != HttpStatusCode.OK) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - r.success = true; - r.content = new About(Encoding.UTF8.GetString(res.content)); - - return r; - } - public StatementLRSResponse SaveStatement(Statement statement) - { - var r = new StatementLRSResponse(); - var req = new MyHTTPRequest(); - req.queryParams = new Dictionary(); - req.resource = "statements"; - - if (statement.id == null) - { - req.method = "POST"; - } - else - { - req.method = "PUT"; - req.queryParams.Add("statementId", statement.id.ToString()); - } - - req.contentType = "application/json"; - req.content = Encoding.UTF8.GetBytes(statement.ToJSON(version)); - - var res = MakeSyncRequest(req); - if (statement.id == null) - { - if (res.status != HttpStatusCode.OK) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - var ids = JArray.Parse(Encoding.UTF8.GetString(res.content)); - statement.id = new Guid((String)ids[0]); - } - else { - if (res.status != HttpStatusCode.NoContent) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - } - - r.success = true; - r.content = statement; - - return r; - } - public StatementLRSResponse VoidStatement(Guid id, Agent agent) - { - var voidStatement = new Statement - { - actor = agent, - verb = new Verb - { - id = new Uri("http://adlnet.gov/expapi/verbs/voided"), - display = new LanguageMap() - }, - target = new StatementRef { id = id } - }; - voidStatement.verb.display.Add("en-US", "voided"); - - return SaveStatement(voidStatement); - } - public StatementsResultLRSResponse SaveStatements(List statements) - { - var r = new StatementsResultLRSResponse(); - - var req = new MyHTTPRequest(); - req.resource = "statements"; - req.method = "POST"; - req.contentType = "application/json"; - - var jarray = new JArray(); - foreach (Statement st in statements) - { - jarray.Add(st.ToJObject(version)); - } - req.content = Encoding.UTF8.GetBytes(jarray.ToString()); - - var res = MakeSyncRequest(req); - if (res.status != HttpStatusCode.OK) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - var ids = JArray.Parse(Encoding.UTF8.GetString(res.content)); - for (int i = 0; i < ids.Count; i++) - { - statements[i].id = new Guid((String)ids[i]); - } - - r.success = true; - r.content = new StatementsResult(statements); - - return r; - } - public StatementLRSResponse RetrieveStatement(Guid id) - { - var queryParams = new Dictionary(); - queryParams.Add("statementId", id.ToString()); - - return GetStatement(queryParams); - } - public StatementLRSResponse RetrieveVoidedStatement(Guid id) - { - var queryParams = new Dictionary(); - queryParams.Add("voidedStatementId", id.ToString()); - - return GetStatement(queryParams); - } - public StatementsResultLRSResponse QueryStatements(StatementsQuery query) - { - var r = new StatementsResultLRSResponse(); - - var req = new MyHTTPRequest(); - req.method = "GET"; - req.resource = "statements"; - req.queryParams = query.ToParameterMap(version); - - var res = MakeSyncRequest(req); - if (res.status != HttpStatusCode.OK) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - r.success = true; - r.content = new StatementsResult(new Json.StringOfJSON(Encoding.UTF8.GetString(res.content))); - - return r; - } - public StatementsResultLRSResponse MoreStatements(StatementsResult result) - { - var r = new StatementsResultLRSResponse(); - - var req = new MyHTTPRequest(); - req.method = "GET"; - req.resource = endpoint.GetLeftPart(UriPartial.Authority); - if (! req.resource.EndsWith("/")) { - req.resource += "/"; - } - req.resource += result.more; - - var res = MakeSyncRequest(req); - if (res.status != HttpStatusCode.OK) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - r.success = true; - r.content = new StatementsResult(new Json.StringOfJSON(Encoding.UTF8.GetString(res.content))); - - return r; - } - - public async Task AboutAsync() - { - var r = new AboutLRSResponse(); - - var req = new MyHTTPRequest(); - req.method = "GET"; - req.resource = "about"; - - var res = await MakeAsyncRequest(req); - if (res.status != HttpStatusCode.OK) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - r.success = true; - r.content = new About(Encoding.UTF8.GetString(res.content)); - - return r; - } - public async Task SaveStatementAsync(Statement statement) - { - var r = new StatementLRSResponse(); - var req = new MyHTTPRequest(); - req.queryParams = new Dictionary(); - req.resource = "statements"; - - if (statement.id == null) - { - req.method = "POST"; - } - else - { - req.method = "PUT"; - req.queryParams.Add("statementId", statement.id.ToString()); - } - - req.contentType = "application/json"; - req.content = Encoding.UTF8.GetBytes(statement.ToJSON(version)); - - MyHTTPResponse res = await MakeAsyncRequest(req); - - if (statement.id == null) - { - if (res.status != HttpStatusCode.OK) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - var ids = JArray.Parse(Encoding.UTF8.GetString(res.content)); - statement.id = new Guid((String)ids[0]); - } - else - { - if (res.status != HttpStatusCode.NoContent) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - } - - r.success = true; - r.content = statement; - - return r; - } - public async Task VoidStatementAsync(Guid id, Agent agent) - { - var voidStatement = new Statement - { - actor = agent, - verb = new Verb - { - id = new Uri("http://adlnet.gov/expapi/verbs/voided"), - display = new LanguageMap() - }, - target = new StatementRef { id = id } - }; - voidStatement.verb.display.Add("en-US", "voided"); - - return await SaveStatementAsync(voidStatement); - } - public async Task SaveStatementsAsync(List statements) - { - var r = new StatementsResultLRSResponse(); - - var req = new MyHTTPRequest(); - req.resource = "statements"; - req.method = "POST"; - req.contentType = "application/json"; - - var jarray = new JArray(); - foreach (Statement st in statements) - { - jarray.Add(st.ToJObject(version)); - } - req.content = Encoding.UTF8.GetBytes(jarray.ToString()); - - MyHTTPResponse res = await MakeAsyncRequest(req); - - if (res.status != HttpStatusCode.OK) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - var ids = JArray.Parse(Encoding.UTF8.GetString(res.content)); - for (int i = 0; i < ids.Count; i++) - { - statements[i].id = new Guid((String)ids[i]); - } - - r.success = true; - r.content = new StatementsResult(statements); - - return r; - } - public async Task RetrieveStatementAsync(Guid id) - { - var queryParams = new Dictionary(); - queryParams.Add("statementId", id.ToString()); - - return await GetStatementAsync(queryParams); - } - public async Task RetrieveVoidedStatementAsync(Guid id) - { - var queryParams = new Dictionary(); - queryParams.Add("voidedStatementId", id.ToString()); - - return await GetStatementAsync(queryParams); - } - public async Task QueryStatementsAsync(StatementsQuery query) - { - var r = new StatementsResultLRSResponse(); - - var req = new MyHTTPRequest(); - req.method = "GET"; - req.resource = "statements"; - req.queryParams = query.ToParameterMap(version); - - MyHTTPResponse res = await MakeAsyncRequest(req); - - if (res.status != HttpStatusCode.OK) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - r.success = true; - r.content = new StatementsResult(new Json.StringOfJSON(Encoding.UTF8.GetString(res.content))); - - return r; - } - public async Task MoreStatementsAsync(StatementsResult result) - { - var r = new StatementsResultLRSResponse(); - - var req = new MyHTTPRequest(); - req.method = "GET"; - req.resource = endpoint.GetLeftPart(UriPartial.Authority); - if (!req.resource.EndsWith("/")) - { - req.resource += "/"; - } - req.resource += result.more; - - MyHTTPResponse res = await MakeAsyncRequest(req); - - if (res.status != HttpStatusCode.OK) - { - r.success = false; - r.httpException = res.ex; - r.SetErrMsgFromBytes(res.content); - return r; - } - - r.success = true; - r.content = new StatementsResult(new Json.StringOfJSON(Encoding.UTF8.GetString(res.content))); - - return r; - } - - // TODO: since param - public ProfileKeysLRSResponse RetrieveStateIds(Activity activity, Agent agent, Nullable registration = null) - { - var queryParams = new Dictionary(); - queryParams.Add("activityId", activity.id.ToString()); - queryParams.Add("agent", agent.ToJSON(version)); - if (registration != null) - { - queryParams.Add("registration", registration.ToString()); - } - - return GetProfileKeys("activities/state", queryParams); - } - public StateLRSResponse RetrieveState(String id, Activity activity, Agent agent, Nullable registration = null) - { - var r = new StateLRSResponse(); - - var queryParams = new Dictionary(); - queryParams.Add("stateId", id); - queryParams.Add("activityId", activity.id.ToString()); - queryParams.Add("agent", agent.ToJSON(version)); - - var state = new StateDocument(); - state.id = id; - state.activity = activity; - state.agent = agent; - - if (registration != null) - { - queryParams.Add("registration", registration.ToString()); - state.registration = registration; - } - - var resp = GetDocument("activities/state", queryParams, state); - if (resp.status != HttpStatusCode.OK && resp.status != HttpStatusCode.NotFound) - { - r.success = false; - r.httpException = resp.ex; - r.SetErrMsgFromBytes(resp.content); - return r; - } - r.success = true; - r.content = state; - - return r; - } - public LRSResponse SaveState(StateDocument state) - { - var queryParams = new Dictionary(); - queryParams.Add("stateId", state.id); - queryParams.Add("activityId", state.activity.id.ToString()); - queryParams.Add("agent", state.agent.ToJSON(version)); - if (state.registration != null) - { - queryParams.Add("registration", state.registration.ToString()); - } - - return SaveDocument("activities/state", queryParams, state); - } - public LRSResponse DeleteState(StateDocument state) - { - var queryParams = new Dictionary(); - queryParams.Add("stateId", state.id); - queryParams.Add("activityId", state.activity.id.ToString()); - queryParams.Add("agent", state.agent.ToJSON(version)); - if (state.registration != null) - { - queryParams.Add("registration", state.registration.ToString()); - } - - return DeleteDocument("activities/state", queryParams); - } - public LRSResponse ClearState(Activity activity, Agent agent, Nullable registration = null) - { - var queryParams = new Dictionary(); - queryParams.Add("activityId", activity.id.ToString()); - queryParams.Add("agent", agent.ToJSON(version)); - if (registration != null) - { - queryParams.Add("registration", registration.ToString()); - } - - return DeleteDocument("activities/state", queryParams); - } - - public async Task RetrieveStateIdsAsync(Activity activity, Agent agent, Nullable registration = null) - { - var queryParams = new Dictionary(); - queryParams.Add("activityId", activity.id.ToString()); - queryParams.Add("agent", agent.ToJSON(version)); - if (registration != null) - { - queryParams.Add("registration", registration.ToString()); - } - - return await GetProfileKeysAsync("activities/state", queryParams); - } - public async Task RetrieveStateAsync(String id, Activity activity, Agent agent, Nullable registration = null) - { - var r = new StateLRSResponse(); - - var queryParams = new Dictionary(); - queryParams.Add("stateId", id); - queryParams.Add("activityId", activity.id.ToString()); - queryParams.Add("agent", agent.ToJSON(version)); - - var state = new StateDocument(); - state.id = id; - state.activity = activity; - state.agent = agent; - - if (registration != null) - { - queryParams.Add("registration", registration.ToString()); - state.registration = registration; - } - - var resp = await GetDocumentAsync("activities/state", queryParams, state); - if (resp.status != HttpStatusCode.OK && resp.status != HttpStatusCode.NotFound) - { - r.success = false; - r.httpException = resp.ex; - r.SetErrMsgFromBytes(resp.content); - return r; - } - r.success = true; - r.content = state; - - return r; - } - public async Task SaveStateAsync(StateDocument state) - { - var queryParams = new Dictionary(); - queryParams.Add("stateId", state.id); - queryParams.Add("activityId", state.activity.id.ToString()); - queryParams.Add("agent", state.agent.ToJSON(version)); - if (state.registration != null) - { - queryParams.Add("registration", state.registration.ToString()); - } - - return await SaveDocumentAsync("activities/state", queryParams, state); - } - public async Task DeleteStateAsync(StateDocument state) - { - var queryParams = new Dictionary(); - queryParams.Add("stateId", state.id); - queryParams.Add("activityId", state.activity.id.ToString()); - queryParams.Add("agent", state.agent.ToJSON(version)); - if (state.registration != null) - { - queryParams.Add("registration", state.registration.ToString()); - } - - return await DeleteDocumentAsync("activities/state", queryParams); - } - public async Task ClearStateAsync(Activity activity, Agent agent, Nullable registration = null) - { - var queryParams = new Dictionary(); - queryParams.Add("activityId", activity.id.ToString()); - queryParams.Add("agent", agent.ToJSON(version)); - if (registration != null) - { - queryParams.Add("registration", registration.ToString()); - } - - return await DeleteDocumentAsync("activities/state", queryParams); - } - - // TODO: since param - public ProfileKeysLRSResponse RetrieveActivityProfileIds(Activity activity) - { - var queryParams = new Dictionary(); - queryParams.Add("activityId", activity.id.ToString()); - - return GetProfileKeys("activities/profile", queryParams); - } - public ActivityProfileLRSResponse RetrieveActivityProfile(String id, Activity activity) - { - var r = new ActivityProfileLRSResponse(); - - var queryParams = new Dictionary(); - queryParams.Add("profileId", id); - queryParams.Add("activityId", activity.id.ToString()); - - var profile = new ActivityProfileDocument(); - profile.id = id; - profile.activity = activity; - - var resp = GetDocument("activities/profile", queryParams, profile); - if (resp.status != HttpStatusCode.OK && resp.status != HttpStatusCode.NotFound) - { - r.success = false; - r.httpException = resp.ex; - r.SetErrMsgFromBytes(resp.content); - return r; - } - r.success = true; - r.content = profile; - - return r; - } - public LRSResponse SaveActivityProfile(ActivityProfileDocument profile) - { - var queryParams = new Dictionary(); - queryParams.Add("profileId", profile.id); - queryParams.Add("activityId", profile.activity.id.ToString()); - - return SaveDocument("activities/profile", queryParams, profile); - } - public LRSResponse DeleteActivityProfile(ActivityProfileDocument profile) - { - var queryParams = new Dictionary(); - queryParams.Add("profileId", profile.id); - queryParams.Add("activityId", profile.activity.id.ToString()); - // TODO: need to pass Etag? - - return DeleteDocument("activities/profile", queryParams); - } - - public async Task RetrieveActivityProfileIdsAsync(Activity activity) - { - var queryParams = new Dictionary(); - queryParams.Add("activityId", activity.id.ToString()); - - return await GetProfileKeysAsync("activities/profile", queryParams); - } - public async Task RetrieveActivityProfileAsync(String id, Activity activity) - { - var r = new ActivityProfileLRSResponse(); - - var queryParams = new Dictionary(); - queryParams.Add("profileId", id); - queryParams.Add("activityId", activity.id.ToString()); - - var profile = new ActivityProfileDocument(); - profile.id = id; - profile.activity = activity; - - var resp = await GetDocumentAsync("activities/profile", queryParams, profile); - if (resp.status != HttpStatusCode.OK && resp.status != HttpStatusCode.NotFound) - { - r.success = false; - r.httpException = resp.ex; - r.SetErrMsgFromBytes(resp.content); - return r; - } - r.success = true; - r.content = profile; - - return r; - } - public async Task SaveActivityProfileAsync(ActivityProfileDocument profile) - { - var queryParams = new Dictionary(); - queryParams.Add("profileId", profile.id); - queryParams.Add("activityId", profile.activity.id.ToString()); - - return await SaveDocumentAsync("activities/profile", queryParams, profile); - } - public async Task DeleteActivityProfileAsync(ActivityProfileDocument profile) - { - var queryParams = new Dictionary(); - queryParams.Add("profileId", profile.id); - queryParams.Add("activityId", profile.activity.id.ToString()); - // TODO: need to pass Etag? - - return await DeleteDocumentAsync("activities/profile", queryParams); - } - - // TODO: since param - public ProfileKeysLRSResponse RetrieveAgentProfileIds(Agent agent) - { - var queryParams = new Dictionary(); - queryParams.Add("agent", agent.ToJSON(version)); - - return GetProfileKeys("agents/profile", queryParams); - } - public AgentProfileLRSResponse RetrieveAgentProfile(String id, Agent agent) - { - var r = new AgentProfileLRSResponse(); - - var queryParams = new Dictionary(); - queryParams.Add("profileId", id); - queryParams.Add("agent", agent.ToJSON(version)); - - var profile = new AgentProfileDocument(); - profile.id = id; - profile.agent = agent; - - var resp = GetDocument("agents/profile", queryParams, profile); - if (resp.status != HttpStatusCode.OK && resp.status != HttpStatusCode.NotFound) - { - r.success = false; - r.httpException = resp.ex; - r.SetErrMsgFromBytes(resp.content); - return r; - } - r.success = true; - r.content = profile; - - return r; - } - public LRSResponse SaveAgentProfile(AgentProfileDocument profile) - { - var queryParams = new Dictionary(); - queryParams.Add("profileId", profile.id); - queryParams.Add("agent", profile.agent.ToJSON(version)); - - return SaveDocument("agents/profile", queryParams, profile); - } - public LRSResponse DeleteAgentProfile(AgentProfileDocument profile) - { - var queryParams = new Dictionary(); - queryParams.Add("profileId", profile.id); - queryParams.Add("agent", profile.agent.ToJSON(version)); - // TODO: need to pass Etag? - - return DeleteDocument("agents/profile", queryParams); - } - - public async Task RetrieveAgentProfileIdsAsync(Agent agent) - { - var queryParams = new Dictionary(); - queryParams.Add("agent", agent.ToJSON(version)); - - return await GetProfileKeysAsync("agents/profile", queryParams); - } - public async Task RetrieveAgentProfileAsync(String id, Agent agent) - { - var r = new AgentProfileLRSResponse(); - - var queryParams = new Dictionary(); - queryParams.Add("profileId", id); - queryParams.Add("agent", agent.ToJSON(version)); - - var profile = new AgentProfileDocument(); - profile.id = id; - profile.agent = agent; - - var resp = await GetDocumentAsync("agents/profile", queryParams, profile); - if (resp.status != HttpStatusCode.OK && resp.status != HttpStatusCode.NotFound) - { - r.success = false; - r.httpException = resp.ex; - r.SetErrMsgFromBytes(resp.content); - return r; - } - r.success = true; - r.content = profile; - - return r; - } - public async Task SaveAgentProfileAsync(AgentProfileDocument profile) - { - var queryParams = new Dictionary(); - queryParams.Add("profileId", profile.id); - queryParams.Add("agent", profile.agent.ToJSON(version)); - - return await SaveDocumentAsync("agents/profile", queryParams, profile); - } - public async Task DeleteAgentProfileAsync(AgentProfileDocument profile) - { - var queryParams = new Dictionary(); - queryParams.Add("profileId", profile.id); - queryParams.Add("agent", profile.agent.ToJSON(version)); - // TODO: need to pass Etag? - - return await DeleteDocumentAsync("agents/profile", queryParams); - } - } -} +/* + Copyright 2014 Rustici Software + + 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. +*/ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using Newtonsoft.Json.Linq; +using TinCan.Documents; +using TinCan.LRSResponses; + +namespace TinCan +{ + public class RemoteLRS : ILRS + { + public Uri endpoint { get; set; } + public TCAPIVersion version { get; set; } + public String auth { get; set; } + public Dictionary extended { get; set; } + + public void SetAuth(String username, String password) + { + auth = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(username + ":" + password)); + } + + public RemoteLRS() { } + public RemoteLRS(Uri endpoint, TCAPIVersion version, String username, String password) + { + this.endpoint = endpoint; + this.version = version; + this.SetAuth(username, password); + } + public RemoteLRS(String endpoint, TCAPIVersion version, String username, String password) : this(new Uri(endpoint), version, username, password) { } + public RemoteLRS(String endpoint, String username, String password) : this(endpoint, TCAPIVersion.latest(), username, password) { } + + private class MyHTTPRequest + { + public String method { get; set; } + public String resource { get; set; } + public Dictionary queryParams { get; set; } + public Dictionary headers { get; set; } + public String contentType { get; set; } + public byte[] content { get; set; } + } + + private class MyHTTPResponse + { + public HttpStatusCode status { get; set; } + public String contentType { get; set; } + public byte[] content { get; set; } + public DateTime lastModified { get; set; } + public String etag { get; set; } + public Exception ex { get; set; } + + public MyHTTPResponse() { } + public MyHTTPResponse(HttpWebResponse webResp) + { + status = webResp.StatusCode; + contentType = webResp.ContentType; + etag = webResp.Headers.Get("Etag"); + lastModified = webResp.LastModified; + + using (var stream = webResp.GetResponseStream()) + { + content = ReadFully(stream, (int)webResp.ContentLength); + } + } + } + + private HttpWebRequest PreprocessRequest(MyHTTPRequest req) + { + String url; + if (req.resource.StartsWith("http", StringComparison.InvariantCultureIgnoreCase)) + { + url = req.resource; + } + else + { + url = endpoint.ToString(); + if (!url.EndsWith("/") && !req.resource.StartsWith("/")) + { + url += "/"; + } + url += req.resource; + } + + if (req.queryParams != null) + { + String qs = ""; + foreach (KeyValuePair entry in req.queryParams) + { + if (qs != "") + { + qs += "&"; + } + qs += HttpUtility.UrlEncode(entry.Key) + "=" + HttpUtility.UrlEncode(entry.Value); + } + if (qs != "") + { + url += "?" + qs; + } + } + + // TODO: handle special properties we recognize, such as content type, modified since, etc. + var webReq = (HttpWebRequest)WebRequest.Create(url); + webReq.Method = req.method; + + webReq.Headers.Add("X-Experience-API-Version", version.ToString()); + if (auth != null) + { + webReq.Headers.Add("Authorization", auth); + } + if (req.headers != null) + { + foreach (KeyValuePair entry in req.headers) + { + webReq.Headers.Add(entry.Key, entry.Value); + } + } + + if (req.contentType != null) + { + webReq.ContentType = req.contentType; + } + else + { + webReq.ContentType = "application/octet-stream"; + } + + if (req.content != null) + { + webReq.ContentLength = req.content.Length; + using (var stream = webReq.GetRequestStream()) + { + stream.Write(req.content, 0, req.content.Length); + } + } + + return webReq; + } + + private MyHTTPResponse MakeSyncRequest(MyHTTPRequest req) + { + HttpWebRequest webReq = PreprocessRequest(req); + MyHTTPResponse resp; + + try + { + using (var webResp = (HttpWebResponse)webReq.GetResponse()) + { + resp = new MyHTTPResponse(webResp); + } + } + catch (WebException ex) + { + if (ex.Response != null) + { + using (var webResp = (HttpWebResponse)ex.Response) + { + resp = new MyHTTPResponse(webResp); + } + } + else + { + resp = new MyHTTPResponse(); + resp.content = Encoding.UTF8.GetBytes("Web exception without '.Response'"); + } + resp.ex = ex; + } + + return resp; + } + + private async Task MakeAsyncRequest(MyHTTPRequest req) + { + HttpWebRequest webReq = PreprocessRequest(req); + MyHTTPResponse resp; + + try + { + using (var webResp = await webReq.GetResponseAsync()) + { + resp = new MyHTTPResponse((HttpWebResponse)webResp); + } + } + catch (WebException ex) + { + if (ex.Response != null) + { + using (var webResp = (HttpWebResponse)ex.Response) + { + resp = new MyHTTPResponse(webResp); + } + } + else + { + resp = new MyHTTPResponse(); + resp.content = Encoding.UTF8.GetBytes("Web exception without '.Response'"); + } + resp.ex = ex; + } + + return resp; + } + + /// + /// See http://www.yoda.arachsys.com/csharp/readbinary.html no license found + /// + /// Reads data from a stream until the end is reached. The + /// data is returned as a byte array. An IOException is + /// thrown if any of the underlying IO calls fail. + /// + /// The stream to read data from + /// The initial buffer length + private static byte[] ReadFully(Stream stream, int initialLength) + { + // If we've been passed an unhelpful initial length, just + // use 32K. + if (initialLength < 1) + { + initialLength = 32768; + } + + byte[] buffer = new byte[initialLength]; + int read = 0; + + int chunk; + while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0) + { + read += chunk; + + // If we've reached the end of our buffer, check to see if there's + // any more information + if (read == buffer.Length) + { + int nextByte = stream.ReadByte(); + + // End of stream? If so, we're done + if (nextByte == -1) + { + return buffer; + } + + // Nope. Resize the buffer, put in the byte we've just + // read, and continue + byte[] newBuffer = new byte[buffer.Length * 2]; + Array.Copy(buffer, newBuffer, buffer.Length); + newBuffer[read] = (byte)nextByte; + buffer = newBuffer; + read++; + } + } + // Buffer is now too big. Shrink it. + byte[] ret = new byte[read]; + Array.Copy(buffer, ret, read); + return ret; + } + + private MyHTTPResponse GetDocument(String resource, Dictionary queryParams, Document document) + { + var req = new MyHTTPRequest(); + req.method = "GET"; + req.resource = resource; + req.queryParams = queryParams; + + var res = MakeSyncRequest(req); + if (res.status == HttpStatusCode.OK) + { + document.content = res.content; + document.contentType = res.contentType; + document.timestamp = res.lastModified; + document.etag = res.etag; + } + + return res; + } + private ProfileKeysLRSResponse GetProfileKeys(String resource, Dictionary queryParams) + { + var r = new ProfileKeysLRSResponse(); + + var req = new MyHTTPRequest(); + req.method = "GET"; + req.resource = resource; + req.queryParams = queryParams; + + var res = MakeSyncRequest(req); + if (res.status != HttpStatusCode.OK) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + r.success = true; + + var keys = JArray.Parse(Encoding.UTF8.GetString(res.content)); + if (keys.Count > 0) { + r.content = new List(); + foreach (JToken key in keys) { + r.content.Add((String)key); + } + } + + return r; + } + private LRSResponse SaveDocument(String resource, Dictionary queryParams, Document document) + { + var r = new LRSResponse(); + + var req = new MyHTTPRequest(); + req.method = "PUT"; + req.resource = resource; + req.queryParams = queryParams; + req.contentType = document.contentType; + req.content = document.content; + + var res = MakeSyncRequest(req); + if (res.status != HttpStatusCode.NoContent) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + r.success = true; + + return r; + } + private LRSResponse DeleteDocument(String resource, Dictionary queryParams) + { + var r = new LRSResponse(); + + var req = new MyHTTPRequest(); + req.method = "DELETE"; + req.resource = resource; + req.queryParams = queryParams; + + var res = MakeSyncRequest(req); + if (res.status != HttpStatusCode.NoContent) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + r.success = true; + + return r; + } + private StatementLRSResponse GetStatement(Dictionary queryParams) + { + var r = new StatementLRSResponse(); + + var req = new MyHTTPRequest(); + req.method = "GET"; + req.resource = "statements"; + req.queryParams = queryParams; + + var res = MakeSyncRequest(req); + if (res.status != HttpStatusCode.OK) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + r.success = true; + r.content = new Statement(new Json.StringOfJSON(Encoding.UTF8.GetString(res.content))); + + return r; + } + + private async Task GetDocumentAsync(String resource, Dictionary queryParams, Document document) + { + var req = new MyHTTPRequest(); + req.method = "GET"; + req.resource = resource; + req.queryParams = queryParams; + + var res = await MakeAsyncRequest(req); + if (res.status == HttpStatusCode.OK) + { + document.content = res.content; + document.contentType = res.contentType; + document.timestamp = res.lastModified; + document.etag = res.etag; + } + + return res; + } + private async Task GetProfileKeysAsync(String resource, Dictionary queryParams) + { + var r = new ProfileKeysLRSResponse(); + + var req = new MyHTTPRequest(); + req.method = "GET"; + req.resource = resource; + req.queryParams = queryParams; + + var res = await MakeAsyncRequest(req); + if (res.status != HttpStatusCode.OK) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + r.success = true; + + var keys = JArray.Parse(Encoding.UTF8.GetString(res.content)); + if (keys.Count > 0) + { + r.content = new List(); + foreach (JToken key in keys) + { + r.content.Add((String)key); + } + } + + return r; + } + private async Task SaveDocumentAsync(String resource, Dictionary queryParams, Document document) + { + var r = new LRSResponse(); + + var req = new MyHTTPRequest(); + req.method = "PUT"; + req.resource = resource; + req.queryParams = queryParams; + req.contentType = document.contentType; + req.content = document.content; + + var res = await MakeAsyncRequest(req); + if (res.status != HttpStatusCode.NoContent) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + r.success = true; + + return r; + } + private async Task DeleteDocumentAsync(String resource, Dictionary queryParams) + { + var r = new LRSResponse(); + + var req = new MyHTTPRequest(); + req.method = "DELETE"; + req.resource = resource; + req.queryParams = queryParams; + + var res = await MakeAsyncRequest(req); + if (res.status != HttpStatusCode.NoContent) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + r.success = true; + + return r; + } + private async Task GetStatementAsync(Dictionary queryParams) + { + var r = new StatementLRSResponse(); + + var req = new MyHTTPRequest(); + req.method = "GET"; + req.resource = "statements"; + req.queryParams = queryParams; + + MyHTTPResponse res = await MakeAsyncRequest(req); + + if (res.status != HttpStatusCode.OK) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + r.success = true; + r.content = new Statement(new Json.StringOfJSON(Encoding.UTF8.GetString(res.content))); + + return r; + } + + public AboutLRSResponse About() + { + var r = new AboutLRSResponse(); + + var req = new MyHTTPRequest(); + req.method = "GET"; + req.resource = "about"; + + var res = MakeSyncRequest(req); + if (res.status != HttpStatusCode.OK) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + r.success = true; + r.content = new About(Encoding.UTF8.GetString(res.content)); + + return r; + } + public StatementLRSResponse SaveStatement(Statement statement) + { + var r = new StatementLRSResponse(); + var req = new MyHTTPRequest(); + req.queryParams = new Dictionary(); + req.resource = "statements"; + + if (statement.id == null) + { + req.method = "POST"; + } + else + { + req.method = "PUT"; + req.queryParams.Add("statementId", statement.id.ToString()); + } + + req.contentType = "application/json"; + req.content = Encoding.UTF8.GetBytes(statement.ToJSON(version)); + + var res = MakeSyncRequest(req); + if (statement.id == null) + { + if (res.status != HttpStatusCode.OK) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + var ids = JArray.Parse(Encoding.UTF8.GetString(res.content)); + statement.id = new Guid((String)ids[0]); + } + else { + if (res.status != HttpStatusCode.NoContent) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + } + + r.success = true; + r.content = statement; + + return r; + } + public StatementLRSResponse VoidStatement(Guid id, Agent agent) + { + var voidStatement = new Statement + { + actor = agent, + verb = new Verb + { + id = new Uri("http://adlnet.gov/expapi/verbs/voided"), + display = new LanguageMap() + }, + target = new StatementRef { id = id } + }; + voidStatement.verb.display.Add("en-US", "voided"); + + return SaveStatement(voidStatement); + } + public StatementsResultLRSResponse SaveStatements(List statements) + { + var r = new StatementsResultLRSResponse(); + + var req = new MyHTTPRequest(); + req.resource = "statements"; + req.method = "POST"; + req.contentType = "application/json"; + + var jarray = new JArray(); + foreach (Statement st in statements) + { + jarray.Add(st.ToJObject(version)); + } + req.content = Encoding.UTF8.GetBytes(jarray.ToString()); + + var res = MakeSyncRequest(req); + if (res.status != HttpStatusCode.OK) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + var ids = JArray.Parse(Encoding.UTF8.GetString(res.content)); + for (int i = 0; i < ids.Count; i++) + { + statements[i].id = new Guid((String)ids[i]); + } + + r.success = true; + r.content = new StatementsResult(statements); + + return r; + } + public StatementLRSResponse RetrieveStatement(Guid id) + { + var queryParams = new Dictionary(); + queryParams.Add("statementId", id.ToString()); + + return GetStatement(queryParams); + } + public StatementLRSResponse RetrieveVoidedStatement(Guid id) + { + var queryParams = new Dictionary(); + queryParams.Add("voidedStatementId", id.ToString()); + + return GetStatement(queryParams); + } + public StatementsResultLRSResponse QueryStatements(StatementsQuery query) + { + var r = new StatementsResultLRSResponse(); + + var req = new MyHTTPRequest(); + req.method = "GET"; + req.resource = "statements"; + req.queryParams = query.ToParameterMap(version); + + var res = MakeSyncRequest(req); + if (res.status != HttpStatusCode.OK) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + r.success = true; + r.content = new StatementsResult(new Json.StringOfJSON(Encoding.UTF8.GetString(res.content))); + + return r; + } + public StatementsResultLRSResponse MoreStatements(StatementsResult result) + { + var r = new StatementsResultLRSResponse(); + + var req = new MyHTTPRequest(); + req.method = "GET"; + req.resource = endpoint.GetLeftPart(UriPartial.Authority); + if (! req.resource.EndsWith("/")) { + req.resource += "/"; + } + req.resource += result.more; + + var res = MakeSyncRequest(req); + if (res.status != HttpStatusCode.OK) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + r.success = true; + r.content = new StatementsResult(new Json.StringOfJSON(Encoding.UTF8.GetString(res.content))); + + return r; + } + + public async Task AboutAsync() + { + var r = new AboutLRSResponse(); + + var req = new MyHTTPRequest(); + req.method = "GET"; + req.resource = "about"; + + var res = await MakeAsyncRequest(req); + if (res.status != HttpStatusCode.OK) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + r.success = true; + r.content = new About(Encoding.UTF8.GetString(res.content)); + + return r; + } + public async Task SaveStatementAsync(Statement statement) + { + var r = new StatementLRSResponse(); + var req = new MyHTTPRequest(); + req.queryParams = new Dictionary(); + req.resource = "statements"; + + if (statement.id == null) + { + req.method = "POST"; + } + else + { + req.method = "PUT"; + req.queryParams.Add("statementId", statement.id.ToString()); + } + + req.contentType = "application/json"; + req.content = Encoding.UTF8.GetBytes(statement.ToJSON(version)); + + MyHTTPResponse res = await MakeAsyncRequest(req); + + if (statement.id == null) + { + if (res.status != HttpStatusCode.OK) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + var ids = JArray.Parse(Encoding.UTF8.GetString(res.content)); + statement.id = new Guid((String)ids[0]); + } + else + { + if (res.status != HttpStatusCode.NoContent) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + } + + r.success = true; + r.content = statement; + + return r; + } + public async Task VoidStatementAsync(Guid id, Agent agent) + { + var voidStatement = new Statement + { + actor = agent, + verb = new Verb + { + id = new Uri("http://adlnet.gov/expapi/verbs/voided"), + display = new LanguageMap() + }, + target = new StatementRef { id = id } + }; + voidStatement.verb.display.Add("en-US", "voided"); + + return await SaveStatementAsync(voidStatement); + } + public async Task SaveStatementsAsync(List statements) + { + var r = new StatementsResultLRSResponse(); + + var req = new MyHTTPRequest(); + req.resource = "statements"; + req.method = "POST"; + req.contentType = "application/json"; + + var jarray = new JArray(); + foreach (Statement st in statements) + { + jarray.Add(st.ToJObject(version)); + } + req.content = Encoding.UTF8.GetBytes(jarray.ToString()); + + MyHTTPResponse res = await MakeAsyncRequest(req); + + if (res.status != HttpStatusCode.OK) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + var ids = JArray.Parse(Encoding.UTF8.GetString(res.content)); + for (int i = 0; i < ids.Count; i++) + { + statements[i].id = new Guid((String)ids[i]); + } + + r.success = true; + r.content = new StatementsResult(statements); + + return r; + } + public async Task RetrieveStatementAsync(Guid id) + { + var queryParams = new Dictionary(); + queryParams.Add("statementId", id.ToString()); + + return await GetStatementAsync(queryParams); + } + public async Task RetrieveVoidedStatementAsync(Guid id) + { + var queryParams = new Dictionary(); + queryParams.Add("voidedStatementId", id.ToString()); + + return await GetStatementAsync(queryParams); + } + public async Task QueryStatementsAsync(StatementsQuery query) + { + var r = new StatementsResultLRSResponse(); + + var req = new MyHTTPRequest(); + req.method = "GET"; + req.resource = "statements"; + req.queryParams = query.ToParameterMap(version); + + MyHTTPResponse res = await MakeAsyncRequest(req); + + if (res.status != HttpStatusCode.OK) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + r.success = true; + r.content = new StatementsResult(new Json.StringOfJSON(Encoding.UTF8.GetString(res.content))); + + return r; + } + public async Task MoreStatementsAsync(StatementsResult result) + { + var r = new StatementsResultLRSResponse(); + + var req = new MyHTTPRequest(); + req.method = "GET"; + req.resource = endpoint.GetLeftPart(UriPartial.Authority); + if (!req.resource.EndsWith("/")) + { + req.resource += "/"; + } + req.resource += result.more; + + MyHTTPResponse res = await MakeAsyncRequest(req); + + if (res.status != HttpStatusCode.OK) + { + r.success = false; + r.httpException = res.ex; + r.SetErrMsgFromBytes(res.content); + return r; + } + + r.success = true; + r.content = new StatementsResult(new Json.StringOfJSON(Encoding.UTF8.GetString(res.content))); + + return r; + } + + // TODO: since param + public ProfileKeysLRSResponse RetrieveStateIds(Activity activity, Agent agent, Nullable registration = null) + { + var queryParams = new Dictionary(); + queryParams.Add("activityId", activity.id.ToString()); + queryParams.Add("agent", agent.ToJSON(version)); + if (registration != null) + { + queryParams.Add("registration", registration.ToString()); + } + + return GetProfileKeys("activities/state", queryParams); + } + public StateLRSResponse RetrieveState(String id, Activity activity, Agent agent, Nullable registration = null) + { + var r = new StateLRSResponse(); + + var queryParams = new Dictionary(); + queryParams.Add("stateId", id); + queryParams.Add("activityId", activity.id.ToString()); + queryParams.Add("agent", agent.ToJSON(version)); + + var state = new StateDocument(); + state.id = id; + state.activity = activity; + state.agent = agent; + + if (registration != null) + { + queryParams.Add("registration", registration.ToString()); + state.registration = registration; + } + + var resp = GetDocument("activities/state", queryParams, state); + if (resp.status != HttpStatusCode.OK && resp.status != HttpStatusCode.NotFound) + { + r.success = false; + r.httpException = resp.ex; + r.SetErrMsgFromBytes(resp.content); + return r; + } + r.success = true; + r.content = state; + + return r; + } + public LRSResponse SaveState(StateDocument state) + { + var queryParams = new Dictionary(); + queryParams.Add("stateId", state.id); + queryParams.Add("activityId", state.activity.id.ToString()); + queryParams.Add("agent", state.agent.ToJSON(version)); + if (state.registration != null) + { + queryParams.Add("registration", state.registration.ToString()); + } + + return SaveDocument("activities/state", queryParams, state); + } + public LRSResponse DeleteState(StateDocument state) + { + var queryParams = new Dictionary(); + queryParams.Add("stateId", state.id); + queryParams.Add("activityId", state.activity.id.ToString()); + queryParams.Add("agent", state.agent.ToJSON(version)); + if (state.registration != null) + { + queryParams.Add("registration", state.registration.ToString()); + } + + return DeleteDocument("activities/state", queryParams); + } + public LRSResponse ClearState(Activity activity, Agent agent, Nullable registration = null) + { + var queryParams = new Dictionary(); + queryParams.Add("activityId", activity.id.ToString()); + queryParams.Add("agent", agent.ToJSON(version)); + if (registration != null) + { + queryParams.Add("registration", registration.ToString()); + } + + return DeleteDocument("activities/state", queryParams); + } + + public async Task RetrieveStateIdsAsync(Activity activity, Agent agent, Nullable registration = null) + { + var queryParams = new Dictionary(); + queryParams.Add("activityId", activity.id.ToString()); + queryParams.Add("agent", agent.ToJSON(version)); + if (registration != null) + { + queryParams.Add("registration", registration.ToString()); + } + + return await GetProfileKeysAsync("activities/state", queryParams); + } + public async Task RetrieveStateAsync(String id, Activity activity, Agent agent, Nullable registration = null) + { + var r = new StateLRSResponse(); + + var queryParams = new Dictionary(); + queryParams.Add("stateId", id); + queryParams.Add("activityId", activity.id.ToString()); + queryParams.Add("agent", agent.ToJSON(version)); + + var state = new StateDocument(); + state.id = id; + state.activity = activity; + state.agent = agent; + + if (registration != null) + { + queryParams.Add("registration", registration.ToString()); + state.registration = registration; + } + + var resp = await GetDocumentAsync("activities/state", queryParams, state); + if (resp.status != HttpStatusCode.OK && resp.status != HttpStatusCode.NotFound) + { + r.success = false; + r.httpException = resp.ex; + r.SetErrMsgFromBytes(resp.content); + return r; + } + r.success = true; + r.content = state; + + return r; + } + public async Task SaveStateAsync(StateDocument state) + { + var queryParams = new Dictionary(); + queryParams.Add("stateId", state.id); + queryParams.Add("activityId", state.activity.id.ToString()); + queryParams.Add("agent", state.agent.ToJSON(version)); + if (state.registration != null) + { + queryParams.Add("registration", state.registration.ToString()); + } + + return await SaveDocumentAsync("activities/state", queryParams, state); + } + public async Task DeleteStateAsync(StateDocument state) + { + var queryParams = new Dictionary(); + queryParams.Add("stateId", state.id); + queryParams.Add("activityId", state.activity.id.ToString()); + queryParams.Add("agent", state.agent.ToJSON(version)); + if (state.registration != null) + { + queryParams.Add("registration", state.registration.ToString()); + } + + return await DeleteDocumentAsync("activities/state", queryParams); + } + public async Task ClearStateAsync(Activity activity, Agent agent, Nullable registration = null) + { + var queryParams = new Dictionary(); + queryParams.Add("activityId", activity.id.ToString()); + queryParams.Add("agent", agent.ToJSON(version)); + if (registration != null) + { + queryParams.Add("registration", registration.ToString()); + } + + return await DeleteDocumentAsync("activities/state", queryParams); + } + + // TODO: since param + public ProfileKeysLRSResponse RetrieveActivityProfileIds(Activity activity) + { + var queryParams = new Dictionary(); + queryParams.Add("activityId", activity.id.ToString()); + + return GetProfileKeys("activities/profile", queryParams); + } + public ActivityProfileLRSResponse RetrieveActivityProfile(String id, Activity activity) + { + var r = new ActivityProfileLRSResponse(); + + var queryParams = new Dictionary(); + queryParams.Add("profileId", id); + queryParams.Add("activityId", activity.id.ToString()); + + var profile = new ActivityProfileDocument(); + profile.id = id; + profile.activity = activity; + + var resp = GetDocument("activities/profile", queryParams, profile); + if (resp.status != HttpStatusCode.OK && resp.status != HttpStatusCode.NotFound) + { + r.success = false; + r.httpException = resp.ex; + r.SetErrMsgFromBytes(resp.content); + return r; + } + r.success = true; + r.content = profile; + + return r; + } + public LRSResponse SaveActivityProfile(ActivityProfileDocument profile) + { + var queryParams = new Dictionary(); + queryParams.Add("profileId", profile.id); + queryParams.Add("activityId", profile.activity.id.ToString()); + + return SaveDocument("activities/profile", queryParams, profile); + } + public LRSResponse DeleteActivityProfile(ActivityProfileDocument profile) + { + var queryParams = new Dictionary(); + queryParams.Add("profileId", profile.id); + queryParams.Add("activityId", profile.activity.id.ToString()); + // TODO: need to pass Etag? + + return DeleteDocument("activities/profile", queryParams); + } + + public async Task RetrieveActivityProfileIdsAsync(Activity activity) + { + var queryParams = new Dictionary(); + queryParams.Add("activityId", activity.id.ToString()); + + return await GetProfileKeysAsync("activities/profile", queryParams); + } + public async Task RetrieveActivityProfileAsync(String id, Activity activity) + { + var r = new ActivityProfileLRSResponse(); + + var queryParams = new Dictionary(); + queryParams.Add("profileId", id); + queryParams.Add("activityId", activity.id.ToString()); + + var profile = new ActivityProfileDocument(); + profile.id = id; + profile.activity = activity; + + var resp = await GetDocumentAsync("activities/profile", queryParams, profile); + if (resp.status != HttpStatusCode.OK && resp.status != HttpStatusCode.NotFound) + { + r.success = false; + r.httpException = resp.ex; + r.SetErrMsgFromBytes(resp.content); + return r; + } + r.success = true; + r.content = profile; + + return r; + } + public async Task SaveActivityProfileAsync(ActivityProfileDocument profile) + { + var queryParams = new Dictionary(); + queryParams.Add("profileId", profile.id); + queryParams.Add("activityId", profile.activity.id.ToString()); + + return await SaveDocumentAsync("activities/profile", queryParams, profile); + } + public async Task DeleteActivityProfileAsync(ActivityProfileDocument profile) + { + var queryParams = new Dictionary(); + queryParams.Add("profileId", profile.id); + queryParams.Add("activityId", profile.activity.id.ToString()); + // TODO: need to pass Etag? + + return await DeleteDocumentAsync("activities/profile", queryParams); + } + + // TODO: since param + public ProfileKeysLRSResponse RetrieveAgentProfileIds(Agent agent) + { + var queryParams = new Dictionary(); + queryParams.Add("agent", agent.ToJSON(version)); + + return GetProfileKeys("agents/profile", queryParams); + } + public AgentProfileLRSResponse RetrieveAgentProfile(String id, Agent agent) + { + var r = new AgentProfileLRSResponse(); + + var queryParams = new Dictionary(); + queryParams.Add("profileId", id); + queryParams.Add("agent", agent.ToJSON(version)); + + var profile = new AgentProfileDocument(); + profile.id = id; + profile.agent = agent; + + var resp = GetDocument("agents/profile", queryParams, profile); + if (resp.status != HttpStatusCode.OK && resp.status != HttpStatusCode.NotFound) + { + r.success = false; + r.httpException = resp.ex; + r.SetErrMsgFromBytes(resp.content); + return r; + } + r.success = true; + r.content = profile; + + return r; + } + public LRSResponse SaveAgentProfile(AgentProfileDocument profile) + { + var queryParams = new Dictionary(); + queryParams.Add("profileId", profile.id); + queryParams.Add("agent", profile.agent.ToJSON(version)); + + return SaveDocument("agents/profile", queryParams, profile); + } + public LRSResponse DeleteAgentProfile(AgentProfileDocument profile) + { + var queryParams = new Dictionary(); + queryParams.Add("profileId", profile.id); + queryParams.Add("agent", profile.agent.ToJSON(version)); + // TODO: need to pass Etag? + + return DeleteDocument("agents/profile", queryParams); + } + + public async Task RetrieveAgentProfileIdsAsync(Agent agent) + { + var queryParams = new Dictionary(); + queryParams.Add("agent", agent.ToJSON(version)); + + return await GetProfileKeysAsync("agents/profile", queryParams); + } + public async Task RetrieveAgentProfileAsync(String id, Agent agent) + { + var r = new AgentProfileLRSResponse(); + + var queryParams = new Dictionary(); + queryParams.Add("profileId", id); + queryParams.Add("agent", agent.ToJSON(version)); + + var profile = new AgentProfileDocument(); + profile.id = id; + profile.agent = agent; + + var resp = await GetDocumentAsync("agents/profile", queryParams, profile); + if (resp.status != HttpStatusCode.OK && resp.status != HttpStatusCode.NotFound) + { + r.success = false; + r.httpException = resp.ex; + r.SetErrMsgFromBytes(resp.content); + return r; + } + r.success = true; + r.content = profile; + + return r; + } + public async Task SaveAgentProfileAsync(AgentProfileDocument profile) + { + var queryParams = new Dictionary(); + queryParams.Add("profileId", profile.id); + queryParams.Add("agent", profile.agent.ToJSON(version)); + + return await SaveDocumentAsync("agents/profile", queryParams, profile); + } + public async Task DeleteAgentProfileAsync(AgentProfileDocument profile) + { + var queryParams = new Dictionary(); + queryParams.Add("profileId", profile.id); + queryParams.Add("agent", profile.agent.ToJSON(version)); + // TODO: need to pass Etag? + + return await DeleteDocumentAsync("agents/profile", queryParams); + } + } +} diff --git a/TinCan/TinCan.csproj b/TinCan/TinCan.csproj index 3b1f335..1b7abce 100644 --- a/TinCan/TinCan.csproj +++ b/TinCan/TinCan.csproj @@ -1,113 +1,113 @@ - - - - - Debug - AnyCPU - {27D0FCA1-E869-440C-9D16-F62D7A068C53} - Library - Properties - TinCan - TinCan - v4.5 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\TinCan.XML - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - true - bin\Documentation\ - DEBUG;TRACE - bin\Debug\TinCan.XML - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - false - - - - ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + AnyCPU + {27D0FCA1-E869-440C-9D16-F62D7A068C53} + Library + Properties + TinCan + TinCan + v4.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\TinCan.XML + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + true + bin\Documentation\ + DEBUG;TRACE + bin\Debug\TinCan.XML + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + false + + + + ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TinCan/packages.config b/TinCan/packages.config index 284ec0a..505e588 100644 --- a/TinCan/packages.config +++ b/TinCan/packages.config @@ -1,4 +1,4 @@ - - - + + + \ No newline at end of file diff --git a/TinCanTests/RemoteLRSResourceTest.cs b/TinCanTests/RemoteLRSResourceTest.cs index bf4c94d..bd9a43b 100644 --- a/TinCanTests/RemoteLRSResourceTest.cs +++ b/TinCanTests/RemoteLRSResourceTest.cs @@ -1,664 +1,664 @@ -/* - Copyright 2014 Rustici Software - - 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. -*/ -namespace TinCanTests -{ - using System; - using System.Collections.Generic; - using System.Xml; - using NUnit.Framework; - using Newtonsoft.Json.Linq; - using TinCan; - using TinCan.Documents; - using TinCan.Json; - using TinCan.LRSResponses; - using System.Threading.Tasks; - - [TestFixture] - class RemoteLRSResourceTest - { - RemoteLRS lrs; - - [SetUp] - public void Init() - { - Console.WriteLine("Running " + TestContext.CurrentContext.Test.FullName); - - // - // these are credentials used by the other OSS libs when building via Travis-CI - // so are okay to include in the repository, if you wish to have access to the - // results of the test suite then supply your own endpoint, username, and password - // - lrs = new RemoteLRS( - "https://cloud.scorm.com/tc/U2S4SI5FY0/sandbox/", - "Nja986GYE1_XrWMmFUE", - "Bd9lDr1kjaWWY6RID_4" - ); - } - - [Test] - public void TestAbout() - { - AboutLRSResponse lrsRes = lrs.About(); - Assert.IsTrue(lrsRes.success); - } - - [Test] - public void TestAboutFailure() - { - lrs.endpoint = new Uri("http://cloud.scorm.com/tc/3TQLAI9/sandbox/"); - - AboutLRSResponse lrsRes = lrs.About(); - Assert.IsFalse(lrsRes.success); - Console.WriteLine("TestAboutFailure - errMsg: " + lrsRes.errMsg); - } - - [Test] - public void TestSaveStatement() - { - var statement = new Statement(); - statement.actor = Support.agent; - statement.verb = Support.verb; - statement.target = Support.activity; - - StatementLRSResponse lrsRes = lrs.SaveStatement(statement); - Assert.IsTrue(lrsRes.success); - Assert.AreEqual(statement, lrsRes.content); - Assert.IsNotNull(lrsRes.content.id); - } - - [Test] - public void TestSaveStatementWithID() - { - var statement = new Statement(); - statement.Stamp(); - statement.actor = Support.agent; - statement.verb = Support.verb; - statement.target = Support.activity; - - StatementLRSResponse lrsRes = lrs.SaveStatement(statement); - Assert.IsTrue(lrsRes.success); - Assert.AreEqual(statement, lrsRes.content); - } - - [Test] - public void TestSaveStatementStatementRef() - { - var statement = new Statement(); - statement.Stamp(); - statement.actor = Support.agent; - statement.verb = Support.verb; - statement.target = Support.statementRef; - - StatementLRSResponse lrsRes = lrs.SaveStatement(statement); - Assert.IsTrue(lrsRes.success); - Assert.AreEqual(statement, lrsRes.content); - } - - [Test] - public void TestSaveStatementSubStatement() - { - var statement = new Statement(); - statement.Stamp(); - statement.actor = Support.agent; - statement.verb = Support.verb; - statement.target = Support.subStatement; - - Console.WriteLine(statement.ToJSON(true)); - - StatementLRSResponse lrsRes = lrs.SaveStatement(statement); - Assert.IsTrue(lrsRes.success); - Assert.AreEqual(statement, lrsRes.content); - } - - [Test] - public void TestVoidStatement() - { - Guid toVoid = Guid.NewGuid(); - StatementLRSResponse lrsRes = lrs.VoidStatement(toVoid, Support.agent); - - Assert.IsTrue(lrsRes.success, "LRS response successful"); - Assert.AreEqual(new Uri("http://adlnet.gov/expapi/verbs/voided"), lrsRes.content.verb.id, "voiding statement uses voided verb"); - Assert.AreEqual(toVoid, ((StatementRef) lrsRes.content.target).id, "voiding statement target correct id"); - } - - [Test] - public void TestSaveStatements() - { - var statement1 = new Statement(); - statement1.actor = Support.agent; - statement1.verb = Support.verb; - statement1.target = Support.parent; - - var statement2 = new Statement(); - statement2.actor = Support.agent; - statement2.verb = Support.verb; - statement2.target = Support.activity; - statement2.context = Support.context; - - var statements = new List(); - statements.Add(statement1); - statements.Add(statement2); - - StatementsResultLRSResponse lrsRes = lrs.SaveStatements(statements); - Assert.IsTrue(lrsRes.success); - // TODO: check statements match and ids not null - } - - [Test] - public void TestRetrieveStatement() - { - var statement = new TinCan.Statement(); - statement.Stamp(); - statement.actor = Support.agent; - statement.verb = Support.verb; - statement.target = Support.activity; - statement.context = Support.context; - statement.result = Support.result; - - StatementLRSResponse saveRes = lrs.SaveStatement(statement); - if (saveRes.success) - { - StatementLRSResponse retRes = lrs.RetrieveStatement(saveRes.content.id.Value); - Assert.IsTrue(retRes.success); - Console.WriteLine("TestRetrieveStatement - statement: " + retRes.content.ToJSON(true)); - } - else - { - // TODO: skipped? - } - } - - [Test] - public void TestQueryStatements() - { - var query = new TinCan.StatementsQuery(); - query.agent = Support.agent; - query.verbId = Support.verb.id; - query.activityId = Support.parent.id; - query.relatedActivities = true; - query.relatedAgents = true; - query.format = StatementsQueryResultFormat.IDS; - query.limit = 10; - - StatementsResultLRSResponse lrsRes = lrs.QueryStatements(query); - Assert.IsTrue(lrsRes.success); - Console.WriteLine("TestQueryStatements - statement count: " + lrsRes.content.statements.Count); - } - - [Test] - public void TestMoreStatements() - { - var query = new TinCan.StatementsQuery(); - query.format = StatementsQueryResultFormat.IDS; - query.limit = 2; - - StatementsResultLRSResponse queryRes = lrs.QueryStatements(query); - if (queryRes.success && queryRes.content.more != null) - { - StatementsResultLRSResponse moreRes = lrs.MoreStatements(queryRes.content); - Assert.IsTrue(moreRes.success); - Console.WriteLine("TestMoreStatements - statement count: " + moreRes.content.statements.Count); - } - else - { - // TODO: skipped? - } - } - - [Test] - public void TestRetrieveStateIds() - { - ProfileKeysLRSResponse lrsRes = lrs.RetrieveStateIds(Support.activity, Support.agent); - Assert.IsTrue(lrsRes.success); - } - - [Test] - public void TestRetrieveState() - { - StateLRSResponse lrsRes = lrs.RetrieveState("test", Support.activity, Support.agent); - Assert.IsTrue(lrsRes.success); - Assert.IsInstanceOf(lrsRes.content); - } - - [Test] - public void TestSaveState() - { - var doc = new StateDocument(); - doc.activity = Support.activity; - doc.agent = Support.agent; - doc.id = "test"; - doc.content = System.Text.Encoding.UTF8.GetBytes("Test value"); - - LRSResponse lrsRes = lrs.SaveState(doc); - Assert.IsTrue(lrsRes.success); - } - - [Test] - public void TestDeleteState() - { - var doc = new StateDocument(); - doc.activity = Support.activity; - doc.agent = Support.agent; - doc.id = "test"; - - LRSResponse lrsRes = lrs.DeleteState(doc); - Assert.IsTrue(lrsRes.success); - } - - [Test] - public void TestClearState() - { - LRSResponse lrsRes = lrs.ClearState(Support.activity, Support.agent); - Assert.IsTrue(lrsRes.success); - } - - [Test] - public void TestRetrieveActivityProfileIds() - { - ProfileKeysLRSResponse lrsRes = lrs.RetrieveActivityProfileIds(Support.activity); - Assert.IsTrue(lrsRes.success); - } - - [Test] - public void TestRetrieveActivityProfile() - { - ActivityProfileLRSResponse lrsRes = lrs.RetrieveActivityProfile("test", Support.activity); - Assert.IsTrue(lrsRes.success); - Assert.IsInstanceOf(lrsRes.content); - } - - [Test] - public void TestSaveActivityProfile() - { - var doc = new ActivityProfileDocument(); - doc.activity = Support.activity; - doc.id = "test"; - doc.content = System.Text.Encoding.UTF8.GetBytes("Test value"); - - LRSResponse lrsRes = lrs.SaveActivityProfile(doc); - Assert.IsTrue(lrsRes.success); - } - - [Test] - public void TestDeleteActivityProfile() - { - var doc = new ActivityProfileDocument(); - doc.activity = Support.activity; - doc.id = "test"; - - LRSResponse lrsRes = lrs.DeleteActivityProfile(doc); - Assert.IsTrue(lrsRes.success); - } - - [Test] - public void TestRetrieveAgentProfileIds() - { - ProfileKeysLRSResponse lrsRes = lrs.RetrieveAgentProfileIds(Support.agent); - Assert.IsTrue(lrsRes.success); - } - - [Test] - public void TestRetrieveAgentProfile() - { - AgentProfileLRSResponse lrsRes = lrs.RetrieveAgentProfile("test", Support.agent); - Assert.IsTrue(lrsRes.success); - Assert.IsInstanceOf(lrsRes.content); - } - - [Test] - public void TestSaveAgentProfile() - { - var doc = new AgentProfileDocument(); - doc.agent = Support.agent; - doc.id = "test"; - doc.content = System.Text.Encoding.UTF8.GetBytes("Test value"); - - LRSResponse lrsRes = lrs.SaveAgentProfile(doc); - Assert.IsTrue(lrsRes.success); - } - - [Test] - public void TestDeleteAgentProfile() - { - var doc = new AgentProfileDocument(); - doc.agent = Support.agent; - doc.id = "test"; - - LRSResponse lrsRes = lrs.DeleteAgentProfile(doc); - Assert.IsTrue(lrsRes.success); - } - - - - [Test] - public void TestAboutAsync() - { - Task lrsRes = lrs.AboutAsync(); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - } - - [Test] - public void TestAboutAsyncFailure() - { - lrs.endpoint = new Uri("http://cloud.scorm.com/tc/3TQLAI9/sandbox/"); - - Task lrsRes = lrs.AboutAsync(); - lrsRes.Wait(); - Assert.IsFalse(lrsRes.Result.success); - Console.WriteLine("TestAboutFailure - errMsg: " + lrsRes.Result.errMsg); - } - - [Test] - public void TestSaveStatementAsync() - { - var statement = new Statement(); - statement.actor = Support.agent; - statement.verb = Support.verb; - statement.target = Support.activity; - - Task lrsRes = lrs.SaveStatementAsync(statement); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - Assert.AreEqual(statement, lrsRes.Result.content); - Assert.IsNotNull(lrsRes.Result.content.id); - } - - [Test] - public void TestSaveStatementWithIDAsync() - { - var statement = new Statement(); - statement.Stamp(); - statement.actor = Support.agent; - statement.verb = Support.verb; - statement.target = Support.activity; - - Task lrsRes = lrs.SaveStatementAsync(statement); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - Assert.AreEqual(statement, lrsRes.Result.content); - } - - [Test] - public void TestSaveStatementStatementRefAsync() - { - var statement = new Statement(); - statement.Stamp(); - statement.actor = Support.agent; - statement.verb = Support.verb; - statement.target = Support.statementRef; - - Task lrsRes = lrs.SaveStatementAsync(statement); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - Assert.AreEqual(statement, lrsRes.Result.content); - } - - [Test] - public void TestSaveStatementSubStatementAsync() - { - var statement = new Statement(); - statement.Stamp(); - statement.actor = Support.agent; - statement.verb = Support.verb; - statement.target = Support.subStatement; - - Console.WriteLine(statement.ToJSON(true)); - - Task lrsRes = lrs.SaveStatementAsync(statement); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - Assert.AreEqual(statement, lrsRes.Result.content); - } - - [Test] - public void TestVoidStatementAsync() - { - Guid toVoid = Guid.NewGuid(); - Task lrsRes = lrs.VoidStatementAsync(toVoid, Support.agent); - lrsRes.Wait(); - - Assert.IsTrue(lrsRes.Result.success, "LRS response successful"); - Assert.AreEqual(new Uri("http://adlnet.gov/expapi/verbs/voided"), lrsRes.Result.content.verb.id, "voiding statement uses voided verb"); - Assert.AreEqual(toVoid, ((StatementRef)lrsRes.Result.content.target).id, "voiding statement target correct id"); - } - - [Test] - public void TestSaveStatementsAsync() - { - var statement1 = new Statement(); - statement1.actor = Support.agent; - statement1.verb = Support.verb; - statement1.target = Support.parent; - - var statement2 = new Statement(); - statement2.actor = Support.agent; - statement2.verb = Support.verb; - statement2.target = Support.activity; - statement2.context = Support.context; - - var statements = new List(); - statements.Add(statement1); - statements.Add(statement2); - - Task lrsRes = lrs.SaveStatementsAsync(statements); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - // TODO: check statements match and ids not null - } - - [Test] - public void TestRetrieveStatementAsync() - { - var statement = new TinCan.Statement(); - statement.Stamp(); - statement.actor = Support.agent; - statement.verb = Support.verb; - statement.target = Support.activity; - statement.context = Support.context; - statement.result = Support.result; - - Task saveRes = lrs.SaveStatementAsync(statement); - saveRes.Wait(); - if (saveRes.Result.success) - { - Task retRes = lrs.RetrieveStatementAsync(saveRes.Result.content.id.Value); - Assert.IsTrue(retRes.Result.success); - Console.WriteLine("TestRetrieveStatement - statement: " + retRes.Result.content.ToJSON(true)); - } - else - { - // TODO: skipped? - } - } - - [Test] - public void TestQueryStatementsAsync() - { - var query = new TinCan.StatementsQuery(); - query.agent = Support.agent; - query.verbId = Support.verb.id; - query.activityId = Support.parent.id; - query.relatedActivities = true; - query.relatedAgents = true; - query.format = StatementsQueryResultFormat.IDS; - query.limit = 10; - - Task lrsRes = lrs.QueryStatementsAsync(query); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - Console.WriteLine("TestQueryStatements - statement count: " + lrsRes.Result.content.statements.Count); - } - - [Test] - public void TestMoreStatementsAsync() - { - var query = new TinCan.StatementsQuery(); - query.format = StatementsQueryResultFormat.IDS; - query.limit = 2; - - Task queryRes = lrs.QueryStatementsAsync(query); - queryRes.Wait(); - if (queryRes.Result.success && queryRes.Result.content.more != null) - { - Task moreRes = lrs.MoreStatementsAsync(queryRes.Result.content); - moreRes.Wait(); - Assert.IsTrue(moreRes.Result.success); - Console.WriteLine("TestMoreStatements - statement count: " + moreRes.Result.content.statements.Count); - } - else - { - // TODO: skipped? - } - } - - [Test] - public void TestRetrieveStateIdsAsync() - { - Task lrsRes = lrs.RetrieveStateIdsAsync(Support.activity, Support.agent); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - } - - [Test] - public void TestRetrieveStateAsync() - { - Task lrsRes = lrs.RetrieveStateAsync("test", Support.activity, Support.agent); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - Assert.IsInstanceOf(lrsRes.Result.content); - } - - [Test] - public void TestSaveStateAsync() - { - var doc = new StateDocument(); - doc.activity = Support.activity; - doc.agent = Support.agent; - doc.id = "test"; - doc.content = System.Text.Encoding.UTF8.GetBytes("Test value"); - - Task lrsRes = lrs.SaveStateAsync(doc); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - } - - [Test] - public void TestDeleteStateAsync() - { - var doc = new StateDocument(); - doc.activity = Support.activity; - doc.agent = Support.agent; - doc.id = "test"; - - Task lrsRes = lrs.DeleteStateAsync(doc); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - } - - [Test] - public void TestClearStateAsync() - { - Task lrsRes = lrs.ClearStateAsync(Support.activity, Support.agent); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - } - - [Test] - public void TestRetrieveActivityProfileIdsAsync() - { - Task lrsRes = lrs.RetrieveActivityProfileIdsAsync(Support.activity); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - } - - [Test] - public void TestRetrieveActivityProfileAsync() - { - Task lrsRes = lrs.RetrieveActivityProfileAsync("test", Support.activity); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - Assert.IsInstanceOf(lrsRes.Result.content); - } - - [Test] - public void TestSaveActivityProfileAsync() - { - var doc = new ActivityProfileDocument(); - doc.activity = Support.activity; - doc.id = "test"; - doc.content = System.Text.Encoding.UTF8.GetBytes("Test value"); - - Task lrsRes = lrs.SaveActivityProfileAsync(doc); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - } - - [Test] - public void TestDeleteActivityProfileAsync() - { - var doc = new ActivityProfileDocument(); - doc.activity = Support.activity; - doc.id = "test"; - - Task lrsRes = lrs.DeleteActivityProfileAsync(doc); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - } - - [Test] - public void TestRetrieveAgentProfileIdsAsync() - { - Task lrsRes = lrs.RetrieveAgentProfileIdsAsync(Support.agent); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - } - - [Test] - public void TestRetrieveAgentProfileAsync() - { - Task lrsRes = lrs.RetrieveAgentProfileAsync("test", Support.agent); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - Assert.IsInstanceOf(lrsRes.Result.content); - } - - [Test] - public void TestSaveAgentProfileAsync() - { - var doc = new AgentProfileDocument(); - doc.agent = Support.agent; - doc.id = "test"; - doc.content = System.Text.Encoding.UTF8.GetBytes("Test value"); - - Task lrsRes = lrs.SaveAgentProfileAsync(doc); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - } - - [Test] - public void TestDeleteAgentProfileAsync() - { - var doc = new AgentProfileDocument(); - doc.agent = Support.agent; - doc.id = "test"; - - Task lrsRes = lrs.DeleteAgentProfileAsync(doc); - lrsRes.Wait(); - Assert.IsTrue(lrsRes.Result.success); - } - } +/* + Copyright 2014 Rustici Software + + 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. +*/ +namespace TinCanTests +{ + using System; + using System.Collections.Generic; + using System.Xml; + using NUnit.Framework; + using Newtonsoft.Json.Linq; + using TinCan; + using TinCan.Documents; + using TinCan.Json; + using TinCan.LRSResponses; + using System.Threading.Tasks; + + [TestFixture] + class RemoteLRSResourceTest + { + RemoteLRS lrs; + + [SetUp] + public void Init() + { + Console.WriteLine("Running " + TestContext.CurrentContext.Test.FullName); + + // + // these are credentials used by the other OSS libs when building via Travis-CI + // so are okay to include in the repository, if you wish to have access to the + // results of the test suite then supply your own endpoint, username, and password + // + lrs = new RemoteLRS( + "https://cloud.scorm.com/tc/U2S4SI5FY0/sandbox/", + "Nja986GYE1_XrWMmFUE", + "Bd9lDr1kjaWWY6RID_4" + ); + } + + [Test] + public void TestAbout() + { + AboutLRSResponse lrsRes = lrs.About(); + Assert.IsTrue(lrsRes.success); + } + + [Test] + public void TestAboutFailure() + { + lrs.endpoint = new Uri("http://cloud.scorm.com/tc/3TQLAI9/sandbox/"); + + AboutLRSResponse lrsRes = lrs.About(); + Assert.IsFalse(lrsRes.success); + Console.WriteLine("TestAboutFailure - errMsg: " + lrsRes.errMsg); + } + + [Test] + public void TestSaveStatement() + { + var statement = new Statement(); + statement.actor = Support.agent; + statement.verb = Support.verb; + statement.target = Support.activity; + + StatementLRSResponse lrsRes = lrs.SaveStatement(statement); + Assert.IsTrue(lrsRes.success); + Assert.AreEqual(statement, lrsRes.content); + Assert.IsNotNull(lrsRes.content.id); + } + + [Test] + public void TestSaveStatementWithID() + { + var statement = new Statement(); + statement.Stamp(); + statement.actor = Support.agent; + statement.verb = Support.verb; + statement.target = Support.activity; + + StatementLRSResponse lrsRes = lrs.SaveStatement(statement); + Assert.IsTrue(lrsRes.success); + Assert.AreEqual(statement, lrsRes.content); + } + + [Test] + public void TestSaveStatementStatementRef() + { + var statement = new Statement(); + statement.Stamp(); + statement.actor = Support.agent; + statement.verb = Support.verb; + statement.target = Support.statementRef; + + StatementLRSResponse lrsRes = lrs.SaveStatement(statement); + Assert.IsTrue(lrsRes.success); + Assert.AreEqual(statement, lrsRes.content); + } + + [Test] + public void TestSaveStatementSubStatement() + { + var statement = new Statement(); + statement.Stamp(); + statement.actor = Support.agent; + statement.verb = Support.verb; + statement.target = Support.subStatement; + + Console.WriteLine(statement.ToJSON(true)); + + StatementLRSResponse lrsRes = lrs.SaveStatement(statement); + Assert.IsTrue(lrsRes.success); + Assert.AreEqual(statement, lrsRes.content); + } + + [Test] + public void TestVoidStatement() + { + Guid toVoid = Guid.NewGuid(); + StatementLRSResponse lrsRes = lrs.VoidStatement(toVoid, Support.agent); + + Assert.IsTrue(lrsRes.success, "LRS response successful"); + Assert.AreEqual(new Uri("http://adlnet.gov/expapi/verbs/voided"), lrsRes.content.verb.id, "voiding statement uses voided verb"); + Assert.AreEqual(toVoid, ((StatementRef) lrsRes.content.target).id, "voiding statement target correct id"); + } + + [Test] + public void TestSaveStatements() + { + var statement1 = new Statement(); + statement1.actor = Support.agent; + statement1.verb = Support.verb; + statement1.target = Support.parent; + + var statement2 = new Statement(); + statement2.actor = Support.agent; + statement2.verb = Support.verb; + statement2.target = Support.activity; + statement2.context = Support.context; + + var statements = new List(); + statements.Add(statement1); + statements.Add(statement2); + + StatementsResultLRSResponse lrsRes = lrs.SaveStatements(statements); + Assert.IsTrue(lrsRes.success); + // TODO: check statements match and ids not null + } + + [Test] + public void TestRetrieveStatement() + { + var statement = new TinCan.Statement(); + statement.Stamp(); + statement.actor = Support.agent; + statement.verb = Support.verb; + statement.target = Support.activity; + statement.context = Support.context; + statement.result = Support.result; + + StatementLRSResponse saveRes = lrs.SaveStatement(statement); + if (saveRes.success) + { + StatementLRSResponse retRes = lrs.RetrieveStatement(saveRes.content.id.Value); + Assert.IsTrue(retRes.success); + Console.WriteLine("TestRetrieveStatement - statement: " + retRes.content.ToJSON(true)); + } + else + { + // TODO: skipped? + } + } + + [Test] + public void TestQueryStatements() + { + var query = new TinCan.StatementsQuery(); + query.agent = Support.agent; + query.verbId = Support.verb.id; + query.activityId = Support.parent.id; + query.relatedActivities = true; + query.relatedAgents = true; + query.format = StatementsQueryResultFormat.IDS; + query.limit = 10; + + StatementsResultLRSResponse lrsRes = lrs.QueryStatements(query); + Assert.IsTrue(lrsRes.success); + Console.WriteLine("TestQueryStatements - statement count: " + lrsRes.content.statements.Count); + } + + [Test] + public void TestMoreStatements() + { + var query = new TinCan.StatementsQuery(); + query.format = StatementsQueryResultFormat.IDS; + query.limit = 2; + + StatementsResultLRSResponse queryRes = lrs.QueryStatements(query); + if (queryRes.success && queryRes.content.more != null) + { + StatementsResultLRSResponse moreRes = lrs.MoreStatements(queryRes.content); + Assert.IsTrue(moreRes.success); + Console.WriteLine("TestMoreStatements - statement count: " + moreRes.content.statements.Count); + } + else + { + // TODO: skipped? + } + } + + [Test] + public void TestRetrieveStateIds() + { + ProfileKeysLRSResponse lrsRes = lrs.RetrieveStateIds(Support.activity, Support.agent); + Assert.IsTrue(lrsRes.success); + } + + [Test] + public void TestRetrieveState() + { + StateLRSResponse lrsRes = lrs.RetrieveState("test", Support.activity, Support.agent); + Assert.IsTrue(lrsRes.success); + Assert.IsInstanceOf(lrsRes.content); + } + + [Test] + public void TestSaveState() + { + var doc = new StateDocument(); + doc.activity = Support.activity; + doc.agent = Support.agent; + doc.id = "test"; + doc.content = System.Text.Encoding.UTF8.GetBytes("Test value"); + + LRSResponse lrsRes = lrs.SaveState(doc); + Assert.IsTrue(lrsRes.success); + } + + [Test] + public void TestDeleteState() + { + var doc = new StateDocument(); + doc.activity = Support.activity; + doc.agent = Support.agent; + doc.id = "test"; + + LRSResponse lrsRes = lrs.DeleteState(doc); + Assert.IsTrue(lrsRes.success); + } + + [Test] + public void TestClearState() + { + LRSResponse lrsRes = lrs.ClearState(Support.activity, Support.agent); + Assert.IsTrue(lrsRes.success); + } + + [Test] + public void TestRetrieveActivityProfileIds() + { + ProfileKeysLRSResponse lrsRes = lrs.RetrieveActivityProfileIds(Support.activity); + Assert.IsTrue(lrsRes.success); + } + + [Test] + public void TestRetrieveActivityProfile() + { + ActivityProfileLRSResponse lrsRes = lrs.RetrieveActivityProfile("test", Support.activity); + Assert.IsTrue(lrsRes.success); + Assert.IsInstanceOf(lrsRes.content); + } + + [Test] + public void TestSaveActivityProfile() + { + var doc = new ActivityProfileDocument(); + doc.activity = Support.activity; + doc.id = "test"; + doc.content = System.Text.Encoding.UTF8.GetBytes("Test value"); + + LRSResponse lrsRes = lrs.SaveActivityProfile(doc); + Assert.IsTrue(lrsRes.success); + } + + [Test] + public void TestDeleteActivityProfile() + { + var doc = new ActivityProfileDocument(); + doc.activity = Support.activity; + doc.id = "test"; + + LRSResponse lrsRes = lrs.DeleteActivityProfile(doc); + Assert.IsTrue(lrsRes.success); + } + + [Test] + public void TestRetrieveAgentProfileIds() + { + ProfileKeysLRSResponse lrsRes = lrs.RetrieveAgentProfileIds(Support.agent); + Assert.IsTrue(lrsRes.success); + } + + [Test] + public void TestRetrieveAgentProfile() + { + AgentProfileLRSResponse lrsRes = lrs.RetrieveAgentProfile("test", Support.agent); + Assert.IsTrue(lrsRes.success); + Assert.IsInstanceOf(lrsRes.content); + } + + [Test] + public void TestSaveAgentProfile() + { + var doc = new AgentProfileDocument(); + doc.agent = Support.agent; + doc.id = "test"; + doc.content = System.Text.Encoding.UTF8.GetBytes("Test value"); + + LRSResponse lrsRes = lrs.SaveAgentProfile(doc); + Assert.IsTrue(lrsRes.success); + } + + [Test] + public void TestDeleteAgentProfile() + { + var doc = new AgentProfileDocument(); + doc.agent = Support.agent; + doc.id = "test"; + + LRSResponse lrsRes = lrs.DeleteAgentProfile(doc); + Assert.IsTrue(lrsRes.success); + } + + + + [Test] + public void TestAboutAsync() + { + Task lrsRes = lrs.AboutAsync(); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + } + + [Test] + public void TestAboutAsyncFailure() + { + lrs.endpoint = new Uri("http://cloud.scorm.com/tc/3TQLAI9/sandbox/"); + + Task lrsRes = lrs.AboutAsync(); + lrsRes.Wait(); + Assert.IsFalse(lrsRes.Result.success); + Console.WriteLine("TestAboutFailure - errMsg: " + lrsRes.Result.errMsg); + } + + [Test] + public void TestSaveStatementAsync() + { + var statement = new Statement(); + statement.actor = Support.agent; + statement.verb = Support.verb; + statement.target = Support.activity; + + Task lrsRes = lrs.SaveStatementAsync(statement); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + Assert.AreEqual(statement, lrsRes.Result.content); + Assert.IsNotNull(lrsRes.Result.content.id); + } + + [Test] + public void TestSaveStatementWithIDAsync() + { + var statement = new Statement(); + statement.Stamp(); + statement.actor = Support.agent; + statement.verb = Support.verb; + statement.target = Support.activity; + + Task lrsRes = lrs.SaveStatementAsync(statement); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + Assert.AreEqual(statement, lrsRes.Result.content); + } + + [Test] + public void TestSaveStatementStatementRefAsync() + { + var statement = new Statement(); + statement.Stamp(); + statement.actor = Support.agent; + statement.verb = Support.verb; + statement.target = Support.statementRef; + + Task lrsRes = lrs.SaveStatementAsync(statement); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + Assert.AreEqual(statement, lrsRes.Result.content); + } + + [Test] + public void TestSaveStatementSubStatementAsync() + { + var statement = new Statement(); + statement.Stamp(); + statement.actor = Support.agent; + statement.verb = Support.verb; + statement.target = Support.subStatement; + + Console.WriteLine(statement.ToJSON(true)); + + Task lrsRes = lrs.SaveStatementAsync(statement); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + Assert.AreEqual(statement, lrsRes.Result.content); + } + + [Test] + public void TestVoidStatementAsync() + { + Guid toVoid = Guid.NewGuid(); + Task lrsRes = lrs.VoidStatementAsync(toVoid, Support.agent); + lrsRes.Wait(); + + Assert.IsTrue(lrsRes.Result.success, "LRS response successful"); + Assert.AreEqual(new Uri("http://adlnet.gov/expapi/verbs/voided"), lrsRes.Result.content.verb.id, "voiding statement uses voided verb"); + Assert.AreEqual(toVoid, ((StatementRef)lrsRes.Result.content.target).id, "voiding statement target correct id"); + } + + [Test] + public void TestSaveStatementsAsync() + { + var statement1 = new Statement(); + statement1.actor = Support.agent; + statement1.verb = Support.verb; + statement1.target = Support.parent; + + var statement2 = new Statement(); + statement2.actor = Support.agent; + statement2.verb = Support.verb; + statement2.target = Support.activity; + statement2.context = Support.context; + + var statements = new List(); + statements.Add(statement1); + statements.Add(statement2); + + Task lrsRes = lrs.SaveStatementsAsync(statements); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + // TODO: check statements match and ids not null + } + + [Test] + public void TestRetrieveStatementAsync() + { + var statement = new TinCan.Statement(); + statement.Stamp(); + statement.actor = Support.agent; + statement.verb = Support.verb; + statement.target = Support.activity; + statement.context = Support.context; + statement.result = Support.result; + + Task saveRes = lrs.SaveStatementAsync(statement); + saveRes.Wait(); + if (saveRes.Result.success) + { + Task retRes = lrs.RetrieveStatementAsync(saveRes.Result.content.id.Value); + Assert.IsTrue(retRes.Result.success); + Console.WriteLine("TestRetrieveStatement - statement: " + retRes.Result.content.ToJSON(true)); + } + else + { + // TODO: skipped? + } + } + + [Test] + public void TestQueryStatementsAsync() + { + var query = new TinCan.StatementsQuery(); + query.agent = Support.agent; + query.verbId = Support.verb.id; + query.activityId = Support.parent.id; + query.relatedActivities = true; + query.relatedAgents = true; + query.format = StatementsQueryResultFormat.IDS; + query.limit = 10; + + Task lrsRes = lrs.QueryStatementsAsync(query); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + Console.WriteLine("TestQueryStatements - statement count: " + lrsRes.Result.content.statements.Count); + } + + [Test] + public void TestMoreStatementsAsync() + { + var query = new TinCan.StatementsQuery(); + query.format = StatementsQueryResultFormat.IDS; + query.limit = 2; + + Task queryRes = lrs.QueryStatementsAsync(query); + queryRes.Wait(); + if (queryRes.Result.success && queryRes.Result.content.more != null) + { + Task moreRes = lrs.MoreStatementsAsync(queryRes.Result.content); + moreRes.Wait(); + Assert.IsTrue(moreRes.Result.success); + Console.WriteLine("TestMoreStatements - statement count: " + moreRes.Result.content.statements.Count); + } + else + { + // TODO: skipped? + } + } + + [Test] + public void TestRetrieveStateIdsAsync() + { + Task lrsRes = lrs.RetrieveStateIdsAsync(Support.activity, Support.agent); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + } + + [Test] + public void TestRetrieveStateAsync() + { + Task lrsRes = lrs.RetrieveStateAsync("test", Support.activity, Support.agent); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + Assert.IsInstanceOf(lrsRes.Result.content); + } + + [Test] + public void TestSaveStateAsync() + { + var doc = new StateDocument(); + doc.activity = Support.activity; + doc.agent = Support.agent; + doc.id = "test"; + doc.content = System.Text.Encoding.UTF8.GetBytes("Test value"); + + Task lrsRes = lrs.SaveStateAsync(doc); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + } + + [Test] + public void TestDeleteStateAsync() + { + var doc = new StateDocument(); + doc.activity = Support.activity; + doc.agent = Support.agent; + doc.id = "test"; + + Task lrsRes = lrs.DeleteStateAsync(doc); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + } + + [Test] + public void TestClearStateAsync() + { + Task lrsRes = lrs.ClearStateAsync(Support.activity, Support.agent); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + } + + [Test] + public void TestRetrieveActivityProfileIdsAsync() + { + Task lrsRes = lrs.RetrieveActivityProfileIdsAsync(Support.activity); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + } + + [Test] + public void TestRetrieveActivityProfileAsync() + { + Task lrsRes = lrs.RetrieveActivityProfileAsync("test", Support.activity); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + Assert.IsInstanceOf(lrsRes.Result.content); + } + + [Test] + public void TestSaveActivityProfileAsync() + { + var doc = new ActivityProfileDocument(); + doc.activity = Support.activity; + doc.id = "test"; + doc.content = System.Text.Encoding.UTF8.GetBytes("Test value"); + + Task lrsRes = lrs.SaveActivityProfileAsync(doc); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + } + + [Test] + public void TestDeleteActivityProfileAsync() + { + var doc = new ActivityProfileDocument(); + doc.activity = Support.activity; + doc.id = "test"; + + Task lrsRes = lrs.DeleteActivityProfileAsync(doc); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + } + + [Test] + public void TestRetrieveAgentProfileIdsAsync() + { + Task lrsRes = lrs.RetrieveAgentProfileIdsAsync(Support.agent); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + } + + [Test] + public void TestRetrieveAgentProfileAsync() + { + Task lrsRes = lrs.RetrieveAgentProfileAsync("test", Support.agent); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + Assert.IsInstanceOf(lrsRes.Result.content); + } + + [Test] + public void TestSaveAgentProfileAsync() + { + var doc = new AgentProfileDocument(); + doc.agent = Support.agent; + doc.id = "test"; + doc.content = System.Text.Encoding.UTF8.GetBytes("Test value"); + + Task lrsRes = lrs.SaveAgentProfileAsync(doc); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + } + + [Test] + public void TestDeleteAgentProfileAsync() + { + var doc = new AgentProfileDocument(); + doc.agent = Support.agent; + doc.id = "test"; + + Task lrsRes = lrs.DeleteAgentProfileAsync(doc); + lrsRes.Wait(); + Assert.IsTrue(lrsRes.Result.success); + } + } } \ No newline at end of file diff --git a/TinCanTests/TinCanTests.csproj b/TinCanTests/TinCanTests.csproj index b5dc489..3f650b1 100644 --- a/TinCanTests/TinCanTests.csproj +++ b/TinCanTests/TinCanTests.csproj @@ -1,112 +1,112 @@ - - - - - Debug - AnyCPU - {854413C2-2F81-4A82-9949-DE2868A10078} - Library - Properties - TinCanTests - TinCanTests - v4.5 - 512 - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - - - - true - bin\Documentation\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - false - - - - ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True - - - ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll - False - - - ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll - False - - - False - ..\packages\NUnit.2.6.4\lib\nunit.framework.dll - - - ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll - False - - - ..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll - False - - - - - - - - - - - - - - - - - - {27d0fca1-e869-440c-9d16-f62d7a068c53} - TinCan - - - - - - - - - - - - - + + + + + Debug + AnyCPU + {854413C2-2F81-4A82-9949-DE2868A10078} + Library + Properties + TinCanTests + TinCanTests + v4.5 + 512 + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + + + true + bin\Documentation\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + false + + + + ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + True + + + ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll + False + + + ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll + False + + + False + ..\packages\NUnit.2.6.4\lib\nunit.framework.dll + + + ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll + False + + + ..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll + False + + + + + + + + + + + + + + + + + + {27d0fca1-e869-440c-9d16-f62d7a068c53} + TinCan + + + + + + + + + + + + + \ No newline at end of file diff --git a/TinCanTests/packages.config b/TinCanTests/packages.config index 1e9d3f3..527f7a5 100644 --- a/TinCanTests/packages.config +++ b/TinCanTests/packages.config @@ -1,6 +1,6 @@ - - - - - + + + + + \ No newline at end of file