Current section
Files
Jump to
Current section
Files
README.md
# FakeRiak
A small tool that fakes several key-value services on TCP ports, all backed by a
single in-memory store. It speaks four wire protocols so you can point real
clients at it:
| Endpoint | Protocol | Buckets? | Default port |
| --------- | ----------------------- | ---------- | ------------- |
| Riak KV | Riak HTTP + PBC APIs | bucketed | 8098 and 8087 |
| Redis | RESP | bucketless | 6379 |
| etcd | etcd v2 HTTP/JSON API | bucketless | 2379 |
| memcached | memcached text protocol | bucketless | 11211 |
## Usage
The simplest way to start using `fake_riak` is to install it on your machine
with the following command:
```console
mix escript.install hex fake_riak
```
This will download from Hex and then install the `fake_riak` script globally.
You can verify that the script is installed by executing `mix escript`. Open a
terminal and start it, for example:
```console
fake_riak --riak 10018 --verbose
```
This will listen for incoming Riak KV requests on the loopback interface at
port 10018 (127.0.0.1:10018), and print information about the requests as
they hit the service.
See `fake_riak --help` for more detailed information about how to use the tool.
## Disclaimer
This software is not meant to run in production, handle high load, or be
accessed by real clients (even though you can open it up to other hosts on
the local network with `--host 0.0.0.0`). It's a tool for testing, debugging,
and developing locally, letting you avoid installing heavy or
hard-to-configure services like Riak.
## Build
Build a single self-contained executable if you've downloaded the source code:
```console
$ mix escript.build
```
This produces a `fake_riak` script in the root of the source tree that you can
copy anywhere on your system.
## Run
Enable one or more endpoints by passing its flag. Each takes an optional port;
without one it uses its well-known default(s):
```console
$ ./fake_riak --riak --redis # Riak on 8098 and 8087, Redis on 6379
$ ./fake_riak --etcd 3000 # etcd on port 3000
$ ./fake_riak --riak=8100 --memcached # equals form works too
```
A flag may also be repeated (`--riak 8098 --riak 8099`), or take several ports
at once as a comma-separated list and/or a `first..last` range:
```console
$ ./fake_riak --riak 10012,10013,10014 # three Riak listeners
$ ./fake_riak --etcd 6700..6705 # six etcd listeners, 6700-6705
$ ./fake_riak --riak 8098,9000..9002 # lists and ranges can be mixed
```
At least one endpoint must be enabled. By default it binds `127.0.0.1`; pass
`--host 0.0.0.0` to listen on all interfaces. Press **Ctrl-C** to stop.
All endpoints enabled in the same `fake_riak` process share its internal
in-memory key-value store. The bucketless services — Redis, etcd, and
memcached — also share one keyspace, so you can set a key through memcached
and read it through etcd or Redis. Riak uses the bucketed part of the store,
where keys remain scoped to their buckets. If services need isolated data,
start a separate `fake_riak` instance for each service or isolation boundary.
Options:
| Flag | Description |
| ------------------- | -------------------------------------------------- |
| `--riak [PORT]` | Enable the Riak KV HTTP + PBC APIs (default 8098 and 8087) |
| `--etcd [PORT]` | Enable the etcd v2 HTTP/JSON API (default 2379) |
| `--redis [PORT]` | Enable the Redis RESP protocol (default 6379) |
| `--memcached [PORT]`| Enable the memcached text protocol (default 11211) |
| `--host HOST` | Interface to bind (default `127.0.0.1`) |
| `--tls-cert PATH` | PEM cert for TLS (requires `--tls-key`) |
| `--tls-key PATH` | PEM private key for TLS (requires `--tls-cert`) |
| `--verbose` | Log every get/put/del (API, bucket, key, value) |
| `--debug` | Log every byte received/sent and how it was parsed, plus TLS handshake detail |
| `--version` | Print the version and exit |
| `--help` | Print usage and exit |
Every `--riak` port serves both the Riak HTTP API and the Riak Protocol
Buffers (PBC) API, detected per connection, so there is no separate PBC flag —
a single port is enough for either kind of client. A bare `--riak` (no port
given) still opens both of Riak's conventional ports, 8098 (HTTP) and 8087
(PBC), so clients that assume the default port for their protocol find it
there without any extra flags.
Every endpoint silently accepts both plain TCP and TLS on the same port — no
extra flag needed to turn TLS on. Without `--tls-cert`/`--tls-key` it
terminates TLS with an ephemeral self-signed certificate generated on
startup, so clients need to skip certificate verification (this is a fake
service, not a real CA-backed one).
When `--tls-cert`/`--tls-key` are given, they're validated up front — read,
checked for expiry, and run through an actual loopback TLS handshake — so a
bad pair (mismatched key, expired cert, garbled PEM, password-protected key)
is a clear startup error instead of every client's handshake silently
closing. If a client still reports something like `handshake failed: :close`
and startup didn't complain, rerun with `--debug` to see the exact bytes and
handshake outcome for that connection.
## Talk to it
```console
# Riak (bucketed, HTTP)
$ curl -X PUT -d 'meow' http://127.0.0.1:8098/buckets/animals/keys/cat
$ curl http://127.0.0.1:8098/buckets/animals/keys/cat # -> meow
# Riak (bucketed, PBC — an RpbPingReq on the same port)
$ printf '\x00\x00\x00\x01\x01' | nc -q1 127.0.0.1 8098 | xxd # -> 00000001 02
# etcd (bucketless, v2 HTTP/JSON; requires etcdctl v3.4 or earlier)
$ export ETCDCTL_API=2
$ etcdctl --endpoints=http://127.0.0.1:2379 set /message hello # -> hello
$ etcdctl --endpoints=http://127.0.0.1:2379 get /message # -> hello
# Redis (bucketless, RESP)
$ redis-cli -p 6379 set foo bar
$ redis-cli -p 6379 get foo # -> "bar"
# memcached (bucketless, text)
$ printf 'set greeting 0 0 5\r\nhello\r\nget greeting\r\n' | nc 127.0.0.1 11211
```
## Notes / limitations
These are deliberately faithful-enough fakes, not full servers:
* **memcached** accepts the `flags`/`exptime` on storage commands but does not
persist them, so `get` always reports flags of `0` and keys never expire.
`add`/`replace`/`append`/`prepend` behave properly, but the CAS value that
`gets` reports is a hash of the value and the `cas` command itself is not
implemented.
* **Redis** accepts the extra `SET` options (`NX`, `XX`, `EX`, ...) but ignores
them — `SET` always stores and replies `OK`.
* **etcd** implements the v2 (HTTP/JSON) API, not the v3 (gRPC) API; indices are
synthetic.
* **Riak** speaks both the HTTP API and the Protocol Buffers (PBC) API on every
`--riak` port (PBC: ping, get, put, delete, server info, and the
`RpbStartTls` in-band TLS upgrade). Vector clocks are a static opaque token,
and siblings, 2i, bucket types/properties, and search are not implemented.
## Trademarks
Riak, Redis, etcd, and memcached are trademarks of their respective owners. This
project is an independent, unofficial testing tool. It is not affiliated with,
sponsored by, or endorsed by any of those projects — it merely speaks their wire
protocols so real clients can talk to it.