Git Product home page Git Product logo

diffy's Introduction

Twitter has decided to archive this project, as it was built on our outdated tech stack, making it unpractical to maintain it in its current form. Furthermore, we are reinventing in this space internally to accommodate newer use-cases for validating our services. As we mature these new approaches, we will reevaluate how and when to re-release these new solutions as open source software. Thank you for your understanding. We won't be accepting pull requests or responding to issues for this project anymore.

Note that @puneetkhanduri, this project's original author and a former Twitter employee maintains their own version of this project, called Opendiffy.

Diffy

GitHub license Build status Coverage status Project status Gitter Maven Central

What is Diffy?

Diffy finds potential bugs in your service using running instances of your new code and your old code side by side. Diffy behaves as a proxy and multicasts whatever requests it receives to each of the running instances. It then compares the responses, and reports any regressions that may surface from those comparisons. The premise for Diffy is that if two implementations of the service return “similar” responses for a sufficiently large and diverse set of requests, then the two implementations can be treated as equivalent and the newer implementation is regression-free. For a more detailed analysis of Diffy checkout this blogpost.

How does Diffy work?

Diffy acts as a proxy that accepts requests drawn from any source that you provide and multicasts each of those requests to three different service instances:

  1. A candidate instance running your new code
  2. A primary instance running your last known-good code
  3. A secondary instance running the same known-good code as the primary instance

As Diffy receives a request, it is multicast and sent to your candidate, primary, and secondary instances. When those services send responses back, Diffy compares those responses and looks for two things:

  1. Raw differences observed between the candidate and primary instances.
  2. Non-deterministic noise observed between the primary and secondary instances. Since both of these instances are running known-good code, you should expect responses to be in agreement. If not, your service may have non-deterministic behavior, which is to be expected. Diffy Topology

Diffy measures how often primary and secondary disagree with each other vs. how often primary and candidate disagree with each other. If these measurements are roughly the same, then Diffy determines that there is nothing wrong and that the error can be ignored.

How to get started?

Running the example

The example.sh script included here builds and launches example servers as well as a diffy instance. Verify that the following ports are available (9000, 9100, 9200, 8880, 8881, & 8888) and run ./example/run.sh start.

Once your local Diffy instance is deployed, you send it a few requests like curl --header "Canonical-Resource: Json" localhost:8880/json?Twitter. You can then go to your browser at http://localhost:8888 to see what the differences across our example instances look like.

Digging deeper

That was cool but now you want to compare old and new versions of your own service. Here’s how you can start using Diffy to compare three instances of your service:

  1. Deploy your old code to localhost:9990. This is your primary.

  2. Deploy your old code to localhost:9991. This is your secondary.

  3. Deploy your new code to localhost:9992. This is your candidate.

  4. Download the latest Diffy binary from maven central or build your own from the code using ./sbt assembly.

  5. Run the Diffy jar with following command line arguments:

    java -jar diffy-server.jar \
    -candidate=localhost:9992 \
    -master.primary=localhost:9990 \
    -master.secondary=localhost:9991 \
    -service.protocol=http \
    -serviceName=My-Service \
    -proxy.port=:8880 \
    -admin.port=:8881 \
    -http.port=:8888 \
    -rootUrl='localhost:8888'
    
  6. Send a few test requests to your Diffy instance on its proxy port:

    curl localhost:8880/your/application/route?with=queryparams
    
  7. Watch the differences show up in your browser at http://localhost:8888.

Using Diffy with Docker

You can pull the official docker image with docker pull diffy/diffy

And run it with

docker run -ti \
  -p 8880:8880 -p 8881:8881 -p 8888:8888 \
  diffy/diffy \
    -candidate=localhost:9992 \
    -master.primary=localhost:9990 \
    -master.secondary=localhost:9991 \
    -service.protocol=http \
    -serviceName="Test-Service" \
    -proxy.port=:8880 \
    -admin.port=:8881 \
    -http.port=:8888 \
    -rootUrl=localhost:8888

You should now be able to point to:

To build from source you can run docker build -t diffy .

FAQ's

For safety reasons POST, PUT, DELETE are ignored by default . Add -allowHttpSideEffects=true to your command line arguments to enable these verbs.

HTTPS

If you are trying to run Diffy over a HTTPS API, the config required is:

-service.protocol=https

And in case of the HTTPS port be different than 443:

-https.port=123

License

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this software except in compliance with the License.

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

diffy's People

Contributors

alanbato avatar alexshadow007 avatar apatil-twitter avatar bjaglin avatar caniszczyk avatar excavader avatar gb avatar khanduri avatar puneetkhanduri avatar radarhere avatar thomaska avatar travisbrown avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

diffy's Issues

Rest ShapeShifter throws exception in docker-compose

I try to setup the example project with docker-compose. All docker images start up correctly, but the rest shapeshifter API throws an exception for the basic curl call

curl http://localhost:31900/endpoint

Results in

primary_1    | 2016-05-12 17:29:04 - NoMethodError - undefined method `response_headers' for #<Endpointprimary:0x0055fd3e0bf108>
primary_1    | Did you mean?  response_sleep:
primary_1    |  /usr/local/bundle/gems/rest_shifter-0.0.28/lib/rest_shifter/shifter.rb:56:in `block in <class:Shifter>'
primary_1    |  /usr/local/bundle/gems/rest_shifter-0.0.28/lib/rest_shifter/shifter.rb:41:in `block (2 levels) in build_services'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1611:in `call'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1611:in `block in compile!'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:975:in `block (3 levels) in route!'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:994:in `route_eval'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:975:in `block (2 levels) in route!'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1015:in `block in process_route'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1013:in `catch'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1013:in `process_route'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:973:in `block in route!'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:972:in `each'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:972:in `route!'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1085:in `block in dispatch!'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1067:in `block in invoke'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1067:in `catch'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1067:in `invoke'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1082:in `dispatch!'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:907:in `block in call!'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1067:in `block in invoke'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1067:in `catch'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1067:in `invoke'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:907:in `call!'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:895:in `call'
primary_1    |  /usr/local/bundle/gems/rack-protection-1.5.3/lib/rack/protection/xss_header.rb:18:in `call'
primary_1    |  /usr/local/bundle/gems/rack-protection-1.5.3/lib/rack/protection/path_traversal.rb:16:in `call'
primary_1    |  /usr/local/bundle/gems/rack-protection-1.5.3/lib/rack/protection/json_csrf.rb:18:in `call'
primary_1    |  /usr/local/bundle/gems/rack-protection-1.5.3/lib/rack/protection/base.rb:49:in `call'
primary_1    |  /usr/local/bundle/gems/rack-protection-1.5.3/lib/rack/protection/base.rb:49:in `call'
primary_1    |  /usr/local/bundle/gems/rack-protection-1.5.3/lib/rack/protection/frame_options.rb:31:in `call'
primary_1    |  /usr/local/bundle/gems/rack-1.6.4/lib/rack/nulllogger.rb:9:in `call'
primary_1    |  /usr/local/bundle/gems/rack-1.6.4/lib/rack/head.rb:13:in `call'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/show_exceptions.rb:25:in `call'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:182:in `call'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:2013:in `call'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1487:in `block in call'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1787:in `synchronize'
primary_1    |  /usr/local/bundle/gems/sinatra-1.4.7/lib/sinatra/base.rb:1487:in `call'
primary_1    |  /usr/local/bundle/gems/rack-1.6.4/lib/rack/handler/webrick.rb:88:in `service'
primary_1    |  /usr/local/lib/ruby/2.3.0/webrick/httpserver.rb:140:in `service'
primary_1    |  /usr/local/lib/ruby/2.3.0/webrick/httpserver.rb:96:in `run'
primary_1    |  /usr/local/lib/ruby/2.3.0/webrick/server.rb:296:in `block in start_thread'
primary_1    | 172.17.0.5 - - [12/May/2016:17:29:04 UTC] "GET /endpoint HTTP/1.1" 500 3530
primary_1    | - -> /endpoint

in the docker logs.

java.lang.NoClassDefFoundError: scala/reflect/internal/Trees

vagrant@precise64:~/diffy-1.0.0$ ./sbt assembly
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=1024m; support was removed in 8.0
java.lang.NoClassDefFoundError: scala/reflect/internal/Trees
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at xsbt.boot.Pre$.xsbt$boot$Pre$$classMissing$1(Pre.scala:66)
at xsbt.boot.Pre$$anonfun$getMissing$1.apply(Pre.scala:67)
at scala.collection.TraversableLike$$anonfun$filter$1.apply(TraversableLike.scala:264)
at scala.collection.immutable.List.foreach(List.scala:318)
at org.apache.ivy.core.RelativeUrlResolver.filter(RelativeUrlResolver.java:263)
at scala.collection.AbstractTraversable.filter(Traversable.scala:105)
at xsbt.boot.Pre$.getMissing$d83f809$3a8a6f87(Pre.scala:67)
at xsbt.boot.Launch.checkLoader$2accd70c(Launch.scala:185)
at xsbt.boot.Launch.xsbt$boot$Launch$$provider$1(Launch.scala:249)
at xsbt.boot.Launch$$anonfun$xsbt$boot$Launch$$getScalaProvider0$2.apply(Launch.scala:252)
at xsbt.boot.Launch$$anonfun$xsbt$boot$Launch$$getScalaProvider0$2.apply(Launch.scala:251)
at scala.Option.flatMap(Option.scala:170)
at xsbt.boot.Launch.xsbt$boot$Launch$$getScalaProvider0(Launch.scala:251)
at xsbt.boot.Launch$$anon$3.call(Launch.scala:240)
at xsbt.boot.Locks$GlobalLock.withLock(Locks.scala:45)
at xsbt.boot.Locks$.apply0(Locks.scala:31)
at xsbt.boot.Locks$.apply(Locks.scala:28)
at xsbt.boot.Launch.locked(Launch.scala:238)
at xsbt.boot.Launch.getScalaProvider(Launch.scala:240)
at xsbt.boot.Launch$$anonfun$1.apply(Launch.scala:141)
at xsbt.boot.Cache.newEntry(Cache.scala:16)
at xsbt.boot.Cache.apply(Cache.scala:11)
at xsbt.boot.Launch.getScala(Launch.scala:144)
at xsbt.boot.Launch.getScala(Launch.scala:143)
at xsbt.boot.Launch.xsbt$boot$Launch$$getAppProvider0(Launch.scala:219)
at xsbt.boot.Launch$$anon$2.call(Launch.scala:196)
at xsbt.boot.Locks$GlobalLock.withChannel$1(Locks.scala:93)
at xsbt.boot.Locks$GlobalLock.xsbt$boot$Locks$GlobalLock$$withChannelRetries$1(Locks.scala:78)
at xsbt.boot.Locks$GlobalLock$$anonfun$withFileLock$1.apply(Locks.scala:97)
at xsbt.boot.Using$.withResource(Using.scala:10)
at xsbt.boot.Using$.apply(Using.scala:9)
at xsbt.boot.Locks$GlobalLock.ignoringDeadlockAvoided(Locks.scala:58)
at xsbt.boot.Locks$GlobalLock.withLock(Locks.scala:48)
at xsbt.boot.Locks$.apply0(Locks.scala:31)
at xsbt.boot.Locks$.apply(Locks.scala:28)
at xsbt.boot.Launch.locked(Launch.scala:238)
at xsbt.boot.Launch.app(Launch.scala:147)
at xsbt.boot.Launch.app(Launch.scala:145)
at xsbt.boot.Launch$.run(Launch.scala:102)
at xsbt.boot.Launch$$anonfun$apply$1.apply(Launch.scala:35)
at xsbt.boot.Launch$.launch(Launch.scala:117)
at xsbt.boot.Launch$.apply(Launch.scala:18)
at xsbt.boot.Boot$.runImpl(Boot.scala:41)
at xsbt.boot.Boot$.main(Boot.scala:17)
at xsbt.boot.Boot.main(Boot.scala)
Caused by: java.lang.ClassNotFoundException: scala.reflect.internal.Trees
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 69 more
Error during sbt execution: java.lang.NoClassDefFoundError: scala/reflect/internal/Trees

proxy does not react to curl request

I have installed diffy and succesfully ran the example in the example directory. Now I try to run it manually, but the diffy proxy does not forward a request to the candidate, primary and secondairy servers.

I have started three services, listening on localhost, ports 2345, 2346 and 2347. When I start the services by running curl, I get the expected json back from them. Then I start the diffy jar, when it is running, I do a curl request to the configured proxy port, but there is no output from the diffy jar run. It seems the requests are not noticed.

script:
java -jar ./target/scala-2.11/diffy-server.jar
-candidate=localhost:2347
-master.primary=localhost:2345
-master.secondary=localhost:2346
-service.protocol=http
-serviceName=genereer
-proxy.port=:31900
-admin.port=:8881
-http.port=:8888
-rootUrl='localhost:8888'

output from script:
ruud@stretchSZ sh diff2.sh
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
I 1113 13:49:05.087 THREAD1: HttpMuxer[/admin/metrics.json] = com.twitter.finagle.stats.MetricsExporter()
I 1113 13:49:05.126 THREAD1: HttpMuxer[/admin/per_host_metrics.json] = com.twitter.finagle.stats.HostMetricsExporter()
I 1113 13:49:05.178 THREAD1: /admin => com.twitter.server.handler.SummaryHandler
I 1113 13:49:05.179 THREAD1: /admin/server_info => com.twitter.finagle.Filter$$anon$2
I 1113 13:49:05.179 THREAD1: /admin/contention => com.twitter.finagle.Filter$$anon$2
I 1113 13:49:05.180 THREAD1: /admin/threads => com.twitter.server.handler.ThreadsHandler
I 1113 13:49:05.181 THREAD1: /admin/threads.json => com.twitter.server.handler.ThreadsHandler
I 1113 13:49:05.182 THREAD1: /admin/announcer => com.twitter.finagle.Filter$$anon$2
I 1113 13:49:05.183 THREAD1: /admin/dtab => com.twitter.finagle.Filter$$anon$2
I 1113 13:49:05.183 THREAD1: /admin/pprof/heap => com.twitter.server.handler.HeapResourceHandler
I 1113 13:49:05.184 THREAD1: /admin/pprof/profile => com.twitter.server.handler.ProfileResourceHandler
I 1113 13:49:05.184 THREAD1: /admin/pprof/contention => com.twitter.server.handler.ProfileResourceHandler
I 1113 13:49:05.185 THREAD1: /admin/ping => com.twitter.server.handler.ReplyHandler
I 1113 13:49:05.185 THREAD1: /admin/shutdown => com.twitter.server.handler.ShutdownHandler
I 1113 13:49:05.185 THREAD1: /admin/tracing => com.twitter.server.handler.TracingHandler
I 1113 13:49:05.186 THREAD1: /admin/events => com.twitter.server.handler.EventsHandler
I 1113 13:49:05.186 THREAD1: /admin/logging => com.twitter.server.handler.LoggingHandler
I 1113 13:49:05.187 THREAD1: /admin/metrics => com.twitter.server.handler.MetricQueryHandler
I 1113 13:49:05.187 THREAD1: /admin/clients/ => com.twitter.server.handler.ClientRegistryHandler
I 1113 13:49:05.187 THREAD1: /admin/servers/ => com.twitter.server.handler.ServerRegistryHandler
I 1113 13:49:05.188 THREAD1: /admin/files/ => com.twitter.server.handler.ResourceHandler
I 1113 13:49:05.188 THREAD1: /admin/registry.json => com.twitter.server.handler.RegistryHandler
I 1113 13:49:05.189 THREAD1: Serving admin http on 0.0.0.0/0.0.0.0:8881
I 1113 13:49:05.212 THREAD1: Finagle version 6.28.0 (rev=de123b8f9d074c4e345ebd67e1a0e870bb921544) built at 20150827-162434
I 1113 13:49:05.890 THREAD1: networkaddress.cache.ttl is not set, DNS cache refresh turned off
I 1113 13:49:06.209 THREAD1: Tracer: com.twitter.finagle.zipkin.thrift.SamplingTracer
I 1113 13:49:06.515 THREAD1: zipkin-tracer resolved to Addr.Bound, current size=1
I 1113 13:49:06.516 THREAD1: candidate resolved to Addr.Bound, current size=2
I 1113 13:49:06.517 THREAD1: primary resolved to Addr.Bound, current size=2
I 1113 13:49:06.517 THREAD1: secondary resolved to Addr.Bound, current size=2
I 1113 13:49:06.625 THREAD1: Scheduling com.twitter.diffy.workflow.FunctionalReport at 2017-11-13 13:49:06 +0000

Commands:
ruud@stretchSZ curl localhost:2347/generate
{"action":"genereer","counter":20,"timestamp":"2017-11-13 15:07:01 +0100"}% ruud@stretchSZ curl localhost:2346/generate
{"action":"generate","counter":9,"timestamp":"2017-11-13 15:07:08 +0100"}% ruud@stretchSZ curl localhost:2345/generate
{"action":"generate","counter":10,"timestamp":"2017-11-13 15:07:12 +0100"}% ruud@stretchSZ curl localhost:8880/generate
curl: (7) Failed to connect to localhost port 8880: Connection refused
[1] 14586 exit 7 curl localhost:8880/generate
ruud@stretchSZ curl localhost:31900/generate

I get no output from the last command and there is no output from the java command in diff2.sh.

What am I doing wrong?

thanks in advance, RUud

Add protobuf support to Diffy

diffy is a regression detection system for thrift and http services, so I want it for protobuffer, do I need other? Thanks.

New release of diffy?

Hey!

Can we get a more recent release of diffy? Seems it's not been released in 2yrs. Is there a threshold (features, etc) that we need before a release?

Are posts supported?

The examples at the minute are all Http GETS.

Does Diffy currently support posts?

I've tried sending a few in but it doesn't seem to be acknowledged by Diffy as I can't see the post being forwarded on to the service nor any results entered?

I've tried adding the Canonical-Resource header as well but with no luck so far

curl --header "Canonical-Resource: Html" -H "Content-Type: application/json" -X POST -d '{"foo":"bar"}' http://localhost:8880

Is my request at the minute or a scaled down version. Probably doing something stupid!

Should the deployments be only localhost

Hi,
We are planning on using diffy for regression testing of our production services.

From the readme doc, the script for the diffy -

java -jar diffy-server.jar
-candidate=localhost:9992
-master.primary=localhost:9990
-master.secondary=localhost:9991
-service.protocol=http
-serviceName=My-Service
-proxy.port=:31900
-admin.port=:31159
-http.port=:31149
-rootUrl='localhost:31149'

I was wondering if the candidate, primary & secondary can be deployed on different machines? and can we also configure different ports? so the end script would endup looking something like this.

-candidate=http://candidate:9001 \
-master.primary=http://primary:9001 \
-master.secondary=http://secondary:9991 \

Thanks!

Undefined_endpoint

i met a problem and that is when i run diffy i got response ,the URL is 192.168.1.85:31900/v2/products?category_id=kNylmZ and what i saw from the page is Undefined_endpoint.i don't know how to deal with it

diffy1

Does diffy support cookies?

I've set up diffy server and tried to use curl with cookies file(cookies from primary, secondary and candidate) to main proxy, e.g.:

curl -b cookies.txt localhost:31900

Actually no luck, it doesn't seem that cookies were applied, and responses look like i've not passed authentication.

Does diffy support cookies or whethere there is any convinient way to pass authentication, as far as i need to be logged in befor performing any actions?

Unable to get started

This might not be a bug, could be an issue on my env.

I'm getting the below error when trying to launch the example servers.

➜  diffy git:(master) ./example/run.sh start
downloading sbt-launch.jar
➜  diffy git:(master) example/ExampleServers.java:8: error: cannot find symbol
        Thread p = new Thread(() -> ExampleUtils.bind(primary, x -> x.toLowerCase()));
                                    ^
  symbol:   variable ExampleUtils
  location: class ExampleServers
example/ExampleServers.java:9: error: cannot find symbol
        Thread s = new Thread(() -> ExampleUtils.bind(secondary, x -> x.toLowerCase()));
                                    ^
  symbol:   variable ExampleUtils
  location: class ExampleServers
example/ExampleServers.java:10: error: cannot find symbol
        Thread c = new Thread(() -> ExampleUtils.bind(candidate, x -> x.toUpperCase()));
                                    ^
  symbol:   variable ExampleUtils
  location: class ExampleServers
3 errors

I don't see the compilation issues on my IntelliJ though!

Thanks

Hooks for results

Is there any way to hook into the request/response process?

i.e. Notify slack that a response is failing, etc...

Diffy proxy working, not showing any results.

The service I'm testing accepts a POST request; I have set -allowHttpSideEffects=true
I have tested each of these services without the diffy proxy and received the expected responses.

The candidate, primary and secondary services are all receiving the POST requests when I send them to the diffy proxy. I understand that the client talking to the diffy proxy is not going to receive a response.

image

No results are showing. Am I missing something?

On the metrics page http://localhost:31159/admin/metrics#clnt/primary/requests I can see a bar that rises when I send a request to the diffie proxy for each of the services; candidate, primary and secondary. Same for the recieved_bytes metric.

Below is the output from from running the jar file:

$ java -jar diffy-server.jar -candidate=localhost:44310 -master.primary=localhost:44311 -master.secondary=localhost:44312 -serviceName=XmlServer -service.protocol=http -proxy.port=:44333 -admin.port=:31159 -http.port=:31149 -rootUrl='localhost:31149' -allowHttpSideEffects=true
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
I 1207 12:47:52.871 THREAD1: HttpMuxer[/admin/metrics.json] = com.twitter.finagle.stats.MetricsExporter(<function1>)
I 1207 12:47:52.904 THREAD1: HttpMuxer[/admin/per_host_metrics.json] = com.twitter.finagle.stats.HostMetricsExporter(<function1>)
I 1207 12:47:52.966 THREAD1: /admin => com.twitter.server.handler.SummaryHandler
I 1207 12:47:52.967 THREAD1: /admin/server_info => com.twitter.finagle.Filter$$anon$2
I 1207 12:47:52.967 THREAD1: /admin/contention => com.twitter.finagle.Filter$$anon$2
I 1207 12:47:52.967 THREAD1: /admin/threads => com.twitter.server.handler.ThreadsHandler
I 1207 12:47:52.967 THREAD1: /admin/threads.json => com.twitter.server.handler.ThreadsHandler
I 1207 12:47:52.967 THREAD1: /admin/announcer => com.twitter.finagle.Filter$$anon$2
I 1207 12:47:52.967 THREAD1: /admin/dtab => com.twitter.finagle.Filter$$anon$2
I 1207 12:47:52.968 THREAD1: /admin/pprof/heap => com.twitter.server.handler.HeapResourceHandler
I 1207 12:47:52.968 THREAD1: /admin/pprof/profile => com.twitter.server.handler.ProfileResourceHandler
I 1207 12:47:52.968 THREAD1: /admin/pprof/contention => com.twitter.server.handler.ProfileResourceHandler
I 1207 12:47:52.968 THREAD1: /admin/ping => com.twitter.server.handler.ReplyHandler
I 1207 12:47:52.968 THREAD1: /admin/shutdown => com.twitter.server.handler.ShutdownHandler
I 1207 12:47:52.968 THREAD1: /admin/tracing => com.twitter.server.handler.TracingHandler
I 1207 12:47:52.969 THREAD1: /admin/events => com.twitter.server.handler.EventsHandler
I 1207 12:47:52.969 THREAD1: /admin/logging => com.twitter.server.handler.LoggingHandler
I 1207 12:47:52.969 THREAD1: /admin/metrics => com.twitter.server.handler.MetricQueryHandler
I 1207 12:47:52.969 THREAD1: /admin/clients/ => com.twitter.server.handler.ClientRegistryHandler
I 1207 12:47:52.971 THREAD1: /admin/servers/ => com.twitter.server.handler.ServerRegistryHandler
I 1207 12:47:52.971 THREAD1: /admin/files/ => com.twitter.server.handler.ResourceHandler
I 1207 12:47:52.971 THREAD1: /admin/registry.json => com.twitter.server.handler.RegistryHandler
I 1207 12:47:52.975 THREAD1: Serving admin http on 0.0.0.0/0.0.0.0:31159
I 1207 12:47:53.004 THREAD1: Finagle version 6.28.0 (rev=de123b8f9d074c4e345ebd67e1a0e870bb921544) built at 20150827-162434
I 1207 12:47:54.275 THREAD1: networkaddress.cache.ttl is not set, DNS cache refresh turned off
I 1207 12:47:54.767 THREAD1: Tracer: com.twitter.finagle.zipkin.thrift.SamplingTracer
I 1207 12:47:55.063 THREAD1: zipkin-tracer resolved to Addr.Bound, current size=1
I 1207 12:47:55.063 THREAD1: candidate resolved to Addr.Bound, current size=2
I 1207 12:47:55.063 THREAD1: primary resolved to Addr.Bound, current size=2
I 1207 12:47:55.063 THREAD1: secondary resolved to Addr.Bound, current size=2
I 1207 12:47:55.170 THREAD1: Scheduling com.twitter.diffy.workflow.FunctionalReport at 2016-12-07 12:47:55 +0000

How to test DockerDiffy

Hello,

I can't clone this : git clone [email protected]:camiloribeiro/dockdiffy.git
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.

and for docker-compose up : bash: docker-compose: command not found

Can some one help me please.
Thanks.

You must specify host and port

First of all, im not that used to coding so this is a little bit out of my league. But i figured i might try and learn and this is probably just be a user error but been trying to google an aswer all day now without going forward.

This is my example.sh file:
#!/usr/bin/env bash java -jar ./target/scala-2.11/diffy-server.jar \ -candidate='http://enviromentname.test.companyname.com:80' \ -master.primary='http://prod-companyname.com:80' \ -master.secondary='http://prod-companyname.com:80' \ -service.protocol='http' \ -serviceName='My Service' \ -proxy.port=:31900 \ -admin.port=:31159 \ -http.port=:31149 \ -rootUrl='localhost:31149'

Im able to start it and i can go to the diffy localhost:31149 page. But whenever i try to run a request to
http://localhost:31149/foo/bar/all?departureDate=2017-11-24 it returns blank and i cant see anything happen in Diffy.

Checking the command promt it seems to be complaining about my host and port?

I 1006 13:50:38.098 THREAD1: candidate resolved to Failed(java.lang.IllegalArgum entException: requirement failed: You must specify host and port) I 1006 13:50:38.099 THREAD1: primary resolved to Failed(java.lang.IllegalArgumen tException: requirement failed: You must specify host and port) I 1006 13:50:38.099 THREAD1: secondary resolved to Failed(java.lang.IllegalArgum entException: requirement failed: You must specify host and port) I 1006 13:50:38.153 THREAD1: Scheduling com.twitter.diffy.workflow.FunctionalRep ort at 2017-10-06 13:50:38 +0000

Can't access twitter maven repository, need packaged jar

hi, puneet

when i installed sbt and scala, then run ./stb assembly, it will return so much exception.

[error] Server access Error: Connection reset url=https://repo1.maven.org/maven2/com/twitter/finagle-thrift_2.11/6.28.0/finagle-thrift_2.11-6.28.0.pom
[error] Server access Error: Operation timed out url=https://maven.twttr.com/com/twitter/finagle-thrift_2.11/6.28.0/finagle-thrift_2.11-6.28.0.pom

I am in China, the network is so bad.
My proxy can not access twitter maven repository.
So, Could you mail a diffy-server.jar to me([email protected]).
Thank you so much.

sever candidate & server primary(diff) has different url

Hi diffy's developers,
If the sever candidate & server primary(diff) has different url, for ex, a.com/v1/getuser & a.com/v2/getuser, how should I write the conf, as long as I know, "-candidate" should be like this "ip:post".
Thanks!

sbt assembly fails, unresolved dependencies

Fails with the follow error,

[warn] [warn] Note: Unresolved dependencies path: [warn] org.slf4j:slf4j-api:1.5.8 [warn] +- org.apache.thrift:libthrift:0.5.0-1 [warn] +- com.twitter:scrooge-generator_2.10:4.0.0 [warn] +- com.twitter:scrooge-sbt-plugin:4.0.0 (scalaVersion=2.10, sbtVersion=0.13) (/Users/jbeck/project/github/diffy/project/plugins.sbt#L9-10) [warn] +- default:diffy-build:0.1-SNAPSHOT (scalaVersion=2.10, sbtVersion=0.13) sbt.ResolveException: unresolved dependency: commons-codec#commons-codec;1.4: configuration not found in commons-codec#commons-codec;1.4: 'master(compile)'. Missing configuration: 'compile'. It was required from net.databinder#unfiltered_2.10;0.7.0 compile unresolved dependency: org.slf4j#slf4j-api;1.5.8: configuration not found in org.slf4j#slf4j-api;1.5.8: 'master(compile)'. Missing configuration: 'compile'. It was required from org.apache.thrift#libthrift;0.5.0-1 compile at sbt.IvyActions$.sbt$IvyActions$$resolve(IvyActions.scala:294) at sbt.IvyActions$$anonfun$updateEither$1.apply(IvyActions.scala:191) at sbt.IvyActions$$anonfun$updateEither$1.apply(IvyActions.scala:168) at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:155) at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:155) at sbt.IvySbt$$anonfun$withIvy$1.apply(Ivy.scala:132) at sbt.IvySbt.sbt$IvySbt$$action$1(Ivy.scala:57) at sbt.IvySbt$$anon$4.call(Ivy.scala:65) at xsbt.boot.Locks$GlobalLock.withChannel$1(Locks.scala:93) at xsbt.boot.Locks$GlobalLock.xsbt$boot$Locks$GlobalLock$$withChannelRetries$1(Locks.scala:78) at xsbt.boot.Locks$GlobalLock$$anonfun$withFileLock$1.apply(Locks.scala:97) at xsbt.boot.Using$.withResource(Using.scala:10) at xsbt.boot.Using$.apply(Using.scala:9) at xsbt.boot.Locks$GlobalLock.ignoringDeadlockAvoided(Locks.scala:58) at xsbt.boot.Locks$GlobalLock.withLock(Locks.scala:48) at xsbt.boot.Locks$.apply0(Locks.scala:31) at xsbt.boot.Locks$.apply(Locks.scala:28) at sbt.IvySbt.withDefaultLogger(Ivy.scala:65) at sbt.IvySbt.withIvy(Ivy.scala:127) at sbt.IvySbt.withIvy(Ivy.scala:124) at sbt.IvySbt$Module.withModule(Ivy.scala:155) at sbt.IvyActions$.updateEither(IvyActions.scala:168) at sbt.Classpaths$$anonfun$sbt$Classpaths$$work$1$1.apply(Defaults.scala:1392) at sbt.Classpaths$$anonfun$sbt$Classpaths$$work$1$1.apply(Defaults.scala:1388) at sbt.Classpaths$$anonfun$doWork$1$1$$anonfun$90.apply(Defaults.scala:1422) at sbt.Classpaths$$anonfun$doWork$1$1$$anonfun$90.apply(Defaults.scala:1420) at sbt.Tracked$$anonfun$lastOutput$1.apply(Tracked.scala:37) at sbt.Classpaths$$anonfun$doWork$1$1.apply(Defaults.scala:1425) at sbt.Classpaths$$anonfun$doWork$1$1.apply(Defaults.scala:1419) at sbt.Tracked$$anonfun$inputChanged$1.apply(Tracked.scala:60) at sbt.Classpaths$.cachedUpdate(Defaults.scala:1442) at sbt.Classpaths$$anonfun$updateTask$1.apply(Defaults.scala:1371) at sbt.Classpaths$$anonfun$updateTask$1.apply(Defaults.scala:1325) at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47) at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:40) at sbt.std.Transform$$anon$4.work(System.scala:63) at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:226) at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:226) at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17) at sbt.Execute.work(Execute.scala:235) at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:226) at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:226) at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:159) at sbt.CompletionService$$anon$2.call(CompletionService.scala:28) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) [error] (*:update) sbt.ResolveException: unresolved dependency: commons-codec#commons-codec;1.4: configuration not found in commons-codec#commons-codec;1.4: 'master(compile)'. Missing configuration: 'compile'. It was required from net.databinder#unfiltered_2.10;0.7.0 compile [error] unresolved dependency: org.slf4j#slf4j-api;1.5.8: configuration not found in org.slf4j#slf4j-api;1.5.8: 'master(compile)'. Missing configuration: 'compile'. It was required from org.apache.thrift#libthrift;0.5.0-1 compile [debug] > load-failed [debug] > last [debug] > load-failed [debug] > last Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore?

Date header - should it be tested?

Hello,
I'm testing my APIs and I found out that Diffy is comparing date headers what is leading to testing fails. My point is: should it be tested in the first place? It is default Apache header and there will always be a possibility for some slight differences in returned time. It's not really a fail/concern when testing APIs.
Am I right?

Date header is not detected as a "noise" when primary and secondary returns the same time.

regards,
Mike

HTTP content length exceeded 5242880 bytes

Hi,

I'm getting this exception "TooLongFrameException", my content is bigger than 5mb that seems to be the default limit

but the configuration flag that changes that limit is ignored, I'm using a modified version of the example.sh

java -jar ./target/scala-2.11/diffy-server.jar \
-candidate=10.5.21.78:9090 \
-master.primary=10.5.21.78:9084 \
-master.secondary=10.5.21.78:9084 \
-service.protocol='http' \
-serviceName='InfoService' \
-proxy.port=:9090 \
-admin.port=:9091 \
-http.port=:9092 \
-rootUrl='10.5.21.205:9092' \
-excludeHttpHeadersComparison='true' \
-maxRequestSize='15728640.bytes'

I also try adding this configuration "java -jar -Dcom.twitter.finatra.config.maxRequestSize="10"" with no success.

this is the stack trace I get

org.jboss.netty.handler.codec.frame.TooLongFrameException: HTTP content length exceeded 5242880 bytes.
    at org.jboss.netty.handler.codec.http.HttpChunkAggregator.messageReceived(HttpChunkAggregator.java:169)
    at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70)
    at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
    at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296)
    at org.jboss.netty.handler.codec.frame.FrameDecoder.unfoldAndFireMessageReceived(FrameDecoder.java:459)
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(ReplayingDecoder.java:536)
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived(ReplayingDecoder.java:435)
    at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70)
    at org.jboss.netty.handler.codec.http.HttpClientCodec.handleUpstream(HttpClientCodec.java:92)
    at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
    at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791)
    at org.jboss.netty.channel.SimpleChannelHandler.messageReceived(SimpleChannelHandler.java:142)
    at com.twitter.finagle.netty3.channel.ChannelStatsHandler.messageReceived(ChannelStatsHandler.scala:80)
    at org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:88)
    at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
    at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791)
    at org.jboss.netty.channel.SimpleChannelHandler.messageReceived(SimpleChannelHandler.java:142)
    at com.twitter.finagle.netty3.channel.ChannelRequestStatsHandler.messageReceived(ChannelRequestStatsHandler.scala:35)
    at org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:88)
    at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
    at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:559)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255)
    at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:88)
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.process(AbstractNioWorker.java:108)
    at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:337)
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:89)
    at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:178)
    at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108)
    at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)

Any help will be appreciated. Thanks.

error: "object file is not a member of package java.nio"

my installation steps are following:

$ export https_proxy=https://10.210.239.82:3128
$ export http_proxy=http://10.210.239.82:3128

$ svn co https://github.com/twitter/diffy.git/trunk/

$ ./sbt assembly
downloading sbt-launch.jar
[info] Loading project definition from /home/wandongde/test11/trunk/project
[info] Updating {file:/home/wandongde/test11/trunk/project/}trunk-build...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Set current project to diffy (in build file:/home/wandongde/test11/trunk/)
[info] Updating {file:/home/wandongde/test11/trunk/}diffy...
[info] Resolving jline#jline;2.12.1 ...
[info] Done updating.
[warn] There may be incompatibilities among your library dependencies.
[warn] Here are some of the libraries that were evicted:
[warn] * com.twitter:finagle-http_2.11:6.25.0 -> 6.28.0
[warn] Run 'evicted' to see detailed eviction warnings
[info] Generating scrooge thrift for /home/wandongde/test11/trunk/src/main/thrift/diffy.thrift ...
[info] Compiling 35 Scala sources to /home/wandongde/test11/trunk/target/scala-2.11/classes...
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/proxy/ClientService.scala:45: Procedure syntax is deprecated. Convert procedure sizeChange to method by adding : Unit =.
[warn] private[this] def sizeChange(size: Int) {
[warn] ^
[warn] /home/wandongde/test11/trunk/target/scala-2.11/src_managed/main/com/twitter/diffy/thriftscala/SampleService$FinagleService.scala:61: Procedure syntax is deprecated. Convert procedure addFunction to method by adding : Unit =.
[warn] protected def addFunction(name: String, f: (TProtocol, Int) => Future[Array[Byte]]) {
[warn] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/Main.scala:22: a pure expression does nothing in statement position; you may be omitting necessary parentheses
[warn] proxy.server
[warn] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/workflow/Workflow.scala:40: implicit numeric widening
[warn] scope.scope(endpoint).provideGauge("total"){ meta.total }
[warn] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/workflow/Workflow.scala:41: implicit numeric widening
[warn] scope.scope(endpoint).provideGauge("differences"){ meta.differences }
[warn] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/analysis/JoinedDifferences.scala:23: postfix operator toSeq should be enabled
[warn] by making the implicit value scala.language.postfixOps visible.
[warn] This can be achieved by adding the import clause 'import scala.language.postfixOps'
[warn] or by setting the compiler option -language:postfixOps.
[warn] See the Scala docs for value scala.language.postfixOps for a discussion
[warn] why the feature should be explicitly enabled.
[warn] } toSeq
[warn] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/compare/Difference.scala:137: abstract type A in type pattern scala.collection.immutable.Set[A](the underlying of Set[A]) is unchecked since it is eliminated by erasure
[warn] case (ls: Set[A], rs: Set[A]) => diffSet(ls, rs)
[warn] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/compare/Difference.scala:137: abstract type A in type pattern scala.collection.immutable.Set[A](the underlying of Set[A]) is unchecked since it is eliminated by erasure
[warn] case (ls: Set[A], rs: Set[A]) => diffSet(ls, rs)
[warn] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/compare/Difference.scala:138: non-variable type argument Any in type pattern com.twitter.diffy.lifter.FieldMap[Any] is unchecked since it is eliminated by erasure
[warn] case (lm: FieldMap[Any], rm: FieldMap[Any]) => diffObjectMap(lm, rm)
[warn] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/compare/Difference.scala:138: non-variable type argument Any in type pattern com.twitter.diffy.lifter.FieldMap[Any] is unchecked since it is eliminated by erasure
[warn] case (lm: FieldMap[Any], rm: FieldMap[Any]) => diffObjectMap(lm, rm)
[warn] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/compare/Difference.scala:139: abstract type A in type pattern scala.collection.immutable.Map[A,Any](the underlying of Map[A,Any]) is unchecked since it is eliminated by erasure
[warn] case (lm: Map[A, Any], rm: Map[A, Any]) => diffMap(lm, rm)
[warn] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/compare/Difference.scala:139: abstract type A in type pattern scala.collection.immutable.Map[A,Any](the underlying of Map[A,Any]) is unchecked since it is eliminated by erasure
[warn] case (lm: Map[A, Any], rm: Map[A, Any]) => diffMap(lm, rm)
[warn] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/lifter/HtmlLifter.scala:24: postfix operator toMap should be enabled
[warn] by making the implicit value scala.language.postfixOps visible.
[warn] } toMap
[warn] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/lifter/ThriftLifter.scala:174: implicit numeric widening
[warn] case None => throw FieldOutOfBoundsException(field.id)
[warn] ^
[error] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/scrooge/ThriftImporter.scala:5: object file is not a member of package java.nio
[error] import java.nio.file.Files
[error] ^
[error] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/scrooge/ThriftImporter.scala:12: not found: value Files
[error] val thriftDir = Files.createTempDirectory("thrift-")
[error] ^
[error] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/scrooge/ThriftImporter.scala:23: not found: value Files
[error] Files.write(newFile.toPath, data.getBytes)
[error] ^
[error] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/scrooge/ThriftImporter.scala:33: not found: value Files
[error] val thriftDir = Files.createTempDirectory("thrift-")
[error] ^
[error] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/scrooge/ThriftImporter.scala:38: not found: value Files
[error] Files.copy(file.toPath, newFile.toPath)
[error] ^
[error] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/scrooge/ThriftImporter.scala:38: value toPath is not a member of java.io.File
[error] Files.copy(file.toPath, newFile.toPath)
[error] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/scrooge/ThriftImporter.scala:5: Unused import
[warn] import java.nio.file.Files
[warn] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/util/EmailSender.scala:41: This catches all Throwables. If this is really intended, use case e : Throwable to clear this warning.
[warn] } catch { case e =>
[warn] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/workflow/ReportGenerator.scala:71: implicit numeric widening
[warn] joinedEndpoint.total,
[warn] ^
[warn] /home/wandongde/test11/trunk/src/main/scala/com/twitter/diffy/workflow/Workflow.scala:5: Unused import
[warn] import com.twitter.diffy.analysis.{RawDifferenceCounter, DifferenceCounter, EndpointMetadata}
[warn] ^
[warn] 18 warnings found
[error] 6 errors found
error Compilation failed
[error] Total time: 23 s, completed Jun 14, 2016 3:39:43 PM

Pls help check why fail. thanks

How to pass on output of one service to another?

Hi, this looks like an interesting tool. I wanted know how to get it working in one particular scenrio. Let's say if I have two services, createUser (http://myservice/createUser) and GetUserInfo (http://myservice/getUserInfo/{userId}). The userId used in the second service is from the first service createUser response.

In this scenario, 1) how do I get the first service' response and pass on to second service?
2) Also the url that we hit proxy is sent to candidate, primary and secondary. If my userId is dynamic and varies across across 3 instances. How do I handle this scenario?

P.S: I don't know if this has been answered already. If that is the case , please point me to it

Quotes in the README example are not needed

I tried following the steps described in README.md to try out and test diffy,

but I would get MatchErrors when trying the command:

java -jar diffy-server.jar
-candidate="localhost:9992"
-master.primary="localhost:9990"
-master.secondary="localhost:9991"
-service.protocol="http"
-serviceName="My Service"
-proxy.port=:31900
-admin.port=:31159
-http.port=:31149
-rootUrl='localhost:31149'

I had to remove the quotes along with the corresponding escape characters for it to work.

I was using a terminal in OS X Yosemite, I don't know if that matters.

Encounter a problem while setting up diffy tutorial...

hi,

i encountered a problem while setting up the tutorial...
and that is probably due to the header "Host" sent by the diffy.

the tutorial has 3 urls,

  1. http://http-candidate.herokuapp.com
  2. http://http-primary.herokuapp.com
  3. http://http-secondary.herokuapp.com

and here is the traffic from diffy,

  1. http://http-candidate.herokuapp.com
    174.129.192.57
    GET / HTTP/1.1
    Host: localhost:8990
    User-Agent: curl/7.43.0
    Accept: /
    Canonical-Resource: Html
  2. http://http-primary.herokuapp.com
    174.129.192.57
    GET / HTTP/1.1
    Host: localhost:8990
    User-Agent: curl/7.43.0
    Accept: /
    Canonical-Resource: Html
  3. http://http-secondary.herokuapp.com
    54.83.197.202
    GET / HTTP/1.1
    Host: localhost:8990
    User-Agent: curl/7.43.0
    Accept: /
    Canonical-Resource: Html

it seems 1. and 2. are in the same instance, and depend on "Host" to determine the response, but the header "Host" from diffy is "localhost:8990", so the services always return 404...

removing the filter of Host from server or using the diffy proxy to change Host to http-xxxxx.herokuapp.com (the value from example.sh) may help.

2015-09-22 2 24 40

2015-09-22 2 24 57

Diffy doesnt capture 'POST requests sent through proxy ports

I have an endpoint in my service which accepts POST requests My curl request looks something like this
curl localhost:31900/messages -H "Content-type: application/json" -X POST -d {"message":"Yello"} ' But i do not see traffic on my server side when using diffy

If i do normal curl request i.e without using diffy as a proxy it works just fine.

Looks like the POST request doesn't get through the proxy
image

Does diffy support POST requests ?

Cannot start diffy, blocked by "./sbt assembly"

Updated on Jan 11th:
When I ran sh example.sh
I got
./target/scala-2.11/diffy-server.jar中没有主清单属性
What can I do?

Hi,
I just got the diffy code and then ran the "./sbt assembly" as the wiki says. It shown updating a lot of dependencies at first, but than ,it was blocked, end with something like this:

...(Omit)
[info] [SUCCESSFUL ] javax.activation#activation;1.1!activation.jar (773ms)
[info] downloading https://repo1.maven.org/maven2/com/twitter/finatra/finatra-jackson_2.11/2.0.0.M2/finatra-jackson_2.11-2.0.0.M2.jar ...
[info] [SUCCESSFUL ] com.twitter.finatra#finatra-jackson_2.11;2.0.0.M2!finatra-jackson_2.11.jar (1302ms)
[info] downloading https://repo1.maven.org/maven2/commons-fileupload/commons-fileupload/1.3.1/commons-fileupload-1.3.1.jar ...
[info] [SUCCESSFUL ] commons-fileupload#commons-fileupload;1.3.1!commons-fileupload.jar (916ms)
[info] downloading https://repo1.maven.org/maven2/javax/servlet/servlet-api/2.5/servlet-api-2.5.jar ...
[info] [SUCCESSFUL ] javax.servlet#servlet-api;2.5!servlet-api.jar (1229ms)
[info] downloading https://repo1.maven.org/maven2/com/twitter/finatra/finatra-utils_2.11/2.0.0.M2/finatra-utils_2.11-2.0.0.M2.jar ...
[info] [SUCCESSFUL ] com.twitter.finatra#finatra-utils_2.11;2.0.0.M2!finatra-utils_2.11.jar (1525ms)
[info] downloading https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.4.4/jackson-databind-2.4.4.jar ...
(end here)

It totally stopped. I have no idea. Maybe I should install the SBT, or other necessary softwares? Since I am from China, and I use MAVEN as the build tool, my OS is mac, maybe there are some different between our environments. Hope getting answers soon~ Thank you

cannot connnect to maven.twttr.com

Hi diffy's developers,

When I run ./sbt assemble, I find the connection error:
[error] Server access Error: Connection timed out: connect url=https://maven.twttr.com/org/apache/thrift/libthrift/0.5.0-1/libthrift-0.5.0-1.pom
[warn] module not found: org.apache.thrift#libthrift;0.5.0-1

My IT colleague has gotten rid of all firewalls but still cannot connect to the url. Could you please make sure if the url (or the resource representing by the url) is available.

Thanks in advance!
name: Lifei
email: [email protected]

Tutorial not working

Hello,

I'm testing Diffy, but when i follow the tutorial it's seems Diffy not working.

  1. The server : java.lang.IllegalArgumentException: requirement failed: You must specify host and port
  2. I use Curl to call proxy and nothing happen on Diffy.

This is my configuration:

java -jar ./target/scala-2.11/diffy-server.jar
-candidate='http://192.168.10.116:50753/tempo/version:9992'
-master.primary='http://192.168.10.116:50752/tempo/version:9990'
-master.secondary='http://192.168.10.116:50752/tempo/version:9991'
-service.protocol='http'
-serviceName='My-Service'
-proxy.port=:31900
-admin.port=:31159
-http.port=:31149
-rootUrl='localhost:31149'

Then i call Curl :
curl localhost:31900/192.168.10.116:50753/tempo/version
curl localhost:31900/192.168.10.116:50752/tempo/version

Can some one help me please?
Thank you,

Feature request: minimizing array differences

Thank you for releasing this great tool! It's a must-have for testing new releases.

Here is a non-trivial feature request:

Right now, when comparing arrays in responses, diffy does line-by-line comparison. It would be nice if the UI can do smarter diffs (like GitHub comparison and the Linux diff command), i.e., shows line insertions, deletions and changes.

For example, the following arrays only differ by 4 elements (2 deletions and 2 insertions in terms of edit distance), but the UI shows 14 line differences:
screen shot 2017-04-16 at 10 26 35 pm

Diffy Return Response Of Primary

It seems as though the response from the clients is not being returned, but always just returning empty response.

in DifferenceProxy.scala line 92 NoReponseException is returned always.

It would be nice to be able to run this under a dev website that is pointing to the proxy and have the results passed through.

Question I can see is what do you return the primary or the candidate.

How to export data from the server

Is there a way to get a representation of the differences?

If not, is this something you would accept? Perhaps through an HTTP endpoint?

The use case for this is to be able to reset Diffy but keep the data regarding the differences.

Sending different header content to different servers

HI this maybe a duplicate of Issue #23 and #37 . If it is so then please close this out.

We have different header www-authenticate (Basic Authentication Scheme) values that is sent while invoking the API endpoints. I am not sure if this support is already in diffy but if not I guess it will be better if we can add a feature where we can send different header key-pair values to different servers.

About new interface and asynchronous request

Hi, I have two problems:

  • If I have one new interface, diffy will not find problem, because the diff result will fail forever, right?
  • If I have one asynchronous request which will return the same result for new and old version, for example one request push one info to kafka, how should do diffy?

Tutorial not working

Hello,

I'm testing Diffy, but when i follow the tutorial it's seems Diffy not working.

  1. The server : java.lang.IllegalArgumentException: requirement failed: You must specify host and port
  2. I use Curl to call proxy and nothing happen on Diffy.

This is my configuration:

java -jar ./target/scala-2.11/diffy-server.jar
-candidate='http://192.168.10.116:50753/tempo/version:9992'
-master.primary='http://192.168.10.116:50752/tempo/version:9990'
-master.secondary='http://192.168.10.116:50752/tempo/version:9991'
-service.protocol='http'
-serviceName='My-Service'
-proxy.port=:31900
-admin.port=:31159
-http.port=:31149
-rootUrl='localhost:31149'

Then i call Curl :
curl localhost:31900/192.168.10.116:50753/tempo/version
curl localhost:31900/192.168.10.116:50752/tempo/version

Can some one help me please?
Thank you,

Errors: Exception propagated to the root monitor! AND Too many open files

We're getting the following stack traces after running a script with many curl requests:

java -jar diffy-server.jar \
-candidate=<candidate host and port> \
-master.primary=<primary host and port> \
-master.secondary=<secondary host and port> \
-service.protocol=http \
-serviceName=<ServiceName> \
-proxy.port=:31900 \
-admin.port=:31159 \
-http.port=:31149 \
-rootUrl='localhost:31149'
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
I 1108 15:42:23.086 THREAD1: HttpMuxer[/admin/metrics.json] = com.twitter.finagle.stats.MetricsExporter(<function1>)
I 1108 15:42:23.108 THREAD1: HttpMuxer[/admin/per_host_metrics.json] = com.twitter.finagle.stats.HostMetricsExporter(<function1>)
I 1108 15:42:23.143 THREAD1: /admin => com.twitter.server.handler.SummaryHandler
I 1108 15:42:23.143 THREAD1: /admin/server_info => com.twitter.finagle.Filter$$anon$2
I 1108 15:42:23.143 THREAD1: /admin/contention => com.twitter.finagle.Filter$$anon$2
I 1108 15:42:23.143 THREAD1: /admin/threads => com.twitter.server.handler.ThreadsHandler
I 1108 15:42:23.143 THREAD1: /admin/threads.json => com.twitter.server.handler.ThreadsHandler
I 1108 15:42:23.143 THREAD1: /admin/announcer => com.twitter.finagle.Filter$$anon$2
I 1108 15:42:23.143 THREAD1: /admin/dtab => com.twitter.finagle.Filter$$anon$2
I 1108 15:42:23.144 THREAD1: /admin/pprof/heap => com.twitter.server.handler.HeapResourceHandler
I 1108 15:42:23.144 THREAD1: /admin/pprof/profile => com.twitter.server.handler.ProfileResourceHandler
I 1108 15:42:23.144 THREAD1: /admin/pprof/contention => com.twitter.server.handler.ProfileResourceHandler
I 1108 15:42:23.144 THREAD1: /admin/ping => com.twitter.server.handler.ReplyHandler
I 1108 15:42:23.144 THREAD1: /admin/shutdown => com.twitter.server.handler.ShutdownHandler
I 1108 15:42:23.144 THREAD1: /admin/tracing => com.twitter.server.handler.TracingHandler
I 1108 15:42:23.144 THREAD1: /admin/events => com.twitter.server.handler.EventsHandler
I 1108 15:42:23.144 THREAD1: /admin/logging => com.twitter.server.handler.LoggingHandler
I 1108 15:42:23.145 THREAD1: /admin/metrics => com.twitter.server.handler.MetricQueryHandler
I 1108 15:42:23.145 THREAD1: /admin/clients/ => com.twitter.server.handler.ClientRegistryHandler
I 1108 15:42:23.145 THREAD1: /admin/servers/ => com.twitter.server.handler.ServerRegistryHandler
I 1108 15:42:23.145 THREAD1: /admin/files/ => com.twitter.server.handler.ResourceHandler
I 1108 15:42:23.145 THREAD1: /admin/registry.json => com.twitter.server.handler.RegistryHandler
I 1108 15:42:23.146 THREAD1: Serving admin http on 0.0.0.0/0.0.0.0:31159
I 1108 15:42:23.159 THREAD1: Finagle version 6.28.0 (rev=de123b8f9d074c4e345ebd67e1a0e870bb921544) built at 20150827-162434
I 1108 15:42:23.622 THREAD1: networkaddress.cache.ttl is not set, DNS cache refresh turned off
I 1108 15:42:23.804 THREAD1: Tracer: com.twitter.finagle.zipkin.thrift.SamplingTracer
I 1108 15:42:23.950 THREAD1: zipkin-tracer resolved to Addr.Bound, current size=1
I 1108 15:42:23.951 THREAD1: candidate resolved to Addr.Bound, current size=1
I 1108 15:42:23.951 THREAD1: primary resolved to Addr.Bound, current size=1
I 1108 15:42:23.951 THREAD1: secondary resolved to Addr.Bound, current size=1
I 1108 15:42:23.997 THREAD1: Scheduling com.twitter.diffy.workflow.FunctionalReport at 2016-11-08 15:42:23 +0000
E 1108 15:54:36.281 THREAD15: Exception propagated to the root monitor!
scala.MatchError: ClientRecvError(scala.MatchError: WireSend (of class com.twitter.finagle.tracing.Annotation$WireSend$)) (of class com.twitter.finagle.tracing.Annotation$ClientRecvError)
	at com.twitter.finagle.zipkin.thrift.RawZipkinTracer.record(RawZipkinTracer.scala:210)
	at com.twitter.finagle.zipkin.thrift.SamplingTracer.record(ZipkinTracer.scala:199)
	at com.twitter.finagle.tracing.DefaultTracer$.record(Tracer.scala:147)
	at com.twitter.finagle.tracing.Trace$$anonfun$uncheckedRecord$1.apply(Trace.scala:266)
	at com.twitter.finagle.tracing.Trace$$anonfun$uncheckedRecord$1.apply(Trace.scala:266)
	at scala.collection.immutable.List.foreach(List.scala:381)
	at com.twitter.finagle.tracing.Trace$.uncheckedRecord(Trace.scala:266)
	at com.twitter.finagle.tracing.Trace$.record(Trace.scala:312)
	at com.twitter.finagle.tracing.AnnotatingTracingFilter$$anonfun$apply$4.apply(TraceInitializerFilter.scala:154)
	at com.twitter.finagle.tracing.AnnotatingTracingFilter$$anonfun$apply$4.apply(TraceInitializerFilter.scala:150)
	at com.twitter.util.Promise$Monitored.apply(Promise.scala:73)
	at com.twitter.util.Promise$Monitored.apply(Promise.scala:64)
	at com.twitter.util.Promise$$anon$2.run(Promise.scala:358)
	at com.twitter.concurrent.LocalScheduler$Activation.run(Scheduler.scala:193)
	at com.twitter.concurrent.LocalScheduler$Activation.submit(Scheduler.scala:140)
	at com.twitter.concurrent.LocalScheduler.submit(Scheduler.scala:222)
	at com.twitter.concurrent.Scheduler$.submit(Scheduler.scala:84)
	at com.twitter.util.Promise.runq(Promise.scala:342)
	at com.twitter.util.Promise.updateIfEmpty(Promise.scala:713)
	at com.twitter.util.Promise.update(Promise.scala:686)
	at com.twitter.util.Promise.setValue(Promise.scala:662)
	at com.twitter.concurrent.AsyncQueue.offer(AsyncQueue.scala:88)
	at com.twitter.finagle.netty3.transport.ChannelTransport.handleUpstream(ChannelTransport.scala:51)
	at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
	at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791)
	at org.jboss.netty.channel.SimpleChannelHandler.messageReceived(SimpleChannelHandler.java:142)
	at org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:88)
	at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
	at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791)
	at org.jboss.netty.channel.SimpleChannelHandler.messageReceived(SimpleChannelHandler.java:142)
	at com.twitter.finagle.netty3.channel.ChannelRequestStatsHandler.messageReceived(ChannelRequestStatsHandler.scala:35)
	at org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:88)
	at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
	at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791)
	at org.jboss.netty.handler.codec.http.HttpChunkAggregator.messageReceived(HttpChunkAggregator.java:145)
	at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70)
	at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
	at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791)
	at org.jboss.netty.channel.SimpleChannelUpstreamHandler.messageReceived(SimpleChannelUpstreamHandler.java:124)
	at com.twitter.finagle.http.codec.RespondToExpectContinue.messageReceived(RespondToExpectContinue.scala:29)
	at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70)
	at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
	at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791)
	at org.jboss.netty.handler.codec.http.HttpContentEncoder.messageReceived(HttpContentEncoder.java:82)
	at org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:88)
	at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
	at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791)
	at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296)
	at org.jboss.netty.handler.codec.frame.FrameDecoder.unfoldAndFireMessageReceived(FrameDecoder.java:459)
	at org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(ReplayingDecoder.java:536)
	at org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived(ReplayingDecoder.java:435)
	at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70)
	at org.jboss.netty.handler.codec.http.HttpServerCodec.handleUpstream(HttpServerCodec.java:56)
	at com.twitter.finagle.http.SafeHttpServerCodec.handleUpstream(Codec.scala:41)
	at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
	at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791)
	at org.jboss.netty.channel.SimpleChannelHandler.messageReceived(SimpleChannelHandler.java:142)
	at com.twitter.finagle.netty3.channel.ChannelStatsHandler.messageReceived(ChannelStatsHandler.scala:80)
	at org.jboss.netty.channel.SimpleChannelHandler.handleUpstream(SimpleChannelHandler.java:88)
	at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
	at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:559)
	at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268)
	at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255)
	at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:88)
	at org.jboss.netty.channel.socket.nio.AbstractNioWorker.process(AbstractNioWorker.java:108)
	at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:337)
	at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:89)
	at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:178)
	at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108)
	at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
.......
W 1108 16:10:17.292 THREAD22 org.jboss.netty.channel.socket.nio.AbstractNioSelector: Failed to accept a connection.
java.io.IOException: Too many open files
	at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
	at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:422)
	at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:250)
	at org.jboss.netty.channel.socket.nio.NioServerBoss.process(NioServerBoss.java:100)
	at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:337)
	at org.jboss.netty.channel.socket.nio.NioServerBoss.run(NioServerBoss.java:42)
	at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108)
	at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

W 1108 16:10:18.293 THREAD22 org.jboss.netty.channel.socket.nio.AbstractNioSelector: Failed to accept a connection.
java.io.IOException: Too many open files
	at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
	at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:422)
	at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:250)
	at org.jboss.netty.channel.socket.nio.NioServerBoss.process(NioServerBoss.java:100)
	at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:337)
	at org.jboss.netty.channel.socket.nio.NioServerBoss.run(NioServerBoss.java:42)
	at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108)
	at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

W 1108 16:10:19.293 THREAD22 org.jboss.netty.channel.socket.nio.AbstractNioSelector: Failed to accept a connection.
java.io.IOException: Too many open files
	at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
	at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:422)
	at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:250)
	at org.jboss.netty.channel.socket.nio.NioServerBoss.process(NioServerBoss.java:100)
	at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:337)
	at org.jboss.netty.channel.socket.nio.NioServerBoss.run(NioServerBoss.java:42)
	at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108)
	at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

Maybe we are straining the process too hard? Do you have any input on the expected scalability and performance that we should expect when running multiple requests?

Can you please add support for the response times too?

I want track difference in response times b/w new release and the old one. I would like to contribute back to but if you are already thinking to add support for the same, I will wait for you else I will try to implement and I can contribute back.

Using Diffy with API with SSL

Is it possible to use Diffy when testing APIs via SSL (https)?

I've tried changing -service.protocol=http to -service.protocol=https and -service.protocol=ssl, but unfortunately a service won't start, instead it's just throwing exceptions... I've change ports to 443 as well.

Feature Request: Support ignoring noisy fields

My understanding is that Diffy saves all the responses with differences in memory. In one of our services, the service returns a random UUID in the response. Therefore, when "Exclude Noise" is disabled, it shows 100% diff. When "Exclude Noise" is enabled, it shows very low percentage diff. Diffy frequently runs out of memory because it saves 100% of the responses.

Is it possible to configure Diffy in a way that it simply discard the responses that only differ in noisy fields? That way, it can process much more requests without running out of memory.

Another solution is to support ignoring certain fields for comparison. The ignored fields can be set in command line.

Thanks!

Unable to get started

Hi,When I run sh example/run.sh start,I'm getting the below error

Embedded app diffy failed to startup
[info] StartupFeatureTest:
[info] - verify startup *** FAILED ***
[info] java.lang.Exception: java.lang.NoClassDefFoundError: com/twitter/common/quantity/Unit
[info] at com.twitter.inject.app.EmbeddedApp$$anonfun$runTwitterUtilAppMain$1.apply$mcV$sp(EmbeddedApp.scala:136)
[info] at com.twitter.inject.app.EmbeddedApp$$anonfun$runTwitterUtilAppMain$1.apply(EmbeddedApp.scala:125)
[info] at com.twitter.inject.app.EmbeddedApp$$anonfun$runTwitterUtilAppMain$1.apply(EmbeddedApp.scala:125)
[info] at com.twitter.util.Try$.apply(Try.scala:13)
[info] at com.twitter.util.ExecutorServiceFuturePool$$anon$2.run(FuturePool.scala:115)
[info] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
[info] at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[info] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
[info] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
[info] at java.lang.Thread.run(Thread.java:748)
[info] ...
[info] Cause: java.lang.NoClassDefFoundError: com/twitter/common/quantity/Unit
[info] at com.twitter.finagle.stats.MetricsBucketedHistogram$.$lessinit$greater$default$2(MetricsBucketedHistogram.scala:19)
[info] at com.twitter.finagle.stats.MetricsStatsReceiver$.com$twitter$finagle$stats$MetricsStatsReceiver$$defaultFactory(MetricsStatsReceiver.scala:71)
[info] at com.twitter.finagle.stats.MetricsStatsReceiver$$anonfun$$lessinit$greater$1.apply(MetricsStatsReceiver.scala:161)
[info] at com.twitter.finagle.stats.MetricsStatsReceiver$$anonfun$$lessinit$greater$1.apply(MetricsStatsReceiver.scala:161)
[info] at com.twitter.finagle.stats.MetricsStatsReceiver$$anon$7.(MetricsStatsReceiver.scala:211)
[info] at com.twitter.finagle.stats.MetricsStatsReceiver.stat(MetricsStatsReceiver.scala:210)
[info] at com.twitter.finagle.stats.StatsReceiverProxy$class.stat(StatsReceiverProxy.scala:9)
[info] at com.twitter.finagle.stats.LoadedStatsReceiver$.stat(LoadedStatsReceiver.scala:9)
[info] at com.twitter.finagle.stats.NameTranslatingStatsReceiver.stat(NameTranslatingStatsReceiver.scala:17)
[info] at com.twitter.finagle.stats.NameTranslatingStatsReceiver.stat(NameTranslatingStatsReceiver.scala:17)
[info] ...
[info] Cause: java.lang.ClassNotFoundException: com.twitter.common.quantity.Unit
[info] at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
[info] at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
[info] at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
[info] at com.twitter.finagle.stats.MetricsBucketedHistogram$.$lessinit$greater$default$2(MetricsBucketedHistogram.scala:19)
[info] at com.twitter.finagle.stats.MetricsStatsReceiver$.com$twitter$finagle$stats$MetricsStatsReceiver$$defaultFactory(MetricsStatsReceiver.scala:71)
[info] at com.twitter.finagle.stats.MetricsStatsReceiver$$anonfun$$lessinit$greater$1.apply(MetricsStatsReceiver.scala:161)
[info] at com.twitter.finagle.stats.MetricsStatsReceiver$$anonfun$$lessinit$greater$1.apply(MetricsStatsReceiver.scala:161)
[info] at com.twitter.finagle.stats.MetricsStatsReceiver$$anon$7.(MetricsStatsReceiver.scala:211)
[info] at com.twitter.finagle.stats.MetricsStatsReceiver.stat(MetricsStatsReceiver.scala:210)
[info] at com.twitter.finagle.stats.StatsReceiverProxy$class.stat(StatsReceiverProxy.scala:9)
[info] ...

How can I fix it?
thanks

Diffy relies too much in the content-type header

I was running some tests here to know how it works, and in one of my tests I have the following setup:

service primary:
- content-type header => application/json
- response-body => { "hello_world" : "primary" }

service secondary:
- content-type header => application/json
- response-body => { "hello_world" : "secondary" }

service candidate:
- content-type header => application/xml
- response-body => { "hello_world" : "candidate" }

In this scenario the diffy never checks the response and hangs forever.

Another test that I did could give you some more context on that issue. The test data in that case is the following:

service primary:
- response code => 401
- content-type header => application/json
- response-body => { "hello_world" : "primary" }

service secondary:
- response code => 402
- content-type header => application/xml
- response-body => { "hello_foo" : "secondary" }

service candidate:
- response code => 403
- content-type header => application/text
- response-body => { "hello_bar" : "candidate" }

In this case diffy holds for a long time, something around 40 seconds, and returns saying that everything is fine and there is no difference in the responses.

In a third scenario for this issue, if I use the same response code for primary and secondary, it returns fast as usual, but still without differences.

Please let me know if you have any questions regarding the scenarios. I am using my docker-compose setup to test it, so if you need feel free to clone it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.