StatefulService implements Service { @Override public URI getUri() { if (this.context.host == null) { return null; } return UriUtils.buildUri(this.context.host, this.context.selfLink); } StatefulService(Class<? extends ServiceDocument> stateType); @Override OperationProcessingChain getOperationProcessingChain(); @Override Service.ProcessingStage getProcessingStage(); @Override void handleCreate(Operation post); @Override void handleStart(Operation post); @Override void authorizeRequest(Operation op); @Override boolean queueRequest(Operation op); @Override void handleRequest(Operation request); @Override void handleRequest(Operation request, OperationProcessingStage opProcessingStage); @RouteDocumentation(supportLevel = SupportLevel.NOT_SUPPORTED) void handlePost(Operation post); @RouteDocumentation(description = "Delete this service instance") void handleDelete(Operation delete); @Override void handleStop(Operation delete); @RouteDocumentation(supportLevel = SupportLevel.NOT_SUPPORTED) void handlePatch(Operation patch); void handleOptions(Operation options); @RouteDocumentation(description = "Replace current state with the body of the request") void handlePut(Operation put); @RouteDocumentation(description = "Read the service document") void handleGet(Operation get); @Override Operation dequeueRequest(); @Override void setStat(String name, double newValue); @Override void setStat(ServiceStat s, double newValue); @Override void adjustStat(ServiceStat s, double delta); @Override void adjustStat(String name, double delta); @Override ServiceStat getStat(String name); @Override String getSelfLink(); @Override URI getUri(); @Override ServiceHost getHost(); @Override boolean hasOption(Service.ServiceOption cap); @Override void toggleOption(ServiceOption option, boolean enable); @Override void setSelfLink(String path); @Override void setHost(ServiceHost serviceHost); @Override void setOperationProcessingChain(OperationProcessingChain opProcessingChain); @Override void setProcessingStage(ProcessingStage stage); @Override Service getUtilityService(String uriPath); @Override void sendRequest(Operation op); ServiceDocumentDescription getStateDescription(); @Override ServiceDocument getDocumentTemplate(); void logSevere(Throwable e); void logSevere(String fmt, Object... args); void logSevere(Supplier<String> messageSupplier); void logInfo(String fmt, Object... args); void logInfo(Supplier<String> messageSupplier); void logFine(String fmt, Object... args); void logFine(Supplier<String> messageSupplier); void logWarning(String fmt, Object... args); void logWarning(Supplier<String> messageSupplier); void log(Level level, String fmt, Object... args); void log(Level level, Supplier<String> messageSupplier); @Override void handleMaintenance(Operation post); void handlePeriodicMaintenance(Operation post); void handleNodeGroupMaintenance(Operation post); @Override ServiceDocument setInitialState(Object state, Long version); @Override String getPeerNodeSelectorPath(); @Override void setPeerNodeSelectorPath(String link); @Override String getDocumentIndexPath(); @Override void setDocumentIndexPath(String link); @Override EnumSet<ServiceOption> getOptions(); @Override void setState(Operation op, ServiceDocument newState); @SuppressWarnings("unchecked") @Override T getState(Operation op); void setAvailable(boolean isAvailable); boolean isAvailable(); @Override void setMaintenanceIntervalMicros(long micros); @Override void setCacheClearDelayMicros(long micros); @Override long getMaintenanceIntervalMicros(); @Override long getCacheClearDelayMicros(); @Override Class<? extends ServiceDocument> getStateType(); @Override void handleConfigurationRequest(Operation request); @Override final void setAuthorizationContext(Operation op, AuthorizationContext ctx); final Signer getTokenSigner(); @Override final AuthorizationContext getSystemAuthorizationContext(); final AuthorizationContext getAuthorizationContextForSubject(String subject);  }
@Test public void optionsValidation() throws Throwable { ExampleServiceState body = new ExampleServiceState(); body.name = UUID.randomUUID().toString(); body.documentSelfLink = UUID.randomUUID().toString(); Operation post = Operation .createPost(UriUtils.buildFactoryUri(this.host, ExampleService.class)) .setCompletion(this.host.getCompletion()) .setBody(body); this.host.testStart(1); this.host.send(post); this.host.testWait(); URI childServiceUri = UriUtils.buildUri(this.host.getUri(), ExampleService.FACTORY_LINK, body.documentSelfLink); URI configUri = UriUtils.buildConfigUri(childServiceUri); ServiceConfiguration cfg = this.host.getServiceState(null, ServiceConfiguration.class, configUri); assertTrue(cfg.options.contains(ServiceOption.CONCURRENT_GET_HANDLING)); childServiceUri = UriUtils.buildUri(this.host, UUID.randomUUID().toString()); this.host.startService(Operation.createPost(childServiceUri), new DefaultHandlerTestService()); String uriPath = childServiceUri.getPath(); this.host.waitForServiceAvailable(uriPath); configUri = UriUtils.buildConfigUri(childServiceUri); cfg = this.host.getServiceState(null, ServiceConfiguration.class, configUri); assertTrue(!cfg.options.contains(ServiceOption.CONCURRENT_GET_HANDLING)); }
@Test public void remotePutNotModified() throws Throwable { int serviceCount = 10; List<Service> services = this.host.doThroughputServiceStart( serviceCount, MinimalTestService.class, this.host.buildMinimalTestState(), EnumSet.noneOf(Service.ServiceOption.class), null); MinimalTestServiceState body = (MinimalTestServiceState) this.host.buildMinimalTestState(); for (int pass = 0; pass < 2; pass++) { this.host.testStart(serviceCount); for (Service s : services) { final int finalPass = pass; Operation put = Operation .createPatch(s.getUri()) .forceRemote() .setBody(body) .setCompletion((o, e) -> { if (e != null) { this.host.failIteration(e); return; } if (finalPass == 1 && o.getStatusCode() != Operation.STATUS_CODE_NOT_MODIFIED) { this.host.failIteration(new IllegalStateException( "Expected not modified status")); return; } this.host.completeIteration(); }); this.host.send(put); } this.host.testWait(); } }
@Test public void serviceStopWithInflightRequests() throws Throwable { long c = 100; this.host.waitForServiceAvailable(ExampleService.FACTORY_LINK); List<Service> services = this.host.doThroughputServiceStart(c, MinimalTestService.class, this.host.buildMinimalTestState(), EnumSet.of(ServiceOption.PERSISTENCE), null); ExampleServiceState body = new ExampleServiceState(); body.name = UUID.randomUUID().toString(); body.documentExpirationTimeMicros = 1; for (Service s : services) { this.host.send(Operation.createPatch(s.getUri()).setBody(body)); } c = 10; CompletionHandler ch = this.host.getSuccessOrFailureCompletion(); this.host.setTimeoutSeconds(20); this.host.toggleNegativeTestMode(true); this.host.testStart(c * 4 * services.size()); for (Service s : services) { for (int i = 0; i < c; i++) { this.host.send(Operation.createPatch(s.getUri()).setBody(body).setCompletion(ch)); if (i >= 0) { this.host.send(Operation.createDelete(s.getUri()).setBody(body) .setCompletion(ch)); } else { this.host.send(Operation.createDelete(s.getUri()).setBody(body) .setCompletion(ch) .forceRemote()); } this.host.send(Operation.createPut(s.getUri()).setBody(body).setCompletion(ch)); this.host.send(Operation.createGet(s.getUri()).setCompletion(ch)); } } this.host.testWait(); this.host.toggleNegativeTestMode(false); }
@Test public void patchDeleteThenPost() throws Throwable { int nodeCount = 3; this.host.setPeerSynchronizationEnabled(true); this.host.setUpPeerHosts(nodeCount); this.host.joinNodesAndVerifyConvergence(nodeCount, true); this.host.setNodeGroupQuorum(nodeCount); for (VerificationHost host : this.host.getInProcessHostMap().values()) { host.waitForServiceAvailable(ExampleService.FACTORY_LINK); } TestRequestSender sender = this.host.getTestRequestSender(); VerificationHost targetHost = this.host.getPeerHost(); List<Operation> posts = new ArrayList<>(); List<Operation> patches = new ArrayList<>(); List<Operation> deletes = new ArrayList<>(); List<Operation> newPosts = new ArrayList<>(); List<Operation> gets = new ArrayList<>(); for (int i = 0; i < this.serviceCount; i++) { String name = "doc-" + i; String selfLink = UriUtils.buildUriPath(ExampleService.FACTORY_LINK, name); ExampleServiceState doc = new ExampleServiceState(); doc.name = name; doc.documentSelfLink = selfLink; posts.add(Operation.createPost(targetHost, ExampleService.FACTORY_LINK).setBody(doc)); doc.name += "-patch"; patches.add(Operation.createPatch(targetHost, selfLink) .setBody(doc)); deletes.add(Operation.createDelete(targetHost, selfLink) .addRequestHeader(Operation.REPLICATION_QUORUM_HEADER, Operation.REPLICATION_QUORUM_HEADER_VALUE_ALL) ); for (VerificationHost host : this.host.getInProcessHostMap().values()) { gets.add(Operation.createGet(host, selfLink).addPragmaDirective(PRAGMA_DIRECTIVE_NO_FORWARDING)); } doc = new ExampleServiceState(); doc.name = name + "-new-post"; doc.documentSelfLink = selfLink; newPosts.add(Operation.createPost(targetHost, ExampleService.FACTORY_LINK) .addPragmaDirective(Operation.PRAGMA_DIRECTIVE_FORCE_INDEX_UPDATE) .setBody(doc) ); } sender.sendAndWait(posts); sender.sendAndWait(patches); sender.sendAndWait(deletes); for (Operation get : gets) { FailureResponse res = sender.sendAndWaitFailure(get); assertEquals("service should be deleted. uri=" + get.getUri(), 404, res.op.getStatusCode()); } sender.sendAndWait(newPosts); }
@Test public void replicationWithNullBody() throws Throwable { int nodeCount = 3; this.host.setPeerSynchronizationEnabled(true); this.host.setUpPeerHosts(nodeCount); this.host.joinNodesAndVerifyConvergence(nodeCount, true); this.host.setNodeGroupQuorum(nodeCount); VerificationHost targetHost = this.host.getPeerHost(); TestRequestSender sender = this.host.getTestRequestSender(); for (VerificationHost host : this.host.getInProcessHostMap().values()) { host.startFactory(new NoBodyExampleService()); } URI serviceUri = UriUtils.buildUri(targetHost.getUri(), NoBodyExampleService.FACTORY_LINK); host.waitForReplicatedFactoryServiceAvailable(serviceUri); String documentSelfLink = UriUtils.buildUriPath(NoBodyExampleService.FACTORY_LINK, "foo"); ExampleServiceState initState = new ExampleServiceState(); initState.name = "foo"; initState.counter = 0L; initState.documentSelfLink = documentSelfLink; Operation post = Operation.createPost(targetHost, NoBodyExampleService.FACTORY_LINK).setBody(initState); sender.sendAndWait(post); ExampleServiceState updateState = new ExampleServiceState(); updateState.counter = 1L; Operation patch = Operation.createPatch(targetHost, documentSelfLink).setBody(updateState); sender.sendAndWait(patch); for (URI peerUri : this.host.getInProcessHostMap().keySet()) { URI indexUri = UriUtils.buildUri(peerUri, ServiceUriPaths.CORE_DOCUMENT_INDEX); URI queryUri = UriUtils.buildIndexQueryUri(indexUri, documentSelfLink, true, false, null); ExampleServiceState state = sender.sendAndWait(Operation.createGet(queryUri), ExampleServiceState.class); assertEquals("Counter in persisted state should be updated", Long.valueOf(1), state.counter); } }
@Test public void forwardWithNullBodyResponse() throws Throwable { int nodeCount = 2; this.host.setPeerSynchronizationEnabled(true); this.host.setUpPeerHosts(nodeCount); this.host.joinNodesAndVerifyConvergence(nodeCount, true); this.host.setNodeGroupQuorum(nodeCount); VerificationHost targetHost = this.host.getPeerHost(); TestRequestSender sender = this.host.getTestRequestSender(); for (VerificationHost host : this.host.getInProcessHostMap().values()) { host.startFactory(new NoBodyExampleService()); } URI serviceUri = UriUtils.buildUri(targetHost.getUri(), NoBodyExampleService.FACTORY_LINK); host.waitForReplicatedFactoryServiceAvailable(serviceUri); String documentSelfLink = UriUtils.buildUriPath(NoBodyExampleService.FACTORY_LINK, "foo"); ExampleServiceState initState = new ExampleServiceState(); initState.name = "foo"; initState.counter = 0L; initState.documentSelfLink = documentSelfLink; Operation post = Operation.createPost(targetHost, NoBodyExampleService.FACTORY_LINK).setBody(initState); sender.sendAndWait(post, ExampleServiceState.class); VerificationHost ownerNode = this.host.getOwnerPeer(documentSelfLink); VerificationHost nonOwnerNode = this.host.getNonOwnerPeer(documentSelfLink); ExampleServiceState updateState; Operation patch; Operation response; updateState = new ExampleServiceState(); updateState.counter = 1L; patch = Operation.createPatch(ownerNode, documentSelfLink).setBody(updateState); response = ownerNode.getTestRequestSender().sendAndWait(patch); assertNull(response.getBodyRaw()); updateState = new ExampleServiceState(); updateState.counter = 2L; patch = Operation.createPatch(ownerNode, documentSelfLink).setBody(updateState).forceRemote(); response = ownerNode.getTestRequestSender().sendAndWait(patch); assertNull(response.getBodyRaw()); updateState = new ExampleServiceState(); updateState.counter = 3L; patch = Operation.createPatch(nonOwnerNode, documentSelfLink).setBody(updateState); response = nonOwnerNode.getTestRequestSender().sendAndWait(patch); assertNull(response.getBodyRaw()); updateState = new ExampleServiceState(); updateState.counter = 4L; patch = Operation.createPatch(nonOwnerNode, documentSelfLink).setBody(updateState).forceRemote(); response = nonOwnerNode.getTestRequestSender().sendAndWait(patch); assertNull(response.getBodyRaw()); }