fluent-plugin-groonga 1.0.0 → 1.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.
- data/.yardopts +5 -0
- data/README.md +7 -52
- data/doc/text/configuration.md +61 -0
- data/doc/text/constitution.md +315 -0
- data/doc/text/news.md +15 -0
- data/fluent-plugin-groonga.gemspec +5 -1
- data/lib/fluent/plugin/in_groonga.rb +3 -0
- data/lib/fluent/plugin/out_groonga.rb +1 -2
- data/test/run-test.rb +42 -0
- data/test/test_input.rb +176 -0
- data/test/test_output.rb +213 -0
- metadata +52 -5
data/.yardopts
ADDED
data/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# @title README
|
2
|
+
|
1
3
|
# README
|
2
4
|
|
3
5
|
## Name
|
@@ -16,7 +18,7 @@ plugin. Both of them are named `groonga`.
|
|
16
18
|
The input plugin provides groonga compatible interface. It means that
|
17
19
|
HTTP and GQTP interface. You can use the input plugin as groonga
|
18
20
|
server. The input plugin receives groonga commands and sends them to
|
19
|
-
the output plugin through
|
21
|
+
the output plugin through zero or more fluentds.
|
20
22
|
|
21
23
|
The output plugin sends received groonga commands to groonga. The
|
22
24
|
output plugin supports all interfaces, HTTP, GQTP and command
|
@@ -30,57 +32,10 @@ You can replicate your data by using `copy` output plugin.
|
|
30
32
|
|
31
33
|
## Usage
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
* `protocol`: It specifies protocol for receiving groonga commands.
|
38
|
-
* available values: `http` and `gqtp`
|
39
|
-
* default: `http`
|
40
|
-
* `bind`: It specifies bind address.
|
41
|
-
* default: `0.0.0.0`
|
42
|
-
* `port`: It specifies port number.
|
43
|
-
* default: `10041`
|
44
|
-
* `real_host`: It specifies real groonga server's address. It is required.
|
45
|
-
* default: no default.
|
46
|
-
* `real_port`: It specifies real groonga server's port number.
|
47
|
-
* default: `10041`
|
48
|
-
* `emit_commands`: TODO
|
49
|
-
|
50
|
-
Here is an example:
|
51
|
-
|
52
|
-
<source>
|
53
|
-
type groonga
|
54
|
-
protocol http
|
55
|
-
bind 127.0.0.1
|
56
|
-
port 10041
|
57
|
-
real_host 192.168.0.1
|
58
|
-
real_port 10041
|
59
|
-
</source>
|
60
|
-
|
61
|
-
### The `groonga` output plugin
|
62
|
-
|
63
|
-
* `protocol`: It specifies protocol for sending groonga commands to groonga.
|
64
|
-
* available values: `http`, `gqtp` and `command`
|
65
|
-
* default: `http`
|
66
|
-
* For `http` and `gqtp` use:
|
67
|
-
* `host`: It specifies groonga server's address.
|
68
|
-
* default: `localhost`
|
69
|
-
* `port`: It specifies groonga server's port number.
|
70
|
-
* default: `10041`
|
71
|
-
* For `command` use:
|
72
|
-
* `groonga`: It specifies path of groonga command.
|
73
|
-
* default: `groonga`
|
74
|
-
* `database`: It specifies path of groonga database. It is required.
|
75
|
-
* default: no default.
|
76
|
-
* `arguments`: It specifies additional arguments for groonga command.
|
77
|
-
* default: no additional arguments.
|
78
|
-
|
79
|
-
<match groonga.command.*>
|
80
|
-
type groonga
|
81
|
-
protocol command
|
82
|
-
database /tmp/groonga/db
|
83
|
-
</match>
|
35
|
+
* [Configuration](doc/text/configuration.md)
|
36
|
+
([on the Web](http://groonga.org/fluent-plugin-groonga/en/file.configuration.html))
|
37
|
+
* [Constitution](doc/text/constitution.md)
|
38
|
+
([on the Web](http://groonga.org/fluent-plugin-groonga/en/file.constitution.html))
|
84
39
|
|
85
40
|
## Authors
|
86
41
|
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# @title Configuration
|
2
|
+
|
3
|
+
# Configuration
|
4
|
+
|
5
|
+
Fluent-plugin-groonga includes two fluentd plugins. They are the
|
6
|
+
`groonga` input plugin and the `groonga` output plugin. This documents
|
7
|
+
describes configuration parameters of them.
|
8
|
+
|
9
|
+
## The `groonga` input plugin
|
10
|
+
|
11
|
+
Here are available parameters:
|
12
|
+
|
13
|
+
* `protocol`: It specifies protocol for receiving groonga commands.
|
14
|
+
* available values: `http` and `gqtp`
|
15
|
+
* default: `http`
|
16
|
+
* `bind`: It specifies bind address.
|
17
|
+
* default: `0.0.0.0`
|
18
|
+
* `port`: It specifies port number.
|
19
|
+
* default: `10041`
|
20
|
+
* `real_host`: It specifies real groonga server's address. It is required.
|
21
|
+
* default: no default.
|
22
|
+
* `real_port`: It specifies real groonga server's port number.
|
23
|
+
* default: `10041`
|
24
|
+
* `emit_commands`: TODO
|
25
|
+
|
26
|
+
Here is an example:
|
27
|
+
|
28
|
+
<source>
|
29
|
+
type groonga
|
30
|
+
protocol http
|
31
|
+
bind 127.0.0.1
|
32
|
+
port 10041
|
33
|
+
real_host 192.168.0.1
|
34
|
+
real_port 10041
|
35
|
+
</source>
|
36
|
+
|
37
|
+
## The `groonga` output plugin
|
38
|
+
|
39
|
+
* `protocol`: It specifies protocol for sending groonga commands to groonga.
|
40
|
+
* available values: `http`, `gqtp` and `command`
|
41
|
+
* default: `http`
|
42
|
+
* For `http` and `gqtp` use:
|
43
|
+
* `host`: It specifies groonga server's address.
|
44
|
+
* default: `localhost`
|
45
|
+
* `port`: It specifies groonga server's port number.
|
46
|
+
* default: `10041`
|
47
|
+
* For `command` use:
|
48
|
+
* `groonga`: It specifies path of groonga command.
|
49
|
+
* default: `groonga`
|
50
|
+
* `database`: It specifies path of groonga database. It is required.
|
51
|
+
* default: no default.
|
52
|
+
* `arguments`: It specifies additional arguments for groonga command.
|
53
|
+
* default: no additional arguments.
|
54
|
+
|
55
|
+
Here is an example:
|
56
|
+
|
57
|
+
<match groonga.command.*>
|
58
|
+
type groonga
|
59
|
+
protocol command
|
60
|
+
database /tmp/groonga/db
|
61
|
+
</match>
|
@@ -0,0 +1,315 @@
|
|
1
|
+
# @title Constitution
|
2
|
+
|
3
|
+
# Constitution
|
4
|
+
|
5
|
+
You can chose some system constitutions to implemented replication
|
6
|
+
ready groonga system. This document describes some patterns.
|
7
|
+
|
8
|
+
Here are available patterns:
|
9
|
+
|
10
|
+
* Master slave replication
|
11
|
+
* Resending data to recovered slave
|
12
|
+
|
13
|
+
Here are unavailable patterns:
|
14
|
+
|
15
|
+
* Multi master replication
|
16
|
+
* Auto slave recovery
|
17
|
+
* Dynamic slave adding
|
18
|
+
* Failover
|
19
|
+
* No SPOF (Single Point of Failure) without downing service level
|
20
|
+
|
21
|
+
## Master slave replication
|
22
|
+
|
23
|
+
Master slave replication is available. This section describes how to
|
24
|
+
configure your system constitution.
|
25
|
+
|
26
|
+
### Small system
|
27
|
+
|
28
|
+
In small system, you just has two servers. One is the master groonga
|
29
|
+
server and the other is the slave groonga server. You send all update
|
30
|
+
commands (e.g. `table_create`, `column_create`, `load` and so on.) to
|
31
|
+
fluentd. In fluentd, the `groonga` input plugin receives commands from
|
32
|
+
client, passes through them to master groonga server and passes
|
33
|
+
through responses from master groonga server to client. The `groonga`
|
34
|
+
input plugin converts update commands to fluent messages when the
|
35
|
+
`groonga` input plugin passes through comamands and responses. The
|
36
|
+
fluent messages are sent to slave groonga server by the `groonga`
|
37
|
+
output plugin.
|
38
|
+
|
39
|
+
Here is a diagram of this constitution.
|
40
|
+
|
41
|
+
update update
|
42
|
+
and and
|
43
|
+
search +---------+ search +---------+
|
44
|
+
+--------+ <------> | fluentd | <------> | master |
|
45
|
+
| | +---------+ | groonga |
|
46
|
+
| client | update | +---------+
|
47
|
+
| | \_/
|
48
|
+
| | search +---------+
|
49
|
+
+--------+ <------> | slave |
|
50
|
+
| groonga |
|
51
|
+
+---------+
|
52
|
+
|
53
|
+
Fluentd should be placed at client or master groonga server. If you
|
54
|
+
have only one client that updates data, client side is reasonable. If
|
55
|
+
you have multiple clients that update data, master groonga server side
|
56
|
+
is reasonable.
|
57
|
+
|
58
|
+
You can use replication for high performance by providing search
|
59
|
+
service with multi servers. You can't use replication for high
|
60
|
+
availability. If master groonga server or fluentd is down, this system
|
61
|
+
can't update data. (Searching is still available because slabe groonga
|
62
|
+
server is alive.)
|
63
|
+
|
64
|
+
Here is an example configuration file:
|
65
|
+
|
66
|
+
# For master groonga server
|
67
|
+
<source>
|
68
|
+
type groonga
|
69
|
+
protocol gqtp # Or use the below line
|
70
|
+
# protocol http
|
71
|
+
bind 127.0.0.1 # For client side fluentd
|
72
|
+
# bind 192.168.0.1 # For master groonga server side fluentd
|
73
|
+
port 10041
|
74
|
+
real_host 192.168.29.1 # IP address of master groonga server
|
75
|
+
real_port 10041 # Port number of master groonga server
|
76
|
+
# real_port 20041 # Use different port number
|
77
|
+
# for master groonga server side fluentd
|
78
|
+
</source>
|
79
|
+
|
80
|
+
# For slave groonga server
|
81
|
+
<match groonga.command.*>
|
82
|
+
type groonga
|
83
|
+
protocol gqtp # Or use the below line
|
84
|
+
# protocol http # You can use different protocol for
|
85
|
+
# master groonga server and slave groonga server
|
86
|
+
host 192.168.29.29 # IP address of slave groonga server
|
87
|
+
port 10041 # Port number of slave groonga server
|
88
|
+
|
89
|
+
# Buffer
|
90
|
+
flush_interval 1s # Use small value for less delay replication
|
91
|
+
|
92
|
+
## Use the following configurations to support resending data to
|
93
|
+
## recovered slave groonga server. If you don't care about slave
|
94
|
+
## groonga server is down case, you don't need the following
|
95
|
+
## configuration.
|
96
|
+
|
97
|
+
## For supporting resending data after fluentd is restarted
|
98
|
+
# buffer_type file
|
99
|
+
# buffer_path /var/log/fluent/groonga.*.buffer
|
100
|
+
## Use large value if a record has many data in load command.
|
101
|
+
## A value in load command is a chunk.
|
102
|
+
# buffer_chunk_limit 256m
|
103
|
+
## Use large value if you want to support resending data after
|
104
|
+
## slave groonga server is down long time.
|
105
|
+
## 17: about 1.5day =
|
106
|
+
## ((2 ** 0) + (2 ** 1) + ... + (2 ** 17)) / 60.0 / 60.0 / 24.0
|
107
|
+
## (default)
|
108
|
+
## 18: about 3.0day = ((2 ** 0) + ... + (2 ** 18)) / ...
|
109
|
+
## 19: about 6.0day = ((2 ** 0) + ... + (2 ** 19)) / ...
|
110
|
+
# retry_limit 19
|
111
|
+
## Use large value if you load many records.
|
112
|
+
## A value in load command is a chunk.
|
113
|
+
# buffer_queue_limit 10000
|
114
|
+
</match>
|
115
|
+
|
116
|
+
#### How to recover from fluentd down
|
117
|
+
|
118
|
+
If fluentd is down, you just restart fluentd. Note that you may resend
|
119
|
+
the last command if fluentd is down while you are sending update
|
120
|
+
commands.
|
121
|
+
|
122
|
+
You cannot update data until fluentd is up.
|
123
|
+
|
124
|
+
#### How to recover from master groonga server down
|
125
|
+
|
126
|
+
Here are recover steps when master groonga server is down:
|
127
|
+
|
128
|
+
1. Stop fluentd.
|
129
|
+
2. Run `grndump /PATH/TO/SLAVE/GROONGA/SERVER/DB >
|
130
|
+
SLAVE_GROONGA_DUMP.grn` on slave groonga server host.
|
131
|
+
3. Run `groonga -n /PATH/TO/MASTER/GROONGA/SERVER/DB <
|
132
|
+
SLAVE_GROONGA_DUMP.grn` on master groonga server.
|
133
|
+
4. Run master groonga server.
|
134
|
+
5. Start fluentd.
|
135
|
+
|
136
|
+
You cannot update data until you finish to recover.
|
137
|
+
|
138
|
+
#### How to recover from slave groonga server down
|
139
|
+
|
140
|
+
Here are recover steps when slave groonga server is down:
|
141
|
+
|
142
|
+
1. Run `grndump /PATH/TO/MASTER/GROONGA/SERVER/DB >
|
143
|
+
MASTER_GROONGA_DUMP.grn` on master groonga server host.
|
144
|
+
2. Run `groonga -n /PATH/TO/SLAVE/GROONGA/SERVER/DB <
|
145
|
+
MASTER_GROONGA_DUMP.grn` on slave groonga server.
|
146
|
+
3. Run slave groonga server.
|
147
|
+
|
148
|
+
You can update data while you recover. If your system can't process
|
149
|
+
all search requests by only master groonga server, your system will be
|
150
|
+
down.
|
151
|
+
|
152
|
+
You need to recover slave groonga server before fluentd's buffer queue
|
153
|
+
is full (see `buffer_queue_limit`) or fluentd gives up retrying (see
|
154
|
+
`retry_limit`). Here are recover steps when you cannot recover slave
|
155
|
+
groonga server before those situations:
|
156
|
+
|
157
|
+
1. Stop fluentd.
|
158
|
+
2. Run `grndump /PATH/TO/MASTER/GROONGA/SERVER/DB >
|
159
|
+
MASTER_GROONGA_DUMP.grn` on master groonga server host.
|
160
|
+
3. Run `groonga -n /PATH/TO/SLAVE/GROONGA/SERVER/DB <
|
161
|
+
MASTER_GROONGA_DUMP.grn` on slave groonga server host.
|
162
|
+
4. Run slave groonga server.
|
163
|
+
5. Start fluentd.
|
164
|
+
|
165
|
+
You cannot update data until you finish to recover.
|
166
|
+
|
167
|
+
### Medium system
|
168
|
+
|
169
|
+
In medium system, you have three or more slave groonga servers. Fluentd
|
170
|
+
updates two or more slave groonga servers with the `copy` output
|
171
|
+
plugin and the `groonga` output plugin.
|
172
|
+
|
173
|
+
Here is a diagram of this constitution.
|
174
|
+
|
175
|
+
update update
|
176
|
+
and and
|
177
|
+
search +---------+ search +---------+
|
178
|
+
+--------+ <------> | fluentd | <------> | master |
|
179
|
+
| | +---------+ | groonga |
|
180
|
+
| client | +--------+ +---------+
|
181
|
+
| | |
|
182
|
+
+--------+ search +---------+ |
|
183
|
+
| | <------> | slave | <-+ update
|
184
|
+
| client | | groonga | |
|
185
|
+
| | +---------+ |
|
186
|
+
+--------+ search +---------+ |
|
187
|
+
| | <------> | slave | <-+ update
|
188
|
+
| client | | groonga | |
|
189
|
+
| | +---------+ |
|
190
|
+
+- ... -+ ... ... ...
|
191
|
+
|
192
|
+
Here is an example configuration file:
|
193
|
+
|
194
|
+
# For master groonga server
|
195
|
+
<source>
|
196
|
+
type groonga
|
197
|
+
protocol gqtp # Or use the below line
|
198
|
+
# protocol http
|
199
|
+
bind 127.0.0.1 # For client side fluentd
|
200
|
+
# bind 192.168.0.1 # For master groonga server side fluentd
|
201
|
+
port 10041
|
202
|
+
real_host 192.168.29.1 # IP address of master groonga server
|
203
|
+
real_port 10041 # Port number of master groonga server
|
204
|
+
# real_port 20041 # Use different port number
|
205
|
+
# for master groonga server side fluentd
|
206
|
+
</source>
|
207
|
+
|
208
|
+
# For slave groonga servers
|
209
|
+
<match groonga.command.*>
|
210
|
+
type copy
|
211
|
+
|
212
|
+
# The first slave groonga server
|
213
|
+
<store>
|
214
|
+
type groonga
|
215
|
+
protocol gqtp # Or use the below line
|
216
|
+
# protocol http # You can use different protocol for
|
217
|
+
# master groonga server and slave groonga server
|
218
|
+
host 192.168.29.2 # IP address of slave groonga server
|
219
|
+
port 10041 # Port number of slave groonga server
|
220
|
+
|
221
|
+
# Buffer
|
222
|
+
flush_interval 1s # Use small value for less delay replication
|
223
|
+
|
224
|
+
## Use the following configurations to support resending data to
|
225
|
+
## recovered slave groonga server. If you don't care about slave
|
226
|
+
## groonga server is down case, you don't need the following
|
227
|
+
## configuration.
|
228
|
+
|
229
|
+
## For supporting resending data after fluentd is restarted
|
230
|
+
# buffer_type file
|
231
|
+
# buffer_path /var/log/fluent/groonga.*.buffer
|
232
|
+
## Use large value if a record has many data in load command.
|
233
|
+
## A value in load command is a chunk.
|
234
|
+
# buffer_chunk_limit 256m
|
235
|
+
## Use large value if you want to support resending data after
|
236
|
+
## slave groonga server is down long time.
|
237
|
+
## 17: about 1.5day =
|
238
|
+
## ((2 ** 0) + (2 ** 1) + ... + (2 ** 17)) / 60.0 / 60.0 / 24.0
|
239
|
+
## (default)
|
240
|
+
## 18: about 3.0day = ((2 ** 0) + ... + (2 ** 18)) / ...
|
241
|
+
## 19: about 6.0day = ((2 ** 0) + ... + (2 ** 19)) / ...
|
242
|
+
# retry_limit 19
|
243
|
+
## Use large value if you load many records.
|
244
|
+
## A value in load command is a chunk.
|
245
|
+
# buffer_queue_limit 10000
|
246
|
+
</store>
|
247
|
+
|
248
|
+
# The second slave groonga server
|
249
|
+
<store>
|
250
|
+
type groonga
|
251
|
+
protocol gqtp # Or use the below line
|
252
|
+
# protocol http # You can use different protocol for
|
253
|
+
# master groonga server and slave groonga server
|
254
|
+
host 192.168.29.3 # IP address of slave groonga server
|
255
|
+
port 10041 # Port number of slave groonga server
|
256
|
+
|
257
|
+
# Buffer
|
258
|
+
# ...
|
259
|
+
</store>
|
260
|
+
|
261
|
+
# More slave groonga servers
|
262
|
+
# <store>
|
263
|
+
# type groonga
|
264
|
+
# ...
|
265
|
+
# </store>
|
266
|
+
</match>
|
267
|
+
|
268
|
+
TODO: ...
|
269
|
+
|
270
|
+
### Large system
|
271
|
+
|
272
|
+
In large system, you have two or more slave groonga server clusters.
|
273
|
+
Fluentd that connects with master groonga server updates two or more
|
274
|
+
fluentds that are in slave groonga server clusters with the `copy`
|
275
|
+
output plugin and the `forward` output plugin. A slave cluster has a
|
276
|
+
fluentd. Fluentd in slave groonga server clusters updates slave
|
277
|
+
groonga server in the same slave groonga server cluster by the `copy`
|
278
|
+
output plugin and `groonga` output plugin.
|
279
|
+
|
280
|
+
Here is a diagram of this constitution.
|
281
|
+
|
282
|
+
update update
|
283
|
+
and and
|
284
|
+
search +---------+ search +---------+
|
285
|
+
+--------+ <--------> | fluentd | <------> | master |
|
286
|
+
| | +---------+ | groonga |
|
287
|
+
| client | | +---------+
|
288
|
+
| | +------------------------------+
|
289
|
+
+--------+ +----------------------------------+ |
|
290
|
+
| | | slave cluster | |
|
291
|
+
| client | search | +---------+ update +---------+ | |
|
292
|
+
| | <------> | | slave | <------- | fluentd | <-+ update
|
293
|
+
+--------| | | groonga | +---------+ | |
|
294
|
+
| | | +---------+ +-----------+ | |
|
295
|
+
| client | search | +---------+ | | |
|
296
|
+
| | <------> | | slave | <-+ update | |
|
297
|
+
+--------| | | groonga | | | |
|
298
|
+
| | | +---------+ | | |
|
299
|
+
| ... | ... | ... ... | |
|
300
|
+
+----------------------------------+ |
|
301
|
+
+--------+ +----------------------------------+ |
|
302
|
+
| | | slave cluster | |
|
303
|
+
| client | search | +---------+ update +---------+ | |
|
304
|
+
| | <------> | | slave | <------- | fluentd | <-+ update
|
305
|
+
+--------| | | groonga | +---------+ | |
|
306
|
+
| | | +---------+ +-----------+ | |
|
307
|
+
| client | search | +---------+ | | |
|
308
|
+
| | <------> | | slave | <-+ update | |
|
309
|
+
+--------| | | groonga | | | |
|
310
|
+
| | | +---------+ | | |
|
311
|
+
| ... | ... | ... ... | |
|
312
|
+
+----------------------------------+ |
|
313
|
+
... ...
|
314
|
+
|
315
|
+
TODO: ...
|
data/doc/text/news.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
|
+
# @title News
|
2
|
+
|
1
3
|
# News
|
2
4
|
|
5
|
+
## 1.0.1: 2012-12-29
|
6
|
+
|
7
|
+
### Improvements
|
8
|
+
|
9
|
+
* Added more destructive emit commands ("delete", "register", "truncate").
|
10
|
+
* [out] Used close instead of sending "shutdown".
|
11
|
+
* Placed documents to http://groonga.org/fluent-plugin-groonga/en/.
|
12
|
+
* [doc] Updated documents:
|
13
|
+
* Added the documents of configuration and constitution.
|
14
|
+
* Added recover steps.
|
15
|
+
* Added documentation about master slave replication in
|
16
|
+
[small/medium/large] system.
|
17
|
+
|
3
18
|
## 1.0.0: 2012-11-29
|
4
19
|
|
5
20
|
The first release!!!
|
@@ -17,7 +17,7 @@
|
|
17
17
|
|
18
18
|
Gem::Specification.new do |spec|
|
19
19
|
spec.name = "fluent-plugin-groonga"
|
20
|
-
spec.version = "1.0.
|
20
|
+
spec.version = "1.0.1"
|
21
21
|
spec.authors = ["Kouhei Sutou"]
|
22
22
|
spec.email = ["kou@clear-code.com"]
|
23
23
|
spec.summary = "Fluentd plugin collection for groonga users"
|
@@ -26,9 +26,11 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.homepage = "https://github.com/groonga/fluent-plugin-groonga"
|
27
27
|
|
28
28
|
spec.files = ["README.md", "Gemfile", "#{spec.name}.gemspec"]
|
29
|
+
spec.files += [".yardopts"]
|
29
30
|
spec.files += Dir.glob("lib/**/*.rb")
|
30
31
|
spec.files += Dir.glob("sample/**/*")
|
31
32
|
spec.files += Dir.glob("doc/text/**/*")
|
33
|
+
spec.test_files += Dir.glob("test/**/*")
|
32
34
|
spec.require_paths = ["lib"]
|
33
35
|
|
34
36
|
spec.add_runtime_dependency("fluentd")
|
@@ -37,6 +39,8 @@ Gem::Specification.new do |spec|
|
|
37
39
|
|
38
40
|
spec.add_development_dependency("rake")
|
39
41
|
spec.add_development_dependency("bundler")
|
42
|
+
spec.add_development_dependency("packnga", ">= 0.9.6")
|
40
43
|
spec.add_development_dependency("test-unit")
|
41
44
|
spec.add_development_dependency("test-unit-notify")
|
45
|
+
spec.add_development_dependency("redcarpet")
|
42
46
|
end
|
@@ -16,7 +16,6 @@
|
|
16
16
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
17
|
|
18
18
|
require "fileutils"
|
19
|
-
require "cgi/util"
|
20
19
|
|
21
20
|
module Fluent
|
22
21
|
class GroongaOutput < BufferedOutput
|
@@ -127,7 +126,7 @@ module Fluent
|
|
127
126
|
|
128
127
|
def shutdown
|
129
128
|
return if @client.nil?
|
130
|
-
@client.
|
129
|
+
@client.close do
|
131
130
|
@loop.stop
|
132
131
|
end
|
133
132
|
@loop.run
|
data/test/run-test.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License version 2.1 as published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# This library is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# Lesser General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Lesser General Public
|
15
|
+
# License along with this library; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
|
+
|
18
|
+
# $VERBOSE = true
|
19
|
+
|
20
|
+
Thread.abort_on_exception = true
|
21
|
+
|
22
|
+
base_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
23
|
+
lib_dir = File.join(base_dir, "lib")
|
24
|
+
test_dir = File.join(base_dir, "test")
|
25
|
+
|
26
|
+
require "test-unit"
|
27
|
+
require "test/unit/notify"
|
28
|
+
|
29
|
+
Test::Unit::Priority.enable
|
30
|
+
|
31
|
+
$LOAD_PATH.unshift(lib_dir)
|
32
|
+
|
33
|
+
require "fluent/log"
|
34
|
+
$log = Fluent::Log.new($stdout, Fluent::Log::LEVEL_WARN)
|
35
|
+
|
36
|
+
Dir.glob("#{base_dir}/test/**/test{_,-}*.rb") do |file|
|
37
|
+
require file.sub(/\.rb$/, '')
|
38
|
+
end
|
39
|
+
|
40
|
+
ENV["TEST_UNIT_MAX_DIFF_TARGET_STRING_SIZE"] ||= "5000"
|
41
|
+
|
42
|
+
exit Test::Unit::AutoRunner.run
|
data/test/test_input.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License version 2.1 as published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# This library is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# Lesser General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Lesser General Public
|
15
|
+
# License along with this library; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
|
+
|
18
|
+
require "time"
|
19
|
+
require "cgi/util"
|
20
|
+
require "net/http"
|
21
|
+
require "webrick/config"
|
22
|
+
require "webrick/httpresponse"
|
23
|
+
|
24
|
+
require "fluent/test"
|
25
|
+
require "fluent/plugin/in_groonga"
|
26
|
+
|
27
|
+
require "http_parser"
|
28
|
+
|
29
|
+
class GroongaInputTest < Test::Unit::TestCase
|
30
|
+
setup
|
31
|
+
def setup_fluent
|
32
|
+
Fluent::Test.setup
|
33
|
+
@now = Time.parse("2012-10-26T08:45:42Z").to_i
|
34
|
+
Fluent::Engine.now = @now
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def create_driver
|
39
|
+
driver = Fluent::Test::InputTestDriver.new(Fluent::GroongaInput)
|
40
|
+
driver.configure(configuration)
|
41
|
+
driver
|
42
|
+
end
|
43
|
+
|
44
|
+
def configuration
|
45
|
+
<<-EOC
|
46
|
+
EOC
|
47
|
+
end
|
48
|
+
|
49
|
+
class HTTPTest < self
|
50
|
+
setup :before => :append
|
51
|
+
def setup_real_server
|
52
|
+
@real_host = "127.0.0.1"
|
53
|
+
@real_port = 29292
|
54
|
+
@real_server = TCPServer.new(@real_host, @real_port)
|
55
|
+
@repeater = nil
|
56
|
+
response_config = WEBrick::Config::HTTP.dup.update(:Logger => $log)
|
57
|
+
@real_response = WEBrick::HTTPResponse.new(response_config)
|
58
|
+
Thread.new do
|
59
|
+
@repeater = @real_server.accept
|
60
|
+
@real_server.close
|
61
|
+
parser = HTTP::Parser.new
|
62
|
+
parser.on_message_complete = lambda do
|
63
|
+
@real_response.send_response(@repeater)
|
64
|
+
@repeater.close
|
65
|
+
end
|
66
|
+
|
67
|
+
loop do
|
68
|
+
break if @repeater.closed?
|
69
|
+
data = @repeater.readpartial(4096)
|
70
|
+
break if data.nil?
|
71
|
+
parser << data
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
teardown
|
77
|
+
def teardown_real_server
|
78
|
+
@real_server.close unless @real_server.closed?
|
79
|
+
|
80
|
+
if @repeater and not @repeater.closed?
|
81
|
+
@repeater.close
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def setup
|
86
|
+
@host = "127.0.0.1"
|
87
|
+
@port = 2929
|
88
|
+
|
89
|
+
@driver = create_driver
|
90
|
+
@last_response = nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def configuration
|
94
|
+
<<-EOC
|
95
|
+
protocol http
|
96
|
+
bind #{@host}
|
97
|
+
port #{@port}
|
98
|
+
real_host #{@real_host}
|
99
|
+
real_port #{@real_port}
|
100
|
+
EOC
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_target_command
|
104
|
+
@driver.expect_emit("groonga.command.table_create",
|
105
|
+
@now,
|
106
|
+
{"name" => "Users"})
|
107
|
+
@driver.run do
|
108
|
+
get("/d/table_create", "name" => "Users")
|
109
|
+
assert_equal("200", @last_response.code)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_not_target_command
|
114
|
+
@driver.run do
|
115
|
+
get("/d/status")
|
116
|
+
assert_equal("200", @last_response.code)
|
117
|
+
end
|
118
|
+
assert_empty(@driver.emits)
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_load
|
122
|
+
json = <<-EOJ
|
123
|
+
[
|
124
|
+
{"name": "Alice"},
|
125
|
+
{"name": "Bob"}
|
126
|
+
]
|
127
|
+
EOJ
|
128
|
+
@driver.expect_emit("groonga.command.load",
|
129
|
+
@now,
|
130
|
+
{
|
131
|
+
"table" => "Users",
|
132
|
+
"values" => json,
|
133
|
+
})
|
134
|
+
|
135
|
+
@driver.run do
|
136
|
+
post("/d/load", json, "table" => "Users")
|
137
|
+
assert_equal("200", @last_response.code)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_not_command
|
142
|
+
@driver.run do
|
143
|
+
@real_response.status = 404
|
144
|
+
get("/index.html")
|
145
|
+
assert_equal("404", @last_response.code)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
def get(path, parameters={})
|
151
|
+
http = Net::HTTP.new(@host, @port)
|
152
|
+
response = http.get(build_path(path, parameters))
|
153
|
+
@last_response = response
|
154
|
+
response
|
155
|
+
end
|
156
|
+
|
157
|
+
def post(path, body, parameters={})
|
158
|
+
http = Net::HTTP.new(@host, @port)
|
159
|
+
response = http.post(build_path(path, parameters),
|
160
|
+
body,
|
161
|
+
{"Content-Type" => "application/json"})
|
162
|
+
@last_response = response
|
163
|
+
response
|
164
|
+
end
|
165
|
+
|
166
|
+
def build_path(path, parameters)
|
167
|
+
unless parameters.empty?
|
168
|
+
url_encoded_parameters = parameters.collect do |key, value|
|
169
|
+
"#{CGI.escape(key)}=#{CGI.escape(value)}"
|
170
|
+
end
|
171
|
+
path += "?" + url_encoded_parameters.join("&")
|
172
|
+
end
|
173
|
+
path
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
data/test/test_output.rb
ADDED
@@ -0,0 +1,213 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License version 2.1 as published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# This library is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# Lesser General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Lesser General Public
|
15
|
+
# License along with this library; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
|
+
|
18
|
+
require "time"
|
19
|
+
require "cgi/util"
|
20
|
+
require "net/http"
|
21
|
+
require "webrick/config"
|
22
|
+
require "webrick/httpresponse"
|
23
|
+
|
24
|
+
require "fluent/test"
|
25
|
+
require "fluent/plugin/out_groonga"
|
26
|
+
|
27
|
+
require "http_parser"
|
28
|
+
|
29
|
+
class GroongaOutputTest < Test::Unit::TestCase
|
30
|
+
setup
|
31
|
+
def setup_fluent
|
32
|
+
Fluent::Test.setup
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def create_driver(tag)
|
37
|
+
driver = Fluent::Test::BufferedOutputTestDriver.new(Fluent::GroongaOutput,
|
38
|
+
tag)
|
39
|
+
driver.configure(configuration)
|
40
|
+
driver
|
41
|
+
end
|
42
|
+
|
43
|
+
def configuration
|
44
|
+
<<-EOC
|
45
|
+
EOC
|
46
|
+
end
|
47
|
+
|
48
|
+
class HTTPTest < self
|
49
|
+
setup :before => :append
|
50
|
+
def setup_real_server
|
51
|
+
@real_host = "127.0.0.1"
|
52
|
+
@real_port = 29292
|
53
|
+
@real_server_pid = fork do
|
54
|
+
exit
|
55
|
+
real_server = TCPServer.new(@real_host, @real_port)
|
56
|
+
response_config = WEBrick::Config::HTTP.dup.update(:Logger => $log)
|
57
|
+
real_response = WEBrick::HTTPResponse.new(response_config)
|
58
|
+
request_headers = nil
|
59
|
+
request_body = ""
|
60
|
+
client = real_server.accept
|
61
|
+
real_server.close
|
62
|
+
parser = HTTP::Parser.new
|
63
|
+
parser.on_headers_complete = lambda do |headers|
|
64
|
+
request_headers = headers
|
65
|
+
end
|
66
|
+
parser.on_body = lambda do |chunk|
|
67
|
+
request_body << chunk
|
68
|
+
end
|
69
|
+
parser.on_message_complete = lambda do
|
70
|
+
real_response.send_response(client)
|
71
|
+
client.close
|
72
|
+
end
|
73
|
+
|
74
|
+
loop do
|
75
|
+
break if client.closed?
|
76
|
+
data = client.readpartial(4096)
|
77
|
+
break if data.nil?
|
78
|
+
parser << data
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
teardown
|
84
|
+
def teardown_real_server
|
85
|
+
Process.kill(:INT, @real_server_pid)
|
86
|
+
Process.kill(:KILL, @real_server_pid)
|
87
|
+
Process.waitpid(@real_server_pid)
|
88
|
+
end
|
89
|
+
|
90
|
+
def configuration
|
91
|
+
<<-EOC
|
92
|
+
protocol http
|
93
|
+
host #{@real_host}
|
94
|
+
port #{@real_port}
|
95
|
+
EOC
|
96
|
+
end
|
97
|
+
|
98
|
+
class CommandTest < self
|
99
|
+
def test_basic_command
|
100
|
+
driver = create_driver("groonga.command.table_create")
|
101
|
+
time = Time.parse("2012-10-26T08:45:42Z").to_i
|
102
|
+
driver.emit({"name" => "Users"}, time)
|
103
|
+
driver.run
|
104
|
+
# p @request_headers
|
105
|
+
# p @request_body
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class CommandLineTest < self
|
111
|
+
setup :before => :append
|
112
|
+
def setup_command
|
113
|
+
@temporary_directory = File.expand_path("tmp", File.dirname(__FILE__))
|
114
|
+
FileUtils.rm_rf(@temporary_directory)
|
115
|
+
FileUtils.mkdir_p(@temporary_directory)
|
116
|
+
|
117
|
+
@groonga_stub_path = File.join(@temporary_directory, "groonga")
|
118
|
+
@command_line_path = File.join(@temporary_directory, "command-line")
|
119
|
+
@input_path = File.join(@temporary_directory, "input")
|
120
|
+
@input_fd_path = File.join(@temporary_directory, "input-fd")
|
121
|
+
@output_fd_path = File.join(@temporary_directory, "output-fd")
|
122
|
+
@database_path = File.join(@temporary_directory, "database")
|
123
|
+
|
124
|
+
File.open(@groonga_stub_path, "w") do |groonga_stub|
|
125
|
+
groonga_stub.puts(<<-EOR)
|
126
|
+
#!#{Gem.ruby}
|
127
|
+
|
128
|
+
File.open(#{@command_line_path.inspect}, "a") do |file|
|
129
|
+
file.puts(ARGV)
|
130
|
+
end
|
131
|
+
|
132
|
+
input_fd = ARGV[ARGV.index("--input-fd") + 1]
|
133
|
+
input = IO.new(input_fd.to_i)
|
134
|
+
|
135
|
+
File.open(#{@input_fd_path.inspect}, "a") do |file|
|
136
|
+
file.print(input_fd)
|
137
|
+
end
|
138
|
+
|
139
|
+
File.open(#{@input_path.inspect}, "a") do |file|
|
140
|
+
input.each_line do |line|
|
141
|
+
file.print(line)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
output_fd = ARGV[ARGV.index("--output-fd") + 1]
|
146
|
+
output = IO.new(output_fd.to_i)
|
147
|
+
|
148
|
+
File.open(#{@output_fd_path.inspect}, "a") do |file|
|
149
|
+
file.print(output_fd)
|
150
|
+
end
|
151
|
+
|
152
|
+
output.puts("done")
|
153
|
+
output.flush
|
154
|
+
EOR
|
155
|
+
end
|
156
|
+
FileUtils.chmod(0755, @groonga_stub_path)
|
157
|
+
|
158
|
+
FileUtils.touch(@command_line_path)
|
159
|
+
FileUtils.touch(@input_path)
|
160
|
+
end
|
161
|
+
|
162
|
+
teardown
|
163
|
+
def teardown_command
|
164
|
+
FileUtils.rm_rf(@temporary_directory)
|
165
|
+
end
|
166
|
+
|
167
|
+
def configuration
|
168
|
+
<<-EOC
|
169
|
+
protocol command
|
170
|
+
groonga #{@groonga_stub_path}
|
171
|
+
database #{@database_path}
|
172
|
+
EOC
|
173
|
+
end
|
174
|
+
|
175
|
+
private
|
176
|
+
def actual_command_line
|
177
|
+
File.read(@command_line_path).split(/\n/)
|
178
|
+
end
|
179
|
+
|
180
|
+
def actual_input
|
181
|
+
File.read(@input_path)
|
182
|
+
end
|
183
|
+
|
184
|
+
def actual_input_fd
|
185
|
+
File.read(@input_fd_path)
|
186
|
+
end
|
187
|
+
|
188
|
+
def actual_output_fd
|
189
|
+
File.read(@output_fd_path)
|
190
|
+
end
|
191
|
+
|
192
|
+
class CommandTest < self
|
193
|
+
def test_basic_command
|
194
|
+
driver = create_driver("groonga.command.table_create")
|
195
|
+
time = Time.parse("2012-10-26T08:45:42Z")
|
196
|
+
driver.emit({"name" => "Users"}, time)
|
197
|
+
driver.run
|
198
|
+
assert_equal([
|
199
|
+
[
|
200
|
+
"--input-fd", actual_input_fd,
|
201
|
+
"--output-fd", actual_output_fd,
|
202
|
+
"-n", @database_path,
|
203
|
+
],
|
204
|
+
"/d/table_create?name=Users\n",
|
205
|
+
],
|
206
|
+
[
|
207
|
+
actual_command_line,
|
208
|
+
actual_input,
|
209
|
+
])
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-groonga
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fluentd
|
@@ -91,6 +91,22 @@ dependencies:
|
|
91
91
|
- - ! '>='
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: packnga
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 0.9.6
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 0.9.6
|
94
110
|
- !ruby/object:Gem::Dependency
|
95
111
|
name: test-unit
|
96
112
|
requirement: !ruby/object:Gem::Requirement
|
@@ -123,6 +139,22 @@ dependencies:
|
|
123
139
|
- - ! '>='
|
124
140
|
- !ruby/object:Gem::Version
|
125
141
|
version: '0'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: redcarpet
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ! '>='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ! '>='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
126
158
|
description: Groonga users can replicate their data by fluent-plugin-groonga
|
127
159
|
email:
|
128
160
|
- kou@clear-code.com
|
@@ -133,13 +165,19 @@ files:
|
|
133
165
|
- README.md
|
134
166
|
- Gemfile
|
135
167
|
- fluent-plugin-groonga.gemspec
|
168
|
+
- .yardopts
|
136
169
|
- lib/fluent/plugin/out_groonga.rb
|
137
170
|
- lib/fluent/plugin/in_groonga.rb
|
138
|
-
- sample/http.conf
|
139
|
-
- sample/command.conf
|
140
171
|
- sample/gqtp.conf
|
172
|
+
- sample/command.conf
|
173
|
+
- sample/http.conf
|
141
174
|
- doc/text/news.md
|
175
|
+
- doc/text/constitution.md
|
142
176
|
- doc/text/lgpl-2.1.txt
|
177
|
+
- doc/text/configuration.md
|
178
|
+
- test/run-test.rb
|
179
|
+
- test/test_input.rb
|
180
|
+
- test/test_output.rb
|
143
181
|
homepage: https://github.com/groonga/fluent-plugin-groonga
|
144
182
|
licenses: []
|
145
183
|
post_install_message:
|
@@ -152,17 +190,26 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
152
190
|
- - ! '>='
|
153
191
|
- !ruby/object:Gem::Version
|
154
192
|
version: '0'
|
193
|
+
segments:
|
194
|
+
- 0
|
195
|
+
hash: -1000993838467277328
|
155
196
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
156
197
|
none: false
|
157
198
|
requirements:
|
158
199
|
- - ! '>='
|
159
200
|
- !ruby/object:Gem::Version
|
160
201
|
version: '0'
|
202
|
+
segments:
|
203
|
+
- 0
|
204
|
+
hash: -1000993838467277328
|
161
205
|
requirements: []
|
162
206
|
rubyforge_project:
|
163
207
|
rubygems_version: 1.8.23
|
164
208
|
signing_key:
|
165
209
|
specification_version: 3
|
166
210
|
summary: Fluentd plugin collection for groonga users
|
167
|
-
test_files:
|
211
|
+
test_files:
|
212
|
+
- test/run-test.rb
|
213
|
+
- test/test_input.rb
|
214
|
+
- test/test_output.rb
|
168
215
|
has_rdoc:
|