private void AssertContainsPublishAck(PublishAck pa, IList <ulong> seqnos)
 {
     Assert.Equal(STREAM, pa.Stream);
     Assert.False(pa.Duplicate);
     Assert.True(seqnos.Contains(pa.Seq));
     seqnos.Remove(pa.Seq);
 }
        public void TestPublishNoAck()
        {
            Context.RunInJsServer(c =>
            {
                CreateDefaultTestStream(c);

                JetStreamOptions jso = JetStreamOptions.Builder().WithPublishNoAck(true).Build();
                IJetStream js        = c.CreateJetStreamContext(jso);

                string data1 = "noackdata1";
                string data2 = "noackdata2";

                PublishAck pa = js.Publish(SUBJECT, Encoding.ASCII.GetBytes(data1));
                Assert.Null(pa);

                Task <PublishAck> task = js.PublishAsync(SUBJECT, Encoding.ASCII.GetBytes(data2));
                Assert.Null(task.Result);

                IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(SUBJECT);
                Msg m = sub.NextMessage(DefaultTimeout);
                Assert.NotNull(m);
                Assert.Equal(data1, Encoding.ASCII.GetString(m.Data));
                m = sub.NextMessage(DefaultTimeout);
                Assert.NotNull(m);
                Assert.Equal(data2, Encoding.ASCII.GetString(m.Data));
            });
        }
        public void TestPublishAckJson()
        {
            string     json = "{\"stream\":\"sname\", \"seq\":42, \"duplicate\":false}";
            PublishAck pa   = new PublishAck(json);

            Assert.Equal("sname", pa.Stream);
            Assert.Equal(42U, pa.Seq);
            Assert.False(pa.Duplicate);
        }
Example #4
0
 public void TestJetStreamPublishDefaultOptions()
 {
     Context.RunInJsServer(c =>
     {
         CreateDefaultTestStream(c);
         IJetStream js  = c.CreateJetStreamContext();
         PublishAck ack = JsPublish(js);
         Assert.Equal(1U, ack.Seq);
     });
 }
Example #5
0
        public void IsValidAck()
        {
            String json = "{\"stream\":\"test-stream\",\"seq\":42,\"domain\":\"test-domain\", \"duplicate\" : true }";

            PublishAck ack = new PublishAck(json);

            Assert.Equal("test-stream", ack.Stream);
            Assert.Equal("test-domain", ack.Domain);
            Assert.Equal(42ul, ack.Seq);
            Assert.True(ack.Duplicate);
        }
        public static void Main(string[] args)
        {
            ArgumentHelper helper = new ArgumentHelperBuilder("JetStream Publish Vs Core Publish", args, Usage)
                                    .DefaultStream("js-or-core-stream")
                                    .DefaultSubject("js-or-core-subject")
                                    .Build();

            try
            {
                using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions()))
                {
                    // Create a JetStreamManagement context.
                    IJetStreamManagement jsm = c.CreateJetStreamManagementContext();

                    // Use the utility to create a stream stored in memory.
                    JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, helper.Subject);

                    // create a JetStream context
                    IJetStream js = c.CreateJetStreamContext();

                    // Regular Nats publish is straightforward
                    c.Publish(helper.Subject, Encoding.ASCII.GetBytes("regular-message"));

                    // A JetStream publish allows you to set publish options
                    // that a regular publish does not.
                    // A JetStream publish returns an ack of the publish. There
                    // is no ack in a regular message.
                    Msg msg = new Msg(helper.Subject, Encoding.ASCII.GetBytes("js-message"));

                    PublishAck pa = js.Publish(msg);
                    Console.WriteLine(pa);

                    // set up the subscription
                    IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(helper.Subject);
                    c.Flush(500); // flush outgoing communication with/to the server

                    // Both messages appear in the stream as JetStream messages
                    msg = sub.NextMessage(500);
                    msg.Ack();
                    Console.WriteLine("Received Data: '" + Encoding.ASCII.GetString(msg.Data) + "'\n         Meta: " + msg.MetaData);

                    msg = sub.NextMessage(500);
                    msg.Ack();
                    Console.WriteLine("Received Data: '" + Encoding.ASCII.GetString(msg.Data) + "'\n         Meta: " + msg.MetaData);

                    // delete the stream since we are done with it.
                    jsm.DeleteStream(helper.Stream);
                }
            }
            catch (Exception ex)
            {
                helper.ReportException(ex);
            }
        }
Example #7
0
        public async Task when_writing_publish_ack_packet_then_succeeds(string jsonPath, string packetPath)
        {
            jsonPath   = Path.Combine(Environment.CurrentDirectory, jsonPath);
            packetPath = Path.Combine(Environment.CurrentDirectory, packetPath);

            byte[] expectedPacket = Packet.ReadAllBytes(packetPath);
            FlowPacketFormatter <PublishAck> formatter = new FlowPacketFormatter <PublishAck>(MqttPacketType.PublishAck, id => new PublishAck(id));
            PublishAck publishAck = Packet.ReadPacket <PublishAck>(jsonPath);

            byte[] result = await formatter.FormatAsync(publishAck);

            expectedPacket.Should().BeEquivalentTo(result);
        }
        public void TestPublishVarieties()
        {
            Context.RunInJsServer(c =>
            {
                CreateDefaultTestStream(c);
                IJetStream js = c.CreateJetStreamContext();

                PublishAck pa = js.Publish(SUBJECT, DataBytes(1));
                AssertPublishAck(pa, 1);

                Msg msg = new Msg(SUBJECT, DataBytes(2));
                pa      = js.Publish(msg);
                AssertPublishAck(pa, 2);

                PublishOptions po = PublishOptions.Builder().Build();
                pa = js.Publish(SUBJECT, DataBytes(3), po);
                AssertPublishAck(pa, 3);

                msg = new Msg(SUBJECT, DataBytes(4));
                pa  = js.Publish(msg, po);
                AssertPublishAck(pa, 4);

                pa = js.Publish(SUBJECT, null);
                AssertPublishAck(pa, 5);

                msg = new Msg(SUBJECT);
                pa  = js.Publish(msg);
                AssertPublishAck(pa, 6);

                pa = js.Publish(SUBJECT, null, po);
                AssertPublishAck(pa, 7);

                msg = new Msg(SUBJECT);
                pa  = js.Publish(msg, po);
                AssertPublishAck(pa, 8);

                IJetStreamPushSyncSubscription s = js.PushSubscribeSync(SUBJECT);
                AssertNextMessage(s, Data(1));
                AssertNextMessage(s, Data(2));
                AssertNextMessage(s, Data(3));
                AssertNextMessage(s, Data(4));
                AssertNextMessage(s, null); // 5
                AssertNextMessage(s, null); // 6
                AssertNextMessage(s, null); // 7
                AssertNextMessage(s, null); // 8

                // bad subject
                Assert.Throws <NATSNoRespondersException>(() => js.Publish(Subject(999), null));
            });
        }
Example #9
0
        public static void Main(string[] args)
        {
            ArgumentHelper helper = new ArgumentHelperBuilder("JetStream Publish", args, Usage)
                                    .DefaultStream("example-stream")
                                    .DefaultSubject("example-subject")
                                    .DefaultPayload("Hello")
                                    .DefaultCount(10)
                                    .Build();

            try
            {
                using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions()))
                {
                    // Use the utility to create a stream stored in memory.
                    JsUtils.CreateStreamOrUpdateSubjects(c, helper.Stream, helper.Subject);

                    // create a JetStream context
                    IJetStream js = c.CreateJetStreamContext();

                    int stop = helper.Count < 2 ? 2 : helper.Count + 1;
                    for (int x = 1; x < stop; x++)
                    {
                        // make unique message data if you want more than 1 message
                        byte[] data = helper.Count < 2
                            ? Encoding.UTF8.GetBytes(helper.Payload)
                            : Encoding.UTF8.GetBytes(helper.Payload + "-" + x);

                        // Publish a message and print the results of the publish acknowledgement.
                        Msg msg = new Msg(helper.Subject, null, helper.Header, data);

                        // We'll use the defaults for this simple example, but there are options
                        // to constrain publishing to certain streams, expect sequence numbers and
                        // more. See the JetStreamPublishWithOptionsUseCases example for details.
                        // An exception will be thrown if there is a failure.
                        PublishAck pa = js.Publish(msg);
                        Console.WriteLine("Published message '{0}' on subject '{1}', stream '{2}', seqno '{3}'.",
                                          Encoding.UTF8.GetString(data), helper.Subject, pa.Stream, pa.Seq);
                    }
                }
            }
            catch (Exception ex)
            {
                helper.ReportException(ex);
            }
        }
Example #10
0
        public void TestDeliveryPolicy()
        {
            Context.RunInJsServer(c =>
            {
                IJetStreamManagement jsm = c.CreateJetStreamManagementContext();
                IJetStream js            = c.CreateJetStreamContext();

                CreateMemoryStream(jsm, STREAM, SUBJECT_STAR);

                string subjectA = SubjectDot("A");
                string subjectB = SubjectDot("B");

                js.Publish(subjectA, DataBytes(1));
                js.Publish(subjectA, DataBytes(2));
                Thread.Sleep(1500);
                js.Publish(subjectA, DataBytes(3));
                js.Publish(subjectB, DataBytes(91));
                js.Publish(subjectB, DataBytes(92));

                // DeliverPolicy.All
                PushSubscribeOptions pso = PushSubscribeOptions.Builder()
                                           .WithConfiguration(ConsumerConfiguration.Builder().WithDeliverPolicy(DeliverPolicy.All).Build())
                                           .Build();
                IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(subjectA, pso);
                Msg m1 = sub.NextMessage(1000);
                AssertMessage(m1, 1);
                Msg m2 = sub.NextMessage(1000);
                AssertMessage(m2, 2);
                Msg m3 = sub.NextMessage(1000);
                AssertMessage(m3, 3);

                // DeliverPolicy.Last
                pso = PushSubscribeOptions.Builder()
                      .WithConfiguration(ConsumerConfiguration.Builder().WithDeliverPolicy(DeliverPolicy.Last).Build())
                      .Build();
                sub   = js.PushSubscribeSync(subjectA, pso);
                Msg m = sub.NextMessage(1000);
                AssertMessage(m, 3);
                AssertNoMoreMessages(sub);

                // DeliverPolicy.New - No new messages between subscribe and next message
                pso = PushSubscribeOptions.Builder()
                      .WithConfiguration(ConsumerConfiguration.Builder().WithDeliverPolicy(DeliverPolicy.New).Build())
                      .Build();
                sub = js.PushSubscribeSync(subjectA, pso);
                AssertNoMoreMessages(sub);

                // DeliverPolicy.New - New message between subscribe and next message
                sub = js.PushSubscribeSync(subjectA, pso);
                js.Publish(subjectA, DataBytes(4));
                m = sub.NextMessage(1000);
                AssertMessage(m, 4);

                // DeliverPolicy.ByStartSequence
                pso = PushSubscribeOptions.Builder()
                      .WithConfiguration(ConsumerConfiguration.Builder()
                                         .WithDeliverPolicy(DeliverPolicy.ByStartSequence)
                                         .WithStartSequence(3)
                                         .Build())
                      .Build();
                sub = js.PushSubscribeSync(subjectA, pso);
                m   = sub.NextMessage(1000);
                AssertMessage(m, 3);
                m = sub.NextMessage(1000);
                AssertMessage(m, 4);

                // DeliverPolicy.ByStartTime
                pso = PushSubscribeOptions.Builder()
                      .WithConfiguration(ConsumerConfiguration.Builder()
                                         .WithDeliverPolicy(DeliverPolicy.ByStartTime)
                                         .WithStartTime(m3.MetaData.Timestamp.AddSeconds(-1))
                                         .Build())
                      .Build();
                sub = js.PushSubscribeSync(subjectA, pso);
                m   = sub.NextMessage(1000);
                AssertMessage(m, 3);
                m = sub.NextMessage(1000);
                AssertMessage(m, 4);

                // DeliverPolicy.LastPerSubject
                pso = PushSubscribeOptions.Builder()
                      .WithConfiguration(ConsumerConfiguration.Builder()
                                         .WithDeliverPolicy(DeliverPolicy.LastPerSubject)
                                         .WithFilterSubject(subjectA)
                                         .Build())
                      .Build();
                sub = js.PushSubscribeSync(subjectA, pso);
                m   = sub.NextMessage(1000);
                AssertMessage(m, 4);

                // DeliverPolicy.ByStartSequence with a deleted record
                PublishAck pa4 = js.Publish(subjectA, DataBytes(4));
                PublishAck pa5 = js.Publish(subjectA, DataBytes(5));
                js.Publish(subjectA, DataBytes(6));
                jsm.DeleteMessage(STREAM, pa4.Seq);
                jsm.DeleteMessage(STREAM, pa5.Seq);

                pso = ConsumerConfiguration.Builder()
                      .WithDeliverPolicy(DeliverPolicy.ByStartSequence)
                      .WithStartSequence(pa4.Seq)
                      .BuildPushSubscribeOptions();

                sub = js.PushSubscribeSync(subjectA, pso);
                m   = sub.NextMessage(1000);
                AssertMessage(m, 6);
            });
        }
        public static void Main(string[] args)
        {
            ArgumentHelper helper = new ArgumentHelperBuilder("JetStream Publish Async", args, Usage)
                                    .DefaultStream("example-stream")
                                    .DefaultSubject("example-subject")
                                    .DefaultPayload("Hello")
                                    .DefaultCount(10)
                                    .Build();

            try
            {
                using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions()))
                {
                    // Use the utility to create a stream stored in memory.
                    JsUtils.CreateStreamOrUpdateSubjects(c, helper.Stream, helper.Subject);

                    // create a JetStream context
                    IJetStream js = c.CreateJetStreamContext();

                    IList <Task <PublishAck> > tasks = new List <Task <PublishAck> >();

                    int stop = helper.Count < 2 ? 2 : helper.Count + 1;
                    for (int x = 1; x < stop; x++)
                    {
                        // make unique message data if you want more than 1 message
                        byte[] data = helper.Count < 2
                            ? Encoding.UTF8.GetBytes(helper.Payload)
                            : Encoding.UTF8.GetBytes(helper.Payload + "-" + x);

                        // Publish a message and print the results of the publish acknowledgement.
                        Msg msg = new Msg(helper.Subject, null, helper.Header, data);

                        // We'll use the defaults for this simple example, but there are options
                        // to constrain publishing to certain streams, expect sequence numbers and
                        // more. See the JetStreamPublishWithOptionsUseCases example for details.
                        // An exception will be thrown if there is a failure.
                        tasks.Add(js.PublishAsync(msg));

                        while (tasks.Count > 0)
                        {
                            Task <PublishAck> task = tasks[0];
                            tasks.RemoveAt(0);

                            if (task.IsCompleted)
                            {
                                try
                                {
                                    PublishAck pa = task.Result;
                                    Console.WriteLine("Published message {0} on subject {1}, stream {2}, seqno {3}.",
                                                      Encoding.UTF8.GetString(data), helper.Subject, pa.Stream, pa.Seq);
                                }
                                catch (Exception e)
                                {
                                    Console.WriteLine("Publish Failed: " + e);
                                }
                            }
                            else
                            {
                                // re queue so will be checked for completed again
                                tasks.Add(task);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                helper.ReportException(ex);
            }
        }
        public static void Main(string[] args)
        {
            ArgumentHelper helper = new ArgumentHelperBuilder("JetStream Publish With Options Use Cases", args, Usage)
                                    .DefaultStream("pubopts-stream")
                                    .DefaultSubject("pubopts-subject")
                                    .Build();

            try
            {
                using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions()))
                {
                    // Create a JetStreamManagement context.
                    IJetStreamManagement jsm = c.CreateJetStreamManagementContext();

                    // Use the utility to create a stream stored in memory.
                    JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, helper.Subject);

                    // get a regular context
                    IJetStream js = c.CreateJetStreamContext();

                    PublishOptions.PublishOptionsBuilder builder = PublishOptions.Builder()
                                                                   .WithExpectedStream(helper.Stream)
                                                                   .WithMessageId("mid1");

                    PublishAck pa = js.Publish(helper.Subject, Encoding.ASCII.GetBytes("message1"), builder.Build());
                    Console.WriteLine("Published message on subject {0}, stream {1}, seqno {2}.",
                                      helper.Subject, pa.Stream, pa.Seq);

                    // IMPORTANT!
                    // You can reuse the builder in 2 ways.
                    // 1. Manually set a field to null or to DefaultLastSequence if you want to clear it out.
                    // 2. Use the clearExpected method to clear the expectedLastId, expectedLastSequence and messageId fields

                    // Manual re-use 1. Clearing some fields
                    builder
                    .WithExpectedLastMsgId("mid1")
                    .WithExpectedLastSequence(PublishOptions.DefaultLastSequence)
                    .WithMessageId(null);
                    pa = js.Publish(helper.Subject, Encoding.ASCII.GetBytes("message2"), builder.Build());
                    Console.WriteLine("Published message on subject {0}, stream {1}, seqno {2}.",
                                      helper.Subject, pa.Stream, pa.Seq);

                    // Manual re-use 2. Setting all the expected fields again
                    builder
                    .WithExpectedLastMsgId(null)
                    .WithExpectedLastSequence(PublishOptions.DefaultLastSequence)
                    .WithMessageId("mid3");
                    pa = js.Publish(helper.Subject, Encoding.ASCII.GetBytes("message3"), builder.Build());
                    Console.WriteLine("Published message on subject {0}, stream {1}, seqno {2}.",
                                      helper.Subject, pa.Stream, pa.Seq);

                    // reuse() method clears all the fields, then we set some fields.
                    builder.ClearExpected()
                    .WithExpectedLastSequence(pa.Seq)
                    .WithMessageId("mid4");
                    pa = js.Publish(helper.Subject, Encoding.ASCII.GetBytes("message4"), builder.Build());
                    Console.WriteLine("Published message on subject {0}, stream {1}, seqno {2}.",
                                      helper.Subject, pa.Stream, pa.Seq);

                    // exception when the expected stream does not match [10060]
                    try
                    {
                        PublishOptions errOpts = PublishOptions.Builder().WithExpectedStream("wrongStream").Build();
                        js.Publish(helper.Subject, Encoding.ASCII.GetBytes("ex1"), errOpts);
                    }
                    catch (NATSJetStreamException e)
                    {
                        Console.WriteLine($"Exception was: '{e.ErrorDescription}'");
                    }

                    // exception with wrong last msg ID [10070]
                    try
                    {
                        PublishOptions errOpts = PublishOptions.Builder().WithExpectedLastMsgId("wrongId").Build();
                        js.Publish(helper.Subject, Encoding.ASCII.GetBytes("ex2"), errOpts);
                    }
                    catch (NATSJetStreamException e)
                    {
                        Console.WriteLine($"Exception was: '{e.ErrorDescription}'");
                    }

                    // exception with wrong last sequence wrong last sequence: 4 [10071]
                    try
                    {
                        PublishOptions errOpts = PublishOptions.Builder().WithExpectedLastSequence(999).Build();
                        js.Publish(helper.Subject, Encoding.ASCII.GetBytes("ex3"), errOpts);
                    }
                    catch (NATSJetStreamException e)
                    {
                        Console.WriteLine($"Exception was: '{e.ErrorDescription}'");
                    }

                    // delete the stream since we are done with it.
                    jsm.DeleteStream(helper.Stream);
                }
            }
            catch (Exception ex)
            {
                helper.ReportException(ex);
            }
        }
Example #13
0
 private void AssertPublishAck(PublishAck pa, ulong seqno)
 {
     Assert.Equal(STREAM, pa.Stream);
     Assert.Equal(seqno, pa.Seq);
     Assert.False(pa.Duplicate);
 }
Example #14
0
        public void TestPublishExpectations()
        {
            Context.RunInJsServer(c =>
            {
                CreateMemoryStream(c, STREAM, Subject(1), Subject(2));
                IJetStream js = c.CreateJetStreamContext();

                PublishOptions po = PublishOptions.Builder()
                                    .WithExpectedStream(STREAM)
                                    .WithMessageId(MessageId(1))
                                    .Build();
                PublishAck pa = js.Publish(Subject(1), DataBytes(1), po);
                AssertPublishAck(pa, 1);

                po = PublishOptions.Builder()
                     .WithExpectedLastMsgId(MessageId(1))
                     .WithMessageId(MessageId(2))
                     .Build();
                pa = js.Publish(Subject(1), DataBytes(2), po);
                AssertPublishAck(pa, 2);

                po = PublishOptions.Builder()
                     .WithExpectedLastSequence(2)
                     .WithMessageId(MessageId(3))
                     .Build();
                pa = js.Publish(Subject(1), DataBytes(3), po);
                AssertPublishAck(pa, 3);

                po = PublishOptions.Builder()
                     .WithExpectedLastSequence(3)
                     .WithMessageId(MessageId(4))
                     .Build();
                pa = js.Publish(Subject(2), DataBytes(4), po);
                AssertPublishAck(pa, 4);

                po = PublishOptions.Builder()
                     .WithExpectedLastSubjectSequence(3)
                     .WithMessageId(MessageId(5))
                     .Build();
                pa = js.Publish(Subject(1), DataBytes(5), po);
                AssertPublishAck(pa, 5);

                po = PublishOptions.Builder()
                     .WithExpectedLastSubjectSequence(4)
                     .WithMessageId(MessageId(6))
                     .Build();
                pa = js.Publish(Subject(2), DataBytes(6), po);
                AssertPublishAck(pa, 6);

                PublishOptions po1 = PublishOptions.Builder().WithExpectedStream(Stream(999)).Build();
                Assert.Throws <NATSJetStreamException>(() => js.Publish(Subject(1), DataBytes(999), po1));

                PublishOptions po2 = PublishOptions.Builder().WithExpectedLastMsgId(MessageId(999)).Build();
                Assert.Throws <NATSJetStreamException>(() => js.Publish(Subject(1), DataBytes(999), po2));

                PublishOptions po3 = PublishOptions.Builder().WithExpectedLastSequence(999).Build();
                Assert.Throws <NATSJetStreamException>(() => js.Publish(Subject(1), DataBytes(999), po3));

                PublishOptions po4 = PublishOptions.Builder().WithExpectedLastSubjectSequence(999).Build();
                Assert.Throws <NATSJetStreamException>(() => js.Publish(Subject(1), DataBytes(999), po4));
            });
        }
        public void TestGetStreamInfo()
        {
            Context.RunInJsServer(c =>
            {
                IJetStreamManagement jsm = c.CreateJetStreamManagementContext();
                Assert.Throws <NATSJetStreamException>(() => jsm.GetStreamInfo(STREAM));

                String[] subjects = new String[6];
                for (int x = 0; x < 5; x++)
                {
                    subjects[x] = Subject(x);
                }
                subjects[5] = "foo.>";
                CreateMemoryStream(jsm, STREAM, subjects);

                IList <PublishAck> packs = new List <PublishAck>();
                IJetStream js            = c.CreateJetStreamContext();
                for (int x = 0; x < 5; x++)
                {
                    JsPublish(js, Subject(x), x + 1);
                    PublishAck pa = JsPublish(js, Subject(x), Data(x + 2));
                    packs.Add(pa);
                    jsm.DeleteMessage(STREAM, pa.Seq);
                }
                JsPublish(js, "foo.bar", 6);

                StreamInfo si = jsm.GetStreamInfo(STREAM);
                Assert.Equal(STREAM, si.Config.Name);
                Assert.Equal(6, si.State.SubjectCount);
                Assert.Null(si.State.Subjects);
                Assert.Equal(5, si.State.DeletedCount);
                Assert.Empty(si.State.Deleted);

                si = jsm.GetStreamInfo(STREAM,
                                       StreamInfoOptions.Builder()
                                       .WithAllSubjects()
                                       .WithDeletedDetails()
                                       .Build());
                Assert.Equal(STREAM, si.Config.Name);
                Assert.Equal(6, si.State.SubjectCount);
                IList <Subject> list = si.State.Subjects;
                Assert.NotNull(list);
                Assert.Equal(6, list.Count);
                Assert.Equal(5, si.State.DeletedCount);
                Assert.Equal(5, si.State.Deleted.Count);
                Dictionary <string, Subject> map = new Dictionary <string, Subject>();
                foreach (Subject su in list)
                {
                    map[su.Name] = su;
                }
                for (int x = 0; x < 5; x++)
                {
                    Subject subj = map[Subject(x)];
                    Assert.NotNull(subj);
                    Assert.Equal(x + 1, subj.Count);
                }
                Subject s = map["foo.bar"];
                Assert.NotNull(s);
                Assert.Equal(6, s.Count);

                foreach (PublishAck pa in packs)
                {
                    Assert.True(si.State.Deleted.Contains(pa.Seq));
                }
            });
        }