github :: MockGithubAPI :: defaultinit
# GithubAPI testing
#
# To avoid test flakyness we test the GithubAPI against a mock of the real one.
# For each api request we return a cache file of the real API response body.
#
# Cache files can be automatically created and updated by setting
# `update_responses_cache` to `true` then running `nitunit`.
class MockGithubAPI
super GithubAPI
# Mock so it returns the response from a file
#
# See `update_responses_cache`.
redef fun send(method, path, headers, body) do
print path # for debugging
assert has_response(path)
if update_responses_cache then
var file = response_file(path)
save_actual_response(path, file)
end
var response = response_string(path)
if response_is_error(path) then
last_error = new GithubAPIError(
response.parse_json.as(JsonObject)["message"].as(String),
response_code(path).to_i,
path
)
was_error = true
return null
end
return response
end
var test_responses: Map[String, String] do
var map = new HashMap[String, String]
map["/user"] = "user_Morriar"
map["/users/Morriar"] = "user_Morriar"
map["/repos/nitlang/nit"] = "repo_nit"
map["/repos/nitlang/nit/labels?page=1&per_page=3"] = "repo_labels_nit"
map["/repos/nitlang/nit/labels/ok_will_merge"] = "repo_labels_ok_will_merge"
map["/repos/nitlang/nit/milestones?page=1&per_page=3"] = "repo_milestones_nit"
map["/repos/nitlang/nit/milestones/4"] = "repo_milestones_4"
map["/repos/nitlang/nit/branches?page=1&per_page=2"] = "repo_branches_nit"
map["/repos/nitlang/nit/branches/master"] = "repo_branches_master"
map["/repos/nitlang/nit/issues?page=1&per_page=3"] = "repo_issues_nit"
map["/repos/nitlang/nit/issues/1000"] = "repo_issues_1000"
map["/repos/nitlang/nit/issues/1000/comments?page=1&per_page=3"] = "repo_issues_comments_nit"
map["/repos/nitlang/nit/issues/comments/6020149"] = "repo_issues_comments_6020149"
map["/repos/nitlang/nit/issues/1000/events?page=1&per_page=3"] = "repo_issues_events_nit"
map["/repos/nitlang/nit/issues/events/199674194"] = "repo_issues_events_199674194"
map["/repos/nitlang/nit/pulls?page=1&per_page=3"] = "repo_pulls_nit"
map["/repos/nitlang/nit/pulls/1000"] = "repo_pulls_1000"
map["/repos/nitlang/nit/pulls/945/comments?page=1&per_page=3"] = "repo_pulls_945_comments"
map["/repos/nitlang/nit/pulls/comments/21010363"] = "repo_pulls_comment_21010363"
map["/repos/nitlang/nit/commits/64ce1f"] = "repo_commits_64ce1f"
map["/repos/nitlang/nit/commits/4e3c688d/status"] = "repo_commits_4e3c68_status"
map["/repos/nitlang/nit/comments/8982707"] = "repo_comments_8982707"
map["/search/issues?q=foo repo:nitlang/nit&page=1&per_page=3"] = "repo_search_issues_nit"
map["/repos/nitlang/nit/stats/contributors"] = "repo_nit_contributors"
# errors
map["/users/not_found/not_found"] = "errors_404"
return map
end
# Does `self` have a mock response for Github `path`?
fun has_response(path: String): Bool do
return test_responses.has_key(path)
end
# Root responses cache directory
var responses_dir: String is lazy do
var path = "NIT_TESTING_PATH".environ.dirname / "mock"
path.mkdir
return path
end
# Returns the response file path for a Github `path`
fun response_file(path: String): String do
assert has_response(path)
return "{responses_dir / test_responses[path]}.res"
end
# Returns the response body string for a Github `path`
fun response_string(path: String): String do
var file = response_file(path)
assert file.file_exists
return file.to_path.read_all
end
# Is this response a simulated error?
fun response_is_error(path: String): Bool do
assert has_response(path)
return test_responses[path].has_prefix("errors_")
end
# Status code of a simulated error
#
# See `response_is_error`.
fun response_code(path: String): String do
assert response_is_error(path)
return test_responses[path].split("_").last
end
# Response caching
# Activate caching
#
# Change this value to `true` then run nitunit to cache the responses
# from the Github API.
#
# Default is `false`.
var update_responses_cache = false
# Save the actual Github API response body for `uri` to a `file`
private fun save_actual_response(uri, file: String) do
assert update_responses_cache
var request = new CurlHTTPRequest("{api_url}{sanitize_uri(uri)}")
request.user_agent = actual_api.user_agent
request.headers = actual_api.new_headers
var response = request.execute
if response isa CurlResponseSuccess then
response.body_str.write_to_file(file)
else if response isa CurlResponseFailed then
response.error_msg.write_to_file(file)
else abort
print "Response to `{uri}` saved at `{file}`"
end
# Actual GithubCurl instance used for caching
private var actual_api = new GithubAPI(get_github_oauth, "nitunit")
end
lib/github/tests/test_api.nit:19,1--155,3