public async Task PutGetLifecycleConfigurationTest(S3Provider provider, string _, ISimpleClient client)
    {
        await CreateTempBucketAsync(provider, client, async tempBucket =>
        {
            S3Rule rule1 = new S3Rule("Transition logs after 30 days to StandardIa and after 60 days to OneZoneIa", true);
            rule1.Transitions.Add(new S3Transition(30, StorageClass.StandardIa));
            rule1.Transitions.Add(new S3Transition(60, StorageClass.OneZoneIa));
            rule1.Filter = new S3Filter {
                Prefix = "logs/"
            };

            S3Rule rule2     = new S3Rule("Expire temp folder after 5 days", true);
            rule2.Expiration = new S3Expiration(5);
            rule2.Filter     = new S3Filter {
                Prefix = "temp/"
            };

            S3Rule rule3     = new S3Rule("Expire things tagged with temp tomorrow", false); //disabled
            rule3.Expiration = new S3Expiration(DateTimeOffset.UtcNow.AddDays(1));
            rule3.Filter     = new S3Filter {
                Tag = new KeyValuePair <string, string>("type", "temp")
            };

            PutBucketLifecycleConfigurationResponse putResp = await client.PutBucketLifecycleConfigurationAsync(tempBucket, new[] { rule1, rule2, rule3 }).ConfigureAwait(false);
            Assert.True(putResp.IsSuccess);

            GetBucketLifecycleConfigurationResponse getResp = await client.GetBucketLifecycleConfigurationAsync(tempBucket).ConfigureAwait(false);
            Assert.True(getResp.IsSuccess);

            S3Rule rule1A = getResp.Rules[0];
            Assert.Equal(rule1.Id, rule1A.Id);
            Assert.Equal(rule1.Enabled, rule1A.Enabled);
            Assert.Equal(rule1.Filter.Prefix, rule1A.Filter?.Prefix);
            Assert.Equal(rule1.Transitions[0].StorageClass, rule1A.Transitions[0].StorageClass);
            Assert.Equal(rule1.Transitions[0].TransitionAfterDays, rule1A.Transitions[0].TransitionAfterDays);
            Assert.Equal(rule1.Transitions[1].StorageClass, rule1A.Transitions[1].StorageClass);
            Assert.Equal(rule1.Transitions[1].TransitionAfterDays, rule1A.Transitions[1].TransitionAfterDays);

            S3Rule rule2A = getResp.Rules[1];
            Assert.Equal(rule2.Id, rule2A.Id);
            Assert.Equal(rule2.Enabled, rule2A.Enabled);
            Assert.Equal(rule2.Filter.Prefix, rule2A.Filter?.Prefix);
            Assert.Equal(rule2.Expiration.ExpireAfterDays, rule2A.Expiration?.ExpireAfterDays);

            S3Rule rule3A = getResp.Rules[2];
            Assert.Equal(rule3.Id, rule3A.Id);
            Assert.Equal(rule3.Enabled, rule3A.Enabled);
            Assert.Equal(rule3.Filter.Tag, rule3A.Filter?.Tag);
            Assert.Equal(rule3.Expiration.ExpireOnDate?.Date, rule3A.Expiration?.ExpireOnDate?.Date); //Amazon round the date to the day instead
        }).ConfigureAwait(false);
    }
    private static void ReadRule(GetBucketLifecycleConfigurationResponse response, XmlReader xmlReader)
    {
        string?id                 = null;
        bool?  status             = null;
        int?   abortMultipartDays = null;
        int?   nonCurrentDays     = null;
        IList <S3NonCurrentVersionTransition>?nonCurrentVersionTransitions = null;
        S3Expiration?        expiration  = null;
        S3Filter?            filter      = null;
        IList <S3Transition>?transitions = null;

        foreach (string name in XmlHelper.ReadElements(xmlReader, "Rule"))
        {
            switch (name)
            {
            case "ID":
                id = xmlReader.ReadString();
                break;

            case "Status":
                status = xmlReader.ReadString() == "Enabled";
                break;

            case "AbortIncompleteMultipartUpload":
                xmlReader.ReadToDescendant("DaysAfterInitiation");
                abortMultipartDays = ValueHelper.ParseInt(xmlReader.ReadString());
                break;

            case "Expiration":
                expiration = ReadExpiration(xmlReader);
                break;

            case "Filter":
                filter = ReadFilter(xmlReader);
                break;

            case "NoncurrentVersionExpiration":
                xmlReader.ReadToDescendant("NoncurrentDays");
                abortMultipartDays = ValueHelper.ParseInt(xmlReader.ReadString());
                break;

            case "NoncurrentVersionTransition":
                nonCurrentVersionTransitions ??= new List <S3NonCurrentVersionTransition>();
                ReadNonCurrentVersionTransition(nonCurrentVersionTransitions, xmlReader);
                break;

            case "Transition":
                transitions ??= new List <S3Transition>();
                ReadTransition(transitions, xmlReader);
                break;
            }
        }

        if (id == null || status == null)
        {
            throw new InvalidOperationException("Missing required values");
        }

        S3Rule rule = new S3Rule(id, status.Value);

        rule.AbortIncompleteMultipartUploadDays = abortMultipartDays;
        rule.Expiration = expiration;
        rule.Filter     = filter;
        rule.NonCurrentVersionExpirationDays = nonCurrentDays;

        if (nonCurrentVersionTransitions != null)
        {
            foreach (S3NonCurrentVersionTransition transition in nonCurrentVersionTransitions)
            {
                rule.NonCurrentVersionTransitions.Add(transition);
            }
        }

        if (transitions != null)
        {
            foreach (S3Transition transition in transitions)
            {
                rule.Transitions.Add(transition);
            }
        }

        response.Rules.Add(rule);
    }