cm_quiz 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b05cd24b052e990f291c22473aef0e934b97036c
4
+ data.tar.gz: 5b36e76983e7e4c0b6e8fce097d2c4a9ceee5da2
5
+ SHA512:
6
+ metadata.gz: b17e359ef50450552ea190d5715092a42680caae1c5e4d0f736c0eb8569319d1255ca9ab62be8c007787f82ec8e8f45fe3c10cdc9721dd3f8070d235dbe0941b
7
+ data.tar.gz: a22c7ecb03e6fa494aec8aad9bd56683c00339c7aea06a284a60171c2b1aa79f52fce9f5f230bcc75eaf15f1ba51e8f907c88eb6c6fe85e91ef5353ce6a4052e
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :development, :test do
4
+ gem 'pry'
5
+ end
6
+
7
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,58 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ cm_quiz (0.0.1)
5
+ httparty
6
+ rspec
7
+ thor (~> 0.19.4)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ addressable (2.5.2)
13
+ public_suffix (>= 2.0.2, < 4.0)
14
+ coderay (1.1.2)
15
+ crack (0.4.3)
16
+ safe_yaml (~> 1.0.0)
17
+ diff-lcs (1.3)
18
+ hashdiff (0.3.6)
19
+ httparty (0.15.6)
20
+ multi_xml (>= 0.5.2)
21
+ method_source (0.8.2)
22
+ multi_xml (0.6.0)
23
+ pry (0.10.4)
24
+ coderay (~> 1.1.0)
25
+ method_source (~> 0.8.1)
26
+ slop (~> 3.4)
27
+ public_suffix (3.0.0)
28
+ rspec (3.6.0)
29
+ rspec-core (~> 3.6.0)
30
+ rspec-expectations (~> 3.6.0)
31
+ rspec-mocks (~> 3.6.0)
32
+ rspec-core (3.6.0)
33
+ rspec-support (~> 3.6.0)
34
+ rspec-expectations (3.6.0)
35
+ diff-lcs (>= 1.2.0, < 2.0)
36
+ rspec-support (~> 3.6.0)
37
+ rspec-mocks (3.6.0)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.6.0)
40
+ rspec-support (3.6.0)
41
+ safe_yaml (1.0.4)
42
+ slop (3.6.0)
43
+ thor (0.19.4)
44
+ webmock (3.0.1)
45
+ addressable (>= 2.3.6)
46
+ crack (>= 0.3.2)
47
+ hashdiff
48
+
49
+ PLATFORMS
50
+ ruby
51
+
52
+ DEPENDENCIES
53
+ cm_quiz!
54
+ pry
55
+ webmock
56
+
57
+ BUNDLED WITH
58
+ 1.15.0
data/README.md ADDED
@@ -0,0 +1 @@
1
+ # cm-quiz
data/bin/cm-quiz ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib_dir = File.expand_path(File.join(File.dirname(__FILE__),'..','lib'))
4
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
5
+
6
+ require 'cm_quiz/cli'
7
+
8
+ CmQuiz::CLI.start(ARGV)
data/cm_quiz.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
2
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
3
+ require 'cm_quiz/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'cm_quiz'
7
+ s.version = CmQuiz::VERSION
8
+ s.date = '2017-09-12'
9
+ s.summary = "Review your codementor quiz"
10
+ s.description = "Review your codementor quiz1"
11
+ s.authors = ["ben"]
12
+ s.email = 'ben@codementor.ios'
13
+ s.executables = ["cm-quiz"]
14
+ s.files = `git ls-files`.split($/)
15
+ s.homepage =
16
+ 'https://github.com/codementordev/cm_quiz'
17
+ s.license = 'MIT'
18
+ s.required_ruby_version = '>= 2.3'
19
+
20
+ s.add_dependency('thor', ["~> 0.19.4"])
21
+ s.add_dependency("rspec", ["~> 3.6"])
22
+ s.add_dependency("httparty", ["~> 0.15.6"])
23
+ s.add_development_dependency("webmock", ["~> 3.0"])
24
+ end
@@ -0,0 +1,22 @@
1
+ require 'thor'
2
+ require 'cm_quiz'
3
+
4
+ module CmQuiz
5
+ class CLI< Thor
6
+ map '--version' => :version
7
+
8
+ desc 'version', 'Prints the cm_quiz version'
9
+ def version
10
+ puts "#{File.basename($0)} #{VERSION}"
11
+ end
12
+
13
+ desc 'test', 'Test your api implement'
14
+ option :endpoint, required: true, banner: "your-test-endpoint.com"
15
+ def test
16
+ endpoint = options[:endpoint]
17
+ puts "Start test #{endpoint}"
18
+ message = CmQuiz::ReviewQuiz.new('http://localhost:6000').perform
19
+ puts message
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,32 @@
1
+ require 'securerandom'
2
+
3
+ module CmQuiz
4
+ module Factory
5
+ class Idea
6
+ def initialize(project_api:, jwt:, idea_params: {})
7
+ @project_api = project_api
8
+ @jwt = jwt
9
+ @idea_params = idea_params
10
+ end
11
+
12
+ def create
13
+ default_idea_params = {
14
+ content: 'the-content',
15
+ impact: 7,
16
+ ease: 8,
17
+ confidence: 9
18
+ }
19
+
20
+ options = {
21
+ headers: {
22
+ 'x-access-token' => @jwt
23
+ },
24
+ body: default_idea_params.merge(@idea_params)
25
+ }
26
+
27
+ res = @project_api.request(:post, '/ideas', options)
28
+ JSON.parse(res.body)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,28 @@
1
+ require 'securerandom'
2
+
3
+ module CmQuiz
4
+ module Factory
5
+ class User
6
+ def initialize(project_api:, name: nil, email: nil, password: nil)
7
+ @project_api = project_api
8
+ @name = name || "codementor-test-#{SecureRandom.hex(5)}"
9
+ @email = email || "#{@name}@codementor.io"
10
+ @password = password || "pAssw0rd!"
11
+ end
12
+
13
+ def create
14
+ options = {
15
+ body: {
16
+ email: @email,
17
+ name: @name,
18
+ password: @password
19
+ }
20
+ }
21
+
22
+ res = @project_api.request(:post, '/users', options)
23
+ payload = JSON.parse(res.body)
24
+ [payload['jwt'], payload['refresh_token']]
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,40 @@
1
+ require 'httparty'
2
+
3
+ module CmQuiz
4
+ class ProjectAPI
5
+ REQUEST_TIMEOUT = 5
6
+
7
+ class PerformFailed < StandardError
8
+ attr_reader :response
9
+
10
+ def initialize(message, response)
11
+ @response = response
12
+ super(message)
13
+ end
14
+ end
15
+
16
+ def initialize(endpoint)
17
+ @endpoint = endpoint
18
+ end
19
+
20
+ def request(verb, path, options = {})
21
+ url = @endpoint + path
22
+
23
+ query = options[:query]
24
+ body = options[:body].to_json
25
+ headers = { 'Content-Type' => 'application/json' }.merge(options[:headers] || {})
26
+
27
+ http_options = {
28
+ query: query,
29
+ body: body,
30
+ headers: headers,
31
+ timeout: REQUEST_TIMEOUT
32
+ }
33
+ res = HTTParty.send(verb, url, http_options)
34
+
35
+ raise PerformFailed.new("[#{res.code}]: #{res.body}", res) unless res.success?
36
+
37
+ res
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,30 @@
1
+ require 'cm_quiz/review_helper'
2
+
3
+ module CmQuiz
4
+ module Review
5
+ class BaseReview
6
+ include ReviewHelper
7
+
8
+ def perform
9
+ run
10
+ build_test_result(test_request)
11
+ rescue RSpec::Expectations::ExpectationNotMetError => e
12
+ build_test_result(test_request, false, e.message)
13
+ rescue => e
14
+ build_test_result(test_request, false, e.message)
15
+ end
16
+
17
+ def run
18
+ raise "Method `run` should be implemented on class #{self.class}"
19
+ end
20
+
21
+ def test_request
22
+ {
23
+ verb: @verb,
24
+ path: @path,
25
+ options: @options
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,49 @@
1
+ module CmQuiz
2
+ module Review
3
+ class CreateIdea < BaseReview
4
+ def initialize(project_api:)
5
+ @project_api = project_api
6
+ @verb = :post
7
+ @path = '/ideas'
8
+ end
9
+
10
+ def run
11
+ jwt, _ = Factory::User.new({
12
+ project_api: @project_api
13
+ }).create
14
+
15
+ res = send_create_idea_request({
16
+ jwt: jwt,
17
+ content: 'test-content',
18
+ impact: 7,
19
+ ease: 8,
20
+ confidence: 9
21
+ })
22
+ payload = JSON.parse(res.body)
23
+
24
+ expect(payload['impact']).to eq(7), "expect impact equal 7, but got #{payload['impact']}"
25
+ expect(payload['ease']).to eq(8), "expect ease equal 8, but got #{payload['ease']}"
26
+ expect(payload['confidence']).to eq(9), "expect confidence equal 9, but got #{payload['confidence']}"
27
+ expect(payload['average_score']).to eq(8.0), "expect average_score equal 8, but got #{payload['average_score']}"
28
+ end
29
+
30
+ private
31
+
32
+ def send_create_idea_request(jwt:, content:, impact:, ease:, confidence:)
33
+ options = {
34
+ headers: {
35
+ 'x-access-token' => jwt
36
+ },
37
+ body: {
38
+ content: content,
39
+ impact: impact,
40
+ ease: ease,
41
+ confidence: confidence
42
+ }
43
+ }
44
+
45
+ @project_api.request(@verb, @path, options)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,50 @@
1
+ module CmQuiz
2
+ module Review
3
+ class DeleteIdea < BaseReview
4
+ def initialize(project_api:)
5
+ @project_api = project_api
6
+ @verb = :delete
7
+ @path = '/ideas/:idea_id'
8
+ end
9
+
10
+ def run
11
+ jwt, _ = Factory::User.new({
12
+ project_api: @project_api
13
+ }).create
14
+ idea_payload = Factory::Idea.new({
15
+ project_api: @project_api,
16
+ jwt: jwt
17
+ }).create
18
+ idea_id = idea_payload['id']
19
+
20
+ send_delete_idea_request(jwt: jwt, idea_id: idea_id)
21
+
22
+ res = send_get_ideas_request(jwt: jwt)
23
+ res_hash = JSON.parse(res.body)
24
+ expect(res_hash.size).to eq(0)
25
+ end
26
+
27
+ private
28
+
29
+ def send_delete_idea_request(jwt:, idea_id:)
30
+ options = {
31
+ headers: {
32
+ 'x-access-token' => jwt
33
+ }
34
+ }
35
+
36
+ @project_api.request(:delete, "/ideas/#{idea_id}", options)
37
+ end
38
+
39
+ def send_get_ideas_request(jwt:)
40
+ options = {
41
+ headers: {
42
+ 'x-access-token' => jwt
43
+ }
44
+ }
45
+
46
+ @project_api.request(:get, "/ideas", options)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,73 @@
1
+ require 'date'
2
+
3
+ module CmQuiz
4
+ module Review
5
+ class GetIdeas < BaseReview
6
+ VALID_TIME_DIFF = 60 * 5
7
+
8
+ def initialize(project_api:)
9
+ @project_api = project_api
10
+ @verb = :get
11
+ @path = '/ideas'
12
+ @now = Time.now
13
+ end
14
+
15
+ def run
16
+ jwt, _ = Factory::User.new({
17
+ project_api: @project_api
18
+ }).create
19
+ idea_payloads = 3.times.map do |i|
20
+ Factory::Idea.new({
21
+ project_api: @project_api,
22
+ jwt: jwt,
23
+ idea_params: {
24
+ confidence: (3 + i) % 10 + 1
25
+ }
26
+ }).create
27
+ end
28
+
29
+ res = send_get_ideas_request(jwt: jwt)
30
+ res_hash = JSON.parse(res.body)
31
+
32
+ idea_payloads.each do |idea_payload|
33
+ item = res_hash.find { |item| item['id'] == idea_payload['id'] }
34
+ raise StandardError, "idea not found" unless item
35
+
36
+ expect(item['content']).to eq(idea_payload['content'])
37
+ expect(item['impact']).to eq(idea_payload['impact'])
38
+ expect(item['ease']).to eq(idea_payload['ease'])
39
+ expect(item['confidence']).to eq(idea_payload['confidence'])
40
+ average_score = (idea_payload['impact'] + idea_payload['ease'] + idea_payload['confidence'])/ 3.0
41
+ expect(item['average_score']).to be_within(0.1).of(average_score)
42
+ diff = Time.now - Time.new(item['created_at'])
43
+ expect(diff).to be <= VALID_TIME_DIFF
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def send_delete_idea_request(jwt:, idea_id:)
50
+ options = {
51
+ headers: {
52
+ 'x-access-token' => jwt
53
+ }
54
+ }
55
+
56
+ @project_api.request(:delete, "/ideas/#{idea_id}", options)
57
+ end
58
+
59
+ def send_get_ideas_request(jwt:, page: 1)
60
+ options = {
61
+ headers: {
62
+ 'x-access-token' => jwt
63
+ },
64
+ query: {
65
+ page: page
66
+ }
67
+ }
68
+
69
+ @project_api.request(@verb, @path, options)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,43 @@
1
+ require 'securerandom'
2
+
3
+ module CmQuiz
4
+ module Review
5
+ class GetUserInfo < BaseReview
6
+ def initialize(project_api:)
7
+ @project_api = project_api
8
+ @verb = :get
9
+ @path = '/me'
10
+ end
11
+
12
+ def run
13
+ name = "codementor-test-#{SecureRandom.hex(5)}"
14
+ email = "#{name}@codementor.io"
15
+ password = "pAssw0rd!"
16
+ jwt, _refresh_token = Factory::User.new({
17
+ project_api: @project_api,
18
+ name: name,
19
+ email: email,
20
+ password: password
21
+ }).create
22
+
23
+ res = send_get_user_info_request(jwt: jwt)
24
+ payload = JSON.parse(res.body)
25
+
26
+ expect(payload['email']).to eq(email)
27
+ expect(payload['name']).to eq(name)
28
+ end
29
+
30
+ private
31
+
32
+ def send_get_user_info_request(jwt:)
33
+ options = {
34
+ headers: {
35
+ 'x-access-token' => jwt
36
+ }
37
+ }
38
+
39
+ @project_api.request(@verb, @path, options)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,47 @@
1
+ require 'securerandom'
2
+
3
+ module CmQuiz
4
+ module Review
5
+ class LoginUser < BaseReview
6
+ def initialize(project_api:)
7
+ @project_api = project_api
8
+ @verb = :post
9
+ @path = '/access-tokens'
10
+ end
11
+
12
+ def run
13
+ name = "codementor-test-#{SecureRandom.hex(5)}"
14
+ email = "#{name}@codementor.io"
15
+ password = "pAssw0rd!"
16
+ Factory::User.new({
17
+ project_api: @project_api,
18
+ name: name,
19
+ email: email,
20
+ password: password
21
+ }).create
22
+
23
+ @options = build_options(email: email, password: password)
24
+ res = send_request(@options)
25
+ payload = JSON.parse(res.body)
26
+
27
+ expect(payload['jwt'].class).to eq(String), '`jwt` should be string'
28
+ expect(payload['refresh_token'].class).to eq(String), '`refresh_token` should be string'
29
+ end
30
+
31
+ private
32
+
33
+ def build_options(email:, password:)
34
+ options = {
35
+ body: {
36
+ email: email,
37
+ password: password
38
+ }
39
+ }
40
+ end
41
+
42
+ def send_request(options)
43
+ @project_api.request(@verb, @path, options)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,43 @@
1
+ require 'securerandom'
2
+
3
+ module CmQuiz
4
+ module Review
5
+ class SignUpUser < BaseReview
6
+ def initialize(project_api:)
7
+ @project_api = project_api
8
+ @verb = :post
9
+ @path = '/users'
10
+ end
11
+
12
+ def run
13
+ name = "codementor-test-#{SecureRandom.hex(5)}"
14
+ email = "#{name}@codementor.io"
15
+ password = "pAssw0rd!"
16
+ res = send_sign_up_user_request(email: email, name: name, password: password)
17
+ payload = JSON.parse(res.body)
18
+
19
+ expect(payload['jwt'].class).to eq(String), '`jwt` should be string'
20
+ expect(payload['refresh_token'].class).to eq(String), '`refresh_token` should be string'
21
+ build_test_result(self.class)
22
+ rescue RSpec::Expectations::ExpectationNotMetError => e
23
+ build_test_result(self.class, false, e.message)
24
+ rescue => e
25
+ build_test_result(self.class, false, e.message)
26
+ end
27
+
28
+ private
29
+
30
+ def send_sign_up_user_request(email:, name:, password:)
31
+ options = {
32
+ body: {
33
+ email: email,
34
+ name: name,
35
+ password: password
36
+ }
37
+ }
38
+
39
+ @project_api.request(@verb, @path, options)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,69 @@
1
+ module CmQuiz
2
+ module Review
3
+ class UpdateIdea < BaseReview
4
+ def initialize(project_api:)
5
+ @project_api = project_api
6
+ @verb = :put
7
+ @path = '/ideas/:idea_id'
8
+ end
9
+
10
+ def run
11
+ jwt, _ = Factory::User.new({
12
+ project_api: @project_api
13
+ }).create
14
+ idea_payload = Factory::Idea.new({
15
+ project_api: @project_api,
16
+ jwt: jwt
17
+ }).create
18
+ idea_id = idea_payload['id']
19
+
20
+ res = send_update_idea_request({
21
+ jwt: jwt,
22
+ idea_id: idea_id,
23
+ content: 'test-new-content',
24
+ impact: 6,
25
+ ease: 7,
26
+ confidence: 8
27
+ })
28
+
29
+ payload = JSON.parse(res.body)
30
+ expect(payload['content']).to eq('test-new-content')
31
+ expect(payload['impact']).to eq(6)
32
+ expect(payload['ease']).to eq(7)
33
+ expect(payload['confidence']).to eq(8)
34
+ expect(payload['average_score']).to eq(7.0)
35
+ end
36
+
37
+ private
38
+
39
+ def send_delete_idea_request(jwt:, idea_id:)
40
+ options = {
41
+ headers: {
42
+ 'x-access-token' => jwt
43
+ }
44
+ }
45
+
46
+ @project_api.request(:delete, "/ideas/#{idea_id}", options)
47
+ end
48
+
49
+ def send_update_idea_request(jwt:, idea_id:, content: nil, impact: nil,
50
+ ease: nil, confidence: nil)
51
+
52
+ options = {
53
+ headers: {
54
+ 'x-access-token' => jwt
55
+ },
56
+ body: {
57
+ content: content,
58
+ impact: impact,
59
+ ease: ease,
60
+ confidence: confidence
61
+ }
62
+ }
63
+
64
+ @project_api.request(:put, "/ideas/#{idea_id}", options)
65
+ end
66
+
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,25 @@
1
+ require 'rspec'
2
+
3
+ module CmQuiz
4
+ module ReviewHelper
5
+ def expect(target)
6
+ RSpec::Expectations::ExpectationTarget.new(target)
7
+ end
8
+
9
+ def eq(obj)
10
+ RSpec::Matchers::BuiltIn::Eq.new(obj)
11
+ end
12
+
13
+ def be
14
+ RSpec::Matchers::BuiltIn::Be.new
15
+ end
16
+
17
+ def be_within(delta)
18
+ RSpec::Matchers::BuiltIn::BeWithin.new(delta)
19
+ end
20
+
21
+ def build_test_result(test_case, passed = true, message = nil)
22
+ [test_case, passed, message]
23
+ end
24
+ end
25
+ end