feedx 0.12.0 → 0.12.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +3 -0
  3. data/.github/workflows/test.yml +60 -0
  4. data/.gitignore +1 -0
  5. data/.rubocop.yml +14 -5
  6. data/Gemfile +0 -2
  7. data/Gemfile.lock +60 -49
  8. data/Makefile +6 -6
  9. data/README.md +1 -1
  10. data/compression.go +18 -0
  11. data/compression_test.go +17 -5
  12. data/consumer.go +12 -3
  13. data/consumer_test.go +50 -19
  14. data/ext/parquet/decoder.go +170 -0
  15. data/ext/parquet/decoder_test.go +88 -0
  16. data/ext/parquet/go.mod +10 -0
  17. data/ext/parquet/go.sum +154 -0
  18. data/ext/parquet/parquet.go +78 -0
  19. data/ext/parquet/parquet_test.go +28 -0
  20. data/ext/parquet/reader.go +89 -0
  21. data/ext/parquet/testdata/alltypes_plain.parquet +0 -0
  22. data/ext/parquet/types.go +51 -0
  23. data/feedx.gemspec +5 -6
  24. data/feedx_ext_test.go +6 -0
  25. data/feedx_test.go +6 -6
  26. data/format.go +45 -15
  27. data/format_test.go +7 -5
  28. data/go.mod +10 -5
  29. data/go.sum +90 -25
  30. data/internal/testdata/testdata.pb.go +176 -77
  31. data/lib/feedx/cache/memory.rb +1 -0
  32. data/lib/feedx/consumer.rb +9 -6
  33. data/lib/feedx/format.rb +1 -1
  34. data/lib/feedx/producer.rb +20 -18
  35. data/lib/feedx/stream.rb +24 -8
  36. data/producer_test.go +4 -4
  37. data/reader_test.go +6 -5
  38. data/spec/feedx/cache/memory_spec.rb +2 -2
  39. data/spec/feedx/cache/value_spec.rb +1 -1
  40. data/spec/feedx/compression/gzip_spec.rb +1 -1
  41. data/spec/feedx/compression/none_spec.rb +1 -1
  42. data/spec/feedx/compression_spec.rb +2 -2
  43. data/spec/feedx/consumer_spec.rb +5 -4
  44. data/spec/feedx/format/abstract_spec.rb +2 -1
  45. data/spec/feedx/format/json_spec.rb +6 -6
  46. data/spec/feedx/format/parquet_spec.rb +1 -1
  47. data/spec/feedx/format/protobuf_spec.rb +1 -1
  48. data/spec/feedx/format_spec.rb +2 -2
  49. data/spec/feedx/producer_spec.rb +10 -9
  50. data/spec/feedx/stream_spec.rb +36 -18
  51. data/writer.go +1 -4
  52. data/writer_test.go +8 -8
  53. metadata +25 -23
  54. data/.travis.yml +0 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78c9ab1f475804897ee6610107515f598c14590878a3134f14abecad23e151ab
4
- data.tar.gz: 89d4d70a336b47ccba2db349fdcc4283e45ddb877599ac6618ba3da173ba8547
3
+ metadata.gz: ab1b8d12efde331dcd1ca96c686c29e1ef16ab895f049121078b9f0503d23276
4
+ data.tar.gz: 3d51319d3ea39cbceeb480252e06c37238fce0cda68aa6b65cf1f59c0f0af38b
5
5
  SHA512:
6
- metadata.gz: 12a539f376dd128eb4eb9d26d7a31812f656c0601375eec8721c814f404326d52feaafa80c6856fc9cf7fe66f1e1e956b9c74621d3ee88f0f8a47307f2ef04c1
7
- data.tar.gz: c1de172489a3404f3c811aa3c41bf6d00708f36e756f4db0d4e58db0adfe8aa3908189cc07a25703682c48293c747351781650582ca4f1f1e5d3ab5681237f7c
6
+ metadata.gz: d08c34b59158c69d500b7cffe8019550dafa87b760e4b0cb3b25afc367801a3f3473486987dcb62e5c1bc62c05d3653bf26692fcbdcbb552d2af1073f4eced50
7
+ data.tar.gz: cfa3f24458cead0c12c1f03b559ded816095e1e9cf29a1918c142cd255f782fa3c51d7c45ca5833ab25b5a745e0e68f4b1b1062c7760c56ff1b57da122767135
data/.editorconfig CHANGED
@@ -7,3 +7,6 @@ end_of_line = lf
7
7
  charset = utf-8
8
8
  trim_trailing_whitespace = true
9
9
  insert_final_newline = true
10
+
11
+ [{*.go,Makefile}]
12
+ indent_style = tab
@@ -0,0 +1,60 @@
1
+ name: Test
2
+ on:
3
+ push:
4
+ branches:
5
+ - main
6
+ pull_request:
7
+ branches:
8
+ - main
9
+ jobs:
10
+ go:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ go-version: [1.15.x, 1.16.x]
15
+ steps:
16
+ - name: Fetch staticcheck
17
+ uses: engineerd/configurator@v0.0.6
18
+ with:
19
+ name: staticcheck
20
+ fromGitHubReleases: true
21
+ repo: dominikh/go-tools
22
+ version: latest
23
+ urlTemplate: "https://github.com/dominikh/go-tools/releases/download/2020.2.3/staticcheck_linux_amd64.tar.gz"
24
+ pathInArchive: staticcheck/staticcheck
25
+ token: ${{ secrets.GITHUB_TOKEN }}
26
+ - name: Checkout
27
+ uses: actions/checkout@v2
28
+ - name: Cache dependencies
29
+ uses: actions/cache@v2
30
+ with:
31
+ path: ~/go/pkg/mod
32
+ key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
33
+ restore-keys: |
34
+ ${{ runner.os }}-go-
35
+ - name: Setup Go
36
+ uses: actions/setup-go@v2
37
+ with:
38
+ go-version: ${{ matrix.go-version }}
39
+ - name: Run tests
40
+ run: make test
41
+ - name: Run staticcheck
42
+ run: make staticcheck
43
+ ruby:
44
+ runs-on: ubuntu-latest
45
+ strategy:
46
+ matrix:
47
+ ruby-version: ["2.6", "2.7", "3.0"]
48
+ steps:
49
+ - name: Install libarrow
50
+ run: |
51
+ wget https://apache.bintray.com/arrow/$(lsb_release --id --short | tr 'A-Z' 'a-z')/apache-arrow-archive-keyring-latest-$(lsb_release --codename --short).deb
52
+ sudo apt install -y ./apache-arrow-archive-keyring-latest-$(lsb_release --codename --short).deb
53
+ sudo apt update
54
+ sudo apt install -y libarrow-dev libarrow-glib-dev libarrow-dataset-dev libplasma-dev libplasma-glib-dev libgandiva-dev libgandiva-glib-dev libparquet-dev libparquet-glib-dev
55
+ - uses: actions/checkout@v2
56
+ - uses: ruby/setup-ruby@v1
57
+ with:
58
+ ruby-version: ${{ matrix.ruby-version }}
59
+ bundler-cache: true
60
+ - run: bundle exec rake
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  .rubocop-*
2
2
  pkg/
3
3
  *~
4
+ *.makefile
data/.rubocop.yml CHANGED
@@ -1,8 +1,17 @@
1
- require: rubocop-performance
2
- inherit_from:
3
- - https://gitlab.com/bsm/misc/raw/master/rubocop/default.yml
1
+ inherit_gem:
2
+ rubocop-bsm:
3
+ - default.yml
4
+ inherit_mode:
5
+ merge:
6
+ - Exclude
4
7
 
5
8
  AllCops:
6
- TargetRubyVersion: "2.4"
9
+ TargetRubyVersion: 2.6
10
+ Naming/MethodParameterName:
11
+ MinNameLength: 2
12
+ Naming/MemoizedInstanceVariableName:
13
+ Enabled: false
14
+ Naming/FileName:
15
+ Exclude: [lib/sortable-by.rb]
7
16
  Metrics/ParameterLists:
8
- Max: 10
17
+ Max: 8
data/Gemfile CHANGED
@@ -1,4 +1,2 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec
3
-
4
- gem 'google-protobuf', '>= 3.7.0-rc2'
data/Gemfile.lock CHANGED
@@ -1,70 +1,83 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- feedx (0.12.0)
5
- bfs (>= 0.5.0)
4
+ feedx (0.12.6)
5
+ bfs (>= 0.8.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- ast (2.4.1)
11
- bfs (0.7.0)
12
- diff-lcs (1.4)
13
- extpp (0.0.8)
14
- gio2 (3.4.3)
15
- gobject-introspection (= 3.4.3)
16
- glib2 (3.4.3)
10
+ ast (2.4.2)
11
+ bfs (0.8.4)
12
+ bigdecimal (3.0.2)
13
+ diff-lcs (1.4.4)
14
+ extpp (0.0.9)
15
+ gio2 (3.4.4)
16
+ gobject-introspection (= 3.4.4)
17
+ glib2 (3.4.4)
17
18
  native-package-installer (>= 1.0.3)
18
19
  pkg-config (>= 1.3.5)
19
- gobject-introspection (3.4.3)
20
- glib2 (= 3.4.3)
21
- google-protobuf (3.12.2)
22
- native-package-installer (1.0.9)
23
- parallel (1.19.2)
24
- parser (2.7.1.4)
20
+ gobject-introspection (3.4.4)
21
+ glib2 (= 3.4.4)
22
+ google-protobuf (3.17.3)
23
+ native-package-installer (1.1.1)
24
+ parallel (1.20.1)
25
+ parser (3.0.1.1)
25
26
  ast (~> 2.4.1)
26
- pbio (0.2.1)
27
+ pbio (0.3.0)
27
28
  google-protobuf
28
- pkg-config (1.4.1)
29
+ pkg-config (1.4.6)
29
30
  rainbow (3.0.0)
30
- rake (13.0.1)
31
- red-arrow (0.17.1)
31
+ rake (13.0.3)
32
+ red-arrow (3.0.0)
33
+ bigdecimal (>= 2.0.3)
32
34
  extpp (>= 0.0.7)
33
35
  gio2 (>= 3.3.6)
34
36
  native-package-installer
35
37
  pkg-config
36
- red-parquet (0.17.1)
37
- red-arrow (= 0.17.1)
38
- regexp_parser (1.7.1)
39
- rexml (3.2.4)
40
- rspec (3.9.0)
41
- rspec-core (~> 3.9.0)
42
- rspec-expectations (~> 3.9.0)
43
- rspec-mocks (~> 3.9.0)
44
- rspec-core (3.9.2)
45
- rspec-support (~> 3.9.3)
46
- rspec-expectations (3.9.2)
38
+ red-parquet (3.0.0)
39
+ red-arrow (= 3.0.0)
40
+ regexp_parser (2.1.1)
41
+ rexml (3.2.5)
42
+ rspec (3.10.0)
43
+ rspec-core (~> 3.10.0)
44
+ rspec-expectations (~> 3.10.0)
45
+ rspec-mocks (~> 3.10.0)
46
+ rspec-core (3.10.1)
47
+ rspec-support (~> 3.10.0)
48
+ rspec-expectations (3.10.1)
47
49
  diff-lcs (>= 1.2.0, < 2.0)
48
- rspec-support (~> 3.9.0)
49
- rspec-mocks (3.9.1)
50
+ rspec-support (~> 3.10.0)
51
+ rspec-mocks (3.10.2)
50
52
  diff-lcs (>= 1.2.0, < 2.0)
51
- rspec-support (~> 3.9.0)
52
- rspec-support (3.9.3)
53
- rubocop (0.86.0)
53
+ rspec-support (~> 3.10.0)
54
+ rspec-support (3.10.2)
55
+ rubocop (1.17.0)
54
56
  parallel (~> 1.10)
55
- parser (>= 2.7.0.1)
57
+ parser (>= 3.0.0.0)
56
58
  rainbow (>= 2.2.2, < 4.0)
57
- regexp_parser (>= 1.7)
59
+ regexp_parser (>= 1.8, < 3.0)
58
60
  rexml
59
- rubocop-ast (>= 0.0.3, < 1.0)
61
+ rubocop-ast (>= 1.7.0, < 2.0)
60
62
  ruby-progressbar (~> 1.7)
61
- unicode-display_width (>= 1.4.0, < 2.0)
62
- rubocop-ast (0.0.3)
63
- parser (>= 2.7.0.1)
64
- rubocop-performance (1.6.1)
65
- rubocop (>= 0.71.0)
66
- ruby-progressbar (1.10.1)
67
- unicode-display_width (1.7.0)
63
+ unicode-display_width (>= 1.4.0, < 3.0)
64
+ rubocop-ast (1.7.0)
65
+ parser (>= 3.0.1.1)
66
+ rubocop-bsm (0.6.0)
67
+ rubocop (~> 1.0)
68
+ rubocop-performance
69
+ rubocop-rake
70
+ rubocop-rspec
71
+ rubocop-performance (1.11.3)
72
+ rubocop (>= 1.7.0, < 2.0)
73
+ rubocop-ast (>= 0.4.0)
74
+ rubocop-rake (0.5.1)
75
+ rubocop
76
+ rubocop-rspec (2.4.0)
77
+ rubocop (~> 1.0)
78
+ rubocop-ast (>= 1.1.0)
79
+ ruby-progressbar (1.11.0)
80
+ unicode-display_width (2.0.0)
68
81
 
69
82
  PLATFORMS
70
83
  ruby
@@ -72,13 +85,11 @@ PLATFORMS
72
85
  DEPENDENCIES
73
86
  bundler
74
87
  feedx!
75
- google-protobuf (>= 3.7.0.pre.rc2)
76
88
  pbio
77
89
  rake
78
- red-parquet
90
+ red-parquet (>= 3.0, < 4.0)
79
91
  rspec
80
- rubocop
81
- rubocop-performance
92
+ rubocop-bsm
82
93
 
83
94
  BUNDLED WITH
84
95
  2.1.4
data/Makefile CHANGED
@@ -1,12 +1,12 @@
1
- default: vet test
1
+ default: test
2
2
 
3
- test:
4
- go test ./...
3
+ .common.makefile:
4
+ curl -fsSL -o $@ https://gitlab.com/bsm/misc/raw/master/make/go/common.makefile
5
5
 
6
- vet:
7
- go vet ./...
6
+ include .common.makefile
8
7
 
9
8
  proto: internal/testdata/testdata.pb.go
10
9
 
11
10
  %.pb.go: %.proto
12
- protoc -I=. --gogo_out=paths=source_relative:. $<
11
+ # may need to `go install google.golang.org/protobuf/cmd/protoc-gen-go`
12
+ protoc -I=. --go_out=paths=source_relative:. $<
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Feedx
2
2
 
3
- [![Build Status](https://travis-ci.org/bsm/feedx.png?branch=master)](https://travis-ci.org/bsm/feedx)
3
+ [![Test](https://github.com/bsm/feedx/actions/workflows/test.yml/badge.svg)](https://github.com/bsm/feedx/actions/workflows/test.yml)
4
4
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
5
5
 
6
6
  Feed-based data exchange between services.
data/compression.go CHANGED
@@ -1,6 +1,7 @@
1
1
  package feedx
2
2
 
3
3
  import (
4
+ "compress/flate"
4
5
  "compress/gzip"
5
6
  "io"
6
7
  "path"
@@ -20,6 +21,8 @@ func DetectCompression(name string) Compression {
20
21
  ext := path.Ext(path.Base(name))
21
22
  if ext != "" && ext[0] == '.' && ext[len(ext)-1] == 'z' {
22
23
  return GZipCompression
24
+ } else if ext == ".flate" {
25
+ return FlateCompression
23
26
  }
24
27
  }
25
28
  return NoCompression
@@ -61,3 +64,18 @@ func (gzipCompression) NewReader(r io.Reader) (io.ReadCloser, error) {
61
64
  func (gzipCompression) NewWriter(w io.Writer) (io.WriteCloser, error) {
62
65
  return gzip.NewWriter(w), nil
63
66
  }
67
+
68
+ // --------------------------------------------------------------------
69
+
70
+ // FlateCompression supports flate compression format.
71
+ var FlateCompression = flateCompression{}
72
+
73
+ type flateCompression struct{}
74
+
75
+ func (flateCompression) NewReader(r io.Reader) (io.ReadCloser, error) {
76
+ return flate.NewReader(r), nil
77
+ }
78
+
79
+ func (flateCompression) NewWriter(w io.Writer) (io.WriteCloser, error) {
80
+ return flate.NewWriter(w, flate.BestSpeed)
81
+ }
data/compression_test.go CHANGED
@@ -4,8 +4,8 @@ import (
4
4
  "bytes"
5
5
 
6
6
  "github.com/bsm/feedx"
7
- . "github.com/onsi/ginkgo"
8
- . "github.com/onsi/gomega"
7
+ . "github.com/bsm/ginkgo"
8
+ . "github.com/bsm/gomega"
9
9
  )
10
10
 
11
11
  var _ = Describe("Compression", func() {
@@ -32,7 +32,7 @@ var _ = Describe("Compression", func() {
32
32
  Expect(r.Close()).To(Succeed())
33
33
  }
34
34
 
35
- It("should detect the format", func() {
35
+ It("detects the format", func() {
36
36
  Expect(feedx.DetectCompression("/path/to/file.json")).To(Equal(feedx.NoCompression))
37
37
  Expect(feedx.DetectCompression("/path/to/file.json.gz")).To(Equal(feedx.GZipCompression))
38
38
  Expect(feedx.DetectCompression("/path/to/file.jsonz")).To(Equal(feedx.GZipCompression))
@@ -41,6 +41,9 @@ var _ = Describe("Compression", func() {
41
41
  Expect(feedx.DetectCompression("/path/to/file.pb.gz")).To(Equal(feedx.GZipCompression))
42
42
  Expect(feedx.DetectCompression("/path/to/file.pbz")).To(Equal(feedx.GZipCompression))
43
43
 
44
+ Expect(feedx.DetectCompression("/path/to/file.flate")).To(Equal(feedx.FlateCompression))
45
+ Expect(feedx.DetectCompression("/path/to/file.whatever.flate")).To(Equal(feedx.FlateCompression))
46
+
44
47
  Expect(feedx.DetectCompression("")).To(Equal(feedx.NoCompression))
45
48
  Expect(feedx.DetectCompression("/path/to/file")).To(Equal(feedx.NoCompression))
46
49
  Expect(feedx.DetectCompression("/path/to/file.txt")).To(Equal(feedx.NoCompression))
@@ -50,7 +53,7 @@ var _ = Describe("Compression", func() {
50
53
  var subject = feedx.NoCompression
51
54
  var _ feedx.Compression = subject
52
55
 
53
- It("should write/read", func() {
56
+ It("writes/reads", func() {
54
57
  runSharedTest(subject)
55
58
  })
56
59
  })
@@ -59,7 +62,16 @@ var _ = Describe("Compression", func() {
59
62
  var subject = feedx.GZipCompression
60
63
  var _ feedx.Compression = subject
61
64
 
62
- It("should write/read", func() {
65
+ It("writes/reads", func() {
66
+ runSharedTest(subject)
67
+ })
68
+ })
69
+
70
+ Describe("FlateCompression", func() {
71
+ var subject = feedx.FlateCompression
72
+ var _ feedx.Compression = subject
73
+
74
+ It("writes/reads", func() {
63
75
  runSharedTest(subject)
64
76
  })
65
77
  })
data/consumer.go CHANGED
@@ -50,6 +50,8 @@ type Consumer interface {
50
50
  Data() interface{}
51
51
  // LastSync returns time of last sync attempt.
52
52
  LastSync() time.Time
53
+ // LastConsumed returns time of last feed consumption.
54
+ LastConsumed() time.Time
53
55
  // LastModified returns time at which the remote feed was last modified.
54
56
  LastModified() time.Time
55
57
  // NumRead returns the number of values consumed during the last sync.
@@ -114,7 +116,7 @@ type consumer struct {
114
116
  cfn ConsumeFunc
115
117
  data atomic.Value
116
118
 
117
- numRead, lastMod, lastSync int64
119
+ numRead, lastMod, lastSync, lastConsumed int64
118
120
  }
119
121
 
120
122
  // Data implements Consumer interface.
@@ -132,6 +134,11 @@ func (c *consumer) LastSync() time.Time {
132
134
  return timestamp(atomic.LoadInt64(&c.lastSync)).Time()
133
135
  }
134
136
 
137
+ // LastConsumed implements Consumer interface.
138
+ func (c *consumer) LastConsumed() time.Time {
139
+ return timestamp(atomic.LoadInt64(&c.lastConsumed)).Time()
140
+ }
141
+
135
142
  // LastModified implements Consumer interface.
136
143
  func (c *consumer) LastModified() time.Time {
137
144
  return timestamp(atomic.LoadInt64(&c.lastMod)).Time()
@@ -147,8 +154,9 @@ func (c *consumer) Close() error {
147
154
  }
148
155
 
149
156
  func (c *consumer) sync(force bool) (*ConsumerSync, error) {
157
+ syncTime := timestampFromTime(time.Now()).Millis()
150
158
  defer func() {
151
- atomic.StoreInt64(&c.lastSync, timestampFromTime(time.Now()).Millis())
159
+ atomic.StoreInt64(&c.lastSync, syncTime)
152
160
  }()
153
161
 
154
162
  // retrieve original last modified time
@@ -158,7 +166,7 @@ func (c *consumer) sync(force bool) (*ConsumerSync, error) {
158
166
  }
159
167
 
160
168
  // skip update if not forced or modified
161
- if lastMod.Millis() == atomic.LoadInt64(&c.lastMod) && !force {
169
+ if !force && lastMod > 0 && lastMod.Millis() == atomic.LoadInt64(&c.lastMod) {
162
170
  return &ConsumerSync{Consumer: c}, nil
163
171
  }
164
172
 
@@ -180,6 +188,7 @@ func (c *consumer) sync(force bool) (*ConsumerSync, error) {
180
188
  c.data.Store(data)
181
189
  atomic.StoreInt64(&c.numRead, int64(reader.NumRead()))
182
190
  atomic.StoreInt64(&c.lastMod, lastMod.Millis())
191
+ atomic.StoreInt64(&c.lastConsumed, syncTime)
183
192
  return &ConsumerSync{
184
193
  Consumer: c,
185
194
  Updated: true,
data/consumer_test.go CHANGED
@@ -8,8 +8,8 @@ import (
8
8
  "github.com/bsm/bfs"
9
9
  "github.com/bsm/feedx"
10
10
  "github.com/bsm/feedx/internal/testdata"
11
- . "github.com/onsi/ginkgo"
12
- . "github.com/onsi/gomega"
11
+ . "github.com/bsm/ginkgo"
12
+ . "github.com/bsm/gomega"
13
13
  )
14
14
 
15
15
  var _ = Describe("Consumer", func() {
@@ -17,25 +17,26 @@ var _ = Describe("Consumer", func() {
17
17
  var obj *bfs.Object
18
18
  var ctx = context.Background()
19
19
 
20
+ consume := func(r *feedx.Reader) (interface{}, error) {
21
+ var msgs []*testdata.MockMessage
22
+ for {
23
+ var msg testdata.MockMessage
24
+ if err := r.Decode(&msg); err == io.EOF {
25
+ break
26
+ } else if err != nil {
27
+ return nil, err
28
+ }
29
+ msgs = append(msgs, &msg)
30
+ }
31
+ return msgs, nil
32
+ }
33
+
20
34
  BeforeEach(func() {
21
35
  obj = bfs.NewInMemObject("path/to/file.jsonz")
22
- Expect(writeMulti(obj, 2)).To(Succeed())
36
+ Expect(writeMulti(obj, 2, mockTime)).To(Succeed())
23
37
 
24
38
  var err error
25
- subject, err = feedx.NewConsumerForRemote(ctx, obj, nil, func(r *feedx.Reader) (interface{}, error) {
26
- var msgs []*testdata.MockMessage
27
- for {
28
- var msg testdata.MockMessage
29
- if err := r.Decode(&msg); err == io.EOF {
30
- break
31
- }
32
- if err != nil {
33
- return nil, err
34
- }
35
- msgs = append(msgs, &msg)
36
- }
37
- return msgs, nil
38
- })
39
+ subject, err = feedx.NewConsumerForRemote(ctx, obj, nil, consume)
39
40
  Expect(err).NotTo(HaveOccurred())
40
41
  })
41
42
 
@@ -43,11 +44,41 @@ var _ = Describe("Consumer", func() {
43
44
  Expect(subject.Close()).To(Succeed())
44
45
  })
45
46
 
46
- It("should sync and retrieve feeds from remote", func() {
47
+ It("syncs/retrieves feeds from remote", func() {
47
48
  Expect(subject.LastSync()).To(BeTemporally("~", time.Now(), time.Second))
48
- Expect(subject.LastModified()).To(BeTemporally("~", time.Unix(1515151515, 0), time.Second))
49
+ Expect(subject.LastConsumed()).To(BeTemporally("==", subject.LastSync()))
50
+ Expect(subject.LastModified()).To(BeTemporally("==", mockTime.Truncate(time.Millisecond)))
49
51
  Expect(subject.NumRead()).To(Equal(2))
50
52
  Expect(subject.Data()).To(ConsistOf(seed(), seed()))
51
53
  Expect(subject.Close()).To(Succeed())
52
54
  })
55
+
56
+ It("consumes feeds only if necessary", func() {
57
+ prevSync := subject.LastSync()
58
+ time.Sleep(2 * time.Millisecond)
59
+
60
+ testable := subject.(interface{ TestSync() error })
61
+ Expect(testable.TestSync()).To(Succeed())
62
+ Expect(subject.LastSync()).To(BeTemporally(">", prevSync))
63
+ Expect(subject.LastConsumed()).To(BeTemporally("==", prevSync)) // skipped on last sync
64
+ Expect(subject.LastModified()).To(BeTemporally("==", mockTime.Truncate(time.Millisecond)))
65
+ Expect(subject.NumRead()).To(Equal(2))
66
+ })
67
+
68
+ It("always consumes if LastModified not set", func() {
69
+ noModTime := bfs.NewInMemObject("path/to/file.json")
70
+ Expect(writeMulti(noModTime, 2, time.Time{})).To(Succeed())
71
+
72
+ csmr, err := feedx.NewConsumerForRemote(ctx, noModTime, nil, consume)
73
+ Expect(err).NotTo(HaveOccurred())
74
+
75
+ prevSync := csmr.LastSync()
76
+ time.Sleep(2 * time.Millisecond)
77
+
78
+ testable := csmr.(interface{ TestSync() error })
79
+ Expect(testable.TestSync()).To(Succeed())
80
+ Expect(csmr.LastSync()).To(BeTemporally(">", prevSync))
81
+ Expect(csmr.LastConsumed()).To(BeTemporally("==", csmr.LastSync())) // consumed on last sync
82
+ Expect(csmr.LastModified()).To(BeTemporally("==", time.Unix(0, 0)))
83
+ })
53
84
  })