1 module tagion.testbench.services.recorder_service; 2 // Default import list for bdd 3 import std.algorithm; 4 import std.array; 5 import std.random; 6 import std.stdio; 7 import std.typecons : Tuple; 8 import tagion.actor; 9 import tagion.behaviour; 10 import tagion.crypto.SecureInterfaceNet; 11 import tagion.crypto.SecureNet : StdSecureNet; 12 import tagion.crypto.Types; 13 import tagion.dart.Recorder; 14 import tagion.hibon.Document; 15 import tagion.hibon.HiBONRecord; 16 import tagion.recorderchain.RecorderChain; 17 import tagion.recorderchain.RecorderChainBlock : RecorderChainBlock; 18 import tagion.services.messages; 19 import tagion.services.replicator; 20 import tagion.testbench.dart.dart_helper_functions; 21 import tagion.testbench.tools.Environment; 22 import tagion.utils.pretend_safe_concurrency; 23 24 enum feature = Feature( 25 "Recorder chain service", 26 [ 27 "This services should store the recorder for each epoch in chain as a file.", 28 "This is an extension of the Recorder backup chain." 29 ]); 30 31 alias FeatureContext = Tuple!( 32 StoreOfTheRecorderChain, "StoreOfTheRecorderChain", 33 FeatureGroup*, "result" 34 ); 35 36 @safe @Scenario("store of the recorder chain", 37 []) 38 class StoreOfTheRecorderChain { 39 immutable(ReplicatorOptions) replicator_opts; 40 SecureNet replicator_net; 41 ActorHandle handle; 42 Mt19937 gen; 43 RandomArchives random_archives; 44 RecordFactory.Recorder insert_recorder; 45 Document[] docs; 46 RecordFactory record_factory; 47 RecorderChainBlock block; 48 49 struct SimpleDoc { 50 ulong n; 51 mixin HiBONRecord!(q{ 52 this(ulong n) { 53 this.n = n; 54 } 55 }); 56 } 57 58 this(immutable(ReplicatorOptions) replicator_opts) { 59 this.replicator_opts = replicator_opts; 60 replicator_net = new StdSecureNet(); 61 record_factory = RecordFactory(replicator_net); 62 replicator_net.generateKeyPair("recordernet very secret"); 63 gen = Mt19937(4321); 64 } 65 66 @Given("a epoch recorder with epoch number has been received") 67 Document received() { 68 thisActor.task_name = "recorder_supervisor"; 69 register(thisActor.task_name, thisTid); 70 handle = spawn!ReplicatorService("ReplicatorService", replicator_opts); 71 waitforChildren(Ctrl.ALIVE); 72 73 random_archives = RandomArchives(gen.front, 4, 10); 74 insert_recorder = record_factory.recorder; 75 docs = (() @trusted => cast(Document[]) random_archives.values.map!(a => SimpleDoc(a).toDoc).array)(); 76 77 insert_recorder.insert(docs, Archive.Type.ADD); 78 auto send_recorder = SendRecorder(); 79 80 Fingerprint dummy_bullseye = Fingerprint([1, 2, 3, 4]); 81 block = new RecorderChainBlock(insert_recorder.toDoc, Fingerprint.init, dummy_bullseye, 0, replicator_net); 82 83 (() @trusted => handle.send(send_recorder, cast(immutable) insert_recorder, dummy_bullseye, immutable long(0)))(); 84 85 import core.thread; 86 import core.time; 87 88 (() @trusted => Thread.sleep(5.msecs))(); 89 90 return result_ok; 91 } 92 93 @When("the recorder has been store to a file") 94 Document file() @trusted { 95 RecorderChainStorage storage = new RecorderChainFileStorage(replicator_opts.folder_path, replicator_net); 96 RecorderChain recorder_chain = new RecorderChain(storage); 97 98 check(recorder_chain.getLastBlock.getHash == block.getHash, "read block not the same"); 99 return result_ok; 100 } 101 102 @Then("the file should be checked") 103 Document checked() { 104 handle.send(Sig.STOP); 105 waitforChildren(Ctrl.END); 106 return result_ok; 107 } 108 109 }