Exemple #1
0
        public async Task InMemoryMarketResolver_Integration_AgreementCancelledScenario()
        {
            // Test scenario

            // Subscribe Demand

            var(demandSubscription, offerSubscription, offerProposal) = await this.DoDefaultDemandOfferMatching();

            // OK, we got an offer proposal, let's haggle a bit...

            var lastOfferProposal = await this.DoSimpleOfferNegotiation(demandSubscription, offerSubscription, offerProposal);

            // OK, so the reqEvents2 now contains an offer which is acceptable.
            // Requestor can move on to propose Agreement...

            var agreement = RequestorProcessor.CreateAgreement(lastOfferProposal.Id);

            Assert.IsNotNull(agreement);
            Assert.AreEqual(lastOfferProposal.Id, agreement.Id);
            Assert.AreEqual(AgreementState.New, agreement.State);
            Assert.IsNotNull(agreement.Demand);

            // Confirm and start waiting for Agreement proposal response
            AgreementResultEnum?agreementResponse = null;

            Task.Run(async() =>
            {
                agreementResponse = await RequestorProcessor.ConfirmAgreementAsync(agreement.Id, 5000);

                Assert.IsNotNull(agreementResponse);
            });

            Thread.Sleep(500); // wait a little to allow the Confirm to be sent, and then...

            RequestorProcessor.CancelAgreement(agreement.Id);

            // ...in the meantime - collect the Agreement proposal on Provider side and send response

            var provEvents3 = await ProviderProcessor.CollectProviderEventsAsync(offerSubscription.Id, 100000, 10);

            // TODO in Cancel implementation...
            // If Agreement Proposal hasn't been yet collected - simply remove it from pipeline
            // otherwise - block the agreement response pipeline with some cancel token
            // so that attempt to Approve ends with Agreement cancelled error...


            Assert.IsTrue(provEvents3.Any());
            var receivedAgreementProposal = provEvents3.First();

            Assert.AreEqual(MarketProviderEvent.MarketProviderEventType.AgreementProposal, receivedAgreementProposal.EventType);

            ProviderProcessor.RejectAgreement(receivedAgreementProposal.Agreement.Id);

            Thread.Sleep(1000);

            Assert.AreEqual(AgreementResultEnum.Rejected, agreementResponse);

            DoSubscriptionCleanup(demandSubscription, offerSubscription);
        }
        public async Task InMemoryMarketResolver_Integration_SimplePositiveScenario()
        {
            // Test scenario

            // Subscribe Demand

            var(demandSubscription, offerSubscription, offerProposal) = await this.DoDefaultDemandOfferMatching();

            // OK, we got an offer proposal, let's haggle a bit...

            var lastOfferProposal = await this.DoSimpleOfferNegotiation(demandSubscription, offerSubscription, offerProposal);

            // OK, so the reqEvents2 now contains an offer which is acceptable.
            // Requestor can move on to propose Agreement...

            var agreement = RequestorProcessor.CreateAgreement(lastOfferProposal.Id, System.DateTime.Now);

            Assert.IsNotNull(agreement);
            Assert.AreEqual(lastOfferProposal.Id, agreement.Id);
            Assert.AreEqual(AgreementState.Proposal, agreement.State);
            Assert.IsNotNull(agreement.DemandProposal);

            // Confirm and start waiting for Agreement proposal response
            AgreementResultEnum?agreementResponse = null;

            Task.Run(async() =>
            {
                agreementResponse = await RequestorProcessor.ConfirmAgreementAsync(agreement.Id, 5.000f);

                Assert.IsNotNull(agreementResponse);
            });


            // ...in the meantime - collect the Agreement proposal on Provider side and send response

            var provEvents3 = await ProviderProcessor.CollectProviderEventsAsync(offerSubscription.Id, 100.000f, 10);

            Assert.IsTrue(provEvents3.Any());
            var receivedAgreementProposal = provEvents3.First();

            Assert.AreEqual(MarketProviderEvent.MarketProviderEventType.AgreementProposal, receivedAgreementProposal.EventType);

            ProviderProcessor.ApproveAgreement(receivedAgreementProposal.Agreement.Id);

            Thread.Sleep(1000);

            Assert.AreEqual(AgreementResultEnum.Approved, agreementResponse);



            // run another collect on Provider side - allegedly this returns a Proposal Event again???

            var provEvents4 = await ProviderProcessor.CollectProviderEventsAsync(offerSubscription.Id, 5.000f, 10);

            Assert.IsFalse(provEvents4.Any());

            DoSubscriptionCleanup(demandSubscription, offerSubscription);
        }
Exemple #3
0
        /// <summary>
        /// Perform the matching part of the Market API basic scenario.
        /// </summary>
        /// <returns></returns>
        public async Task <(DemandSubscription, OfferSubscription, OfferProposal)> DoDefaultDemandOfferMatching()
        {
            // Subscribe Demand

            var demand = new Demand()
            {
                Constraints = @"(&" +
                              @"(golem.srv.comp.container.docker.image=golemfactory/ffmpeg)" +
                              @"(golem.srv.comp.container.docker.benchmark{golemfactory/ffmpeg}>300)" +
                              @"(golem.com.payment.scheme=after)" +
                              @"(golem.usage.vector=[golem.usage.duration_sec])" +
                              @"(golem.com.pricing.model=linear)" +
                                           //@"(golem.com.pricing.est{[30]}<125)" +
                              @")",
                NodeId     = "RequestorA", // must be assigned from the outside
                Properties = new Dictionary <string, string>()
            };

            var demandSubscription = RequestorProcessor.SubscribeDemand(demand);


            Assert.IsNotNull(demandSubscription.Id);
            Assert.IsNotNull(demandSubscription.Demand);
            Assert.IsNull(demandSubscription.LastReceivedProposalId);

            // Subscribe Offers

            var offer1 = new Offer()
            {
                Constraints = "()",
                NodeId      = "ProviderA",
                Properties  = new Dictionary <string, string>()
                {
                    { "golem.srv.comp.container.docker.image", @"[""golemfactory/ffmpeg""]" },
                    { "golem.srv.comp.container.docker.benchmark{golemfactory/ffmpeg}", @"7" },
                    { "golem.srv.comp.container.docker.benchmark{*}", null },
                    { "golem.inf.cpu.cores", @"4" },
                    { "golem.inf.cpu.threads", @"8" },
                    { "golem.inf.mem.gib", @"16" },
                    { "golem.inf.storage.gib", @"30" },
                    { "golem.usage.vector", @"[""golem.usage.duration_sec""]" },
                    { "golem.com.payment.scheme", @"""after""" },
                    { "golem.com.pricing.model", @"""linear""" },
                    { "golem.com.pricing.est{*}", null },
                }
            };

            var offer2 = new Offer()
            {
                Constraints = "()",
                NodeId      = "ProviderB",
                Properties  = new Dictionary <string, string>()
                {
                    { "golem.srv.comp.container.docker.image", @"[""golemfactory/ffmpeg""]" },
                    { "golem.srv.comp.container.docker.benchmark{golemfactory/ffmpeg}", @"723" },
                    { "golem.srv.comp.container.docker.benchmark{*}", null },
                    { "golem.inf.cpu.cores", @"4" },
                    { "golem.inf.cpu.threads", @"8" },
                    { "golem.inf.mem.gib", @"16" },
                    { "golem.inf.storage.gib", @"30" },
                    { "golem.usage.vector", @"[""golem.usage.duration_sec""]" },
                    { "golem.com.payment.scheme", @"""after""" },
                    { "golem.com.pricing.model", @"""linear""" },
                    { "golem.com.pricing.est{*}", null },
                }
            };

            var offer1Subscription = ProviderProcessor.SubscribeOffer(offer1);
            var offer2Subscription = ProviderProcessor.SubscribeOffer(offer2);

            Assert.IsNotNull(offer1Subscription.Id);
            Assert.IsNotNull(offer1Subscription.Offer);
            Assert.IsNull(offer1Subscription.LastReceivedProposalId);

            Assert.IsNotNull(offer2Subscription.Id);
            Assert.IsNotNull(offer2Subscription.Offer);
            Assert.IsNull(offer2Subscription.LastReceivedProposalId);


            // ...at this point in scenario, the Collect on Requestor side should return an offer already...

            var reqEvents = await RequestorProcessor.CollectRequestorEventsAsync(demandSubscription.Id, 1000, 10);

            var offerProposal = reqEvents.First();

            Assert.IsTrue(reqEvents.Any());

            // note that these should not be equal
            // (SubscriptionId as perceived by Provider is different than Offer Proposal Id as seen by the Requestor)
            Assert.AreNotEqual(offer2Subscription.Id, offerProposal.OfferProposal.Id);

            return(demandSubscription, offer2Subscription, offerProposal.OfferProposal);
        }
Exemple #4
0
        public async Task <OfferProposal> DoSimpleOfferNegotiation(DemandSubscription demandSubscription, OfferSubscription offerSubscription, OfferProposal offerProposal)
        {
            // OK, we got an offer proposal, we can now send a direct Demand counterproposal

            var counterDemand = new Demand()
            {
                Constraints = @"(&" +
                              @"(golem.srv.comp.container.docker.image=golemfactory/ffmpeg)" +
                              @"(golem.srv.comp.container.docker.benchmark{golemfactory/ffmpeg}>300)" +
                              @"(golem.com.payment.scheme=after)" +
                              @"(golem.usage.vector=[golem.usage.duration_sec])" +
                              @"(golem.com.pricing.model=linear)" +
                              @"(golem.com.pricing.model.linear.coeffs=*)" +
                                           //@"(golem.com.pricing.est{[30]}<125)" +
                              @")",
                NodeId     = "RequestorA", // must be assigned from the outside
                Properties = new Dictionary <string, string>()
            };

            var counterDemandProposal = RequestorProcessor.CreateDemandProposal(demandSubscription.Id, offerProposal.Id, counterDemand);

            // At this point, the Provider should be able to read the Demand Proposal on the Offer subscription

            var provEvents = await ProviderProcessor.CollectProviderEventsAsync(offerSubscription.Id, 1000, 10);

            Assert.IsTrue(provEvents.Any());
            Assert.AreEqual(counterDemandProposal.Id, provEvents.First().DemandProposal.Id);
            Assert.AreEqual(offerProposal.Id, provEvents.First().DemandProposal.OfferId);

            // ...if we call again - there should be no proposals, so a timeout is expected after 100ms
            var provEvents2 = await ProviderProcessor.CollectProviderEventsAsync(offerSubscription.Id, 100, 10);

            Assert.IsFalse(provEvents2.Any());

            // Now test the blocking logic of Collect - hang on Collect on Requestor side, while Provider sends counter-offer

            ICollection <MarketRequestorEvent> reqEvents2 = null;

            Task.Run(async() =>
            {
                reqEvents2 = await RequestorProcessor.CollectRequestorEventsAsync(demandSubscription.Id, 5000, 10);

                Assert.IsTrue(reqEvents2.Any());
            });

            // ...and prepare counter-offer with price

            var counterOffer = new Offer()
            {
                Constraints = "()",
                NodeId      = "ProviderB",
                Properties  = new Dictionary <string, string>()
                {
                    { "golem.srv.comp.container.docker.image", @"[""golemfactory/ffmpeg""]" },
                    { "golem.srv.comp.container.docker.benchmark{golemfactory/ffmpeg}", @"723" },
                    { "golem.srv.comp.container.docker.benchmark{*}", null },
                    { "golem.inf.cpu.cores", @"4" },
                    { "golem.inf.cpu.threads", @"8" },
                    { "golem.inf.mem.gib", @"16" },
                    { "golem.inf.storage.gib", @"30" },
                    { "golem.usage.vector", @"[""golem.usage.duration_sec""]" },
                    { "golem.com.payment.scheme", @"""after""" },
                    { "golem.com.pricing.model", @"""linear""" },
                    { "golem.com.pricing.model.linear.coeffs", @"[0, 0.2]" },
                    { "golem.com.pricing.est{*}", null },
                }
            };

            var counterOfferProposal = ProviderProcessor.CreateOfferProposal(offerSubscription.Id, provEvents.First().DemandProposal.Id, counterOffer);

            Thread.Sleep(1000);

            Assert.IsTrue(reqEvents2.Any());
            Assert.AreEqual(counterDemandProposal.Id, reqEvents2.First().OfferProposal.DemandId);

            return(reqEvents2.First().OfferProposal);
        }