package clusters

import (
	"testing"

	"code.justin.tv/d8a/buddy/lib/config"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/rds"
	"github.com/aws/aws-sdk-go/service/rds/rdsiface"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
)

type MockRDS struct {
	rdsiface.RDSAPI
	mock.Mock
}

func (c MockRDS) DescribeDBInstances(input *rds.DescribeDBInstancesInput) (*rds.DescribeDBInstancesOutput, error) {
	retVal := c.Called(input)
	return retVal.Get(0).(*rds.DescribeDBInstancesOutput), retVal.Error(1)
}

func (c MockRDS) DescribeDBInstancesPages(input *rds.DescribeDBInstancesInput, fn func(p *rds.DescribeDBInstancesOutput, lastPage bool) (shouldContinue bool)) error {
	input.Marker = nil
	input.MaxRecords = aws.Int64(100)

	for {
		resp, err := c.DescribeDBInstances(input)
		if err != nil {
			return err
		}

		if !fn(resp, resp.Marker != nil) || resp.Marker == nil {
			return nil
		}

		input.Marker = resp.Marker
	}
}

func (c MockRDS) DescribeDBClusters(input *rds.DescribeDBClustersInput) (*rds.DescribeDBClustersOutput, error) {
	retVal := c.Called(input)
	return retVal.Get(0).(*rds.DescribeDBClustersOutput), retVal.Error(1)
}

func checkInstances(t *testing.T, instances map[string]*rds.DBInstance, identifiers ...string) {
	require.Len(t, instances, len(identifiers))
	for _, instance := range instances {
		require.Contains(t, identifiers, *instance.DBInstanceIdentifier)
	}
}

func checkClusters(t *testing.T, clusters map[string]*rds.DBCluster, identifiers ...string) {
	require.Len(t, clusters, len(identifiers))
	for _, cluster := range clusters {
		require.Contains(t, identifiers, *cluster.DBClusterIdentifier)
	}
}

func TestSingleTierPostgresFetch(t *testing.T) {
	client := MockRDS{}

	client.On("DescribeDBInstances", &rds.DescribeDBInstancesInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-instance-id"),
				Values: []*string{
					aws.String("test-cluster-master"),
				},
			},
		},
		MaxRecords: aws.Int64(100),
	}).Return(&rds.DescribeDBInstancesOutput{
		DBInstances: []*rds.DBInstance{
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-master"),
				ReadReplicaDBInstanceIdentifiers: []*string{
					aws.String("test-cluster-rep-0"),
					aws.String("test-cluster-rep-1"),
				},
			},
		},
	}, nil)

	client.On("DescribeDBInstances", &rds.DescribeDBInstancesInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-instance-id"),
				Values: []*string{
					aws.String("test-cluster-rep-0"),
					aws.String("test-cluster-rep-1"),
				},
			},
		},
		MaxRecords: aws.Int64(100),
	}).Return(&rds.DescribeDBInstancesOutput{
		DBInstances: []*rds.DBInstance{
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-0"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-master"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-1"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-master"),
			},
		},
	}, nil)

	clusters := config.ClusterList{
		&config.Cluster{
			Name:           "test_cluster",
			RootIdentifier: "test-cluster-master",
		},
	}

	rdsInstances, rdsClusters, errors := FetchMeta(clusters, client)
	require.Nil(t, errors)

	checkInstances(t, rdsInstances, "test-cluster-master", "test-cluster-rep-0", "test-cluster-rep-1")
	require.Empty(t, rdsClusters)

	client.AssertExpectations(t)
}

func TestMultiTierTierPostgresFetch(t *testing.T) {
	client := MockRDS{}

	client.On("DescribeDBInstances", &rds.DescribeDBInstancesInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-instance-id"),
				Values: []*string{
					aws.String("test-cluster-master"),
				},
			},
		},
		MaxRecords: aws.Int64(100),
	}).Return(&rds.DescribeDBInstancesOutput{
		DBInstances: []*rds.DBInstance{
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-master"),
				ReadReplicaDBInstanceIdentifiers: []*string{
					aws.String("test-cluster-rep-0"),
					aws.String("test-cluster-rep-1"),
				},
			},
		},
	}, nil)

	client.On("DescribeDBInstances", &rds.DescribeDBInstancesInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-instance-id"),
				Values: []*string{
					aws.String("test-cluster-rep-0"),
					aws.String("test-cluster-rep-1"),
				},
			},
		},
		MaxRecords: aws.Int64(100),
	}).Return(&rds.DescribeDBInstancesOutput{
		DBInstances: []*rds.DBInstance{
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-0"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-master"),
				ReadReplicaDBInstanceIdentifiers: []*string{
					aws.String("test-cluster-rep-2"),
					aws.String("test-cluster-rep-3"),
				},
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-1"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-master"),
				ReadReplicaDBInstanceIdentifiers: []*string{
					aws.String("test-cluster-rep-4"),
					aws.String("test-cluster-rep-5"),
				},
			},
		},
	}, nil)

	client.On("DescribeDBInstances", &rds.DescribeDBInstancesInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-instance-id"),
				Values: []*string{
					aws.String("test-cluster-rep-2"),
					aws.String("test-cluster-rep-3"),
					aws.String("test-cluster-rep-4"),
					aws.String("test-cluster-rep-5"),
				},
			},
		},
		MaxRecords: aws.Int64(100),
	}).Return(&rds.DescribeDBInstancesOutput{
		DBInstances: []*rds.DBInstance{
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-2"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-rep-0"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-3"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-rep-0"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-4"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-rep-1"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-5"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-rep-1"),
			},
		},
	}, nil)

	clusters := config.ClusterList{
		&config.Cluster{
			Name:           "test_cluster",
			RootIdentifier: "test-cluster-master",
		},
	}

	rdsInstances, rdsClusters, errors := FetchMeta(clusters, client)
	require.Nil(t, errors)
	require.Empty(t, rdsClusters)

	checkInstances(t, rdsInstances, "test-cluster-master", "test-cluster-rep-0", "test-cluster-rep-1", "test-cluster-rep-2", "test-cluster-rep-3", "test-cluster-rep-4", "test-cluster-rep-5")

	client.AssertExpectations(t)
}

func TestThreeTierTierPostgresFetch(t *testing.T) {
	client := MockRDS{}

	client.On("DescribeDBInstances", &rds.DescribeDBInstancesInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-instance-id"),
				Values: []*string{
					aws.String("test-cluster-master"),
				},
			},
		},
		MaxRecords: aws.Int64(100),
	}).Return(&rds.DescribeDBInstancesOutput{
		DBInstances: []*rds.DBInstance{
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-master"),
				ReadReplicaDBInstanceIdentifiers: []*string{
					aws.String("test-cluster-rep-0"),
					aws.String("test-cluster-rep-1"),
				},
			},
		},
	}, nil)

	client.On("DescribeDBInstances", &rds.DescribeDBInstancesInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-instance-id"),
				Values: []*string{
					aws.String("test-cluster-rep-0"),
					aws.String("test-cluster-rep-1"),
				},
			},
		},
		MaxRecords: aws.Int64(100),
	}).Return(&rds.DescribeDBInstancesOutput{
		DBInstances: []*rds.DBInstance{
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-0"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-master"),
				ReadReplicaDBInstanceIdentifiers: []*string{
					aws.String("test-cluster-rep-2"),
				},
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-1"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-master"),
				ReadReplicaDBInstanceIdentifiers: []*string{
					aws.String("test-cluster-rep-4"),
				},
			},
		},
	}, nil)

	client.On("DescribeDBInstances", &rds.DescribeDBInstancesInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-instance-id"),
				Values: []*string{
					aws.String("test-cluster-rep-2"),
					aws.String("test-cluster-rep-4"),
				},
			},
		},
		MaxRecords: aws.Int64(100),
	}).Return(&rds.DescribeDBInstancesOutput{
		DBInstances: []*rds.DBInstance{
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-2"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-rep-0"),
				ReadReplicaDBInstanceIdentifiers: []*string{
					aws.String("test-cluster-rep-3"),
				},
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-4"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-rep-1"),
				ReadReplicaDBInstanceIdentifiers: []*string{
					aws.String("test-cluster-rep-5"),
				},
			},
		},
	}, nil)

	client.On("DescribeDBInstances", &rds.DescribeDBInstancesInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-instance-id"),
				Values: []*string{
					aws.String("test-cluster-rep-3"),
					aws.String("test-cluster-rep-5"),
				},
			},
		},
		MaxRecords: aws.Int64(100),
	}).Return(&rds.DescribeDBInstancesOutput{
		DBInstances: []*rds.DBInstance{
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-3"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-rep-2"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-5"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-rep-4"),
			},
		},
	}, nil)

	clusters := config.ClusterList{
		&config.Cluster{
			Name:           "test_cluster",
			RootIdentifier: "test-cluster-master",
		},
	}

	rdsIdentifiers, rdsClusters, errors := FetchMeta(clusters, client)
	require.Nil(t, errors)
	require.Empty(t, rdsClusters)

	checkInstances(t, rdsIdentifiers, "test-cluster-master", "test-cluster-rep-0", "test-cluster-rep-1", "test-cluster-rep-2", "test-cluster-rep-3", "test-cluster-rep-4", "test-cluster-rep-5")

	client.AssertExpectations(t)
}

func TestSingleClusterAuroraFetch(t *testing.T) {
	client := MockRDS{}

	client.On("DescribeDBClusters", &rds.DescribeDBClustersInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-cluster-id"),
				Values: []*string{
					aws.String("test-cluster"),
				},
			},
		},
	}).Return(&rds.DescribeDBClustersOutput{
		DBClusters: []*rds.DBCluster{
			&rds.DBCluster{
				DBClusterIdentifier: aws.String("test-cluster"),
				DBClusterMembers: []*rds.DBClusterMember{
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-master"),
						IsClusterWriter:      aws.Bool(true),
					},
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-rep-0"),
						IsClusterWriter:      aws.Bool(false),
					},
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-rep-1"),
						IsClusterWriter:      aws.Bool(false),
					},
				},
			},
		},
	}, nil)

	client.On("DescribeDBInstances", &rds.DescribeDBInstancesInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-instance-id"),
				Values: []*string{
					aws.String("test-cluster-master"),
					aws.String("test-cluster-rep-0"),
					aws.String("test-cluster-rep-1"),
				},
			},
		},
		MaxRecords: aws.Int64(100),
	}).Return(&rds.DescribeDBInstancesOutput{
		DBInstances: []*rds.DBInstance{
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-master"),
				DBClusterIdentifier:  aws.String("test-cluster"),
				ReadReplicaDBInstanceIdentifiers: []*string{
					aws.String("test-cluster-rep-0"),
					aws.String("test-cluster-rep-1"),
				},
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-0"),
				DBClusterIdentifier:                   aws.String("test-cluster"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-master"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-1"),
				DBClusterIdentifier:                   aws.String("test-cluster"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-master"),
			},
		},
	}, nil)

	clusters := config.ClusterList{
		&config.Cluster{
			Name:           "test_cluster",
			RootIdentifier: "test-cluster",
			IsAurora:       true,
		},
	}

	rdsInstances, rdsClusters, errors := FetchMeta(clusters, client)
	require.Nil(t, errors)

	checkClusters(t, rdsClusters, "test-cluster")
	checkInstances(t, rdsInstances, "test-cluster-master", "test-cluster-rep-0", "test-cluster-rep-1")

	client.AssertExpectations(t)
}

func TestMultiClusterAuroraFetch(t *testing.T) {
	client := MockRDS{}

	client.On("DescribeDBClusters", &rds.DescribeDBClustersInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-cluster-id"),
				Values: []*string{
					aws.String("test-cluster"),
				},
			},
		},
	}).Return(&rds.DescribeDBClustersOutput{
		DBClusters: []*rds.DBCluster{
			&rds.DBCluster{
				DBClusterIdentifier: aws.String("test-cluster"),
				DBClusterMembers: []*rds.DBClusterMember{
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-master"),
						IsClusterWriter:      aws.Bool(true),
					},
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-rep-0"),
						IsClusterWriter:      aws.Bool(false),
					},
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-rep-1"),
						IsClusterWriter:      aws.Bool(false),
					},
				},
				ReadReplicaIdentifiers: []*string{
					aws.String("test-cluster-a"),
					aws.String("test-cluster-b"),
				},
			},
		},
	}, nil)

	client.On("DescribeDBClusters", &rds.DescribeDBClustersInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-cluster-id"),
				Values: []*string{
					aws.String("test-cluster-a"),
					aws.String("test-cluster-b"),
				},
			},
		},
	}).Return(&rds.DescribeDBClustersOutput{
		DBClusters: []*rds.DBCluster{
			&rds.DBCluster{
				DBClusterIdentifier: aws.String("test-cluster-a"),
				DBClusterMembers: []*rds.DBClusterMember{
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-a-master"),
						IsClusterWriter:      aws.Bool(true),
					},
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-a-rep-0"),
						IsClusterWriter:      aws.Bool(false),
					},
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-a-rep-1"),
						IsClusterWriter:      aws.Bool(false),
					},
				},
				ReplicationSourceIdentifier: aws.String("test-cluster"),
			},
			&rds.DBCluster{
				DBClusterIdentifier: aws.String("test-cluster-b"),
				DBClusterMembers: []*rds.DBClusterMember{
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-b-master"),
						IsClusterWriter:      aws.Bool(true),
					},
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-b-rep-0"),
						IsClusterWriter:      aws.Bool(false),
					},
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-b-rep-1"),
						IsClusterWriter:      aws.Bool(false),
					},
				},
				ReplicationSourceIdentifier: aws.String("test-cluster"),
			},
		},
	}, nil)

	client.On("DescribeDBInstances", &rds.DescribeDBInstancesInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-instance-id"),
				Values: []*string{
					aws.String("test-cluster-master"),
					aws.String("test-cluster-rep-0"),
					aws.String("test-cluster-rep-1"),
					aws.String("test-cluster-a-master"),
					aws.String("test-cluster-a-rep-0"),
					aws.String("test-cluster-a-rep-1"),
					aws.String("test-cluster-b-master"),
					aws.String("test-cluster-b-rep-0"),
					aws.String("test-cluster-b-rep-1"),
				},
			},
		},
		MaxRecords: aws.Int64(100),
	}).Return(&rds.DescribeDBInstancesOutput{
		DBInstances: []*rds.DBInstance{
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-master"),
				DBClusterIdentifier:  aws.String("test-cluster"),
				ReadReplicaDBInstanceIdentifiers: []*string{
					aws.String("test-cluster-rep-0"),
					aws.String("test-cluster-rep-1"),
				},
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-0"),
				DBClusterIdentifier:                   aws.String("test-cluster"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-master"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-1"),
				DBClusterIdentifier:                   aws.String("test-cluster"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-master"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-a-master"),
				DBClusterIdentifier:  aws.String("test-cluster-a"),
				ReadReplicaDBInstanceIdentifiers: []*string{
					aws.String("test-cluster-a-rep-0"),
					aws.String("test-cluster-a-rep-1"),
				},
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-a-rep-0"),
				DBClusterIdentifier:                   aws.String("test-cluster-a"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-a-master"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-a-rep-1"),
				DBClusterIdentifier:                   aws.String("test-cluster-a"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-a-master"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-b-master"),
				DBClusterIdentifier:  aws.String("test-cluster-b"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-b-rep-0"),
				DBClusterIdentifier:  aws.String("test-cluster-b"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-b-rep-1"),
				DBClusterIdentifier:  aws.String("test-cluster-b"),
			},
		},
	}, nil)

	clusters := config.ClusterList{
		&config.Cluster{
			Name:           "test_cluster",
			RootIdentifier: "test-cluster",
			IsAurora:       true,
		},
	}

	rdsInstances, rdsClusters, errors := FetchMeta(clusters, client)
	require.Nil(t, errors)

	checkClusters(t, rdsClusters, "test-cluster", "test-cluster-a", "test-cluster-b")
	checkInstances(t, rdsInstances, "test-cluster-master", "test-cluster-rep-0", "test-cluster-rep-1", "test-cluster-a-master", "test-cluster-a-rep-0", "test-cluster-a-rep-1", "test-cluster-b-master", "test-cluster-b-rep-0", "test-cluster-b-rep-1")

	client.AssertExpectations(t)
}

func TestThreeTierClusterAuroraFetch(t *testing.T) {
	client := MockRDS{}

	client.On("DescribeDBClusters", &rds.DescribeDBClustersInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-cluster-id"),
				Values: []*string{
					aws.String("test-cluster"),
				},
			},
		},
	}).Return(&rds.DescribeDBClustersOutput{
		DBClusters: []*rds.DBCluster{
			&rds.DBCluster{
				DBClusterIdentifier: aws.String("test-cluster"),
				DBClusterMembers: []*rds.DBClusterMember{
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-master"),
						IsClusterWriter:      aws.Bool(true),
					},
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-rep-0"),
						IsClusterWriter:      aws.Bool(false),
					},
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-rep-1"),
						IsClusterWriter:      aws.Bool(false),
					},
				},
				ReadReplicaIdentifiers: []*string{
					aws.String("test-cluster-a"),
					aws.String("test-cluster-b"),
				},
			},
		},
	}, nil)

	client.On("DescribeDBClusters", &rds.DescribeDBClustersInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-cluster-id"),
				Values: []*string{
					aws.String("test-cluster-a"),
					aws.String("test-cluster-b"),
				},
			},
		},
	}).Return(&rds.DescribeDBClustersOutput{
		DBClusters: []*rds.DBCluster{
			&rds.DBCluster{
				DBClusterIdentifier: aws.String("test-cluster-a"),
				DBClusterMembers: []*rds.DBClusterMember{
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-a-master"),
						IsClusterWriter:      aws.Bool(true),
					},
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-a-rep-0"),
						IsClusterWriter:      aws.Bool(false),
					},
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-a-rep-1"),
						IsClusterWriter:      aws.Bool(false),
					},
				},
				ReplicationSourceIdentifier: aws.String("test-cluster"),
				ReadReplicaIdentifiers: []*string{
					aws.String("test-cluster-c"),
				},
			},
			&rds.DBCluster{
				DBClusterIdentifier: aws.String("test-cluster-b"),
				DBClusterMembers: []*rds.DBClusterMember{
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-b-master"),
						IsClusterWriter:      aws.Bool(true),
					},
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-b-rep-0"),
						IsClusterWriter:      aws.Bool(false),
					},
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-b-rep-1"),
						IsClusterWriter:      aws.Bool(false),
					},
				},
				ReplicationSourceIdentifier: aws.String("test-cluster"),
				ReadReplicaIdentifiers: []*string{
					aws.String("test-cluster-d"),
				},
			},
		},
	}, nil)

	client.On("DescribeDBClusters", &rds.DescribeDBClustersInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-cluster-id"),
				Values: []*string{
					aws.String("test-cluster-c"),
					aws.String("test-cluster-d"),
				},
			},
		},
	}).Return(&rds.DescribeDBClustersOutput{
		DBClusters: []*rds.DBCluster{
			&rds.DBCluster{
				DBClusterIdentifier: aws.String("test-cluster-c"),
				DBClusterMembers: []*rds.DBClusterMember{
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-c-master"),
						IsClusterWriter:      aws.Bool(true),
					},
				},
				ReplicationSourceIdentifier: aws.String("test-cluster-a"),
			},
			&rds.DBCluster{
				DBClusterIdentifier: aws.String("test-cluster-d"),
				DBClusterMembers: []*rds.DBClusterMember{
					&rds.DBClusterMember{
						DBInstanceIdentifier: aws.String("test-cluster-d-master"),
						IsClusterWriter:      aws.Bool(true),
					},
				},
				ReplicationSourceIdentifier: aws.String("test-cluster-b"),
			},
		},
	}, nil)

	client.On("DescribeDBInstances", &rds.DescribeDBInstancesInput{
		Filters: []*rds.Filter{
			&rds.Filter{
				Name: aws.String("db-instance-id"),
				Values: []*string{
					aws.String("test-cluster-master"),
					aws.String("test-cluster-rep-0"),
					aws.String("test-cluster-rep-1"),
					aws.String("test-cluster-a-master"),
					aws.String("test-cluster-a-rep-0"),
					aws.String("test-cluster-a-rep-1"),
					aws.String("test-cluster-b-master"),
					aws.String("test-cluster-b-rep-0"),
					aws.String("test-cluster-b-rep-1"),
					aws.String("test-cluster-c-master"),
					aws.String("test-cluster-d-master"),
				},
			},
		},
		MaxRecords: aws.Int64(100),
	}).Return(&rds.DescribeDBInstancesOutput{
		DBInstances: []*rds.DBInstance{
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-master"),
				DBClusterIdentifier:  aws.String("test-cluster"),
				ReadReplicaDBInstanceIdentifiers: []*string{
					aws.String("test-cluster-rep-0"),
					aws.String("test-cluster-rep-1"),
				},
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-0"),
				DBClusterIdentifier:                   aws.String("test-cluster"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-master"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-rep-1"),
				DBClusterIdentifier:                   aws.String("test-cluster"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-master"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-a-master"),
				DBClusterIdentifier:  aws.String("test-cluster-a"),
				ReadReplicaDBInstanceIdentifiers: []*string{
					aws.String("test-cluster-a-rep-0"),
					aws.String("test-cluster-a-rep-1"),
				},
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-a-rep-0"),
				DBClusterIdentifier:                   aws.String("test-cluster-a"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-a-master"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier:                  aws.String("test-cluster-a-rep-1"),
				DBClusterIdentifier:                   aws.String("test-cluster-a"),
				ReadReplicaSourceDBInstanceIdentifier: aws.String("test-cluster-a-master"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-b-master"),
				DBClusterIdentifier:  aws.String("test-cluster-b"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-b-rep-0"),
				DBClusterIdentifier:  aws.String("test-cluster-b"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-b-rep-1"),
				DBClusterIdentifier:  aws.String("test-cluster-b"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-c-master"),
				DBClusterIdentifier:  aws.String("test-cluster-c"),
			},
			&rds.DBInstance{
				DBInstanceIdentifier: aws.String("test-cluster-d-master"),
				DBClusterIdentifier:  aws.String("test-cluster-d"),
			},
		},
	}, nil)

	clusters := config.ClusterList{
		&config.Cluster{
			Name:           "test_cluster",
			RootIdentifier: "test-cluster",
			IsAurora:       true,
		},
	}

	rdsInstances, rdsClusters, errors := FetchMeta(clusters, client)
	require.Nil(t, errors)

	checkClusters(t, rdsClusters, "test-cluster", "test-cluster-a", "test-cluster-b", "test-cluster-c", "test-cluster-d")
	checkInstances(t, rdsInstances, "test-cluster-master", "test-cluster-rep-0", "test-cluster-rep-1",
		"test-cluster-a-master", "test-cluster-a-rep-0", "test-cluster-a-rep-1", "test-cluster-b-master",
		"test-cluster-b-rep-0", "test-cluster-b-rep-1", "test-cluster-c-master", "test-cluster-d-master")

	client.AssertExpectations(t)
}
