Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rafa 15 unit test #17

Merged
merged 5 commits into from
May 25, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ lazy val dependencies = libraryDependencies ++= Seq(
"io.circe" %% "circe-core" % "0.3.0",
"io.circe" %% "circe-generic" % "0.3.0",
"io.circe" %% "circe-parser" % "0.3.0",
"com.typesafe" % "config" % "1.3.0",
"org.scalatest" %% "scalatest" % "2.2.6" % "test",
"com.ironcorelabs" %% "cats-scalatest" % "1.1.2" % "test"
"com.ironcorelabs" %% "cats-scalatest" % "1.1.2" % "test",
"org.mock-server" % "mockserver-netty" % "3.10.4" % "test"
)

lazy val scalariformSettings = SbtScalariform.scalariformSettings ++ Seq(
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/application.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
github.baseUrl = "https://api.github.com/"
github.authorizeUrl = "https://github.com/login/oauth/authorize?client_id=%s&redirect_uri=%s&scope=%s&state=%s"
github.accessTokenUrl = "https://github.com/login/oauth/access_token"
15 changes: 15 additions & 0 deletions src/main/scala/github4s/GithubApiConfig.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package github4s

import com.typesafe.config.ConfigFactory

class GithubApiConfig(hocon: Option[String] = None) {

val config = hocon.fold(ConfigFactory.load)(ConfigFactory.parseString)

def getString(key: String) = sys.props.getOrElse(key, config.getString(key))
}

object GithubApiConfig {

implicit val defaultConfig: GithubApiConfig = new GithubApiConfig
}
5 changes: 3 additions & 2 deletions src/main/scala/github4s/HttpClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import github4s.free.domain.Pagination
import io.circe.Decoder
import scalaj.http._

class HttpClient {
class HttpClient(implicit config: GithubApiConfig) {

val defaultPagination = Pagination(1, 1000)

Expand Down Expand Up @@ -132,6 +132,7 @@ class HttpClient {
data: String
)(implicit D: Decoder[A]): GHResponse[A] =
GithubResponses.toEntity(HttpRequestBuilder(url)
.postMethod
.withHeaders(Map("Accept" → "application/json"))
.withData(data)
.run)
Expand All @@ -147,6 +148,6 @@ class HttpClient {
val defaultPage: Int = 1
val defaultPerPage: Int = 30

private def buildURL(method: String) = s"https://api.github.com/$method"
private def buildURL(method: String) = config.getString("github.baseUrl") + method

}
11 changes: 5 additions & 6 deletions src/main/scala/github4s/api/Auth.scala
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
package github4s.api

import java.util.UUID

import cats.data.Xor
import github4s.GithubResponses.{ GHResult, GHResponse }
import github4s.free.domain._
import github4s.HttpClient
import github4s.{ GithubApiConfig, HttpClient }
import io.circe.generic.auto._
import io.circe.syntax._
import scalaj.http.HttpConstants._

/** Factory to encapsulate calls related to Auth operations */
object Auth {
class Auth(implicit config: GithubApiConfig) {

protected val httpClient = new HttpClient()
val httpClient = new HttpClient

val authorizeUrl = "https://github.com/login/oauth/authorize?client_id=%s&redirect_uri=%s&scope=%s&state=%s"
val accessTokenUrl = "https://github.com/login/oauth/access_token"
val authorizeUrl = config.getString("github.authorizeUrl")
val accessTokenUrl = config.getString("github.accessTokenUrl")

/**
* Call to request a new authorization given a basic authentication, the returned object Authorization includes an
Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/github4s/api/Repos.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ package github4s.api

import github4s.GithubResponses.GHResponse
import github4s.free.domain.{ Pagination, Commit, Repository, User }
import github4s.{ Decoders, HttpClient }
import github4s.{ GithubApiConfig, Decoders, HttpClient }
import io.circe.generic.auto._

/** Factory to encapsulate calls related to Repositories operations */
object Repos {
class Repos(implicit config: GithubApiConfig) {

import Decoders._

protected val httpClient = new HttpClient()
val httpClient = new HttpClient

/**
* Get information of a particular repository
Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/github4s/api/Users.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package github4s.api

import github4s.GithubResponses.GHResponse
import github4s.HttpClient
import github4s.{ GithubApiConfig, HttpClient }
import github4s.free.domain.{ Pagination, User }
import io.circe.generic.auto._

/** Factory to encapsulate calls related to Users operations */
object Users {
class Users(implicit config: GithubApiConfig) {

protected val httpClient = new HttpClient()
val httpClient = new HttpClient

/**
* Get information for a particular user
Expand Down
29 changes: 16 additions & 13 deletions src/main/scala/github4s/free/interpreters/Interpreters.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package github4s.free.interpreters

import cats.{ MonadError, ApplicativeError, ~>, Eval }
import github4s.HttpClient
import github4s.api.{ Auth, Repos }
import github4s.api.{ Users, Auth, Repos }
import github4s.app.{ COGH01, GitHub4s }
import github4s.free.algebra._
import io.circe.Decoder
Expand All @@ -18,15 +17,16 @@ trait Interpreters[M[_]] {
all
}

protected val httpClient = new HttpClient()

/**
* Lifts Repository Ops to an effect capturing Monad such as Task via natural transformations
*/
def repositoryOpsInterpreter(implicit A: ApplicativeError[M, Throwable]): RepositoryOp ~> M = new (RepositoryOp ~> M) {

val repos = new Repos()

def apply[A](fa: RepositoryOp[A]): M[A] = fa match {
case GetRepo(owner, repo, accessToken) ⇒ A.pureEval(Eval.later(Repos.get(accessToken, owner, repo)))
case ListCommits(owner, repo, sha, path, author, since, until, pagination, accessToken) ⇒ A.pureEval(Eval.later(Repos.listCommits(accessToken, owner, repo, sha, path, author, since, until, pagination)))
case GetRepo(owner, repo, accessToken) ⇒ A.pureEval(Eval.later(repos.get(accessToken, owner, repo)))
case ListCommits(owner, repo, sha, path, author, since, until, pagination, accessToken) ⇒ A.pureEval(Eval.later(repos.listCommits(accessToken, owner, repo, sha, path, author, since, until, pagination)))
}
}

Expand All @@ -35,23 +35,26 @@ trait Interpreters[M[_]] {
*/
def userOpsInterpreter(implicit A: ApplicativeError[M, Throwable]): UserOp ~> M = new (UserOp ~> M) {

import github4s.api.Users
val users = new Users()

def apply[A](fa: UserOp[A]): M[A] = fa match {
case GetUser(username, accessToken) ⇒ A.pureEval(Eval.later(Users.get(accessToken, username)))
case GetAuthUser(accessToken) ⇒ A.pureEval(Eval.later(Users.getAuth(accessToken)))
case GetUsers(since, pagination, accessToken) ⇒ A.pureEval(Eval.later(Users.getUsers(accessToken, since, pagination)))
case GetUser(username, accessToken) ⇒ A.pureEval(Eval.later(users.get(accessToken, username)))
case GetAuthUser(accessToken) ⇒ A.pureEval(Eval.later(users.getAuth(accessToken)))
case GetUsers(since, pagination, accessToken) ⇒ A.pureEval(Eval.later(users.getUsers(accessToken, since, pagination)))
}
}

/**
* Lifts Auth Ops to an effect capturing Monad such as Task via natural transformations
*/
def authOpsInterpreter(implicit A: ApplicativeError[M, Throwable]): AuthOp ~> M = new (AuthOp ~> M) {

val auth = new Auth()

def apply[A](fa: AuthOp[A]): M[A] = fa match {
case NewAuth(username, password, scopes, note, client_id, client_secret) ⇒ A.pureEval(Eval.later(Auth.newAuth(username, password, scopes, note, client_id, client_secret)))
case AuthorizeUrl(client_id, redirect_uri, scopes) ⇒ A.pureEval(Eval.later(Auth.authorizeUrl(client_id, redirect_uri, scopes)))
case GetAccessToken(client_id, client_secret, code, redirect_uri, state) ⇒ A.pureEval(Eval.later(Auth.getAccessToken(client_id, client_secret, code, redirect_uri, state)))
case NewAuth(username, password, scopes, note, client_id, client_secret) ⇒ A.pureEval(Eval.later(auth.newAuth(username, password, scopes, note, client_id, client_secret)))
case AuthorizeUrl(client_id, redirect_uri, scopes) ⇒ A.pureEval(Eval.later(auth.authorizeUrl(client_id, redirect_uri, scopes)))
case GetAccessToken(client_id, client_secret, code, redirect_uri, state) ⇒ A.pureEval(Eval.later(auth.getAccessToken(client_id, client_secret, code, redirect_uri, state)))
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/test/scala/github4s/integration/GHAuthSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import cats.Id
import cats.scalatest.{ XorMatchers, XorValues }
import github4s.Github._
import github4s.free.interpreters.IdInterpreters._
import github4s.{ Github, TestUtils }
import github4s.Github
import github4s.utils.TestUtils
import org.scalatest._

class GHAuthSpec extends FlatSpec with Matchers with XorMatchers with XorValues with TestUtils {
Expand Down
3 changes: 2 additions & 1 deletion src/test/scala/github4s/integration/GHReposSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import cats.scalatest.{ XorMatchers, XorValues }
import github4s.Github._
import github4s.GithubResponses._
import github4s.free.interpreters.IdInterpreters._
import github4s.{ Github, TestUtils }
import github4s.Github
import github4s.utils.TestUtils
import org.scalatest.{ Matchers, FlatSpec }

class GHReposSpec extends FlatSpec with Matchers with XorMatchers with XorValues with TestUtils {
Expand Down
8 changes: 4 additions & 4 deletions src/test/scala/github4s/integration/GHUsersSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package github4s.integration
import cats.Id
import cats.scalatest.{ XorMatchers, XorValues }
import github4s.Github._
import github4s.GithubResponses._
import github4s.free.interpreters.IdInterpreters._
import github4s.{ Github, TestUtils }
import github4s.Github
import github4s.utils.TestUtils
import org.scalatest._

class GHUsersSpec extends FlatSpec with Matchers with XorMatchers with XorValues with TestUtils {
Expand Down Expand Up @@ -34,10 +34,10 @@ class GHUsersSpec extends FlatSpec with Matchers with XorMatchers with XorValues
response.value.statusCode shouldBe okStatusCode
}

it should "return error on Left when a invalid since value is provided" in {
it should "return an empty list when a invalid since value is provided" in {
val response = Github(accessToken).users.getUsers(invalidSinceInt).exec[Id]
response shouldBe right
response.value.value.nonEmpty shouldBe true
response.value.value.isEmpty shouldBe true
response.value.statusCode shouldBe okStatusCode
}

Expand Down
136 changes: 136 additions & 0 deletions src/test/scala/github4s/unit/ApiSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package github4s.unit

import cats.scalatest.{ XorMatchers, XorValues }
import github4s.api.{ Users, Repos, Auth }
import github4s.free.domain.Pagination
import github4s.utils.{ DummyGithubConfig, MockGithubApiServer, TestUtils }
import org.scalatest._

class ApiSpec
extends FlatSpec
with Matchers
with XorMatchers
with XorValues
with TestUtils
with MockGithubApiServer
with DummyGithubConfig {

val auth = new Auth
val repos = new Repos
val users = new Users

"Auth >> NewAuth" should "return a valid token when valid credential is provided" in {
val response = auth.newAuth(validUsername, "", validScopes, validNote, validClientId, "")
response shouldBe right
response.value.value.token.nonEmpty shouldBe true
response.value.statusCode shouldBe okStatusCode
}

it should "return error on Left when invalid credential is provided" in {
val response = auth.newAuth(validUsername, invalidPassword, validScopes, validNote, validClientId, "")
response shouldBe left
}

"Auth >> AuthorizeUrl" should "return the expected URL for valid username" in {
val response = auth.authorizeUrl(validClientId, validRedirectUri, validScopes)
response shouldBe right
response.value.value.url.contains(validRedirectUri) shouldBe true
response.value.statusCode shouldBe okStatusCode
}

"Auth >> GetAccessToken" should "return a valid access_token when a valid code is provided" in {
val response = auth.getAccessToken("", "", validCode, "", "")
response shouldBe right
response.value.value.access_token.nonEmpty shouldBe true
response.value.statusCode shouldBe okStatusCode
}

it should "return error on Left when invalid code is provided" in {
val response = auth.getAccessToken("", "", invalidCode, "", "")
response shouldBe left
}

"Repos >> Get" should "return the expected name when valid repo is provided" in {

val response = repos.get(accessToken, validRepoOwner, validRepoName)
response shouldBe right
response.value.value.name shouldBe validRepoName
response.value.statusCode shouldBe okStatusCode
}

it should "return error when an invalid repo name is passed" in {
val response = repos.get(accessToken, validRepoOwner, invalidRepoName)
response shouldBe left
}

"Repos >> ListCommits" should "return the expected list of commits for valid data" in {
val response = repos.listCommits(
accessToken = accessToken,
owner = validRepoOwner,
repo = validRepoName,
pagination = Option(Pagination(validPage, validPerPage))
)
response shouldBe right
response.value.value.nonEmpty shouldBe true
response.value.statusCode shouldBe okStatusCode
}

it should "return an empty list of commits for invalid page parameter" in {
val response = repos.listCommits(
accessToken = accessToken,
owner = validRepoOwner,
repo = validRepoName,
pagination = Option(Pagination(invalidPage, validPerPage))
)

response shouldBe right
response.value.value.isEmpty shouldBe true
response.value.statusCode shouldBe okStatusCode
}

it should "return error for invalid repo name" in {
val response = repos.listCommits(accessToken, validRepoOwner, invalidRepoName)
response shouldBe left
}

"Users >> Get" should "return the expected login for a valid username" in {

val response = users.get(accessToken, validUsername)

response shouldBe right
response.value.value.login shouldBe validUsername
response.value.statusCode shouldBe okStatusCode
}

it should "return error on Left for invalid username" in {
val response = users.get(accessToken, invalidUsername)
response shouldBe left
}

"Users >> GetAuth" should "return the expected login for a valid accessToken" in {
val response = users.getAuth(accessToken)
response shouldBe right
response.value.value.login shouldBe validUsername
response.value.statusCode shouldBe okStatusCode
}

it should "return error on Left when no accessToken is provided" in {
val response = users.getAuth(None)
response shouldBe left
}

"Users >> GetUsers" should "return users for a valid since value" in {
val response = users.getUsers(accessToken, validSinceInt)
response shouldBe right
response.value.value.nonEmpty shouldBe true
response.value.statusCode shouldBe okStatusCode
}

it should "return an empty list when a invalid since value is provided" in {
val response = users.getUsers(accessToken, invalidSinceInt)
response shouldBe right
response.value.value.isEmpty shouldBe true
response.value.statusCode shouldBe okStatusCode
}

}
15 changes: 15 additions & 0 deletions src/test/scala/github4s/utils/DummyGithubConfig.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package github4s.utils

import github4s.GithubApiConfig

trait DummyGithubConfig {

val dummyConfigHocon =
"""
|github.baseUrl = "http://127.0.0.1:9999/"
|github.authorizeUrl = "http://127.0.0.1:9999/authorize?client_id=%s&redirect_uri=%s&scope=%s&state=%s"
|github.accessTokenUrl = "http://127.0.0.1:9999/login/oauth/access_token"
|""".stripMargin

implicit val dummyConfig = new GithubApiConfig(Option(dummyConfigHocon))
}