Browse Source

Merge branch 'feature/parse-hours' into develop

* feature/parse-hours:
  Remove week_stable as we don't need that ATM.
  Use parser to parse the Opening Hours String.
  Introduce and use test assertion helper to check for http status
  Refactor iterator object creation into a constant
  Replace hardcoded address with hstore object
  Add a console for manual investigation and debugging
  Remove nodejs server runner
  Autocorrect with rubocop after upgrading.
  Update Ruby and Rubygems.
  Remove kml builder
  Add parser for opening_hours to determine the state
develop
Bèr Kessels 2 months ago
parent
commit
740a0bd44a

+ 1
- 0
.ruby-version View File

@@ -0,0 +1 @@
1
+2.5.0

+ 2
- 1
Gemfile View File

@@ -11,7 +11,6 @@ gem 'jsonapi-rb'
11 11
 gem 'nominatim', github: 'lukaszsliwa/nominatim'
12 12
 gem 'opening_hours_converter'
13 13
 gem 'rake'
14
-gem 'ruby_kml'
15 14
 gem 'semver'
16 15
 gem 'sequel-postgis-georuby'
17 16
 gem 'sinatra'
@@ -23,12 +22,14 @@ group :development, :test do
23 22
   gem 'minitest'
24 23
   gem 'nokogiri'
25 24
   gem 'rack-test'
25
+  gem 'timecop'
26 26
 
27 27
   gem 'rubocop'
28 28
 
29 29
   gem 'awesome_print'
30 30
   gem 'better_errors'
31 31
   gem 'byebug'
32
+  gem 'pry'
32 33
 
33 34
   gem 'foreman'
34 35
 end

+ 9
- 7
Gemfile.lock View File

@@ -15,7 +15,6 @@ GEM
15 15
       coderay (>= 1.0.0)
16 16
       erubi (>= 1.0.0)
17 17
       rack (>= 0.9.0)
18
-    builder (3.2.3)
19 18
     byebug (10.0.2)
20 19
     coderay (1.1.2)
21 20
     database_cleaner (1.7.0)
@@ -41,6 +40,7 @@ GEM
41 40
     jsonapi-renderer (0.2.0)
42 41
     jsonapi-serializable (0.3.1)
43 42
       jsonapi-renderer (~> 0.2.0)
43
+    method_source (0.9.2)
44 44
     mini_portile2 (2.3.0)
45 45
     minitest (5.11.3)
46 46
     multi_json (1.13.1)
@@ -51,10 +51,13 @@ GEM
51 51
     opening_hours_converter (1.7.20)
52 52
       json
53 53
     parallel (1.12.1)
54
-    parser (2.5.0.4)
54
+    parser (2.5.0.5)
55 55
       ast (~> 2.4.0)
56 56
     pg (1.1.4)
57 57
     powerpack (0.1.2)
58
+    pry (0.12.2)
59
+      coderay (~> 1.1.0)
60
+      method_source (~> 0.9.0)
58 61
     rack (2.0.6)
59 62
     rack-protection (2.0.5)
60 63
       rack
@@ -71,9 +74,6 @@ GEM
71 74
       ruby-progressbar (~> 1.7)
72 75
       unicode-display_width (~> 1.4.0)
73 76
     ruby-progressbar (1.10.0)
74
-    ruby_kml (0.1.7)
75
-      builder
76
-      nokogiri
77 77
     semver (1.0.1)
78 78
     sequel (5.21.0)
79 79
     sequel-postgis-georuby (0.1.2)
@@ -86,6 +86,7 @@ GEM
86 86
       tilt (~> 2.0)
87 87
     thor (0.19.4)
88 88
     tilt (2.0.9)
89
+    timecop (0.9.1)
89 90
     unicode-display_width (1.4.1)
90 91
 
91 92
 PLATFORMS
@@ -106,13 +107,14 @@ DEPENDENCIES
106 107
   nokogiri
107 108
   nominatim!
108 109
   opening_hours_converter
110
+  pry
109 111
   rack-test
110 112
   rake
111 113
   rubocop
112
-  ruby_kml
113 114
   semver
114 115
   sequel-postgis-georuby
115 116
   sinatra
117
+  timecop
116 118
 
117 119
 BUNDLED WITH
118
-   1.16.1
120
+   1.17.3

+ 4
- 4
Rakefile View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 $LOAD_PATH.unshift '.'
2 4
 
3 5
 require 'dotenv/load'
@@ -22,10 +24,7 @@ task run_processors: :environment do
22 24
   Hours.projections_database.disconnect
23 25
 
24 26
   esps = [
25
-    Hours::Projections::Nodes::Projector.new,
26
-    Hours::Projections::ProposedNodesKml::Projector.new(
27
-      tracker: EventSourcery::Memory::Tracker.new
28
-    )
27
+    Hours::Projections::Nodes::Projector.new
29 28
   ]
30 29
 
31 30
   # The ESPRunner will fork child processes for each of the ESPs passed to it.
@@ -48,6 +47,7 @@ namespace :db do
48 47
       pg_db.disconnect
49 48
       app_db = Sequel.connect(Hours.config.database_url)
50 49
       app_db.run('CREATE EXTENSION postgis')
50
+      app_db.run('CREATE EXTENSION hstore')
51 51
     rescue Sequel::DatabaseError => e
52 52
       raise unless e.message.include?(
53 53
         "database \"#{ENV['DB_NAME']}\" already exists"

+ 2
- 0
app/aggregates/node.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 module Hours
2 4
   module Aggregates
3 5
     ##

+ 2
- 0
app/commands/node/add.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 module Hours
2 4
   module Commands
3 5
     module Node

+ 2
- 0
app/events/node_added.rb View File

@@ -1 +1,3 @@
1
+# frozen_string_literal: true
2
+
1 3
 NodeAdded = Class.new(EventSourcery::Event)

+ 45
- 0
app/models/node.rb View File

@@ -1,3 +1,7 @@
1
+# frozen_string_literal: true
2
+
3
+require 'opening_hours_converter'
4
+
1 5
 module Hours
2 6
   module Models
3 7
     ##
@@ -6,6 +10,9 @@ module Hours
6 10
     #   enforced in the database-server and user setup. RO only means that
7 11
     #   this model is only tested and optimized against reading.
8 12
     class Node < Sequel::Model(::Hours.projections_database[:query_nodes])
13
+      ITERATOR = OpeningHoursConverter::Iterator.new
14
+      PARSER   = OpeningHoursConverter::OpeningHoursParser.new
15
+
9 16
       def lat
10 17
         location.lat
11 18
       end
@@ -13,6 +20,44 @@ module Hours
13 20
       def lon
14 21
         location.lon
15 22
       end
23
+
24
+      def status
25
+        ITERATOR.is_opened?(opening_hours)
26
+      end
27
+
28
+      def open_this_week
29
+        date_ranges = PARSER.parse(opening_hours)
30
+        get_intervals_as_week(date_ranges, Date.today)
31
+      end
32
+
33
+      private
34
+
35
+      def get_intervals_as_week(date_ranges, date_in_week)
36
+        from = beginning_of_week(date_in_week)
37
+        to   = end_of_week(date_in_week)
38
+        # Ensure we always get an array to append to.
39
+        as_week = Hash.new { |hash, key| hash[key] = [] }
40
+
41
+        this_week = ITERATOR.get_time_iterator(date_ranges).select do |interval|
42
+          interval[:start] >= from && interval[:end] <= to
43
+        end
44
+
45
+        this_week.each do |interval|
46
+          as_week[interval[:start].wday] << interval
47
+        end
48
+
49
+        as_week
50
+      end
51
+
52
+      def beginning_of_week(date)
53
+        days_to_monday = date.wday != 0 ? date.wday - 1 : 6
54
+        (date - days_to_monday).to_time
55
+      end
56
+
57
+      def end_of_week(date)
58
+        days_to_sunday = date.wday != 0 ? 7 - date.wday : 0
59
+        (date + days_to_sunday).to_time
60
+      end
16 61
     end
17 62
   end
18 63
 end

+ 11
- 2
app/projections/nodes.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 module Hours
2 4
   module Projections
3 5
     module Nodes
@@ -14,11 +16,11 @@ module Hours
14 16
           column :name, :text
15 17
           column :opening_hours, :text
16 18
           column :location, 'geography(POINT)'
19
+          column :address, :hstore
17 20
         end
18 21
 
19 22
         # Event handlers that update the projection in response to different
20 23
         # events from the store.
21
-
22 24
         project NodeAdded do |event|
23 25
           table.insert(
24 26
             node_id: event.aggregate_id,
@@ -27,7 +29,14 @@ module Hours
27 29
             location: GeoRuby::SimpleFeatures::Point.from_x_y(
28 30
               event.body['lon'],
29 31
               event.body['lat']
30
-            )
32
+            ),
33
+            address: Sequel.hstore(
34
+              street: event.body['addr_street'],
35
+              housenumber: event.body['addr_housenumber'],
36
+              postcode: event.body['addr_postcode'],
37
+              city: event.body['addr_city'],
38
+              addr_country_code: event.body['addr_country_code']
39
+            ) # TODO: implement as Address Model PORO instead.
31 40
           )
32 41
         end
33 42
       end

+ 0
- 44
app/projections/proposed_nodes_kml.rb View File

@@ -1,44 +0,0 @@
1
-require 'ruby_kml'
2
-
3
-module Hours
4
-  module Projections
5
-    module ProposedNodesKml
6
-      ##
7
-      # Handles the ProposedNodes Projection
8
-      class Projector
9
-        include EventSourcery::EventProcessing::EventStreamProcessor
10
-        attr_accessor :filename
11
-        attr_writer :kml_file
12
-
13
-        def initialize(tracker:)
14
-          @tracker = tracker
15
-          @filename = File.join('public', 'proposed_nodes.kml')
16
-        end
17
-
18
-        def setup
19
-          KMLFile.new.save(filename)
20
-        end
21
-
22
-        process NodeAdded do |event|
23
-          kml_file.objects << KML::Placemark.new(
24
-            id: event.aggregate_id,
25
-            name: event.body[:author_email],
26
-            geometry: KML::Point.new(
27
-              coordinates: {
28
-                lat: event.body['lat'],
29
-                lng: event.body['lon']
30
-              }
31
-            )
32
-          )
33
-          kml_file.save(filename)
34
-        end
35
-
36
-        private
37
-
38
-        def kml_file
39
-          @kml_file ||= KMLFile.parse(File.open(filename, 'r'))
40
-        end
41
-      end
42
-    end
43
-  end
44
-end

+ 2
- 0
app/projections/query.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 module Hours
2 4
   module Projections
3 5
     module Nodes

+ 6
- 58
app/serializers/node.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 module Hours
2 4
   module Serializers
3 5
     ##
@@ -5,70 +7,16 @@ module Hours
5 7
     class Node < JSONAPI::Serializable::Resource
6 8
       type 'node'
7 9
 
8
-      attributes :name, :lat, :lon
10
+      attributes :name, :lat, :lon, :status, :open_this_week
9 11
       id { @object.node_id }
10 12
 
11 13
       attribute :raw_opening_hours do
12
-        'Mo-We 10:00-18:00; Th 10:00-21:00; Fr 10:00-18:00; Sa 09:30-17:30; '\
13
-         'PH closed; Su 12:00-17:00 open "Koopzondag"'
14
-      end
15
-
16
-      attribute :week_stable do
17
-        false
18
-      end
19
-
20
-      attribute :open_this_week do
21
-        [
22
-          {
23
-            from: '1989-11-06T09:00:00.000Z',
24
-            to: '1989-11-06T17:00:00.000Z',
25
-            unknown: false
26
-          },
27
-          {
28
-            to: '1989-11-07T17:00:00.000Z',
29
-            unknown: false,
30
-            from: '1989-11-07T09:00:00.000Z'
31
-          },
32
-          {
33
-            unknown: false,
34
-            to: '1989-11-08T17:00:00.000Z',
35
-            from: '1989-11-08T09:00:00.000Z'
36
-          },
37
-          {
38
-            from: '1989-11-09T09:00:00.000Z',
39
-            to: '1989-11-09T20:00:00.000Z',
40
-            unknown: false
41
-          },
42
-          {
43
-            to: '1989-11-10T17:00:00.000Z',
44
-            unknown: false,
45
-            from: '1989-11-10T09:00:00.000Z'
46
-          },
47
-          {
48
-            to: '1989-11-11T16:30:00.000Z',
49
-            unknown: false,
50
-            from: '1989-11-11T08:30:00.000Z'
51
-          },
52
-          {
53
-            comment: 'Koopzondag',
54
-            to: '1989-11-12T16:00:00.000Z',
55
-            unknown: false,
56
-            from: '1989-11-12T11:00:00.000Z'
57
-          }
58
-        ]
59
-      end
60
-
61
-      attribute :status do
62
-        true
14
+        @object.opening_hours
63 15
       end
64 16
 
65 17
       attribute :address do
66
-        {
67
-          postcode: '6511RA',
68
-          city: 'Nijmegen',
69
-          housenumber: '1',
70
-          street: 'Burchtstraat'
71
-        }
18
+        as_hash = Sequel::Postgres::HStore.parse(@object.address).to_hash
19
+        as_hash.slice('postcode', 'city', 'housenumber', 'street')
72 20
       end
73 21
 
74 22
       link :self do

+ 11
- 0
bin/console View File

@@ -0,0 +1,11 @@
1
+#!/usr/bin/env ruby
2
+# frozen_string_literal: true
3
+
4
+require 'bundler/setup'
5
+require_relative '../lib/hours.rb'
6
+
7
+require 'opening_hours_converter'
8
+
9
+require 'pry'
10
+
11
+Pry.start

+ 0
- 8
bin/server View File

@@ -1,8 +0,0 @@
1
-#!/usr/bin/env nodejs
2
-
3
-const { app } = require("../app")
4
-const { config } = require("../config/environment")
5
-
6
-app.listen(config.port, () => {
7
-  console.log(`Server loaded on port: ${config.port}`)
8
-})

+ 2
- 0
config.ru View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 $LOAD_PATH << '.'
2 4
 
3 5
 require 'lib/app.rb'

+ 2
- 0
config/environment.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 ##
2 4
 # Setup of database.
3 5
 Hours.configure do |config|

+ 5
- 0
config/event_sourcery.rb View File

@@ -1,9 +1,14 @@
1
+# frozen_string_literal: true
2
+
1 3
 ##
2 4
 # Configure the event sourcery databases.
3 5
 # This assumes they already exist!
4 6
 EventSourcery::Postgres.configure do |config|
5 7
   database = Sequel.connect(Hours.config.database_url)
6 8
 
9
+  Sequel.extension :pg_hstore
10
+  Sequel.extension :pg_hstore_ops
11
+
7 12
   # NOTE: Often we choose to split our events and projections into separate
8 13
   # databases. For the purposes of this example we'll use one.
9 14
   config.event_store_database = database

+ 2
- 0
lib/app.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 # This contains the Sinatra App
2 4
 require_relative './hours.rb'
3 5
 require_relative '../config/event_sourcery.rb'

+ 2
- 1
lib/hours.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 require 'dotenv/load'
2 4
 
3 5
 require 'event_sourcery'
@@ -9,7 +11,6 @@ require_relative '../app/events/node_added.rb'
9 11
 require_relative '../app/commands/node/add.rb'
10 12
 require_relative '../app/aggregates/node.rb'
11 13
 require_relative '../app/projections/nodes.rb'
12
-require_relative '../app/projections/proposed_nodes_kml.rb'
13 14
 require_relative '../app/projections/query.rb'
14 15
 
15 16
 # Monkey patch

+ 2
- 0
test/commands/node/add_test.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 require 'test_helper'
2 4
 
3 5
 describe Hours::Commands::Node::Add::Command do

+ 1
- 1
test/fixtures/db/full.json View File

@@ -6,7 +6,7 @@
6 6
   "addr_street": "Burchtstraat",
7 7
   "addr_city": "Nijmegen",
8 8
   "addr_country_code": "nl",
9
-  "opening_hours": "Mo-We 10:00-18:00; Th 10:00-21:00; Fr 10:00-18:00; Sa 09:30-17:30; PH closed; Su 12:00-17:00 open \"Koopzondag\"",
9
+  "opening_hours": "Mo-We 10:00-18:00; Th 10:00-21:00; Fr 10:00-18:00; Sa 09:30-17:30",
10 10
   "lat": 51.8473397,
11 11
   "lon": 5.8653234
12 12
 }

+ 27
- 40
test/fixtures/json/nodes.json View File

@@ -9,46 +9,33 @@
9 9
        },
10 10
        "type" : "node",
11 11
        "attributes" : {
12
-         "raw_opening_hours" : "Mo-We 10:00-18:00; Th 10:00-21:00; Fr 10:00-18:00; Sa 09:30-17:30; PH closed; Su 12:00-17:00 open \"Koopzondag\"",
13
-         "week_stable" : false,
14
-         "open_this_week" : [
15
-           {
16
-             "from" : "1989-11-06T09:00:00.000Z",
17
-             "to" : "1989-11-06T17:00:00.000Z",
18
-             "unknown" : false
19
-           },
20
-           {
21
-             "to" : "1989-11-07T17:00:00.000Z",
22
-             "unknown" : false,
23
-             "from" : "1989-11-07T09:00:00.000Z"
24
-           },
25
-           {
26
-             "unknown" : false,
27
-             "to" : "1989-11-08T17:00:00.000Z",
28
-             "from" : "1989-11-08T09:00:00.000Z"
29
-           },
30
-           {
31
-             "from" : "1989-11-09T09:00:00.000Z",
32
-             "to" : "1989-11-09T20:00:00.000Z",
33
-             "unknown" : false
34
-           },
35
-           {
36
-             "to" : "1989-11-10T17:00:00.000Z",
37
-             "unknown" : false,
38
-             "from" : "1989-11-10T09:00:00.000Z"
39
-           },
40
-           {
41
-             "to" : "1989-11-11T16:30:00.000Z",
42
-             "unknown" : false,
43
-             "from" : "1989-11-11T08:30:00.000Z"
44
-           },
45
-           {
46
-             "comment" : "Koopzondag",
47
-             "to" : "1989-11-12T16:00:00.000Z",
48
-             "unknown" : false,
49
-             "from" : "1989-11-12T11:00:00.000Z"
50
-           }
51
-         ],
12
+         "raw_opening_hours" : "Mo-We 10:00-18:00; Th 10:00-21:00; Fr 10:00-18:00; Sa 09:30-17:30",
13
+         "open_this_week" : {
14
+           "1": [{
15
+             "start" : "1989-11-06 10:00:00 +0100",
16
+             "end" : "1989-11-06 18:00:00 +0100"
17
+           }],
18
+           "2": [{
19
+             "start" : "1989-11-07 10:00:00 +0100",
20
+             "end" : "1989-11-07 18:00:00 +0100"
21
+           }],
22
+           "3": [{
23
+             "start" : "1989-11-08 10:00:00 +0100",
24
+             "end" : "1989-11-08 18:00:00 +0100"
25
+           }],
26
+           "4": [{
27
+             "start" : "1989-11-09 10:00:00 +0100",
28
+             "end" : "1989-11-09 21:00:00 +0100"
29
+           }],
30
+           "5": [{
31
+             "start" : "1989-11-10 10:00:00 +0100",
32
+             "end" : "1989-11-10 18:00:00 +0100"
33
+           }],
34
+           "6": [{
35
+             "start" : "1989-11-11 09:30:00 +0100",
36
+             "end" : "1989-11-11 17:30:00 +0100"
37
+           }]
38
+         },
52 39
          "name" : "H&M",
53 40
          "status" : true,
54 41
          "lat": 51.8473397,

+ 2
- 17
test/integration/add_node_test.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 require 'test_helper'
2 4
 
3 5
 describe 'add node' do
@@ -41,23 +43,6 @@ describe 'add node' do
41 43
       )
42 44
     end
43 45
 
44
-    # TODO: we probably don't want a KML file, do we?
45
-    it 'adds a node to proposed_nodes KML projection' do
46
-      setup_projectors
47
-      post_json "/nodes/#{node_id}",
48
-                lat: lat,
49
-                lon: lon,
50
-                author_email: 'harry@example.com',
51
-                contact_details: 'h.potter@example.com or visit me at home'
52
-
53
-      projector_process_event(node_id)
54
-
55
-      kml = File.read(File.join('public', 'proposed_nodes.kml'))
56
-      placemarks = Nokogiri::XML(kml).xpath('//xmlns:Placemark')
57
-
58
-      assert_includes("#{lon},#{lat}", placemarks.inner_text.strip!)
59
-    end
60
-
61 46
     describe 'when the node id already exists' do
62 47
       before do
63 48
         post_json "/nodes/#{node_id}", lat: lat, lon: lon

+ 43
- 7
test/integration/view_proposed_nodes_test.rb View File

@@ -1,5 +1,8 @@
1
+# frozen_string_literal: true
2
+
1 3
 require 'test_helper'
2 4
 require 'json_expressions/minitest'
5
+require 'timecop'
3 6
 
4 7
 describe 'pending nodes' do
5 8
   describe 'GET /nodes' do
@@ -24,16 +27,49 @@ describe 'pending nodes' do
24 27
         projector.process(event)
25 28
       end
26 29
 
27
-      get '/nodes'
28
-      assert_equal(200, last_response.status)
30
+      Timecop.travel(die_wende) do
31
+        assert Time.now.hour < 21 # Before 21:00
32
+        assert Time.now.thursday?
33
+
34
+        get '/nodes'
35
+        assert_status(200)
36
+
37
+        expected = json_fixtures('json/nodes.json')
38
+        expected[:data][0][:links][:self] = String
39
+        expected[:data][0][:id] = String
40
+
41
+        parsed = JSON.parse(last_response.body, symbolize_names: true)
42
+
43
+        assert_json_match(expected, parsed)
44
+      end
45
+    end
46
+
47
+    it 'on a thursday, after 21:00 it is closed' do
48
+      projector.setup
49
+
50
+      events.each do |event|
51
+        projector.process(event)
52
+      end
53
+
54
+      after_hours = die_wende + (60 * 60 * 4)
55
+      Timecop.travel(after_hours) do
56
+        assert Time.now.hour > 21 # After 21:00
29 57
 
30
-      expected = json_fixtures('json/nodes.json')
31
-      expected[:data][0][:links][:self] = String
32
-      expected[:data][0][:id] = String
58
+        get '/nodes'
33 59
 
34
-      parsed = JSON.parse(last_response.body, symbolize_names: true)
60
+        assert_status(200)
61
+        parsed = JSON.parse(last_response.body, symbolize_names: true)
35 62
 
36
-      assert_json_match(expected, parsed)
63
+        expected = {
64
+          "data": [
65
+            {
66
+              attributes: { status: false }.ignore_extra_keys!
67
+            }.ignore_extra_keys!
68
+          ]
69
+        }.ignore_extra_keys!
70
+
71
+        assert_json_match(expected, parsed)
72
+      end
37 73
     end
38 74
   end
39 75
 end

+ 28
- 0
test/models/node_test.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 require 'test_helper'
2 4
 
3 5
 describe Hours::Models::Node do
@@ -33,4 +35,30 @@ describe Hours::Models::Node do
33 35
       assert_equal lon, Hours::Models::Node.new(location: point).lon
34 36
     end
35 37
   end
38
+
39
+  describe 'opening_hours' do
40
+    let(:opening_hours) { '1989 Mo-Fr 10:00-19:00' }
41
+
42
+    before do
43
+      subject.opening_hours = opening_hours
44
+    end
45
+
46
+    describe 'status' do
47
+      it 'is true between 10:00 and 19:00' do
48
+        at_time do
49
+          assert_time_after(Time.parse('10:00'))
50
+          assert_time_before(Time.parse('19:00'))
51
+
52
+          assert_equal true, subject.status
53
+        end
54
+      end
55
+
56
+      it 'is false after 19:00' do
57
+        at_time(die_wende + 3600) do
58
+          assert_time_after(Time.parse('19:00'))
59
+          assert_equal false, subject.status
60
+        end
61
+      end
62
+    end
63
+  end
36 64
 end

+ 0
- 70
test/projections/proposed_nodes_kml_test.rb View File

@@ -1,70 +0,0 @@
1
-require 'test_helper'
2
-
3
-describe Hours::Projections::ProposedNodesKml::Projector do
4
-  let(:file) { File.join('public', 'proposed_nodes.kml') }
5
-  let(:tracker) { Minitest::Mock.new }
6
-  subject do
7
-    Hours::Projections::ProposedNodesKml::Projector.new(tracker: tracker)
8
-  end
9
-
10
-  before do
11
-    File.delete(file) if File.exist?(file)
12
-  end
13
-
14
-  describe 'setup' do
15
-    it 'creates a KML file' do
16
-      subject.setup
17
-
18
-      assert(File.exist?(file), "File #{file} not found")
19
-    end
20
-  end
21
-
22
-  describe 'process on NodeAdded' do
23
-    let(:event) do
24
-      NodeAdded.new(
25
-        aggregate_id: SecureRandom.uuid,
26
-        body: {
27
-          lat: 20.01,
28
-          lon: 20.02,
29
-          author_email: 'ronweasly@example.com',
30
-          contact_details: 'The Nest'
31
-        }
32
-      )
33
-    end
34
-
35
-    let(:kml_file_mock) do
36
-      Minitest::Mock.new.expect(:objects, [])
37
-    end
38
-
39
-    before do
40
-      subject.setup
41
-    end
42
-
43
-    it 'inserts a PlaceMark' do
44
-      subject.process(event)
45
-      assert_file_contains(file, '<coordinates>20.02,20.01</coordinates>')
46
-    end
47
-
48
-    it 'saves a file' do
49
-      kml_file_mock.expect(:save, true, [file])
50
-      subject.kml_file = kml_file_mock
51
-
52
-      subject.process(event)
53
-      assert_mock kml_file_mock
54
-    end
55
-
56
-    it 'appends a file' do
57
-      kml_builder = KMLFile.new
58
-      kml_builder.objects << KML::Placemark.new(
59
-        geometry: KML::Point.new(coordinates: { lat: 30.01, lng: 30.02 })
60
-      )
61
-      kml_builder.save(file)
62
-
63
-      subject.process(event)
64
-
65
-      # the order does not really matter
66
-      assert_file_contains(file, '<coordinates>20.02,20.01</coordinates>')
67
-      assert_file_contains(file, '<coordinates>30.02,30.01</coordinates>')
68
-    end
69
-  end
70
-end

+ 2
- 0
test/projections/query_test.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 require 'test_helper'
2 4
 
3 5
 describe Hours::Projections::Nodes::Query do

+ 3
- 4
test/support/event_helpers.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 ##
2 4
 # Helpers for testing events.
3 5
 module EventHelpers
@@ -19,10 +21,7 @@ module EventHelpers
19 21
 
20 22
   def projectors
21 23
     @projectors = [
22
-      Hours::Projections::Nodes::Projector.new,
23
-      Hours::Projections::ProposedNodesKml::Projector.new(
24
-        tracker: EventSourcery::Memory::Tracker.new
25
-      )
24
+      Hours::Projections::Nodes::Projector.new
26 25
     ]
27 26
   end
28 27
 end

+ 2
- 0
test/support/file_helpers.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 ##
2 4
 # Helpers for testing against files
3 5
 module FileHelpers

+ 8
- 0
test/support/request_helpers.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 require 'ostruct'
2 4
 require 'json'
3 5
 require 'rack/test'
@@ -13,4 +15,10 @@ module RequestHelpers
13 15
     defaults = { 'Content-Type' => 'application/json' }
14 16
     post url, body.to_json, headers.merge(defaults)
15 17
   end
18
+
19
+  def assert_status(status, message = nil)
20
+    message ||= "Expected #{status}, got #{last_response.status}.\n"\
21
+                "#{last_response.body}"
22
+    assert_equal(status, last_response.status, message)
23
+  end
16 24
 end

+ 17
- 3
test/support/time_helpers.rb View File

@@ -1,9 +1,11 @@
1
+# frozen_string_literal: true
2
+
1 3
 module TimeHelpers
2 4
   ##
3 5
   # Time Helper to freeze the time at die_wende for the duration of a block
4 6
   # stub goes away once the block is done
5
-  def at_die_wende(&block)
6
-    Time.stub :now, die_wende do
7
+  def at_time(time = die_wende, &block)
8
+    Time.stub :now, time do
7 9
       yield block
8 10
     end
9 11
   end
@@ -11,6 +13,18 @@ module TimeHelpers
11 13
   ##
12 14
   # Time Helper, returns a Time
13 15
   def die_wende
14
-    Time.new(1989, 11, 9, 18, 57, 0, 0)
16
+    Time.local(1989, 11, 9, 18, 57, 0, 0)
17
+  end
18
+
19
+  ##
20
+  # Assert after a certain time
21
+  def assert_time_after(expected, actual = Time.now.getlocal)
22
+    assert expected < actual, "#{actual} is not after #{expected}"
23
+  end
24
+
25
+  ##
26
+  # Assert before a certain time
27
+  def assert_time_before(expected, actual = Time.now.getlocal)
28
+    assert expected > actual, "#{actual} is not before #{expected}"
15 29
   end
16 30
 end

+ 2
- 0
test/test_helper.rb View File

@@ -1,3 +1,5 @@
1
+# frozen_string_literal: true
2
+
1 3
 require 'minitest/autorun'
2 4
 require 'database_cleaner'
3 5
 require 'byebug'

Loading…
Cancel
Save