# Copyright 2018 Google Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# ----------------------------------------------------------------------------
#
#     ***     AUTO GENERATED CODE    ***    AUTO GENERATED CODE     ***
#
# ----------------------------------------------------------------------------
#
#     This file is automatically generated by Magic Modules and manual
#     changes will be clobbered when the file is regenerated.
#
#     Please read more about how to change this file in README.md and
#     CONTRIBUTING.md located at the root of this package.
#
# ----------------------------------------------------------------------------

require 'spec_helper'

describe Puppet::Type.type(:gcompute_target_pool).provider(:google) do
  before(:all) do
    cred = Google::FakeAuthorization.new
    Puppet::Type.type(:gauth_credential)
                .define_singleton_method(:fetch) { |_resource| cred }
  end

  it '#instances' do
    expect { described_class.instances }.to raise_error(StandardError,
                                                        /not supported/)
  end

  context 'ensure == present' do
    context 'resource exists' do
      # Ensure present: resource exists, no change
      context 'no changes == no action' do
        # Ensure present: resource exists, no change, no name
        context 'title == name' do
          # Ensure present: resource exists, no change, no name, pass
          context 'title == name (pass)' do
            before do
              allow(Time).to receive(:now).and_return(
                Time.new(2017, 1, 2, 3, 4, 5)
              )
              expect_network_get_success 1, name: 'title0', region: 'test name#0 data'
              expect_network_get_success 2, name: 'title1', region: 'test name#1 data'
              expect_network_get_success 3, name: 'title2', region: 'test name#2 data'
              expect_network_get_success_http_health_check 1
              expect_network_get_success_http_health_check 2
              expect_network_get_success_http_health_check 3
              expect_network_get_success_zone 1
              expect_network_get_success_zone 2
              expect_network_get_success_zone 3
              expect_network_get_success_instance 1, zone: 'test name#0 data'
              expect_network_get_success_instance 2, zone: 'test name#1 data'
              expect_network_get_success_instance 3, zone: 'test name#2 data'
              expect_network_get_success_region 1
              expect_network_get_success_region 2
              expect_network_get_success_region 3
            end

            let(:catalog) do
              apply_with_error_check(
                <<-MANIFEST
                gcompute_http_health_check { 'resource(http_health_check,0)':
                  ensure     => present,
                  name       => 'test name#0 data',
                  project    => 'test project#0 data',
                  credential => 'cred0',
                }

                gcompute_http_health_check { 'resource(http_health_check,1)':
                  ensure     => present,
                  name       => 'test name#1 data',
                  project    => 'test project#1 data',
                  credential => 'cred1',
                }

                gcompute_http_health_check { 'resource(http_health_check,2)':
                  ensure     => present,
                  name       => 'test name#2 data',
                  project    => 'test project#2 data',
                  credential => 'cred2',
                }

                gcompute_zone { 'resource(zone,0)':
                  name       => 'test name#0 data',
                  project    => 'test project#0 data',
                  credential => 'cred0',
                }

                gcompute_zone { 'resource(zone,1)':
                  name       => 'test name#1 data',
                  project    => 'test project#1 data',
                  credential => 'cred1',
                }

                gcompute_zone { 'resource(zone,2)':
                  name       => 'test name#2 data',
                  project    => 'test project#2 data',
                  credential => 'cred2',
                }

                gcompute_instance { 'resource(instance,0)':
                  ensure     => present,
                  name       => 'test name#0 data',
                  zone       => 'resource(zone,0)',
                  project    => 'test project#0 data',
                  credential => 'cred0',
                }

                gcompute_instance { 'resource(instance,1)':
                  ensure     => present,
                  name       => 'test name#1 data',
                  zone       => 'resource(zone,1)',
                  project    => 'test project#1 data',
                  credential => 'cred1',
                }

                gcompute_instance { 'resource(instance,2)':
                  ensure     => present,
                  name       => 'test name#2 data',
                  zone       => 'resource(zone,2)',
                  project    => 'test project#2 data',
                  credential => 'cred2',
                }

                gcompute_region { 'resource(region,0)':
                  name       => 'test name#0 data',
                  project    => 'test project#0 data',
                  credential => 'cred0',
                }

                gcompute_region { 'resource(region,1)':
                  name       => 'test name#1 data',
                  project    => 'test project#1 data',
                  credential => 'cred1',
                }

                gcompute_region { 'resource(region,2)':
                  name       => 'test name#2 data',
                  project    => 'test project#2 data',
                  credential => 'cred2',
                }

                gcompute_target_pool { 'title0':
                  ensure           => present,
                  backup_pool      => 'resource(target_pool,0)',
                  description      => 'test description#0 data',
                  failover_ratio   => 14369408.15,
                  health_check     => 'resource(http_health_check,0)',
                  instances        => ['resource(instance,0)'],
                  region           => 'resource(region,0)',
                  session_affinity => 'NONE',
                  project          => 'test project#0 data',
                  credential       => 'cred0',
                }

                gcompute_target_pool { 'title1':
                  ensure           => present,
                  backup_pool      => 'resource(target_pool,1)',
                  description      => 'test description#1 data',
                  failover_ratio   => 28738816.31,
                  health_check     => 'resource(http_health_check,1)',
                  instances        => ['resource(instance,0)', 'resource(instance,1)', 'resource(instance,2)'],
                  region           => 'resource(region,1)',
                  session_affinity => 'CLIENT_IP',
                  project          => 'test project#1 data',
                  credential       => 'cred1',
                }

                gcompute_target_pool { 'title2':
                  ensure           => present,
                  backup_pool      => 'resource(target_pool,2)',
                  description      => 'test description#2 data',
                  failover_ratio   => 43108224.47,
                  health_check     => 'resource(http_health_check,2)',
                  instances        => ['resource(instance,0)'],
                  region           => 'resource(region,2)',
                  session_affinity => 'CLIENT_IP_PROTO',
                  project          => 'test project#2 data',
                  credential       => 'cred2',
                }
                MANIFEST
              ).catalog
            end

            context 'Gcompute_target_pool[title0]' do
              subject do
                catalog.resource('Gcompute_target_pool[title0]').provider
              end

              it 'was expected to be present', broken: true do
                pending('Implement tests where object references its own type.')
              end
            end

            context 'Gcompute_target_pool[title1]' do
              subject do
                catalog.resource('Gcompute_target_pool[title1]').provider
              end

              it 'was expected to be present', broken: true do
                pending('Implement tests where object references its own type.')
              end
            end

            context 'Gcompute_target_pool[title2]' do
              subject do
                catalog.resource('Gcompute_target_pool[title2]').provider
              end

              it 'was expected to be present', broken: true do
                pending('Implement tests where object references its own type.')
              end
            end
          end

          # Ensure present: resource exists, no change, no name, fail
          context 'title == name (fail)' do
            # TODO(nelsonjr): Implement new test format.
            subject { -> { raise '[placeholder] This should fail.' } }
            it { is_expected.to raise_error(RuntimeError, /placeholder/) }
          end
        end

        # Ensure present: resource exists, no change, has name
        context 'title != name' do
          # Ensure present: resource exists, no change, has name, pass
          context 'title != name (pass)' do
            before do
              allow(Time).to receive(:now).and_return(
                Time.new(2017, 1, 2, 3, 4, 5)
              )
              expect_network_get_success 1, region: 'test name#0 data'
              expect_network_get_success 2, region: 'test name#1 data'
              expect_network_get_success 3, region: 'test name#2 data'
              expect_network_get_success_http_health_check 1
              expect_network_get_success_http_health_check 2
              expect_network_get_success_http_health_check 3
              expect_network_get_success_zone 1
              expect_network_get_success_zone 2
              expect_network_get_success_zone 3
              expect_network_get_success_instance 1, zone: 'test name#0 data'
              expect_network_get_success_instance 2, zone: 'test name#1 data'
              expect_network_get_success_instance 3, zone: 'test name#2 data'
              expect_network_get_success_region 1
              expect_network_get_success_region 2
              expect_network_get_success_region 3
            end

            let(:catalog) do
              apply_with_error_check(
                <<-MANIFEST
                gcompute_http_health_check { 'resource(http_health_check,0)':
                  ensure     => present,
                  name       => 'test name#0 data',
                  project    => 'test project#0 data',
                  credential => 'cred0',
                }

                gcompute_http_health_check { 'resource(http_health_check,1)':
                  ensure     => present,
                  name       => 'test name#1 data',
                  project    => 'test project#1 data',
                  credential => 'cred1',
                }

                gcompute_http_health_check { 'resource(http_health_check,2)':
                  ensure     => present,
                  name       => 'test name#2 data',
                  project    => 'test project#2 data',
                  credential => 'cred2',
                }

                gcompute_zone { 'resource(zone,0)':
                  name       => 'test name#0 data',
                  project    => 'test project#0 data',
                  credential => 'cred0',
                }

                gcompute_zone { 'resource(zone,1)':
                  name       => 'test name#1 data',
                  project    => 'test project#1 data',
                  credential => 'cred1',
                }

                gcompute_zone { 'resource(zone,2)':
                  name       => 'test name#2 data',
                  project    => 'test project#2 data',
                  credential => 'cred2',
                }

                gcompute_instance { 'resource(instance,0)':
                  ensure     => present,
                  name       => 'test name#0 data',
                  zone       => 'resource(zone,0)',
                  project    => 'test project#0 data',
                  credential => 'cred0',
                }

                gcompute_instance { 'resource(instance,1)':
                  ensure     => present,
                  name       => 'test name#1 data',
                  zone       => 'resource(zone,1)',
                  project    => 'test project#1 data',
                  credential => 'cred1',
                }

                gcompute_instance { 'resource(instance,2)':
                  ensure     => present,
                  name       => 'test name#2 data',
                  zone       => 'resource(zone,2)',
                  project    => 'test project#2 data',
                  credential => 'cred2',
                }

                gcompute_region { 'resource(region,0)':
                  name       => 'test name#0 data',
                  project    => 'test project#0 data',
                  credential => 'cred0',
                }

                gcompute_region { 'resource(region,1)':
                  name       => 'test name#1 data',
                  project    => 'test project#1 data',
                  credential => 'cred1',
                }

                gcompute_region { 'resource(region,2)':
                  name       => 'test name#2 data',
                  project    => 'test project#2 data',
                  credential => 'cred2',
                }

                gcompute_target_pool { 'title0':
                  ensure           => present,
                  backup_pool      => 'resource(target_pool,0)',
                  description      => 'test description#0 data',
                  failover_ratio   => 14369408.15,
                  health_check     => 'resource(http_health_check,0)',
                  instances        => ['resource(instance,0)'],
                  name             => 'test name#0 data',
                  region           => 'resource(region,0)',
                  session_affinity => 'NONE',
                  project          => 'test project#0 data',
                  credential       => 'cred0',
                }

                gcompute_target_pool { 'title1':
                  ensure           => present,
                  backup_pool      => 'resource(target_pool,1)',
                  description      => 'test description#1 data',
                  failover_ratio   => 28738816.31,
                  health_check     => 'resource(http_health_check,1)',
                  instances        => ['resource(instance,0)', 'resource(instance,1)', 'resource(instance,2)'],
                  name             => 'test name#1 data',
                  region           => 'resource(region,1)',
                  session_affinity => 'CLIENT_IP',
                  project          => 'test project#1 data',
                  credential       => 'cred1',
                }

                gcompute_target_pool { 'title2':
                  ensure           => present,
                  backup_pool      => 'resource(target_pool,2)',
                  description      => 'test description#2 data',
                  failover_ratio   => 43108224.47,
                  health_check     => 'resource(http_health_check,2)',
                  instances        => ['resource(instance,0)'],
                  name             => 'test name#2 data',
                  region           => 'resource(region,2)',
                  session_affinity => 'CLIENT_IP_PROTO',
                  project          => 'test project#2 data',
                  credential       => 'cred2',
                }
                MANIFEST
              ).catalog
            end

            context 'Gcompute_target_pool[title0]' do
              subject do
                catalog.resource('Gcompute_target_pool[title0]').provider
              end

              it 'was expected to be present', broken: true do
                pending('Implement tests where object references its own type.')
              end
            end

            context 'Gcompute_target_pool[title1]' do
              subject do
                catalog.resource('Gcompute_target_pool[title1]').provider
              end

              it 'was expected to be present', broken: true do
                pending('Implement tests where object references its own type.')
              end
            end

            context 'Gcompute_target_pool[title2]' do
              subject do
                catalog.resource('Gcompute_target_pool[title2]').provider
              end

              it 'was expected to be present', broken: true do
                pending('Implement tests where object references its own type.')
              end
            end
          end

          # Ensure present: resource exists, no change, has name, fail
          context 'title != name (fail)' do
            # TODO(nelsonjr): Implement new test format.
            subject { -> { raise '[placeholder] This should fail.' } }
            it { is_expected.to raise_error(RuntimeError, /placeholder/) }
          end
        end
      end

      # Ensure present: resource exists, changes
      context 'changes == action' do
        # Ensure present: resource exists, changes, no name
        context 'title == name' do
          # Ensure present: resource exists, changes, no name, pass
          context 'title == name (pass)' do
            # TODO(nelsonjr): Implement new test format.
          end

          # Ensure present: resource exists, changes, no name, fail
          context 'title == name (fail)' do
            # TODO(nelsonjr): Implement new test format.
            subject { -> { raise '[placeholder] This should fail.' } }
            it { is_expected.to raise_error(RuntimeError, /placeholder/) }
          end
        end

        # Ensure present: resource exists, changes, has name
        context 'title != name' do
          # Ensure present: resource exists, changes, has name, pass
          context 'title != name (pass)' do
            # TODO(nelsonjr): Implement new test format.
          end

          # Ensure present: resource exists, changes, has name, fail
          context 'title != name (fail)' do
            # TODO(nelsonjr): Implement new test format.
            subject { -> { raise '[placeholder] This should fail.' } }
            it { is_expected.to raise_error(RuntimeError, /placeholder/) }
          end
        end
      end
    end

    context 'resource missing' do
      # Ensure present: resource missing, ignore, no name
      context 'title == name' do
        # Ensure present: resource missing, ignore, no name, pass
        context 'title == name (pass)' do
          before(:each) do
            expect_network_get_failed 1, name: 'title0', region: 'test name#0 data'
            expect_network_create \
              1,
              {
                'kind' => 'compute#targetPool',
                'backupPool' => 'selflink(resource(target_pool,0))',
                'description' => 'test description#0 data',
                'failoverRatio' => 14_369_408.15,
                'healthCheck' => 'selflink(resource(http_health_check,0))',
                'instances' => [
                  'selflink(resource(instance,0))'
                ],
                'name' => 'title0',
                'sessionAffinity' => 'NONE'
              },
              name: 'title0',
              region: 'test name#0 data'
            expect_network_get_async 1, name: 'title0', region: 'test name#0 data'
            expect_network_get_success_http_health_check 1
            expect_network_get_success_zone 1
            expect_network_get_success_instance 1, zone: 'test name#0 data'
            expect_network_get_success_region 1
          end

          subject do
            apply_with_error_check(
              <<-MANIFEST
              gcompute_http_health_check { 'resource(http_health_check,0)':
                ensure     => present,
                name       => 'test name#0 data',
                project    => 'test project#0 data',
                credential => 'cred0',
              }

              gcompute_zone { 'resource(zone,0)':
                name       => 'test name#0 data',
                project    => 'test project#0 data',
                credential => 'cred0',
              }

              gcompute_instance { 'resource(instance,0)':
                ensure     => present,
                name       => 'test name#0 data',
                zone       => 'resource(zone,0)',
                project    => 'test project#0 data',
                credential => 'cred0',
              }

              gcompute_region { 'resource(region,0)':
                name       => 'test name#0 data',
                project    => 'test project#0 data',
                credential => 'cred0',
              }

              gcompute_target_pool { 'title0':
                ensure           => present,
                backup_pool      => 'resource(target_pool,0)',
                description      => 'test description#0 data',
                failover_ratio   => 14369408.15,
                health_check     => 'resource(http_health_check,0)',
                instances        => ['resource(instance,0)'],
                region           => 'resource(region,0)',
                session_affinity => 'NONE',
                project          => 'test project#0 data',
                credential       => 'cred0',
              }
              MANIFEST
            ).catalog.resource('Gcompute_target_pool[title0]').provider.ensure
          end

          it 'was expected to be present', broken: true do
            pending('Implement tests where object references its own type.')
          end
        end

        # Ensure present: resource missing, ignore, no name, fail
        context 'title == name (fail)' do
          # TODO(nelsonjr): Implement new test format.
          subject { -> { raise '[placeholder] This should fail.' } }
          it { is_expected.to raise_error(RuntimeError, /placeholder/) }
        end
      end

      # Ensure present: resource missing, ignore, has name
      context 'title != name' do
        # Ensure present: resource missing, ignore, has name, pass
        context 'title != name (pass)' do
          before(:each) do
            expect_network_get_failed 1, region: 'test name#0 data'
            expect_network_create \
              1,
              {
                'kind' => 'compute#targetPool',
                'backupPool' => 'selflink(resource(target_pool,0))',
                'description' => 'test description#0 data',
                'failoverRatio' => 14_369_408.15,
                'healthCheck' => 'selflink(resource(http_health_check,0))',
                'instances' => [
                  'selflink(resource(instance,0))'
                ],
                'name' => 'test name#0 data',
                'sessionAffinity' => 'NONE'
              },
              region: 'test name#0 data'
            expect_network_get_async 1, region: 'test name#0 data'
            expect_network_get_success_http_health_check 1
            expect_network_get_success_zone 1
            expect_network_get_success_instance 1, zone: 'test name#0 data'
            expect_network_get_success_region 1
          end

          subject do
            apply_with_error_check(
              <<-MANIFEST
              gcompute_http_health_check { 'resource(http_health_check,0)':
                ensure     => present,
                name       => 'test name#0 data',
                project    => 'test project#0 data',
                credential => 'cred0',
              }

              gcompute_zone { 'resource(zone,0)':
                name       => 'test name#0 data',
                project    => 'test project#0 data',
                credential => 'cred0',
              }

              gcompute_instance { 'resource(instance,0)':
                ensure     => present,
                name       => 'test name#0 data',
                zone       => 'resource(zone,0)',
                project    => 'test project#0 data',
                credential => 'cred0',
              }

              gcompute_region { 'resource(region,0)':
                name       => 'test name#0 data',
                project    => 'test project#0 data',
                credential => 'cred0',
              }

              gcompute_target_pool { 'title0':
                ensure           => present,
                backup_pool      => 'resource(target_pool,0)',
                description      => 'test description#0 data',
                failover_ratio   => 14369408.15,
                health_check     => 'resource(http_health_check,0)',
                instances        => ['resource(instance,0)'],
                name             => 'test name#0 data',
                region           => 'resource(region,0)',
                session_affinity => 'NONE',
                project          => 'test project#0 data',
                credential       => 'cred0',
              }
              MANIFEST
            ).catalog.resource('Gcompute_target_pool[title0]').provider.ensure
          end

          it 'was expected to be present', broken: true do
            pending('Implement tests where object references its own type.')
          end
        end

        # Ensure present: resource missing, ignore, has name, fail
        context 'title != name (fail)' do
          # TODO(nelsonjr): Implement new test format.
          subject { -> { raise '[placeholder] This should fail.' } }
          it { is_expected.to raise_error(RuntimeError, /placeholder/) }
        end
      end
    end
  end

  context 'ensure == absent' do
    context 'resource missing' do
      # Ensure absent: resource missing, ignore, no name
      context 'title == name' do
        # Ensure absent: resource missing, ignore, no name, pass
        context 'title == name (pass)' do
          before(:each) do
            expect_network_get_failed 1, name: 'title0', region: 'test name#0 data'
            expect_network_get_success_region 1
          end

          subject do
            apply_with_error_check(
              <<-MANIFEST
              gcompute_region { 'resource(region,0)':
                name       => 'test name#0 data',
                project    => 'test project#0 data',
                credential => 'cred0',
              }

              gcompute_target_pool { 'title0':
                ensure     => absent,
                region     => 'resource(region,0)',
                project    => 'test project#0 data',
                credential => 'cred0',
              }
              MANIFEST
            ).catalog.resource('Gcompute_target_pool[title0]')
              .provider.ensure
          end

          it { is_expected.to eq :absent }
        end

        # Ensure absent: resource missing, ignore, no name, fail
        context 'title == name (fail)' do
          # TODO(nelsonjr): Implement new test format.
          subject { -> { raise '[placeholder] This should fail.' } }
          it { is_expected.to raise_error(RuntimeError, /placeholder/) }
        end
      end

      # Ensure absent: resource missing, ignore, has name
      context 'title != name' do
        # Ensure absent: resource missing, ignore, has name, pass
        context 'title != name (pass)' do
          before(:each) do
            expect_network_get_failed 1, region: 'test name#0 data'
            expect_network_get_success_region 1
          end

          subject do
            apply_with_error_check(
              <<-MANIFEST
              gcompute_region { 'resource(region,0)':
                name       => 'test name#0 data',
                project    => 'test project#0 data',
                credential => 'cred0',
              }

              gcompute_target_pool { 'title0':
                ensure     => absent,
                name       => 'test name#0 data',
                region     => 'resource(region,0)',
                project    => 'test project#0 data',
                credential => 'cred0',
              }
              MANIFEST
            ).catalog.resource('Gcompute_target_pool[title0]')
              .provider.ensure
          end

          it { is_expected.to eq :absent }
        end

        # Ensure absent: resource missing, ignore, has name, fail
        context 'title != name (fail)' do
          # TODO(nelsonjr): Implement new test format.
          subject { -> { raise '[placeholder] This should fail.' } }
          it { is_expected.to raise_error(RuntimeError, /placeholder/) }
        end
      end
    end

    context 'resource exists' do
      # Ensure absent: resource exists, ignore, no name
      context 'title == name' do
        # Ensure absent: resource exists, ignore, no name, pass
        context 'title == name (pass)' do
          before(:each) do
            expect_network_get_success 1, name: 'title0', region: 'test name#0 data'
            expect_network_delete 1, 'title0', region: 'test name#0 data'
            expect_network_get_async 1, name: 'title0', region: 'test name#0 data'
            expect_network_get_success_region 1
          end

          subject do
            apply_with_error_check(
              <<-MANIFEST
              gcompute_region { 'resource(region,0)':
                name       => 'test name#0 data',
                project    => 'test project#0 data',
                credential => 'cred0',
              }

              gcompute_target_pool { 'title0':
                ensure     => absent,
                region     => 'resource(region,0)',
                project    => 'test project#0 data',
                credential => 'cred0',
              }
              MANIFEST
            ).catalog.resource('Gcompute_target_pool[title0]')
              .provider.ensure
          end

          it { is_expected.to eq :absent }
        end

        # Ensure absent: resource exists, ignore, no name, fail
        context 'title == name (fail)' do
          # TODO(nelsonjr): Implement new test format.
          subject { -> { raise '[placeholder] This should fail.' } }
          it { is_expected.to raise_error(RuntimeError, /placeholder/) }
        end
      end

      # Ensure absent: resource exists, ignore, has name
      context 'title != name' do
        # Ensure absent: resource exists, ignore, has name, pass
        context 'title != name (pass)' do
          before(:each) do
            expect_network_get_success 1, region: 'test name#0 data'
            expect_network_delete 1, nil, region: 'test name#0 data'
            expect_network_get_async 1, region: 'test name#0 data'
            expect_network_get_success_region 1
          end

          subject do
            apply_with_error_check(
              <<-MANIFEST
              gcompute_region { 'resource(region,0)':
                name       => 'test name#0 data',
                project    => 'test project#0 data',
                credential => 'cred0',
              }

              gcompute_target_pool { 'title0':
                ensure     => absent,
                name       => 'test name#0 data',
                region     => 'resource(region,0)',
                project    => 'test project#0 data',
                credential => 'cred0',
              }
              MANIFEST
            ).catalog.resource('Gcompute_target_pool[title0]')
              .provider.ensure
          end

          it { is_expected.to eq :absent }
        end

        # Ensure absent: resource exists, ignore, has name, fail
        context 'title != name (fail)' do
          # TODO(nelsonjr): Implement new test format.
          subject { -> { raise '[placeholder] This should fail.' } }
          it { is_expected.to raise_error(RuntimeError, /placeholder/) }
        end
      end
    end
  end

  context '#flush' do
    subject do
      Puppet::Type.type(:gcompute_target_pool).new(
        ensure: :present,
        name: 'my-name'
      ).provider
    end
    context 'no-op' do
      it { subject.flush }
    end
    context 'modified object' do
      before do
        subject.dirty :some_property, 'current', 'newvalue'
      end
      context 'no-op if created' do
        before { subject.instance_variable_set(:@created, true) }
        it { expect { subject.flush }.not_to raise_error }
      end
      context 'no-op if deleted' do
        before { subject.instance_variable_set(:@deleted, true) }
        it { expect { subject.flush }.not_to raise_error }
      end
    end
  end

  private

  def expect_network_get_success(id, data = {})
    id_data = data.fetch(:name, '').include?('title') ? 'title' : 'name'
    body = load_network_result("success#{id}~#{id_data}.yaml").to_json

    request = double('request')
    allow(request).to receive(:send).and_return(http_success(body))

    debug_network "!! GET #{self_link(uri_data(id).merge(data))}"
    expect(Google::Compute::Network::Get).to receive(:new)
      .with(self_link(uri_data(id).merge(data)),
            instance_of(Google::FakeAuthorization)) do |args|
      debug_network ">> GET #{args}"
      request
    end
  end

  def http_success(body)
    response = Net::HTTPOK.new(1.0, 200, 'OK')
    response.body = body
    response.instance_variable_set(:@read, true)
    response
  end

  def expect_network_get_async(id, data = {})
    body = { kind: 'compute#targetPool' }.to_json

    request = double('request')
    allow(request).to receive(:send).and_return(http_success(body))

    debug_network "!! #{self_link(uri_data(id).merge(data))}"
    expect(Google::Compute::Network::Get).to receive(:new)
      .with(self_link(uri_data(id).merge(data)),
            instance_of(Google::FakeAuthorization)) do |args|
      debug_network ">> GET <async> #{args}"
      request
    end
  end

  def expect_network_get_failed(id, data = {})
    request = double('request')
    allow(request).to receive(:send).and_return(http_failed_object_missing)

    debug_network "!! #{self_link(uri_data(id).merge(data))}"
    expect(Google::Compute::Network::Get).to receive(:new)
      .with(self_link(uri_data(id).merge(data)),
            instance_of(Google::FakeAuthorization)) do |args|
      debug_network ">> GET [failed] #{args}"
      request
    end
  end

  def http_failed_object_missing
    Net::HTTPNotFound.new(1.0, 404, 'Not Found')
  end

  def expect_network_create(id, expected_body, data = {})
    merged_uri = uri_data(id).merge(data)
    body = { kind: 'compute#operation',
             status: 'DONE', targetLink: self_link(merged_uri) }.to_json

    # Remove refs that are also part of the body
    expected_body = Hash[expected_body.map do |k, v|
      [k.is_a?(Symbol) ? k.id2name : k, v]
    end]

    # Encode the object to conform with the API
    expected_body = encode_request(expected_body)
    request = double('request')
    allow(request).to receive(:send).and_return(http_success(body))

    debug_network "!! POST #{collection(merged_uri)}"
    expect(Google::Compute::Network::Post).to receive(:new)
      .with(collection(merged_uri), instance_of(Google::FakeAuthorization),
            'application/json', expected_body.to_json) do |args|
      debug_network ">> POST #{args} = body(#{body})"
      request
    end
  end

  def expect_network_delete(id, name = nil, data = {})
    delete_data = uri_data(id).merge(data)
    delete_data[:name] = name unless name.nil?
    body = { kind: 'compute#operation',
             status: 'DONE',
             targetLink: self_link(delete_data) }.to_json

    request = double('request')
    allow(request).to receive(:send).and_return(http_success(body))

    debug_network "!! DELETE #{self_link(delete_data)}"
    expect(Google::Compute::Network::Delete).to receive(:new)
      .with(self_link(delete_data),
            instance_of(Google::FakeAuthorization)) do |args|
      debug_network ">> DELETE #{args}"
      request
    end
  end

  def load_network_result(file)
    results = File.join(File.dirname(__FILE__), 'data', 'network',
                        'gcompute_target_pool', file)
    debug("Loading result file: #{results}")
    raise "Network result data file #{results}" unless File.exist?(results)
    data = YAML.safe_load(File.read(results))
    raise "Invalid network results #{results}" unless data.class <= Hash
    data
  end

  def expect_network_get_success_http_health_check(id, data = {})
    id_data = data.fetch(:name, '').include?('title') ? 'title' : 'name'
    body = load_network_result_http_health_check("success#{id}~" \
                                                           "#{id_data}.yaml")
           .to_json
    uri = uri_data_http_health_check(id).merge(data)

    request = double('request')
    allow(request).to receive(:send).and_return(http_success(body))

    debug_network "!! GET #{uri}"
    expect(Google::Compute::Network::Get).to receive(:new)
      .with(self_link_http_health_check(uri),
            instance_of(Google::FakeAuthorization)) do |args|
      debug_network ">> GET #{args}"
      request
    end
  end

  def load_network_result_http_health_check(file)
    results = File.join(File.dirname(__FILE__), 'data', 'network',
                        'gcompute_http_health_check', file)
    raise "Network result data file #{results}" unless File.exist?(results)
    data = YAML.safe_load(File.read(results))
    raise "Invalid network results #{results}" unless data.class <= Hash
    data
  end

  # Creates variable test data to comply with self_link URI parameters
  # Only used for gcompute_http_health_check objects
  def uri_data_http_health_check(id)
    {
      project: GoogleTests::Constants::HHC_PROJECT_DATA[(id - 1) \
        % GoogleTests::Constants::HHC_PROJECT_DATA.size],
      name: GoogleTests::Constants::HHC_NAME_DATA[(id - 1) \
        % GoogleTests::Constants::HHC_NAME_DATA.size]
    }
  end

  def self_link_http_health_check(data)
    URI.join(
      'https://www.googleapis.com/compute/v1/',
      expand_variables_http_health_check(
        'projects/{{project}}/global/httpHealthChecks/{{name}}',
        data
      )
    )
  end

  def expect_network_get_success_instance(id, data = {})
    id_data = data.fetch(:name, '').include?('title') ? 'title' : 'name'
    body = load_network_result_instance("success#{id}~" \
                                                           "#{id_data}.yaml")
           .to_json
    uri = uri_data_instance(id).merge(data)

    request = double('request')
    allow(request).to receive(:send).and_return(http_success(body))

    debug_network "!! GET #{uri}"
    expect(Google::Compute::Network::Get).to receive(:new)
      .with(self_link_instance(uri),
            instance_of(Google::FakeAuthorization)) do |args|
      debug_network ">> GET #{args}"
      request
    end
  end

  def load_network_result_instance(file)
    results = File.join(File.dirname(__FILE__), 'data', 'network',
                        'gcompute_instance', file)
    raise "Network result data file #{results}" unless File.exist?(results)
    data = YAML.safe_load(File.read(results))
    raise "Invalid network results #{results}" unless data.class <= Hash
    data
  end

  # Creates variable test data to comply with self_link URI parameters
  # Only used for gcompute_instance objects
  def uri_data_instance(id)
    {
      project: GoogleTests::Constants::I_PROJECT_DATA[(id - 1) \
        % GoogleTests::Constants::I_PROJECT_DATA.size],
      zone: GoogleTests::Constants::I_ZONE_DATA[(id - 1) \
        % GoogleTests::Constants::I_ZONE_DATA.size],
      name: GoogleTests::Constants::I_NAME_DATA[(id - 1) \
        % GoogleTests::Constants::I_NAME_DATA.size]
    }
  end

  def self_link_instance(data)
    URI.join(
      'https://www.googleapis.com/compute/v1/',
      expand_variables_instance(
        'projects/{{project}}/zones/{{zone}}/instances/{{name}}',
        data
      )
    )
  end

  def expect_network_get_success_zone(id, data = {})
    id_data = data.fetch(:name, '').include?('title') ? 'title' : 'name'
    body = load_network_result_zone("success#{id}~" \
                                                           "#{id_data}.yaml")
           .to_json
    uri = uri_data_zone(id).merge(data)

    request = double('request')
    allow(request).to receive(:send).and_return(http_success(body))

    debug_network "!! GET #{uri}"
    expect(Google::Compute::Network::Get).to receive(:new)
      .with(self_link_zone(uri),
            instance_of(Google::FakeAuthorization)) do |args|
      debug_network ">> GET #{args}"
      request
    end
  end

  def load_network_result_zone(file)
    results = File.join(File.dirname(__FILE__), 'data', 'network',
                        'gcompute_zone', file)
    raise "Network result data file #{results}" unless File.exist?(results)
    data = YAML.safe_load(File.read(results))
    raise "Invalid network results #{results}" unless data.class <= Hash
    data
  end

  # Creates variable test data to comply with self_link URI parameters
  # Only used for gcompute_zone objects
  def uri_data_zone(id)
    {
      project: GoogleTests::Constants::Z_PROJECT_DATA[(id - 1) \
        % GoogleTests::Constants::Z_PROJECT_DATA.size],
      name: GoogleTests::Constants::Z_NAME_DATA[(id - 1) \
        % GoogleTests::Constants::Z_NAME_DATA.size]
    }
  end

  def self_link_zone(data)
    URI.join(
      'https://www.googleapis.com/compute/v1/',
      expand_variables_zone(
        'projects/{{project}}/zones/{{name}}',
        data
      )
    )
  end

  def expect_network_get_success_region(id, data = {})
    id_data = data.fetch(:name, '').include?('title') ? 'title' : 'name'
    body = load_network_result_region("success#{id}~" \
                                                           "#{id_data}.yaml")
           .to_json
    uri = uri_data_region(id).merge(data)

    request = double('request')
    allow(request).to receive(:send).and_return(http_success(body))

    debug_network "!! GET #{uri}"
    expect(Google::Compute::Network::Get).to receive(:new)
      .with(self_link_region(uri),
            instance_of(Google::FakeAuthorization)) do |args|
      debug_network ">> GET #{args}"
      request
    end
  end

  def load_network_result_region(file)
    results = File.join(File.dirname(__FILE__), 'data', 'network',
                        'gcompute_region', file)
    raise "Network result data file #{results}" unless File.exist?(results)
    data = YAML.safe_load(File.read(results))
    raise "Invalid network results #{results}" unless data.class <= Hash
    data
  end

  # Creates variable test data to comply with self_link URI parameters
  # Only used for gcompute_region objects
  def uri_data_region(id)
    {
      project: GoogleTests::Constants::R_PROJECT_DATA[(id - 1) \
        % GoogleTests::Constants::R_PROJECT_DATA.size],
      name: GoogleTests::Constants::R_NAME_DATA[(id - 1) \
        % GoogleTests::Constants::R_NAME_DATA.size]
    }
  end

  def self_link_region(data)
    URI.join(
      'https://www.googleapis.com/compute/v1/',
      expand_variables_region(
        'projects/{{project}}/regions/{{name}}',
        data
      )
    )
  end

  def debug(message)
    puts(message) if ENV['RSPEC_DEBUG']
  end

  def debug_network(message)
    puts("Network #{message}") \
      if ENV['RSPEC_DEBUG'] || ENV['RSPEC_HTTP_VERBOSE']
  end

  def expand_variables_http_health_check(template, data, ext_dat = {})
    Puppet::Type.type(:gcompute_http_health_check).provider(:google)
                .expand_variables(template, data, ext_dat)
  end

  def expand_variables_instance(template, data, ext_dat = {})
    Puppet::Type.type(:gcompute_instance).provider(:google)
                .expand_variables(template, data, ext_dat)
  end

  def expand_variables_zone(template, data, ext_dat = {})
    Puppet::Type.type(:gcompute_zone).provider(:google)
                .expand_variables(template, data, ext_dat)
  end

  def expand_variables_region(template, data, ext_dat = {})
    Puppet::Type.type(:gcompute_region).provider(:google)
                .expand_variables(template, data, ext_dat)
  end

  def create_type(id)
    Puppet::Type.type(:gcompute_target_pool).new(
      ensure: :present,
      title: "title#{id - 1}",
      credential: "cred#{id - 1}",
      project: GoogleTests::Constants::TP_PROJECT_DATA[(id - 1) \
        % GoogleTests::Constants::TP_PROJECT_DATA.size],
      region: GoogleTests::Constants::TP_REGION_DATA[(id - 1) \
        % GoogleTests::Constants::TP_REGION_DATA.size],
      name: GoogleTests::Constants::TP_NAME_DATA[(id - 1) \
        % GoogleTests::Constants::TP_NAME_DATA.size]
    )
  end

  def expand_variables(template, data, extra_data = {})
    Puppet::Type.type(:gcompute_target_pool).provider(:google)
                .expand_variables(template, data, extra_data)
  end

  def encode_request(resource)
    Puppet::Type.type(:gcompute_target_pool).provider(:google)
                .encode_request(resource)
  end

  def collection(data)
    URI.join(
      'https://www.googleapis.com/compute/v1/',
      expand_variables(
        'projects/{{project}}/regions/{{region}}/targetPools',
        data
      )
    )
  end

  def self_link(data)
    URI.join(
      'https://www.googleapis.com/compute/v1/',
      expand_variables(
        'projects/{{project}}/regions/{{region}}/targetPools/{{name}}',
        data
      )
    )
  end

  # Creates variable test data to comply with self_link URI parameters
  def uri_data(id)
    {
      project: GoogleTests::Constants::TP_PROJECT_DATA[(id - 1) \
        % GoogleTests::Constants::TP_PROJECT_DATA.size],
      region: GoogleTests::Constants::TP_REGION_DATA[(id - 1) \
        % GoogleTests::Constants::TP_REGION_DATA.size],
      name: GoogleTests::Constants::TP_NAME_DATA[(id - 1) \
        % GoogleTests::Constants::TP_NAME_DATA.size]
    }
  end
end
