Overview
SPY — SPecification RecoverY — infers behavior models of stateful software components from their executions, rather than asking developers to write those models by hand. Given a component and a way to exercise it, SPY recovers a model describing how the component actually behaves: which sequences of operations are legal, and what each of them does to the component’s state.
Two flavors of model are produced for a component. A behavioral equivalence model describes its behavior precisely, within a small scope. A protocol behavior model generalizes that into the component’s protocol of interaction — the order in which its operations may legitimately be called.
SPY was developed in the deepse group↗ at Politecnico di Milano. The section below covers SPY-monitoring, the branch of the work that puts the recovered models to use at run time.
SPY-monitoring
Applications routinely depend on components they do not control, and those components change: an update fixes one behavior and quietly alters another, or tightens a protocol that callers were relying on. SPY-monitoring watches for exactly that. It observes an external component while the system runs, keeps its behavior model up to date with what it sees, and reports a misbehavior the moment the component stops matching the model.
Monitoring proceeds in two phases. Before deployment, a trial phase builds the initial models, drawing on whatever knowledge of the component is already available — in the packaged example, the parameters and call sequences found in the component’s own JUnit test suite. Those initial models are necessarily partial: a behavior the test suite never exercises cannot appear in them. So at run time the models are refined with the behaviors actually observed, which both completes the picture and separates genuinely new behavior from a real change. Execution traces collected from the running system are then checked against the models, and a trace the model cannot explain is flagged as a functional change in the component.
The approach was evaluated on two components. StorageService is a purpose-built example that lets clients store data in compressed form over RMI, chosen because it combines a non-trivial interaction protocol with container-like behavior; faults injected into the server — making its methods always succeed, or always throw — were detected as behavioral changes. The Java client of RabbitMQ served as the real-world case: the server was modified so that a queue may be declared only once, turning a previously harmless redeclaration into an error, and SPY-monitoring correctly reported the protocol change.
The tool package ships the monitor together with the StorageService server, client, and test suite, plus the RabbitMQ client and both the original and modified servers. Its workflow runs as a short sequence of scripts: collect instances and generate a component wrapper from the test suite, generate the trial-phase models from that wrapper, then run the application with monitoring enabled against a configuration file.





